xref: /reactos/drivers/network/dd/e1000/hardware.c (revision 7eead935)
1 /*
2  * PROJECT:     ReactOS Intel PRO/1000 Driver
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Hardware specific functions
5  * COPYRIGHT:   2018 Mark Jansen (mark.jansen@reactos.org)
6  *              2019 Victor Perevertkin (victor.perevertkin@reactos.org)
7  */
8 
9 #include "nic.h"
10 
11 #include <debug.h>
12 
13 
14 static USHORT SupportedDevices[] =
15 {
16     /* 8254x Family adapters. Not all of them are tested */
17     0x1000,     // Intel 82542
18     0x1001,     // Intel 82543GC Fiber
19     0x1004,     // Intel 82543GC Copper
20     0x1008,     // Intel 82544EI Copper
21     0x1009,     // Intel 82544EI Fiber
22     0x100A,     // Intel 82540EM
23     0x100C,     // Intel 82544GC Copper
24     0x100D,     // Intel 82544GC LOM (LAN on Motherboard)
25     0x100E,     // Intel 82540EM
26     0x100F,     // Intel 82545EM Copper
27     0x1010,     // Intel 82546EB Copper
28     0x1011,     // Intel 82545EM Fiber
29     0x1012,     // Intel 82546EB Fiber
30     0x1013,     // Intel 82541EI
31     0x1014,     // Intel 82541EI LOM
32     0x1015,     // Intel 82540EM LOM
33     0x1016,     // Intel 82540EP LOM
34     0x1017,     // Intel 82540EP
35     0x1018,     // Intel 82541EI Mobile
36     0x1019,     // Intel 82547EI
37     0x101A,     // Intel 82547EI Mobile
38     0x101D,     // Intel 82546EB Quad Copper
39     0x101E,     // Intel 82540EP LP (Low profile)
40     0x1026,     // Intel 82545GM Copper
41     0x1027,     // Intel 82545GM Fiber
42     0x1028,     // Intel 82545GM SerDes
43     0x1075,     // Intel 82547GI
44     0x1076,     // Intel 82541GI
45     0x1077,     // Intel 82541GI Mobile
46     0x1078,     // Intel 82541ER
47     0x1079,     // Intel 82546GB Copper
48     0x107A,     // Intel 82546GB Fiber
49     0x107B,     // Intel 82546GB SerDes
50     0x107C,     // Intel 82541PI
51     0x108A,     // Intel 82546GB PCI-E
52     0x1099,     // Intel 82546GB Quad Copper
53     0x10B5,     // Intel 82546GB Quad Copper KSP3
54 };
55 
56 
57 static ULONG E1000WriteFlush(IN PE1000_ADAPTER Adapter)
58 {
59     volatile ULONG Value;
60 
61     NdisReadRegisterUlong(Adapter->IoBase + E1000_REG_STATUS, &Value);
62     return Value;
63 }
64 
65 VOID NTAPI E1000WriteUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, IN ULONG Value)
66 {
67     NdisWriteRegisterUlong((PULONG)(Adapter->IoBase + Address), Value);
68 }
69 
70 VOID NTAPI E1000ReadUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, OUT PULONG Value)
71 {
72     NdisReadRegisterUlong((PULONG)(Adapter->IoBase + Address), Value);
73 }
74 
75 static VOID E1000WriteIoUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, IN ULONG Value)
76 {
77     NdisRawWritePortUlong((PULONG)(Adapter->IoPort), Address);
78     E1000WriteFlush(Adapter);
79     NdisRawWritePortUlong((PULONG)(Adapter->IoPort + 4), Value);
80 }
81 
82 static ULONG PacketFilterToMask(ULONG PacketFilter)
83 {
84     ULONG FilterMask = 0;
85 
86     if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)
87     {
88         /* Multicast Promiscuous Enabled */
89         FilterMask |= E1000_RCTL_MPE;
90     }
91     if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
92     {
93         /* Unicast Promiscuous Enabled */
94         FilterMask |= E1000_RCTL_UPE;
95         /* Multicast Promiscuous Enabled */
96         FilterMask |= E1000_RCTL_MPE;
97     }
98     if (PacketFilter & NDIS_PACKET_TYPE_MAC_FRAME)
99     {
100         /* Pass MAC Control Frames */
101         FilterMask |= E1000_RCTL_PMCF;
102     }
103     if (PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
104     {
105         /* Broadcast Accept Mode */
106         FilterMask |= E1000_RCTL_BAM;
107     }
108 
109     return FilterMask;
110 }
111 
112 static ULONG RcvBufAllocationSize(E1000_RCVBUF_SIZE BufSize)
113 {
114     static ULONG PredefSizes[4] = {
115         2048, 1024, 512, 256,
116     };
117     ULONG Size;
118 
119     Size = PredefSizes[BufSize & E1000_RCVBUF_INDEXMASK];
120     if (BufSize & E1000_RCVBUF_RESERVED)
121     {
122         ASSERT(BufSize != 2048);
123         Size *= 16;
124     }
125     return Size;
126 }
127 
128 static ULONG RcvBufRegisterMask(E1000_RCVBUF_SIZE BufSize)
129 {
130     ULONG Mask = 0;
131 
132     Mask |= BufSize & E1000_RCVBUF_INDEXMASK;
133     Mask <<= E1000_RCTL_BSIZE_SHIFT;
134     if (BufSize & E1000_RCVBUF_RESERVED)
135         Mask |= E1000_RCTL_BSEX;
136 
137     return Mask;
138 }
139 
140 #if 0
141 /* This function works, but the driver does not use PHY register access right now */
142 static BOOLEAN E1000ReadMdic(IN PE1000_ADAPTER Adapter, IN ULONG Address, USHORT *Result)
143 {
144     ULONG ResultAddress;
145     ULONG Mdic;
146     UINT n;
147 
148     if (Address > MAX_PHY_REG_ADDRESS)
149     {
150         NDIS_DbgPrint(MIN_TRACE, ("PHY Address %d is invalid\n", Address));
151         return 1;
152     }
153 
154     Mdic = (Address << E1000_MDIC_REGADD_SHIFT);
155     Mdic |= (E1000_MDIC_PHYADD_GIGABIT << E1000_MDIC_PHYADD_SHIFT);
156     Mdic |= E1000_MDIC_OP_READ;
157 
158     E1000WriteUlong(Adapter, E1000_REG_MDIC, Mdic);
159 
160     for (n = 0; n < MAX_PHY_READ_ATTEMPTS; n++)
161     {
162         NdisStallExecution(50);
163         E1000ReadUlong(Adapter, E1000_REG_MDIC, &Mdic);
164         if (Mdic & E1000_MDIC_R)
165             break;
166     }
167     if (!(Mdic & E1000_MDIC_R))
168     {
169         NDIS_DbgPrint(MIN_TRACE, ("MDI Read incomplete\n"));
170         return FALSE;
171     }
172     if (Mdic & E1000_MDIC_E)
173     {
174         NDIS_DbgPrint(MIN_TRACE, ("MDI Read error\n"));
175         return FALSE;
176     }
177 
178     ResultAddress = (Mdic >> E1000_MDIC_REGADD_SHIFT) & MAX_PHY_REG_ADDRESS;
179 
180     if (ResultAddress!= Address)
181     {
182         /* Add locking? */
183         NDIS_DbgPrint(MIN_TRACE, ("MDI Read got wrong address (%d instead of %d)\n",
184                                   ResultAddress, Address));
185         return FALSE;
186     }
187     *Result = (USHORT) Mdic;
188     return TRUE;
189 }
190 #endif
191 
192 
193 static BOOLEAN E1000ReadEeprom(IN PE1000_ADAPTER Adapter, IN UCHAR Address, USHORT *Result)
194 {
195     ULONG Value;
196     UINT n;
197 
198     E1000WriteUlong(Adapter, E1000_REG_EERD, E1000_EERD_START | ((UINT)Address << E1000_EERD_ADDR_SHIFT));
199 
200     for (n = 0; n < MAX_EEPROM_READ_ATTEMPTS; ++n)
201     {
202         NdisStallExecution(5);
203 
204         E1000ReadUlong(Adapter, E1000_REG_EERD, &Value);
205 
206         if (Value & E1000_EERD_DONE)
207             break;
208     }
209     if (!(Value & E1000_EERD_DONE))
210     {
211         NDIS_DbgPrint(MIN_TRACE, ("EEPROM Read incomplete\n"));
212         return FALSE;
213     }
214     *Result = (USHORT)(Value >> E1000_EERD_DATA_SHIFT);
215     return TRUE;
216 }
217 
218 BOOLEAN E1000ValidateNvmChecksum(IN PE1000_ADAPTER Adapter)
219 {
220     USHORT Checksum = 0, Data;
221     UINT n;
222 
223     /* 5.6.35 Checksum Word Calculation (Word 3Fh) */
224     for (n = 0; n <= E1000_NVM_REG_CHECKSUM; n++)
225     {
226         if (!E1000ReadEeprom(Adapter, n, &Data))
227         {
228             return FALSE;
229         }
230         Checksum += Data;
231     }
232 
233     if (Checksum != NVM_MAGIC_SUM)
234     {
235         NDIS_DbgPrint(MIN_TRACE, ("EEPROM has an invalid checksum of 0x%x\n", (ULONG)Checksum));
236         return FALSE;
237     }
238 
239     return TRUE;
240 }
241 
242 
243 BOOLEAN
244 NTAPI
245 NICRecognizeHardware(
246     IN PE1000_ADAPTER Adapter)
247 {
248     UINT n;
249     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
250 
251     if (Adapter->VendorID != HW_VENDOR_INTEL)
252     {
253         NDIS_DbgPrint(MIN_TRACE, ("Unknown vendor: 0x%x\n", Adapter->VendorID));
254         return FALSE;
255     }
256 
257     for (n = 0; n < ARRAYSIZE(SupportedDevices); ++n)
258     {
259         if (SupportedDevices[n] == Adapter->DeviceID)
260         {
261             return TRUE;
262         }
263     }
264 
265     NDIS_DbgPrint(MIN_TRACE, ("Unknown device: 0x%x\n", Adapter->DeviceID));
266 
267     return FALSE;
268 }
269 
270 NDIS_STATUS
271 NTAPI
272 NICInitializeAdapterResources(
273     IN PE1000_ADAPTER Adapter,
274     IN PNDIS_RESOURCE_LIST ResourceList)
275 {
276     UINT n;
277     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
278 
279     for (n = 0; n < ResourceList->Count; n++)
280     {
281         PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor = ResourceList->PartialDescriptors + n;
282 
283         switch (ResourceDescriptor->Type)
284         {
285         case CmResourceTypePort:
286             ASSERT(Adapter->IoPortAddress == 0);
287             ASSERT(ResourceDescriptor->u.Port.Start.HighPart == 0);
288 
289             Adapter->IoPortAddress = ResourceDescriptor->u.Port.Start.LowPart;
290             Adapter->IoPortLength = ResourceDescriptor->u.Port.Length;
291 
292             NDIS_DbgPrint(MID_TRACE, ("I/O port range is %p to %p\n",
293                                       Adapter->IoPortAddress,
294                                       Adapter->IoPortAddress + Adapter->IoPortLength));
295             break;
296         case CmResourceTypeInterrupt:
297             ASSERT(Adapter->InterruptVector == 0);
298             ASSERT(Adapter->InterruptLevel == 0);
299 
300             Adapter->InterruptVector = ResourceDescriptor->u.Interrupt.Vector;
301             Adapter->InterruptLevel = ResourceDescriptor->u.Interrupt.Level;
302             Adapter->InterruptShared = (ResourceDescriptor->ShareDisposition == CmResourceShareShared);
303             Adapter->InterruptFlags = ResourceDescriptor->Flags;
304 
305             NDIS_DbgPrint(MID_TRACE, ("IRQ vector is %d\n", Adapter->InterruptVector));
306             break;
307         case CmResourceTypeMemory:
308             /* Internal registers and memories (including PHY) */
309             if (ResourceDescriptor->u.Memory.Length ==  (128 * 1024))
310             {
311                 ASSERT(Adapter->IoAddress.LowPart == 0);
312                 ASSERT(ResourceDescriptor->u.Port.Start.HighPart == 0);
313 
314 
315                 Adapter->IoAddress.QuadPart = ResourceDescriptor->u.Memory.Start.QuadPart;
316                 Adapter->IoLength = ResourceDescriptor->u.Memory.Length;
317                 NDIS_DbgPrint(MID_TRACE, ("Memory range is %I64x to %I64x\n",
318                                           Adapter->IoAddress.QuadPart,
319                                           Adapter->IoAddress.QuadPart + Adapter->IoLength));
320             }
321             break;
322 
323         default:
324             NDIS_DbgPrint(MIN_TRACE, ("Unrecognized resource type: 0x%x\n", ResourceDescriptor->Type));
325             break;
326         }
327     }
328 
329     if (Adapter->IoAddress.QuadPart == 0 || Adapter->IoPortAddress == 0 || Adapter->InterruptVector == 0)
330     {
331         NDIS_DbgPrint(MIN_TRACE, ("Adapter didn't receive enough resources\n"));
332         return NDIS_STATUS_RESOURCES;
333     }
334 
335     return NDIS_STATUS_SUCCESS;
336 }
337 
338 NDIS_STATUS
339 NTAPI
340 NICAllocateIoResources(
341     IN PE1000_ADAPTER Adapter)
342 {
343     NDIS_STATUS Status;
344     ULONG AllocationSize;
345     UINT n;
346 
347     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
348 
349     Status = NdisMRegisterIoPortRange((PVOID*)&Adapter->IoPort,
350                                       Adapter->AdapterHandle,
351                                       Adapter->IoPortAddress,
352                                       Adapter->IoPortLength);
353     if (Status != NDIS_STATUS_SUCCESS)
354     {
355         NDIS_DbgPrint(MIN_TRACE, ("Unable to register IO port range (0x%x)\n", Status));
356         return NDIS_STATUS_RESOURCES;
357     }
358 
359     Status = NdisMMapIoSpace((PVOID*)&Adapter->IoBase,
360                              Adapter->AdapterHandle,
361                              Adapter->IoAddress,
362                              Adapter->IoLength);
363 
364 
365     NdisMAllocateSharedMemory(Adapter->AdapterHandle,
366                               sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS,
367                               FALSE,
368                               (PVOID*)&Adapter->TransmitDescriptors,
369                               &Adapter->TransmitDescriptorsPa);
370     if (Adapter->TransmitDescriptors == NULL)
371     {
372         NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate transmit descriptors\n"));
373         return NDIS_STATUS_RESOURCES;
374     }
375 
376     for (n = 0; n < NUM_TRANSMIT_DESCRIPTORS; ++n)
377     {
378         PE1000_TRANSMIT_DESCRIPTOR Descriptor = Adapter->TransmitDescriptors + n;
379         Descriptor->Address = 0;
380         Descriptor->Length = 0;
381     }
382 
383     NdisMAllocateSharedMemory(Adapter->AdapterHandle,
384                               sizeof(E1000_RECEIVE_DESCRIPTOR) * NUM_RECEIVE_DESCRIPTORS,
385                               FALSE,
386                               (PVOID*)&Adapter->ReceiveDescriptors,
387                               &Adapter->ReceiveDescriptorsPa);
388     if (Adapter->ReceiveDescriptors == NULL)
389     {
390         NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate receive descriptors\n"));
391         return NDIS_STATUS_RESOURCES;
392     }
393 
394     AllocationSize = RcvBufAllocationSize(Adapter->ReceiveBufferType);
395     ASSERT(Adapter->ReceiveBufferEntrySize == 0 || Adapter->ReceiveBufferEntrySize == AllocationSize);
396     Adapter->ReceiveBufferEntrySize = AllocationSize;
397 
398     NdisMAllocateSharedMemory(Adapter->AdapterHandle,
399                               Adapter->ReceiveBufferEntrySize * NUM_RECEIVE_DESCRIPTORS,
400                               FALSE,
401                               (PVOID*)&Adapter->ReceiveBuffer,
402                               &Adapter->ReceiveBufferPa);
403 
404     if (Adapter->ReceiveBuffer == NULL)
405     {
406         NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate receive buffer\n"));
407         return NDIS_STATUS_RESOURCES;
408     }
409 
410     for (n = 0; n < NUM_RECEIVE_DESCRIPTORS; ++n)
411     {
412         PE1000_RECEIVE_DESCRIPTOR Descriptor = Adapter->ReceiveDescriptors + n;
413 
414         RtlZeroMemory(Descriptor, sizeof(*Descriptor));
415         Descriptor->Address = Adapter->ReceiveBufferPa.QuadPart + n * Adapter->ReceiveBufferEntrySize;
416     }
417 
418     return NDIS_STATUS_SUCCESS;
419 }
420 
421 NDIS_STATUS
422 NTAPI
423 NICRegisterInterrupts(
424     IN PE1000_ADAPTER Adapter)
425 {
426     NDIS_STATUS Status;
427     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
428 
429     Status = NdisMRegisterInterrupt(&Adapter->Interrupt,
430                                     Adapter->AdapterHandle,
431                                     Adapter->InterruptVector,
432                                     Adapter->InterruptLevel,
433                                     TRUE, // We always want ISR calls
434                                     Adapter->InterruptShared,
435                                     (Adapter->InterruptFlags & CM_RESOURCE_INTERRUPT_LATCHED) ?
436                                     NdisInterruptLatched : NdisInterruptLevelSensitive);
437 
438     if (Status == NDIS_STATUS_SUCCESS)
439     {
440         Adapter->InterruptRegistered = TRUE;
441     }
442 
443     return Status;
444 }
445 
446 NDIS_STATUS
447 NTAPI
448 NICUnregisterInterrupts(
449     IN PE1000_ADAPTER Adapter)
450 {
451     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
452 
453     if (Adapter->InterruptRegistered)
454     {
455         NdisMDeregisterInterrupt(&Adapter->Interrupt);
456         Adapter->InterruptRegistered = FALSE;
457     }
458 
459     return NDIS_STATUS_SUCCESS;
460 }
461 
462 NDIS_STATUS
463 NTAPI
464 NICReleaseIoResources(
465     IN PE1000_ADAPTER Adapter)
466 {
467     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
468 
469     if (Adapter->ReceiveDescriptors != NULL)
470     {
471         /* Disassociate our shared buffer before freeing it to avoid NIC-induced memory corruption */
472         if (Adapter->IoBase)
473         {
474             E1000WriteUlong(Adapter, E1000_REG_RDH, 0);
475             E1000WriteUlong(Adapter, E1000_REG_RDT, 0);
476         }
477 
478         NdisMFreeSharedMemory(Adapter->AdapterHandle,
479                               sizeof(E1000_RECEIVE_DESCRIPTOR) * NUM_RECEIVE_DESCRIPTORS,
480                               FALSE,
481                               Adapter->ReceiveDescriptors,
482                               Adapter->ReceiveDescriptorsPa);
483 
484         Adapter->ReceiveDescriptors = NULL;
485     }
486 
487     if (Adapter->ReceiveBuffer != NULL)
488     {
489         NdisMFreeSharedMemory(Adapter->AdapterHandle,
490                               Adapter->ReceiveBufferEntrySize * NUM_RECEIVE_DESCRIPTORS,
491                               FALSE,
492                               Adapter->ReceiveBuffer,
493                               Adapter->ReceiveBufferPa);
494 
495         Adapter->ReceiveBuffer = NULL;
496         Adapter->ReceiveBufferEntrySize = 0;
497     }
498 
499 
500     if (Adapter->TransmitDescriptors != NULL)
501     {
502         /* Disassociate our shared buffer before freeing it to avoid NIC-induced memory corruption */
503         if (Adapter->IoBase)
504         {
505             E1000WriteUlong(Adapter, E1000_REG_TDH, 0);
506             E1000WriteUlong(Adapter, E1000_REG_TDT, 0);
507         }
508 
509         NdisMFreeSharedMemory(Adapter->AdapterHandle,
510                               sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS,
511                               FALSE,
512                               Adapter->TransmitDescriptors,
513                               Adapter->TransmitDescriptorsPa);
514 
515         Adapter->TransmitDescriptors = NULL;
516     }
517 
518 
519 
520     if (Adapter->IoPort)
521     {
522         NdisMDeregisterIoPortRange(Adapter->AdapterHandle,
523                                    Adapter->IoPortAddress,
524                                    Adapter->IoPortLength,
525                                    Adapter->IoPort);
526     }
527 
528     if (Adapter->IoBase)
529     {
530         NdisMUnmapIoSpace(Adapter->AdapterHandle, Adapter->IoBase, Adapter->IoLength);
531     }
532 
533 
534     return NDIS_STATUS_SUCCESS;
535 }
536 
537 
538 NDIS_STATUS
539 NTAPI
540 NICPowerOn(
541     IN PE1000_ADAPTER Adapter)
542 {
543     NDIS_STATUS Status;
544     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
545 
546     Status = NICSoftReset(Adapter);
547     if (Status != NDIS_STATUS_SUCCESS)
548     {
549         return Status;
550     }
551 
552     if (!E1000ValidateNvmChecksum(Adapter))
553     {
554         return NDIS_STATUS_INVALID_DATA;
555     }
556 
557     return NDIS_STATUS_SUCCESS;
558 }
559 
560 NDIS_STATUS
561 NTAPI
562 NICSoftReset(
563     IN PE1000_ADAPTER Adapter)
564 {
565     ULONG Value, ResetAttempts;
566     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
567 
568     NICDisableInterrupts(Adapter);
569     E1000WriteUlong(Adapter, E1000_REG_RCTL, 0);
570     E1000WriteUlong(Adapter, E1000_REG_TCTL, 0);
571     E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value);
572     /* Write this using IO port, some devices cannot ack this otherwise */
573     E1000WriteIoUlong(Adapter, E1000_REG_CTRL, Value | E1000_CTRL_RST);
574 
575 
576     for (ResetAttempts = 0; ResetAttempts < MAX_RESET_ATTEMPTS; ResetAttempts++)
577     {
578         /* Wait 1us after reset (according to manual) */
579         NdisStallExecution(1);
580         E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value);
581 
582         if (!(Value & E1000_CTRL_RST))
583         {
584             NDIS_DbgPrint(MAX_TRACE, ("Device is back (%u)\n", ResetAttempts));
585 
586             NICDisableInterrupts(Adapter);
587             /* Clear out interrupts (the register is cleared upon read) */
588             E1000ReadUlong(Adapter, E1000_REG_ICR, &Value);
589 
590             E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value);
591             Value &= ~(E1000_CTRL_LRST|E1000_CTRL_VME);
592             Value |= (E1000_CTRL_ASDE|E1000_CTRL_SLU);
593             E1000WriteUlong(Adapter, E1000_REG_CTRL, Value);
594 
595             return NDIS_STATUS_SUCCESS;
596         }
597     }
598 
599     NDIS_DbgPrint(MIN_TRACE, ("Device did not recover\n"));
600     return NDIS_STATUS_FAILURE;
601 }
602 
603 NDIS_STATUS
604 NTAPI
605 NICEnableTxRx(
606     IN PE1000_ADAPTER Adapter)
607 {
608     ULONG Value;
609 
610     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
611     NDIS_DbgPrint(MID_TRACE, ("Setting up transmit.\n"));
612 
613     /* Make sure the thing is disabled first. */
614     E1000WriteUlong(Adapter, E1000_REG_TCTL, 0);
615 
616     /* Transmit descriptor ring buffer */
617     E1000WriteUlong(Adapter, E1000_REG_TDBAH, Adapter->TransmitDescriptorsPa.HighPart);
618     E1000WriteUlong(Adapter, E1000_REG_TDBAL, Adapter->TransmitDescriptorsPa.LowPart);
619 
620     /* Transmit descriptor buffer size */
621     E1000WriteUlong(Adapter, E1000_REG_TDLEN, sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS);
622 
623     /* Transmit descriptor tail / head */
624     E1000WriteUlong(Adapter, E1000_REG_TDH, 0);
625     E1000WriteUlong(Adapter, E1000_REG_TDT, 0);
626     Adapter->CurrentTxDesc = 0;
627 
628     /* Set up interrupt timers */
629     E1000WriteUlong(Adapter, E1000_REG_TADV, 96); // value is in 1.024 of usec
630     E1000WriteUlong(Adapter, E1000_REG_TIDV, 16);
631 
632     E1000WriteUlong(Adapter, E1000_REG_TCTL, E1000_TCTL_EN | E1000_TCTL_PSP);
633 
634     E1000WriteUlong(Adapter, E1000_REG_TIPG, E1000_TIPG_IPGT_DEF | E1000_TIPG_IPGR1_DEF | E1000_TIPG_IPGR2_DEF);
635 
636     NDIS_DbgPrint(MID_TRACE, ("Setting up receive.\n"));
637 
638     /* Make sure the thing is disabled first. */
639     E1000WriteUlong(Adapter, E1000_REG_RCTL, 0);
640 
641     /* Receive descriptor ring buffer */
642     E1000WriteUlong(Adapter, E1000_REG_RDBAH, Adapter->ReceiveDescriptorsPa.HighPart);
643     E1000WriteUlong(Adapter, E1000_REG_RDBAL, Adapter->ReceiveDescriptorsPa.LowPart);
644 
645     /* Receive descriptor buffer size */
646     E1000WriteUlong(Adapter, E1000_REG_RDLEN, sizeof(E1000_RECEIVE_DESCRIPTOR) * NUM_RECEIVE_DESCRIPTORS);
647 
648     /* Receive descriptor tail / head */
649     E1000WriteUlong(Adapter, E1000_REG_RDH, 0);
650     E1000WriteUlong(Adapter, E1000_REG_RDT, NUM_RECEIVE_DESCRIPTORS - 1);
651 
652     /* Set up interrupt timers */
653     E1000WriteUlong(Adapter, E1000_REG_RADV, 96);
654     E1000WriteUlong(Adapter, E1000_REG_RDTR, 16);
655 
656     /* Some defaults */
657     Value = E1000_RCTL_SECRC | E1000_RCTL_EN;
658 
659     /* Receive buffer size */
660     Value |= RcvBufRegisterMask(Adapter->ReceiveBufferType);
661 
662     /* Add our current packet filter */
663     Value |= PacketFilterToMask(Adapter->PacketFilter);
664 
665     E1000WriteUlong(Adapter, E1000_REG_RCTL, Value);
666 
667     return NDIS_STATUS_SUCCESS;
668 }
669 
670 NDIS_STATUS
671 NTAPI
672 NICDisableTxRx(
673     IN PE1000_ADAPTER Adapter)
674 {
675     ULONG Value;
676 
677     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
678 
679     E1000ReadUlong(Adapter, E1000_REG_TCTL, &Value);
680     Value &= ~E1000_TCTL_EN;
681     E1000WriteUlong(Adapter, E1000_REG_TCTL, Value);
682 
683     E1000ReadUlong(Adapter, E1000_REG_RCTL, &Value);
684     Value &= ~E1000_RCTL_EN;
685     E1000WriteUlong(Adapter, E1000_REG_RCTL, Value);
686 
687     return NDIS_STATUS_SUCCESS;
688 }
689 
690 NDIS_STATUS
691 NTAPI
692 NICGetPermanentMacAddress(
693     IN PE1000_ADAPTER Adapter,
694     OUT PUCHAR MacAddress)
695 {
696     USHORT AddrWord;
697     UINT n;
698 
699     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
700 
701     /* Should we read from RAL/RAH first? */
702     for (n = 0; n < (IEEE_802_ADDR_LENGTH / 2); ++n)
703     {
704         if (!E1000ReadEeprom(Adapter, (UCHAR)n, &AddrWord))
705             return NDIS_STATUS_FAILURE;
706         Adapter->PermanentMacAddress[n * 2 + 0] = AddrWord & 0xff;
707         Adapter->PermanentMacAddress[n * 2 + 1] = (AddrWord >> 8) & 0xff;
708     }
709 
710     NDIS_DbgPrint(MIN_TRACE, ("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
711                               Adapter->PermanentMacAddress[0],
712                               Adapter->PermanentMacAddress[1],
713                               Adapter->PermanentMacAddress[2],
714                               Adapter->PermanentMacAddress[3],
715                               Adapter->PermanentMacAddress[4],
716                               Adapter->PermanentMacAddress[5]));
717     return NDIS_STATUS_SUCCESS;
718 }
719 
720 NDIS_STATUS
721 NTAPI
722 NICUpdateMulticastList(
723     IN PE1000_ADAPTER Adapter)
724 {
725     UINT n;
726     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
727 
728     for (n = 0; n < MAXIMUM_MULTICAST_ADDRESSES; ++n)
729     {
730         ULONG Ral = *(ULONG *)Adapter->MulticastList[n].MacAddress;
731         ULONG Rah = *(USHORT *)&Adapter->MulticastList[n].MacAddress[4];
732 
733         if (Rah || Ral)
734         {
735             Rah |= E1000_RAH_AV;
736 
737             E1000WriteUlong(Adapter, E1000_REG_RAL + (8*n), Ral);
738             E1000WriteUlong(Adapter, E1000_REG_RAH + (8*n), Rah);
739         }
740         else
741         {
742             E1000WriteUlong(Adapter, E1000_REG_RAH + (8*n), 0);
743             E1000WriteUlong(Adapter, E1000_REG_RAL + (8*n), 0);
744         }
745     }
746 
747     return NDIS_STATUS_SUCCESS;
748 }
749 
750 NDIS_STATUS
751 NTAPI
752 NICApplyPacketFilter(
753     IN PE1000_ADAPTER Adapter)
754 {
755     ULONG FilterMask;
756 
757     E1000ReadUlong(Adapter, E1000_REG_RCTL, &FilterMask);
758 
759     FilterMask &= ~E1000_RCTL_FILTER_BITS;
760     FilterMask |= PacketFilterToMask(Adapter->PacketFilter);
761     E1000WriteUlong(Adapter, E1000_REG_RCTL, FilterMask);
762 
763     return NDIS_STATUS_SUCCESS;
764 }
765 
766 NDIS_STATUS
767 NTAPI
768 NICApplyInterruptMask(
769     IN PE1000_ADAPTER Adapter)
770 {
771     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
772 
773     E1000WriteUlong(Adapter, E1000_REG_IMS, Adapter->InterruptMask /*| 0x1F6DC*/);
774     return NDIS_STATUS_SUCCESS;
775 }
776 
777 NDIS_STATUS
778 NTAPI
779 NICDisableInterrupts(
780     IN PE1000_ADAPTER Adapter)
781 {
782     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
783 
784     E1000WriteUlong(Adapter, E1000_REG_IMC, ~0);
785     return NDIS_STATUS_SUCCESS;
786 }
787 
788 ULONG
789 NTAPI
790 NICInterruptRecognized(
791     IN PE1000_ADAPTER Adapter,
792     OUT PBOOLEAN InterruptRecognized)
793 {
794     ULONG Value;
795 
796     /* Reading the interrupt acknowledges them */
797     E1000ReadUlong(Adapter, E1000_REG_ICR, &Value);
798 
799     *InterruptRecognized = (Value & Adapter->InterruptMask) != 0;
800 
801     NDIS_DbgPrint(MAX_TRACE, ("NICInterruptRecognized(0x%x, 0x%x).\n", Value, *InterruptRecognized));
802 
803     return (Value & Adapter->InterruptMask);
804 }
805 
806 VOID
807 NTAPI
808 NICUpdateLinkStatus(
809     IN PE1000_ADAPTER Adapter)
810 {
811     ULONG DeviceStatus;
812     SIZE_T SpeedIndex;
813     static ULONG SpeedValues[] = { 10, 100, 1000, 1000 };
814 
815     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
816 
817     E1000ReadUlong(Adapter, E1000_REG_STATUS, &DeviceStatus);
818     Adapter->MediaState = (DeviceStatus & E1000_STATUS_LU) ? NdisMediaStateConnected : NdisMediaStateDisconnected;
819     SpeedIndex = (DeviceStatus & E1000_STATUS_SPEEDMASK) >> E1000_STATUS_SPEEDSHIFT;
820     Adapter->LinkSpeedMbps = SpeedValues[SpeedIndex];
821 }
822 
823 NDIS_STATUS
824 NTAPI
825 NICTransmitPacket(
826     IN PE1000_ADAPTER Adapter,
827     IN PHYSICAL_ADDRESS PhysicalAddress,
828     IN ULONG Length)
829 {
830     volatile PE1000_TRANSMIT_DESCRIPTOR TransmitDescriptor;
831 
832     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
833 
834     TransmitDescriptor = Adapter->TransmitDescriptors + Adapter->CurrentTxDesc;
835     TransmitDescriptor->Address = PhysicalAddress.QuadPart;
836     TransmitDescriptor->Length = Length;
837     TransmitDescriptor->ChecksumOffset = 0;
838     TransmitDescriptor->Command = E1000_TDESC_CMD_RS | E1000_TDESC_CMD_IFCS | E1000_TDESC_CMD_EOP | E1000_TDESC_CMD_IDE;
839     TransmitDescriptor->Status = 0;
840     TransmitDescriptor->ChecksumStartField = 0;
841     TransmitDescriptor->Special = 0;
842 
843     Adapter->CurrentTxDesc = (Adapter->CurrentTxDesc + 1) % NUM_TRANSMIT_DESCRIPTORS;
844 
845     E1000WriteUlong(Adapter, E1000_REG_TDT, Adapter->CurrentTxDesc);
846 
847     if (Adapter->CurrentTxDesc == Adapter->LastTxDesc)
848     {
849         NDIS_DbgPrint(MID_TRACE, ("All TX descriptors are full now\n"));
850         Adapter->TxFull = TRUE;
851     }
852 
853     return NDIS_STATUS_SUCCESS;
854 }
855