PageRenderTime 56ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/verify/src/Checked/Drivers/Network/Intel/Intel.cs

#
C# | 950 lines | 612 code | 164 blank | 174 comment | 66 complexity | 1a90390fc92a9beb392b143c69082b6e MD5 | raw file
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Microsoft Research Singularity
  4. //
  5. // Copyright (c) Microsoft Corporation. All rights reserved.
  6. //
  7. // Notes:
  8. //
  9. // Simple Driver for Intel 8254x PCI Ethernet Cards.
  10. //
  11. // Useful reference URLs:
  12. // http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf
  13. //
  14. // We use standard IP/TCP checksum offloading.
  15. //
  16. // The driver currently runs in interrupt driven mode using hardware based
  17. // interrupt throttling.
  18. //
  19. // Phy handling is automatic and relies on attached phy supporting
  20. // auto-negotiation. The phy update interrupt is used to keep track
  21. // of phy state.
  22. //
  23. // TODO:
  24. //
  25. // - Flow Control Support
  26. // - Support for packet fragments (all packets must have a single fragment
  27. // currently)
  28. // - Jumbo Packets
  29. // - Transmit TCP/IP checksum offloading
  30. //
  31. //#define DEBUG_INTEL
  32. using System;
  33. using System.Threading;
  34. using System.Diagnostics;
  35. using System.Collections;
  36. using Microsoft.Contracts;
  37. using Microsoft.Singularity.Channels;
  38. using Microsoft.Singularity.Io;
  39. //using Microsoft.Singularity.Configuration;
  40. using Microsoft.Singularity.Io.Net;
  41. using Microsoft.Singularity.V1.Services;
  42. using Microsoft.Singularity.Drivers;
  43. using Microsoft.SingSharp;
  44. using Microsoft.Singularity.Directory;
  45. //using Microsoft.Singularity.Extending;
  46. using Drivers.Net;
  47. namespace Microsoft.Singularity.Drivers.Network.Intel
  48. {
  49. [CLSCompliant(false)]
  50. public class Intel: IThreadStart
  51. {
  52. internal const uint MaxTxFragmentsPerPacket = 1; // Todo: allow frags
  53. internal const uint MaxRxFragmentsPerPacket = 1; // Todo: allow frags
  54. internal const uint MaxRxPackets = 511; // TODO: 1023; // one less than full buffer
  55. internal const uint MaxTxPackets = 511; // TODO: 2047;
  56. // Fragments must be power of two.
  57. internal const uint MaxTxFragmentsInRing = ((MaxTxPackets + 1) *
  58. MaxTxFragmentsPerPacket) ;
  59. internal const uint MaxRxFragmentsInRing = ((MaxRxPackets + 1) *
  60. MaxRxFragmentsPerPacket);
  61. internal const ChecksumSupport ChecksumSupport =
  62. Microsoft.Singularity.Io.Net.ChecksumSupport.AllIp4Receive
  63. | Microsoft.Singularity.Io.Net.ChecksumSupport.AllIp6Receive;
  64. internal const uint IEEE8023FrameBytes = 1518;
  65. internal const uint MtuBytes = 1514;
  66. internal const uint PhyAddress = 1;
  67. private string cardName;
  68. private CardType cardType;
  69. //private PciDeviceConfig pciConfig;
  70. private PciMemory ioMemory;
  71. //TODO: private IoIrq irq;
  72. private Thread irqWorkerThread;
  73. private bool irqWorkerStop;
  74. private bool ioRunning;
  75. private IntelEventRelay eventRelay;
  76. private EerdRegister eerdReg;
  77. private EthernetAddress macAddress;
  78. private IntelRxRingBuffer rxRingBuffer;
  79. private IntelTxRingBuffer txRingBuffer;
  80. [NotDelayed]
  81. internal Intel(PciDeviceConfig config, PciMemory ioMemory, string cardName, CardType cardType)
  82. {
  83. this.ioMemory = ioMemory;
  84. this.cardName = cardName;
  85. this.cardType = cardType;
  86. //TODO: IoIrqRange iir = res.irq;
  87. //TODO: irq = iir.IrqAtOffset(0);
  88. rxRingBuffer = new IntelRxRingBuffer(MaxRxFragmentsInRing);
  89. txRingBuffer = new IntelTxRingBuffer(MaxTxFragmentsInRing);
  90. //PciDeviceConfig config = (PciDeviceConfig)IoConfig.GetConfig();
  91. //this.pciConfig = config;
  92. // DebugWriteLine("PCI Control {0:x8} Status {1:x8}",
  93. // DebugStub.ArgList(config.Control, config.Status));
  94. /*
  95. byte cap = config.Capabilities;
  96. while (cap != 0 && cap < 0xff) {
  97. DebugWriteLine("Capability at: {0:x2}", DebugStub.ArgList(cap));
  98. byte id = config.Read8(cap);
  99. if (id == 7) {
  100. DebugWriteLine("PCI-X Command {0:x4} Status {1:x8}",
  101. DebugStub.ArgList(
  102. config.Read16(cap + 2) & 0x3f,
  103. config.Read32(cap + 4)
  104. )
  105. );
  106. }
  107. else if (id == 5) {
  108. // MSI capability - only reached if enabled,
  109. // but usually present.
  110. DebugWriteLine("MSI Control {0:x4} Address {1:x8}.{2:x8} Data {3:x4}",
  111. DebugStub.ArgList(config.Read16(cap + 2),
  112. config.Read32(cap + 8),
  113. config.Read32(cap + 4),
  114. config.Read16(cap + 10)
  115. )
  116. );
  117. }
  118. else {
  119. DebugWriteLine("Unknown capability {0:x2}", DebugStub.ArgList(id));
  120. }
  121. cap = config.Read8(cap + 1);
  122. }
  123. */
  124. eerdReg = new EerdRegister(config.DeviceId);
  125. //DebugWriteLine("Irq {0}", DebugStub.ArgList(irq.Irq));
  126. // Debug.Assert((config.Control & PciConfig.PCI_ENABLE_BUS_MASTER) != 0);
  127. // Debug.Assert((config.Control & PciConfig.PCI_ENABLE_MEMORY_SPACE) != 0);
  128. // DebugStub.Assert(config.InterruptsEnabled);
  129. }
  130. ~Intel()
  131. {
  132. ReleaseResources();
  133. }
  134. ///////////////////////////////////////////////////////////////////////
  135. //
  136. // Initialisation and finalisation code
  137. //
  138. internal void Initialize()
  139. {
  140. DebugPrint("Initialising " + DriverName + " Version " + DriverVersion);
  141. //TODO: if (!irq.RegisterInterrupt()) {
  142. // DebugStub.Break();
  143. //}
  144. ResetDevice();
  145. SetupPhys();
  146. SetupMac();
  147. }
  148. void ReleaseResources()
  149. {
  150. DisableInterrupts();
  151. StopIo();
  152. //TODO: irq.ReleaseInterrupt();
  153. irqWorkerThread = null;
  154. }
  155. internal void Shutdown()
  156. {
  157. if (irqWorkerThread != null) {
  158. // XXX This is not the right way to do this.
  159. DisableInterrupts();
  160. StopIo();
  161. }
  162. }
  163. public void Run()
  164. {
  165. System.DebugStub.Print("Intel@" + Kernel.CurrentThread + ". ");
  166. IrqWorkerMain();
  167. }
  168. internal void StartIo()
  169. {
  170. irqWorkerStop = false;
  171. irqWorkerThread = new Thread(this);
  172. irqWorkerThread.Start();
  173. SetupMac();
  174. DisableInterrupts();//TODO: EnableInterrupts();
  175. StartReceiver();
  176. StartTransmitter();
  177. this.ioRunning = true;
  178. }
  179. internal void StopIo()
  180. {
  181. StopTransmitter();
  182. StopReceiver();
  183. if (irqWorkerThread != null) {
  184. // Set stop flag, wake-up irqWorker thread, then wait.
  185. irqWorkerStop = true;
  186. //TODO: irq.Pulse();
  187. //TODO: irqWorkerThread.Join();
  188. irqWorkerThread = null;
  189. }
  190. this.ioRunning = false;
  191. }
  192. internal void SetEventRelay(IntelEventRelay intelEventRelay)
  193. {
  194. eventRelay = intelEventRelay;
  195. }
  196. ///////////////////////////////////////////////////////////////////////
  197. //
  198. // Setup functions
  199. //
  200. private void ResetDevice()
  201. {
  202. // Disable all interrupts
  203. DisableInterrupts();
  204. DebugWriteLine("CTRL pre-device-reset : {0:x8}\n",
  205. DebugStub.ArgList(Read32(Register.CTRL)));
  206. Write32(Register.RECV_CTRL, 0);
  207. Write32(Register.TSMT_CTRL, TsmtCtrlBits.PAD_SHORT_PACKETS);
  208. Read32(Register.STATUS);
  209. // Allow pending PCI transactions to complete
  210. Delay(10);
  211. // Reset the device
  212. RegSetBits((int)Register.CTRL, CtrlBits.RST | CtrlBits.PHY_RST);
  213. // Wait for 3us before board is really reset
  214. Delay(3);
  215. Delay(100);
  216. Read32(Register.CTRL);
  217. // Set the control register to the proper initial values,
  218. // clearing RST and PHY_RST as a side-effect.
  219. Write32(Register.CTRL, CtrlBits.FD | CtrlBits.ASDE | CtrlBits.SLU);
  220. while ((Read32(Register.CTRL) & CtrlBits.RST) != 0) {
  221. DebugWriteLine(".");
  222. }
  223. DebugWriteLine("Autonegotiation complete");
  224. }
  225. private void SetupPhys()
  226. {
  227. if (this.cardType == CardType.I82545GM ) {
  228. Write32(Register.MDIC, Mdic.MdiRead);
  229. while ((Read32(Register.MDIC) & Mdic.Ready) == 0);
  230. uint mdic = Read32(Register.MDIC) & Mdic.DataMask;
  231. mdic |= Mdic.MdiWrite;
  232. mdic &= Mdic.PowerMask;
  233. Write32(Register.MDIC, mdic);
  234. while ((Read32(Register.MDIC) & Mdic.Ready) == 0);
  235. DumpPhy();
  236. uint ctrl = Read32(Register.CTRL);
  237. ctrl |= CtrlBits.SLU | CtrlBits.ASDE;
  238. ctrl &= ~(CtrlBits.ILOS | CtrlBits.FRCSPD | CtrlBits.FRCDPLX);
  239. Write32(Register.CTRL, ctrl);
  240. Delay(20);
  241. // Wait for link to come up
  242. int attempts = 5000;
  243. while ((MiiRead(PhyAddress, 1) & 0x4) == 0) {
  244. Delay(1000);
  245. if (0 == attempts--) {
  246. DumpPhy();
  247. DebugStub.Break();
  248. }
  249. }
  250. DumpPhy();
  251. uint phyCtrl = MiiRead(PhyAddress, 0);
  252. phyCtrl |= 0x1200; // Enable-AutoNeg + Restart-AutoNeg
  253. MiiWrite(PhyAddress, 0, phyCtrl);
  254. uint phyStat;
  255. attempts = 5000;
  256. do {
  257. Delay(1000);
  258. phyStat = MiiRead(PhyAddress, 1);
  259. phyStat = MiiRead(PhyAddress, 1);
  260. } while ((phyStat & 0x20) == 0 && --attempts > 0); // wait for autoneg complete
  261. DebugStub.Assert((phyStat & 0x20) != 0);
  262. // Transfer settings from phy to ctrl
  263. uint phyPssr = MiiRead(PhyAddress, 17);
  264. ctrl = Read32(Register.CTRL);
  265. ctrl &= ~(CtrlBits.SPEED | CtrlBits.FD);
  266. if ((phyPssr & (1 << 13)) != 0) {
  267. ctrl |= CtrlBits.FD;
  268. }
  269. ctrl |= ((phyPssr >> 14) & 3) << 8;
  270. ctrl |= CtrlBits.FRCSPD | CtrlBits.FRCDPLX;
  271. Write32(Register.CTRL, ctrl);
  272. Delay(1000000);
  273. DumpPhy();
  274. }
  275. else if (this.cardType == CardType.I82541PI) {
  276. // Use Internal Phys mode (SerDes is not possible for some 8254x cards)
  277. Write32BitRange(Register.CTRL_EXT,
  278. CtrlExtBits.LINK_MODE_PHYS,
  279. CtrlExtBits.LINK_MODE_LO_BIT,
  280. CtrlExtBits.LINK_MODE_HI_BIT);
  281. }
  282. // We don't want flow control
  283. Write32(Register.FCAL, 0x0);
  284. Write32(Register.FCAH, 0x0);
  285. Write32(Register.FCT, 0x0);
  286. Write32(Register.FCTTV, 0x0);
  287. }
  288. private void SetupMac()
  289. {
  290. uint ral, rah;
  291. // Setup our Ethernet address
  292. macAddress = GetMacFromEeprom();
  293. DebugStub.Print("Setting Ethernet Mac Address to " + macAddress + ". ");
  294. GetMacHiLow(out ral, out rah, macAddress);
  295. rah = rah | RahRegister.ADDRESS_VALID;
  296. Write32(Register.RAL0, ral);
  297. Write32(Register.RAH0, rah);
  298. // Clear the mutlicast table array
  299. for (uint i = 0; i < MtaRegister.MTA_LENGTH; i++)
  300. {
  301. Write32(Register.MTA_START + (4*i), 0);
  302. }
  303. // Setup Descriptor buffers for rx
  304. ResetRxRingBuffer();
  305. // Setup Receiever Control flags
  306. Write32(Register.RECV_CTRL, (RecvCtrlBits.BROADCAST_ACCEPT |
  307. RecvCtrlBits.STRIP_CRC |
  308. RecvCtrlBits.LOOPBACK_MODE_DISABLE |
  309. RecvCtrlBits.MULTICAST_OFFSET_47_36 |
  310. RecvCtrlBits.BUFFER_SIZE_2KB |
  311. RecvCtrlBits.RECV_DESC_THRESHOLD_QUARTER));
  312. // Note: If MTU ever changes (e.g. for jumbo frames), the
  313. // recv buffer size will need to be increased.
  314. // Setup the rx interrupt delay
  315. Write32(Register.RECV_DELAY_TIMER, RxDelayTimers.RECV_DELAY_TIMER);
  316. Write32(Register.RECV_INT_ABS_TIMER, RxDelayTimers.RECV_ABSOLUTE_TIMER);
  317. // Enable IP and TCP checksum calculation offloading
  318. Write32(Register.RECV_CHECKSUM, (RecvChecksumBits.IP_CHECKSUM_ENABLE |
  319. RecvChecksumBits.TCP_CHECKSUM_ENABLE |
  320. RecvChecksumBits.IP6_CHECKSUM_ENABLE));
  321. // Setup Descriptor buffers for tx
  322. ResetTxRingBuffer();
  323. // Setup Transmit Control flags
  324. Write32(Register.TSMT_CTRL,
  325. TsmtCtrlBits.PAD_SHORT_PACKETS |
  326. TsmtCtrlBits.COLL_THRESHOLD_DEFAULT |
  327. TsmtCtrlBits.COLL_DISTANCE_DEFAULT);
  328. // Setup Transmit Inter Frame Gap
  329. Write32(Register.TSMT_IPG, TsmtIpg.DEFAULT_IPG);
  330. // TODO enable transmit checksum offloading
  331. }
  332. ///////////////////////////////////////////////////////////////////////
  333. //
  334. // Helper functions
  335. //
  336. internal void GetMacHiLow(out uint addr_low,
  337. out uint addr_hi,
  338. EthernetAddress mac)
  339. {
  340. byte[] macBytes = mac.GetAddressBytes();
  341. addr_hi = (uint) ((macBytes[5] << 8) |
  342. (macBytes[4]));
  343. addr_low = (uint) ((macBytes[3] << 24) |
  344. (macBytes[2] << 16) |
  345. (macBytes[1] << 8) |
  346. (macBytes[0]));
  347. }
  348. internal EthernetAddress GetMacFromEeprom()
  349. {
  350. ushort eepromData;
  351. byte[] macBytes = new byte[6];
  352. // Mac address is in reverse byte order in the EEPROM
  353. eepromData = ReadEepromWord(0);
  354. macBytes[0] = (byte) (eepromData & 0xff);
  355. macBytes[1] = (byte) (eepromData >> 8);
  356. eepromData = ReadEepromWord(1);
  357. macBytes[2] = (byte) (eepromData & 0xff);
  358. macBytes[3] = (byte) (eepromData >> 8);
  359. eepromData = ReadEepromWord(2);
  360. macBytes[4] = (byte) (eepromData & 0xff);
  361. macBytes[5] = (byte) (eepromData >> 8);
  362. return new EthernetAddress(macBytes);
  363. }
  364. private ushort ReadEepromWord(ushort eepromAddress)
  365. {
  366. uint eepromRead;
  367. // Write address required
  368. uint writeVal = (EerdRegister.Start |
  369. ((uint) eepromAddress << eerdReg.AddressShift));
  370. Write32(Register.EERD, writeVal);
  371. // wait until read has completed
  372. do {
  373. eepromRead = Read32(Register.EERD);
  374. } while ((eepromRead & eerdReg.Done) == 0);
  375. // return data value
  376. return (ushort) (eepromRead >> EerdRegister.DataShift);
  377. }
  378. ///////////////////////////////////////////////////////////////////////
  379. //
  380. // Interrupt Handling
  381. //
  382. internal void EnableInterrupts()
  383. {
  384. // Clear existing interrupts
  385. Write32(Register.IMC, 0xffffffff);
  386. Read32(Register.ICR);
  387. // Set interrupts we are interested in
  388. RegSetBits((int)Register.IMS, (InterruptMasks.RXT0 | InterruptMasks.RXO |
  389. InterruptMasks.RXDMT0 |
  390. InterruptMasks.LSC | InterruptMasks.TXQE |
  391. InterruptMasks.TXDW));
  392. }
  393. internal void DisableInterrupts()
  394. {
  395. // Clear existing interrupts
  396. Write32(Register.IMC, 0xffffffff);
  397. Read32(Register.ICR);
  398. }
  399. private bool HandleInterrupts(uint intrCause)
  400. {
  401. if (intrCause == 0) {
  402. //TODO: return false;
  403. }
  404. //DebugPrint("HandleInterrupts ???\n");
  405. NicEventType ev = NicEventType.NoEvent;
  406. if ((intrCause & InterruptMasks.LSC) != 0) {
  407. DebugPrint("Link Status Change\n");
  408. ev |= NicEventType.LinkEvent;
  409. }
  410. if ((intrCause & InterruptMasks.RXSEQ) != 0) {
  411. DebugPrint("Sequence Error\n");
  412. ev |= NicEventType.LinkEvent;
  413. }
  414. if (((InterruptMasks.RXT0 |
  415. InterruptMasks.RXO |
  416. InterruptMasks.RXDMT0) & intrCause) != 0) {
  417. ev |= NicEventType.ReceiveEvent;
  418. }
  419. // no transmit interupts are set, check rxbuffer to see
  420. // if any packets have been sent since last time
  421. if (txRingBuffer.NewTransmitEvent()) {
  422. ev |= NicEventType.TransmitEvent;
  423. }
  424. // TODO: not necessary
  425. if (rxRingBuffer.NewReceiveEvent()) {
  426. ev |= NicEventType.ReceiveEvent;
  427. }
  428. if (ev == NicEventType.NoEvent) {
  429. // DebugPrint("HandleInterrupt: no event\n");
  430. return false;
  431. }
  432. if (eventRelay != null) {
  433. eventRelay.ForwardEvent(ev);
  434. } else {
  435. DebugPrint("event relay is NULL!\n");
  436. }
  437. return true;
  438. }
  439. private void IrqWorkerMain()
  440. {
  441. DebugPrint(
  442. "Intel {0} Ethernet Driver irq worker thread started.\n",
  443. DebugStub.ArgList(this.cardName)
  444. );
  445. uint rcnt = 0;
  446. uint missed = 0;
  447. uint nobuf = 0;
  448. while (irqWorkerStop == false) {
  449. Thread.Yield(); //TODO: irq.WaitForInterrupt();
  450. uint icr = Read32(Register.ICR);
  451. HandleInterrupts(icr);
  452. rcnt += Read32(Register.TOTAL_RECV_PACKETS);
  453. missed += Read32(0x4010);
  454. nobuf += Read32(0x40a0);
  455. INucleusCalls.DebugPrintHex(10, rcnt - nobuf);
  456. INucleusCalls.DebugPrintHex(20, rcnt);
  457. INucleusCalls.DebugPrintHex(30, missed);
  458. //TODO: irq.AckInterrupt();
  459. }
  460. DisableInterrupts();
  461. DebugPrint(
  462. "Intel {0} Ethernet Driver irq worker thread stopped.\n",
  463. DebugStub.ArgList(this.cardName)
  464. );
  465. }
  466. ///////////////////////////////////////////////////////////////////////
  467. //
  468. // Rx buffer operations
  469. //
  470. internal void PopulateRecvBuffer(PacketFifo fromUser)
  471. {
  472. if (fromUser.Count < 1) {
  473. return;
  474. }
  475. using (rxRingBuffer.thisLock.Lock()) {
  476. while (fromUser.Count > 0) {
  477. rxRingBuffer.LockedPushRecvBuffer(fromUser.Pop());
  478. }
  479. Write32(Register.RECV_DESC_TAIL, rxRingBuffer.Head);
  480. }
  481. }
  482. internal void DrainRecvBuffer(PacketFifo toUser)
  483. {
  484. using (rxRingBuffer.thisLock.Lock()) {
  485. rxRingBuffer.LockedDrainRecvBuffer(toUser);
  486. }
  487. }
  488. private void ResetRxRingBuffer()
  489. {
  490. ulong descBase;
  491. uint descBaseLo, descBaseHi;
  492. rxRingBuffer.Reset();
  493. descBase = rxRingBuffer.BaseAddress.ToUInt64();
  494. descBaseLo = (uint)(0xffffffff & descBase);
  495. descBaseHi = (uint) (0xffffffff & (descBase >> 32));
  496. Write32(Register.RECV_DESC_BASE_LO, ByteOrder.HostToLittleEndian(descBaseLo));
  497. Write32(Register.RECV_DESC_BASE_HI, ByteOrder.HostToLittleEndian(descBaseHi));
  498. Write32(Register.RECV_DESC_LENGTH, ByteOrder.HostToLittleEndian(rxRingBuffer.DescLength));
  499. Write32(Register.RECV_DESC_HEAD, ByteOrder.HostToLittleEndian(rxRingBuffer.Head));
  500. Write32(Register.RECV_DESC_TAIL, ByteOrder.HostToLittleEndian(rxRingBuffer.Tail));
  501. }
  502. private void StartReceiver()
  503. {
  504. ResetRxRingBuffer();
  505. // RegSetBits((int)Register.RECV_CTRL, RecvCtrlBits.RECV_ENABLE | RecvCtrlBits.UNICAST_PROMISCUOUS | RecvCtrlBits.MULTICAST_PROMISCUOUS);
  506. RegSetBits((int)Register.RECV_CTRL, RecvCtrlBits.RECV_ENABLE);
  507. DebugPrint("Receiver Enabled.\n");
  508. }
  509. private void StopReceiver()
  510. {
  511. RegClrBits((int)Register.RECV_CTRL, RecvCtrlBits.RECV_ENABLE);
  512. }
  513. ///////////////////////////////////////////////////////////////////////
  514. //
  515. // Tx buffer operations
  516. //
  517. internal void PopulateTsmtBuffer(PacketFifo fromUser)
  518. {
  519. DebugStub.Assert(this.ioRunning);
  520. // since no transmit interrupts are sent, we must check for
  521. // transmission events here
  522. if (txRingBuffer.NewTransmitEvent()) {
  523. NicEventType ev = NicEventType.TransmitEvent;
  524. if (eventRelay != null) {
  525. eventRelay.ForwardEvent(ev);
  526. }
  527. }
  528. using (txRingBuffer.thisLock.Lock()) {
  529. while (fromUser.Count > 0) {
  530. Packet packet = fromUser.Pop();
  531. txRingBuffer.LockedPushTsmtBuffer(packet);
  532. }
  533. // update hardware tail pointer
  534. // so that hardware knows it has new packets to transmit
  535. Write32(Register.TSMT_DESC_TAIL, txRingBuffer.Head); // sw head is hw tail
  536. }
  537. }
  538. internal void DrainTsmtBuffer(PacketFifo toUser)
  539. {
  540. using (txRingBuffer.thisLock.Lock()) {
  541. txRingBuffer.LockedDrainTsmtBuffer(toUser);
  542. }
  543. }
  544. private void ResetTxRingBuffer()
  545. {
  546. ulong descBase;
  547. uint descBaseLo, descBaseHi;
  548. txRingBuffer.Reset();
  549. descBase = txRingBuffer.BaseAddress.ToUInt64();
  550. descBaseLo = (uint)(0xffffffff & descBase);
  551. descBaseHi = (uint) (0xffffffff & (descBase >> 32));
  552. Write32(Register.TSMT_DESC_BASE_LO, ByteOrder.HostToLittleEndian(descBaseLo));
  553. Write32(Register.TSMT_DESC_BASE_HI, ByteOrder.HostToLittleEndian(descBaseHi));
  554. Write32(Register.TSMT_DESC_LENGTH, ByteOrder.HostToLittleEndian(txRingBuffer.DescLength));
  555. Write32(Register.TSMT_DESC_HEAD, ByteOrder.HostToLittleEndian(txRingBuffer.Head));
  556. Write32(Register.TSMT_DESC_TAIL, ByteOrder.HostToLittleEndian(txRingBuffer.Tail));
  557. }
  558. private void StartTransmitter()
  559. {
  560. ResetTxRingBuffer();
  561. RegSetBits((int)Register.TSMT_CTRL, TsmtCtrlBits.TSMT_ENABLE);
  562. DebugPrint("Transmitter Enabled.\n");
  563. }
  564. private void StopTransmitter()
  565. {
  566. RegClrBits((int)Register.TSMT_CTRL, TsmtCtrlBits.TSMT_ENABLE);
  567. }
  568. ///////////////////////////////////////////////////////////////////////
  569. //
  570. // Driver Details
  571. //
  572. internal string DriverName
  573. {
  574. get { return string.Format("Intel {0} Ethernet Driver", this.cardName); }
  575. }
  576. internal string DriverVersion
  577. {
  578. get { return "0.1"; }
  579. }
  580. internal EthernetAddress getMacAddress
  581. {
  582. get { return macAddress; }
  583. }
  584. ///////////////////////////////////////////////////////////////////////
  585. //
  586. // MII
  587. //
  588. private uint MiiRead(uint phy, uint register)
  589. {
  590. uint mdic = (((phy & Mdic.PhyMask) << Mdic.PhyRoll) |
  591. ((register & Mdic.RegMask) << Mdic.RegRoll) |
  592. Mdic.MdiRead);
  593. Write32(Register.MDIC, mdic);
  594. do {
  595. mdic = Read32(Register.MDIC);
  596. DebugStub.Assert((mdic & Mdic.Error) == 0);
  597. } while ((mdic & Mdic.Ready) == 0);
  598. return mdic & Mdic.DataMask;
  599. }
  600. private uint MiiWrite(uint phy, uint register, uint value)
  601. {
  602. DebugStub.Assert((value & ~Mdic.DataMask) == 0);
  603. uint mdic = (((phy & Mdic.PhyMask) << Mdic.PhyRoll) |
  604. ((register & Mdic.RegMask) << Mdic.RegRoll) |
  605. Mdic.MdiWrite);
  606. mdic |= (uint)value;
  607. Write32(Register.MDIC, mdic);
  608. do {
  609. mdic = Read32(Register.MDIC);
  610. DebugStub.Assert((mdic & Mdic.Error) == 0);
  611. } while ((mdic & Mdic.Ready) == 0);
  612. return mdic & Mdic.DataMask;
  613. }
  614. ///////////////////////////////////////////////////////////////////////
  615. //
  616. // Register accessors / modifiers / utilities
  617. //
  618. private uint Read32(uint offset)
  619. {
  620. return ioMemory.Read32((int) offset);
  621. }
  622. private void Write32(uint offset, uint value)
  623. {
  624. ioMemory.Write32((int) offset, value);
  625. }
  626. private void Write32BitRange(uint offset,
  627. uint new_val,
  628. int hiBit,
  629. int loBit)
  630. {
  631. uint write_val = SetValueBits(Read32(offset), new_val, hiBit, loBit);
  632. Write32(offset, write_val);
  633. }
  634. private void RegSetBits(int offset, uint bits)
  635. {
  636. ioMemory.Write32(offset, ioMemory.Read32(offset) | bits);
  637. }
  638. private void RegClrBits(int offset, uint bits)
  639. {
  640. ioMemory.Write32(offset, ioMemory.Read32(offset) & ~bits);
  641. }
  642. private uint SetValueBits(uint value,
  643. uint bits,
  644. int hiBit,
  645. int loBit)
  646. {
  647. int width = (hiBit - loBit) + 1;
  648. uint mask = (1u << width) - 1u;
  649. bits = (bits & mask);
  650. value &= ~(mask << loBit);
  651. value |= bits << loBit;
  652. return value;
  653. }
  654. private void SetBit(ref uint value, int bit)
  655. {
  656. value = value | (1u << bit);
  657. }
  658. private void ClearBit(ref uint value, int bit)
  659. {
  660. value = value & ~(1u << bit);
  661. }
  662. private static void Delay(int us)
  663. {
  664. long expiry = DateTime.Now.Ticks + (us * 10);
  665. while (DateTime.Now.Ticks < expiry);
  666. }
  667. ///////////////////////////////////////////////////////////////////////
  668. //
  669. // Debug Helper Functions
  670. //
  671. [Conditional("DEBUG_INTEL")]
  672. internal static void DebugPrint(string format, object arglist)
  673. {
  674. DebugStub.Print(format, arglist);
  675. }
  676. [Conditional("DEBUG_INTEL")]
  677. internal static void DebugPrint(string format)
  678. {
  679. DebugStub.Print(format);
  680. }
  681. [Conditional("DEBUG_INTEL")]
  682. internal static void DebugWriteLine(string format, object arglist)
  683. {
  684. DebugStub.WriteLine(format, arglist);
  685. }
  686. [Conditional("DEBUG_INTEL")]
  687. internal static void DebugWriteLine(string format)
  688. {
  689. DebugStub.WriteLine(format);
  690. }
  691. ///////////////////////////////////////////////////////////////////////
  692. //
  693. // Debugging methods
  694. //
  695. [Conditional("DEBUG_INTEL")]
  696. private void DumpBufferDebugRegisters()
  697. {
  698. // TODO, uses Tracing log
  699. DebugPrint("Device Control {0:x8} Device Status {1:x8}\n",
  700. DebugStub.ArgList(Read32(Register.CTRL),
  701. Read32(Register.STATUS)));
  702. //DebugPrint("PCI Status {0:x4}", DebugStub.ArgList(this.pciConfig.Status));
  703. DebugPrint("Recv Control {0:x8} Tsmt Control {1:x8}\n",
  704. DebugStub.ArgList(Read32(Register.RECV_CTRL),
  705. Read32(Register.TSMT_CTRL)));
  706. DebugPrint("RDTR {0:x8} RADV {1:x8}\n",
  707. DebugStub.ArgList(Read32(0x2820), Read32(0x282c)));
  708. DebugPrint("Total Transmit {0:x8} Total Received {1:x8}\n",
  709. DebugStub.ArgList(Read32(Register.TOTAL_TSMT_PACKETS),
  710. Read32(Register.TOTAL_RECV_PACKETS)));
  711. DebugPrint("Interrupt Mask {0:x8} Rx Error Count {1:x8}\n",
  712. DebugStub.ArgList(Read32(Register.IMS),
  713. Read32(Register.RX_ERR_COUNT)));
  714. DebugPrint("Recv Addr High {0:x8} Recv Addr Low {1:x8}\n",
  715. DebugStub.ArgList(Read32(Register.RAH0),
  716. Read32(Register.RAL0)));
  717. DebugPrint("Recv Desc Head {0:x8} Recv Desc Tail {1:x8}\n",
  718. DebugStub.ArgList(Read32(Register.RECV_DESC_HEAD),
  719. Read32(Register.RECV_DESC_TAIL)));
  720. DebugPrint("Tsmt Desc Head {0:x8} Tsmt Desc Tail {1:x8}\n",
  721. DebugStub.ArgList(Read32(Register.TSMT_DESC_HEAD),
  722. Read32(Register.TSMT_DESC_TAIL)));
  723. }
  724. [Conditional("DEBUG_INTEL")]
  725. private void DumpPhy()
  726. {
  727. for (uint i = 0; i < 32; i += 8) {
  728. DebugWriteLine("PHY {0:x4} : {1:x4} {2:x4} {3:x4} {4:x4} {5:x4} {6:x4} {7:x4} {8:x4}",
  729. DebugStub.ArgList(i,
  730. MiiRead(PhyAddress, i + 0),
  731. MiiRead(PhyAddress, i + 1),
  732. MiiRead(PhyAddress, i + 2),
  733. MiiRead(PhyAddress, i + 3),
  734. MiiRead(PhyAddress, i + 4),
  735. MiiRead(PhyAddress, i + 5),
  736. MiiRead(PhyAddress, i + 6),
  737. MiiRead(PhyAddress, i + 7))
  738. );
  739. }
  740. }
  741. //#if DEBUG_INTEL
  742. #if false
  743. // Occasionally helpful when debugging.
  744. Thread statsThread = null;
  745. internal void StartStatistics()
  746. {
  747. DebugStub.Assert(statsThread == null);
  748. statsThread = new Thread(new ThreadStart(this.StatisticsMain));
  749. statsThread.Start();
  750. }
  751. internal void ReportChanges(uint[] now)
  752. {
  753. DebugWriteLine("Changes.");
  754. for (int i = 0; i < now.Length; i++) {
  755. if (now[i] != 0) {
  756. DebugWriteLine("{0} [0x40{1:x1}] -> {2}",
  757. DebugStub.ArgList(i, i * 4, now[i]));
  758. }
  759. }
  760. rxRingBuffer.Dump();
  761. DebugWriteLine("Rx head {0:x8} tail {1:x8}",
  762. DebugStub.ArgList(Read32(Register.RECV_DESC_HEAD),
  763. Read32(Register.RECV_DESC_TAIL)));
  764. DebugWriteLine("ICS = {0:x8} ICR = {1:x8}",
  765. DebugStub.ArgList(Read32(Register.ICS),
  766. Read32(Register.ICR)));
  767. }
  768. internal void StatisticsMain()
  769. {
  770. uint [] counters1 = new uint[64];
  771. for (;;) {
  772. Thread.Sleep(TimeSpan.FromSeconds(10));
  773. GetStatistics(counters1);
  774. ReportChanges(counters1);
  775. }
  776. }
  777. internal void GetStatistics(uint [] counters)
  778. {
  779. for (uint i = 0; i < counters.Length; i++) {
  780. counters[i] = Read32(0x4000 + i * 4);
  781. }
  782. }
  783. #endif
  784. }
  785. }