Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

419 lines
15 KiB

  1. /****************************************************************************
  2. ** COPYRIGHT (C) 1994-1997 INTEL CORPORATION **
  3. ** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON **
  4. ** HTTP://WWW.INTEL.COM/ **
  5. ** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND **
  6. ** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER **
  7. ****************************************************************************/
  8. /****************************************************************************
  9. Module Name:
  10. routines.c
  11. This driver runs on the following hardware:
  12. - 82558 based PCI 10/100Mb ethernet adapters
  13. (aka Intel EtherExpress(TM) PRO Adapters)
  14. Environment:
  15. Kernel Mode - Or whatever is the equivalent on WinNT
  16. Revision History
  17. - JCB 8/14/97 Example Driver Created
  18. - Dchen 11-01-99 Modified for the new sample driver
  19. *****************************************************************************/
  20. #include "precomp.h"
  21. #pragma hdrstop
  22. #pragma warning (disable: 4514 4706)
  23. //-----------------------------------------------------------------------------
  24. // Procedure: MdiWrite
  25. //
  26. // Description: This routine will write a value to the specified MII register
  27. // of an external MDI compliant device (e.g. PHY 100). The
  28. // command will execute in polled mode.
  29. //
  30. // Arguments:
  31. // Adapter - ptr to Adapter object instance
  32. // RegAddress - The MII register that we are writing to
  33. // PhyAddress - The MDI address of the Phy component.
  34. // DataValue - The value that we are writing to the MII register.
  35. //
  36. // Returns:
  37. // NOTHING
  38. //-----------------------------------------------------------------------------
  39. VOID MdiWrite(
  40. IN PMP_ADAPTER Adapter,
  41. IN ULONG RegAddress,
  42. IN ULONG PhyAddress,
  43. IN USHORT DataValue)
  44. {
  45. BOOLEAN bResult;
  46. // Issue the write command to the MDI control register.
  47. Adapter->CSRAddress->MDIControl = (((ULONG) DataValue) |
  48. (RegAddress << 16) |
  49. (PhyAddress << 21) |
  50. (MDI_WRITE << 26));
  51. // wait 20usec before checking status
  52. NdisStallExecution(20);
  53. // wait 2 seconds for the mdi write to complete
  54. MP_STALL_AND_WAIT(Adapter->CSRAddress->MDIControl & MDI_PHY_READY, 2000, bResult);
  55. if (!bResult)
  56. {
  57. MP_SET_HARDWARE_ERROR(Adapter);
  58. }
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Procedure: MdiRead
  62. //
  63. // Description: This routine will read a value from the specified MII register
  64. // of an external MDI compliant device (e.g. PHY 100), and return
  65. // it to the calling routine. The command will execute in polled
  66. // mode.
  67. //
  68. // Arguments:
  69. // Adapter - ptr to Adapter object instance
  70. // RegAddress - The MII register that we are reading from
  71. // PhyAddress - The MDI address of the Phy component.
  72. // Recoverable - Whether the hardware error(if any)if recoverable or not
  73. //
  74. // Results:
  75. // DataValue - The value that we read from the MII register.
  76. //
  77. // Returns:
  78. // None
  79. //-----------------------------------------------------------------------------
  80. BOOLEAN MdiRead(
  81. IN PMP_ADAPTER Adapter,
  82. IN ULONG RegAddress,
  83. IN ULONG PhyAddress,
  84. IN BOOLEAN Recoverable,
  85. IN OUT PUSHORT DataValue)
  86. {
  87. BOOLEAN bResult;
  88. // Issue the read command to the MDI control register.
  89. Adapter->CSRAddress->MDIControl = ((RegAddress << 16) |
  90. (PhyAddress << 21) |
  91. (MDI_READ << 26));
  92. // wait 20usec before checking status
  93. NdisStallExecution(20);
  94. // Wait up to 2 seconds for the mdi read to complete
  95. MP_STALL_AND_WAIT(Adapter->CSRAddress->MDIControl & MDI_PHY_READY, 2000, bResult);
  96. if (!bResult)
  97. {
  98. if (!Recoverable)
  99. {
  100. MP_SET_NON_RECOVER_ERROR(Adapter);
  101. }
  102. MP_SET_HARDWARE_ERROR(Adapter);
  103. return bResult;
  104. }
  105. *DataValue = (USHORT) Adapter->CSRAddress->MDIControl;
  106. return bResult;
  107. }
  108. //-----------------------------------------------------------------------------
  109. // Procedure: DumpStatsCounters
  110. //
  111. // Description: This routine will dump and reset the 82557's internal
  112. // Statistics counters. The current stats dump values will be
  113. // added to the "Adapter's" overall statistics.
  114. // Arguments:
  115. // Adapter - ptr to Adapter object instance
  116. //
  117. // Returns:
  118. // NOTHING
  119. //-----------------------------------------------------------------------------
  120. VOID DumpStatsCounters(
  121. IN PMP_ADAPTER Adapter)
  122. {
  123. BOOLEAN bResult;
  124. // The query is for a driver statistic, so we need to first
  125. // update our statistics in software.
  126. // clear the dump counters complete DWORD
  127. Adapter->StatsCounters->CommandComplete = 0;
  128. NdisAcquireSpinLock(&Adapter->Lock);
  129. // Dump and reset the hardware's statistic counters
  130. D100IssueScbCommand(Adapter, SCB_CUC_DUMP_RST_STAT, TRUE);
  131. // Restore the resume transmit software flag. After the dump counters
  132. // command is issued, we should do a WaitSCB before issuing the next send.
  133. Adapter->ResumeWait = TRUE;
  134. NdisReleaseSpinLock(&Adapter->Lock);
  135. // wait up to 2 seconds for the dump/reset to complete
  136. MP_STALL_AND_WAIT(Adapter->StatsCounters->CommandComplete == 0xA007, 2000, bResult);
  137. if (!bResult)
  138. {
  139. MP_SET_HARDWARE_ERROR(Adapter);
  140. return;
  141. }
  142. // Output the debug counters to the debug terminal.
  143. DBGPRINT(MP_INFO, ("Good Transmits %d\n", Adapter->StatsCounters->XmtGoodFrames));
  144. DBGPRINT(MP_INFO, ("Good Receives %d\n", Adapter->StatsCounters->RcvGoodFrames));
  145. DBGPRINT(MP_INFO, ("Max Collisions %d\n", Adapter->StatsCounters->XmtMaxCollisions));
  146. DBGPRINT(MP_INFO, ("Late Collisions %d\n", Adapter->StatsCounters->XmtLateCollisions));
  147. DBGPRINT(MP_INFO, ("Transmit Underruns %d\n", Adapter->StatsCounters->XmtUnderruns));
  148. DBGPRINT(MP_INFO, ("Transmit Lost CRS %d\n", Adapter->StatsCounters->XmtLostCRS));
  149. DBGPRINT(MP_INFO, ("Transmits Deferred %d\n", Adapter->StatsCounters->XmtDeferred));
  150. DBGPRINT(MP_INFO, ("One Collision xmits %d\n", Adapter->StatsCounters->XmtSingleCollision));
  151. DBGPRINT(MP_INFO, ("Mult Collision xmits %d\n", Adapter->StatsCounters->XmtMultCollisions));
  152. DBGPRINT(MP_INFO, ("Total Collisions %d\n", Adapter->StatsCounters->XmtTotalCollisions));
  153. DBGPRINT(MP_INFO, ("Receive CRC errors %d\n", Adapter->StatsCounters->RcvCrcErrors));
  154. DBGPRINT(MP_INFO, ("Receive Alignment errors %d\n", Adapter->StatsCounters->RcvAlignmentErrors));
  155. DBGPRINT(MP_INFO, ("Receive no resources %d\n", Adapter->StatsCounters->RcvResourceErrors));
  156. DBGPRINT(MP_INFO, ("Receive overrun errors %d\n", Adapter->StatsCounters->RcvOverrunErrors));
  157. DBGPRINT(MP_INFO, ("Receive CDT errors %d\n", Adapter->StatsCounters->RcvCdtErrors));
  158. DBGPRINT(MP_INFO, ("Receive short frames %d\n", Adapter->StatsCounters->RcvShortFrames));
  159. // update packet counts
  160. Adapter->GoodTransmits += Adapter->StatsCounters->XmtGoodFrames;
  161. Adapter->GoodReceives += Adapter->StatsCounters->RcvGoodFrames;
  162. // update transmit error counts
  163. Adapter->TxAbortExcessCollisions += Adapter->StatsCounters->XmtMaxCollisions;
  164. Adapter->TxLateCollisions += Adapter->StatsCounters->XmtLateCollisions;
  165. Adapter->TxDmaUnderrun += Adapter->StatsCounters->XmtUnderruns;
  166. Adapter->TxLostCRS += Adapter->StatsCounters->XmtLostCRS;
  167. Adapter->TxOKButDeferred += Adapter->StatsCounters->XmtDeferred;
  168. Adapter->OneRetry += Adapter->StatsCounters->XmtSingleCollision;
  169. Adapter->MoreThanOneRetry += Adapter->StatsCounters->XmtMultCollisions;
  170. Adapter->TotalRetries += Adapter->StatsCounters->XmtTotalCollisions;
  171. // update receive error counts
  172. Adapter->RcvCrcErrors += Adapter->StatsCounters->RcvCrcErrors;
  173. Adapter->RcvAlignmentErrors += Adapter->StatsCounters->RcvAlignmentErrors;
  174. Adapter->RcvResourceErrors += Adapter->StatsCounters->RcvResourceErrors;
  175. Adapter->RcvDmaOverrunErrors += Adapter->StatsCounters->RcvOverrunErrors;
  176. Adapter->RcvCdtFrames += Adapter->StatsCounters->RcvCdtErrors;
  177. Adapter->RcvRuntErrors += Adapter->StatsCounters->RcvShortFrames;
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Procedure: NICIssueSelectiveReset
  181. //
  182. // Description: This routine will issue a selective reset, forcing the adapter
  183. // the CU and RU back into their idle states. The receive unit
  184. // will then be re-enabled if it was previously enabled, because
  185. // an RNR interrupt will be generated when we abort the RU.
  186. //
  187. // Arguments:
  188. // Adapter - ptr to Adapter object instance
  189. //
  190. // Returns:
  191. // NOTHING
  192. //-----------------------------------------------------------------------------
  193. VOID NICIssueSelectiveReset(
  194. PMP_ADAPTER Adapter)
  195. {
  196. NDIS_STATUS Status;
  197. BOOLEAN bResult;
  198. // Wait for the SCB to clear before we check the CU status.
  199. if (!MP_TEST_FLAG(Adapter, fMP_ADAPTER_HARDWARE_ERROR))
  200. {
  201. WaitScb(Adapter);
  202. }
  203. // If we have issued any transmits, then the CU will either be active, or
  204. // in the suspended state. If the CU is active, then we wait for it to be
  205. // suspended. If the the CU is suspended, then we need to put the CU back
  206. // into the idle state by issuing a selective reset.
  207. if (Adapter->TransmitIdle == FALSE)
  208. {
  209. // Wait up to 2 seconds for suspended state
  210. MP_STALL_AND_WAIT((Adapter->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_ACTIVE, 2000, bResult)
  211. if (!bResult)
  212. {
  213. MP_SET_HARDWARE_ERROR(Adapter);
  214. }
  215. // Check the current status of the receive unit
  216. if ((Adapter->CSRAddress->ScbStatus & SCB_RUS_MASK) != SCB_RUS_IDLE)
  217. {
  218. // Issue an RU abort. Since an interrupt will be issued, the
  219. // RU will be started by the DPC.
  220. Status = D100IssueScbCommand(Adapter, SCB_RUC_ABORT, TRUE);
  221. }
  222. // Issue a selective reset.
  223. DBGPRINT(MP_INFO, ("CU suspended. ScbStatus=%04x Issue selective reset\n", Adapter->CSRAddress->ScbStatus));
  224. Adapter->CSRAddress->Port = PORT_SELECTIVE_RESET;
  225. // Wait after a port sel-reset command
  226. NdisStallExecution(NIC_DELAY_POST_RESET);
  227. // wait up to 2 ms for port command to complete
  228. MP_STALL_AND_WAIT(Adapter->CSRAddress->Port == 0, 2, bResult)
  229. if (!bResult)
  230. {
  231. MP_SET_HARDWARE_ERROR(Adapter);
  232. }
  233. // disable interrupts after issuing reset, because the int
  234. // line gets raised when reset completes.
  235. NICDisableInterrupt(Adapter);
  236. // Restore the transmit software flags.
  237. Adapter->TransmitIdle = TRUE;
  238. Adapter->ResumeWait = TRUE;
  239. }
  240. }
  241. VOID NICIssueFullReset(
  242. PMP_ADAPTER Adapter)
  243. {
  244. BOOLEAN bResult;
  245. NICIssueSelectiveReset(Adapter);
  246. Adapter->CSRAddress->Port = PORT_SOFTWARE_RESET;
  247. // wait up to 2 ms for port command to complete
  248. MP_STALL_AND_WAIT(Adapter->CSRAddress->Port == 0, 2, bResult);
  249. if (!bResult)
  250. {
  251. MP_SET_HARDWARE_ERROR(Adapter);
  252. return;
  253. }
  254. NICDisableInterrupt(Adapter);
  255. }
  256. //-----------------------------------------------------------------------------
  257. // Procedure: D100SubmitCommandBlockAndWait
  258. //
  259. // Description: This routine will submit a command block to be executed, and
  260. // then it will wait for that command block to be executed. Since
  261. // board ints will be disabled, we will ack the interrupt in
  262. // this routine.
  263. //
  264. // Arguments:
  265. // Adapter - ptr to Adapter object instance
  266. //
  267. // Returns:
  268. // NDIS_STATUS_SUCCESS
  269. // NDIS_STATUS_HARD_ERRORS
  270. //-----------------------------------------------------------------------------
  271. NDIS_STATUS D100SubmitCommandBlockAndWait(
  272. IN PMP_ADAPTER Adapter)
  273. {
  274. NDIS_STATUS Status;
  275. BOOLEAN bResult;
  276. // Points to the Non Tx Command Block.
  277. volatile PNON_TRANSMIT_CB CommandBlock = Adapter->NonTxCmdBlock;
  278. // Set the Command Block to be the last command block
  279. CommandBlock->NonTxCb.Config.ConfigCBHeader.CbCommand |= CB_EL_BIT;
  280. // Clear the status of the command block
  281. CommandBlock->NonTxCb.Config.ConfigCBHeader.CbStatus = 0;
  282. #if DBG
  283. // Don't try to start the CU if the command unit is active.
  284. if ((Adapter->CSRAddress->ScbStatus & SCB_CUS_MASK) == SCB_CUS_ACTIVE)
  285. {
  286. DBGPRINT(MP_ERROR, ("Scb "PTR_FORMAT" ScbStatus %04x\n", Adapter->CSRAddress, Adapter->CSRAddress->ScbStatus));
  287. ASSERT(FALSE);
  288. MP_SET_HARDWARE_ERROR(Adapter);
  289. return(NDIS_STATUS_HARD_ERRORS);
  290. }
  291. #endif
  292. // Start the command unit.
  293. D100IssueScbCommand(Adapter, SCB_CUC_START, FALSE);
  294. // Wait for the SCB to clear, indicating the completion of the command.
  295. if (!WaitScb(Adapter))
  296. {
  297. return(NDIS_STATUS_HARD_ERRORS);
  298. }
  299. // Wait for some status, timeout value 3 secs
  300. MP_STALL_AND_WAIT(CommandBlock->NonTxCb.Config.ConfigCBHeader.CbStatus & CB_STATUS_COMPLETE, 3000, bResult);
  301. if (!bResult)
  302. {
  303. MP_SET_HARDWARE_ERROR(Adapter);
  304. return(NDIS_STATUS_HARD_ERRORS);
  305. }
  306. // Ack any interrupts
  307. if (Adapter->CSRAddress->ScbStatus & SCB_ACK_MASK)
  308. {
  309. // Ack all pending interrupts now
  310. Adapter->CSRAddress->ScbStatus &= SCB_ACK_MASK;
  311. }
  312. // Check the status of the command, and if the command failed return FALSE,
  313. // otherwise return TRUE.
  314. if (!(CommandBlock->NonTxCb.Config.ConfigCBHeader.CbStatus & CB_STATUS_OK))
  315. {
  316. DBGPRINT(MP_ERROR, ("Command failed\n"));
  317. MP_SET_HARDWARE_ERROR(Adapter);
  318. Status = NDIS_STATUS_HARD_ERRORS;
  319. }
  320. else
  321. Status = NDIS_STATUS_SUCCESS;
  322. return(Status);
  323. }
  324. //-----------------------------------------------------------------------------
  325. // Procedure: GetConnectionStatus
  326. //
  327. // Description: This function returns the connection status that is
  328. // a required indication for PC 97 specification from MS
  329. // the value we are looking for is if there is link to the
  330. // wire or not.
  331. //
  332. // Arguments: IN Adapter structure pointer
  333. //
  334. // Returns: NdisMediaStateConnected
  335. // NdisMediaStateDisconnected
  336. //-----------------------------------------------------------------------------
  337. NDIS_MEDIA_STATE NICGetMediaState(IN PMP_ADAPTER Adapter)
  338. {
  339. USHORT MdiStatusReg = 0;
  340. BOOLEAN bResult1;
  341. BOOLEAN bResult2;
  342. // Read the status register at phy 1
  343. bResult1 = MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, TRUE, &MdiStatusReg);
  344. bResult2 = MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, TRUE, &MdiStatusReg);
  345. // if there is hardware failure, or let the state remains the same
  346. if (!bResult1 || !bResult2)
  347. {
  348. return Adapter->MediaState;
  349. }
  350. if (MdiStatusReg & MDI_SR_LINK_STATUS)
  351. return(NdisMediaStateConnected);
  352. else
  353. return(NdisMediaStateDisconnected);
  354. }