xref: /reactos/drivers/network/dd/e1000/hardware.c (revision 84344399)
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 static ULONG PacketFilterToMask(ULONG PacketFilter)
57 {
58     ULONG FilterMask = 0;
59 
60     if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)
61     {
62         /* Multicast Promiscuous Enabled */
63         FilterMask |= E1000_RCTL_MPE;
64     }
65     if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
66     {
67         /* Unicast Promiscuous Enabled */
68         FilterMask |= E1000_RCTL_UPE;
69         /* Multicast Promiscuous Enabled */
70         FilterMask |= E1000_RCTL_MPE;
71     }
72     if (PacketFilter & NDIS_PACKET_TYPE_MAC_FRAME)
73     {
74         /* Pass MAC Control Frames */
75         FilterMask |= E1000_RCTL_PMCF;
76     }
77     if (PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
78     {
79         /* Broadcast Accept Mode */
80         FilterMask |= E1000_RCTL_BAM;
81     }
82 
83     return FilterMask;
84 }
85 
86 static ULONG RcvBufAllocationSize(E1000_RCVBUF_SIZE BufSize)
87 {
88     static ULONG PredefSizes[4] = {
89         2048, 1024, 512, 256,
90     };
91     ULONG Size;
92 
93     Size = PredefSizes[BufSize & E1000_RCVBUF_INDEXMASK];
94     if (BufSize & E1000_RCVBUF_RESERVED)
95     {
96         ASSERT(BufSize != 2048);
97         Size *= 16;
98     }
99     return Size;
100 }
101 
102 static ULONG RcvBufRegisterMask(E1000_RCVBUF_SIZE BufSize)
103 {
104     ULONG Mask = 0;
105 
106     Mask |= BufSize & E1000_RCVBUF_INDEXMASK;
107     Mask <<= E1000_RCTL_BSIZE_SHIFT;
108     if (BufSize & E1000_RCVBUF_RESERVED)
109         Mask |= E1000_RCTL_BSEX;
110 
111     return Mask;
112 }
113 
114 #if 0
115 /* This function works, but the driver does not use PHY register access right now */
116 static BOOLEAN E1000ReadMdic(IN PE1000_ADAPTER Adapter, IN ULONG Address, USHORT *Result)
117 {
118     ULONG ResultAddress;
119     ULONG Mdic;
120     UINT n;
121 
122     ASSERT(Address <= MAX_PHY_REG_ADDRESS)
123 
124     Mdic = (Address << E1000_MDIC_REGADD_SHIFT);
125     Mdic |= (E1000_MDIC_PHYADD_GIGABIT << E1000_MDIC_PHYADD_SHIFT);
126     Mdic |= E1000_MDIC_OP_READ;
127     E1000WriteUlong(Adapter, E1000_REG_MDIC, Mdic);
128 
129     for (n = 0; n < MAX_PHY_READ_ATTEMPTS; n++)
130     {
131         NdisStallExecution(50);
132         E1000ReadUlong(Adapter, E1000_REG_MDIC, &Mdic);
133         if (Mdic & E1000_MDIC_R)
134             break;
135     }
136     if (!(Mdic & E1000_MDIC_R))
137     {
138         NDIS_DbgPrint(MIN_TRACE, ("MDI Read incomplete\n"));
139         return FALSE;
140     }
141     if (Mdic & E1000_MDIC_E)
142     {
143         NDIS_DbgPrint(MIN_TRACE, ("MDI Read error\n"));
144         return FALSE;
145     }
146 
147     ResultAddress = (Mdic >> E1000_MDIC_REGADD_SHIFT) & MAX_PHY_REG_ADDRESS;
148 
149     if (ResultAddress!= Address)
150     {
151         /* Add locking? */
152         NDIS_DbgPrint(MIN_TRACE, ("MDI Read got wrong address (%d instead of %d)\n",
153                                   ResultAddress, Address));
154         return FALSE;
155     }
156     *Result = (USHORT) Mdic;
157     return TRUE;
158 }
159 #endif
160 
161 
162 static BOOLEAN E1000ReadEeprom(IN PE1000_ADAPTER Adapter, IN UCHAR Address, USHORT *Result)
163 {
164     ULONG Value;
165     UINT n;
166 
167     E1000WriteUlong(Adapter, E1000_REG_EERD, E1000_EERD_START | ((UINT)Address << E1000_EERD_ADDR_SHIFT));
168 
169     for (n = 0; n < MAX_EEPROM_READ_ATTEMPTS; ++n)
170     {
171         NdisStallExecution(5);
172 
173         E1000ReadUlong(Adapter, E1000_REG_EERD, &Value);
174 
175         if (Value & E1000_EERD_DONE)
176             break;
177     }
178     if (!(Value & E1000_EERD_DONE))
179     {
180         NDIS_DbgPrint(MIN_TRACE, ("EEPROM Read incomplete\n"));
181         return FALSE;
182     }
183     *Result = (USHORT)(Value >> E1000_EERD_DATA_SHIFT);
184     return TRUE;
185 }
186 
187 BOOLEAN E1000ValidateNvmChecksum(IN PE1000_ADAPTER Adapter)
188 {
189     USHORT Checksum = 0, Data;
190     UINT n;
191 
192     /* 5.6.35 Checksum Word Calculation (Word 3Fh) */
193     for (n = 0; n <= E1000_NVM_REG_CHECKSUM; n++)
194     {
195         if (!E1000ReadEeprom(Adapter, n, &Data))
196         {
197             return FALSE;
198         }
199         Checksum += Data;
200     }
201 
202     if (Checksum != NVM_MAGIC_SUM)
203     {
204         NDIS_DbgPrint(MIN_TRACE, ("EEPROM has an invalid checksum of 0x%x\n", (ULONG)Checksum));
205         return FALSE;
206     }
207 
208     return TRUE;
209 }
210 
211 
212 BOOLEAN
213 NTAPI
214 NICRecognizeHardware(
215     IN PE1000_ADAPTER Adapter)
216 {
217     UINT n;
218     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
219 
220     if (Adapter->VendorID != HW_VENDOR_INTEL)
221     {
222         NDIS_DbgPrint(MIN_TRACE, ("Unknown vendor: 0x%x\n", Adapter->VendorID));
223         return FALSE;
224     }
225 
226     for (n = 0; n < ARRAYSIZE(SupportedDevices); ++n)
227     {
228         if (SupportedDevices[n] == Adapter->DeviceID)
229         {
230             return TRUE;
231         }
232     }
233 
234     NDIS_DbgPrint(MIN_TRACE, ("Unknown device: 0x%x\n", Adapter->DeviceID));
235 
236     return FALSE;
237 }
238 
239 NDIS_STATUS
240 NTAPI
241 NICInitializeAdapterResources(
242     IN PE1000_ADAPTER Adapter,
243     IN PNDIS_RESOURCE_LIST ResourceList)
244 {
245     UINT n;
246     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
247 
248     for (n = 0; n < ResourceList->Count; n++)
249     {
250         PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor = ResourceList->PartialDescriptors + n;
251 
252         switch (ResourceDescriptor->Type)
253         {
254         case CmResourceTypePort:
255             ASSERT(Adapter->IoPortAddress == 0);
256             ASSERT(ResourceDescriptor->u.Port.Start.HighPart == 0);
257 
258             Adapter->IoPortAddress = ResourceDescriptor->u.Port.Start.LowPart;
259             Adapter->IoPortLength = ResourceDescriptor->u.Port.Length;
260 
261             NDIS_DbgPrint(MID_TRACE, ("I/O port range is %p to %p\n",
262                                       Adapter->IoPortAddress,
263                                       Adapter->IoPortAddress + Adapter->IoPortLength));
264             break;
265         case CmResourceTypeInterrupt:
266             ASSERT(Adapter->InterruptVector == 0);
267             ASSERT(Adapter->InterruptLevel == 0);
268 
269             Adapter->InterruptVector = ResourceDescriptor->u.Interrupt.Vector;
270             Adapter->InterruptLevel = ResourceDescriptor->u.Interrupt.Level;
271             Adapter->InterruptShared = (ResourceDescriptor->ShareDisposition == CmResourceShareShared);
272             Adapter->InterruptFlags = ResourceDescriptor->Flags;
273 
274             NDIS_DbgPrint(MID_TRACE, ("IRQ vector is %d\n", Adapter->InterruptVector));
275             break;
276         case CmResourceTypeMemory:
277             /* Internal registers and memories (including PHY) */
278             if (ResourceDescriptor->u.Memory.Length ==  (128 * 1024))
279             {
280                 ASSERT(Adapter->IoAddress.LowPart == 0);
281                 ASSERT(ResourceDescriptor->u.Port.Start.HighPart == 0);
282 
283 
284                 Adapter->IoAddress.QuadPart = ResourceDescriptor->u.Memory.Start.QuadPart;
285                 Adapter->IoLength = ResourceDescriptor->u.Memory.Length;
286                 NDIS_DbgPrint(MID_TRACE, ("Memory range is %I64x to %I64x\n",
287                                           Adapter->IoAddress.QuadPart,
288                                           Adapter->IoAddress.QuadPart + Adapter->IoLength));
289             }
290             break;
291 
292         default:
293             NDIS_DbgPrint(MIN_TRACE, ("Unrecognized resource type: 0x%x\n", ResourceDescriptor->Type));
294             break;
295         }
296     }
297 
298     if (Adapter->IoAddress.QuadPart == 0 || Adapter->IoPortAddress == 0 || Adapter->InterruptVector == 0)
299     {
300         NDIS_DbgPrint(MIN_TRACE, ("Adapter didn't receive enough resources\n"));
301         return NDIS_STATUS_RESOURCES;
302     }
303 
304     return NDIS_STATUS_SUCCESS;
305 }
306 
307 NDIS_STATUS
308 NTAPI
309 NICAllocateIoResources(
310     IN PE1000_ADAPTER Adapter)
311 {
312     NDIS_STATUS Status;
313     ULONG AllocationSize;
314     UINT n;
315 
316     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
317 
318     Status = NdisMRegisterIoPortRange((PVOID*)&Adapter->IoPort,
319                                       Adapter->AdapterHandle,
320                                       Adapter->IoPortAddress,
321                                       Adapter->IoPortLength);
322     if (Status != NDIS_STATUS_SUCCESS)
323     {
324         NDIS_DbgPrint(MIN_TRACE, ("Unable to register IO port range (0x%x)\n", Status));
325         return NDIS_STATUS_RESOURCES;
326     }
327 
328     Status = NdisMMapIoSpace((PVOID*)&Adapter->IoBase,
329                              Adapter->AdapterHandle,
330                              Adapter->IoAddress,
331                              Adapter->IoLength);
332 
333 
334     NdisMAllocateSharedMemory(Adapter->AdapterHandle,
335                               sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS,
336                               FALSE,
337                               (PVOID*)&Adapter->TransmitDescriptors,
338                               &Adapter->TransmitDescriptorsPa);
339     if (Adapter->TransmitDescriptors == NULL)
340     {
341         NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate transmit descriptors\n"));
342         return NDIS_STATUS_RESOURCES;
343     }
344 
345     for (n = 0; n < NUM_TRANSMIT_DESCRIPTORS; ++n)
346     {
347         PE1000_TRANSMIT_DESCRIPTOR Descriptor = Adapter->TransmitDescriptors + n;
348         Descriptor->Address = 0;
349         Descriptor->Length = 0;
350     }
351 
352     NdisMAllocateSharedMemory(Adapter->AdapterHandle,
353                               sizeof(E1000_RECEIVE_DESCRIPTOR) * NUM_RECEIVE_DESCRIPTORS,
354                               FALSE,
355                               (PVOID*)&Adapter->ReceiveDescriptors,
356                               &Adapter->ReceiveDescriptorsPa);
357     if (Adapter->ReceiveDescriptors == NULL)
358     {
359         NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate receive descriptors\n"));
360         return NDIS_STATUS_RESOURCES;
361     }
362 
363     AllocationSize = RcvBufAllocationSize(Adapter->ReceiveBufferType);
364     ASSERT(Adapter->ReceiveBufferEntrySize == 0 || Adapter->ReceiveBufferEntrySize == AllocationSize);
365     Adapter->ReceiveBufferEntrySize = AllocationSize;
366 
367     NdisMAllocateSharedMemory(Adapter->AdapterHandle,
368                               Adapter->ReceiveBufferEntrySize * NUM_RECEIVE_DESCRIPTORS,
369                               FALSE,
370                               (PVOID*)&Adapter->ReceiveBuffer,
371                               &Adapter->ReceiveBufferPa);
372 
373     if (Adapter->ReceiveBuffer == NULL)
374     {
375         NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate receive buffer\n"));
376         return NDIS_STATUS_RESOURCES;
377     }
378 
379     for (n = 0; n < NUM_RECEIVE_DESCRIPTORS; ++n)
380     {
381         PE1000_RECEIVE_DESCRIPTOR Descriptor = Adapter->ReceiveDescriptors + n;
382 
383         RtlZeroMemory(Descriptor, sizeof(*Descriptor));
384         Descriptor->Address = Adapter->ReceiveBufferPa.QuadPart + n * Adapter->ReceiveBufferEntrySize;
385     }
386 
387     return NDIS_STATUS_SUCCESS;
388 }
389 
390 NDIS_STATUS
391 NTAPI
392 NICRegisterInterrupts(
393     IN PE1000_ADAPTER Adapter)
394 {
395     NDIS_STATUS Status;
396     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
397 
398     Status = NdisMRegisterInterrupt(&Adapter->Interrupt,
399                                     Adapter->AdapterHandle,
400                                     Adapter->InterruptVector,
401                                     Adapter->InterruptLevel,
402                                     TRUE, // We always want ISR calls
403                                     Adapter->InterruptShared,
404                                     (Adapter->InterruptFlags & CM_RESOURCE_INTERRUPT_LATCHED) ?
405                                     NdisInterruptLatched : NdisInterruptLevelSensitive);
406 
407     if (Status == NDIS_STATUS_SUCCESS)
408     {
409         Adapter->InterruptRegistered = TRUE;
410     }
411 
412     return Status;
413 }
414 
415 NDIS_STATUS
416 NTAPI
417 NICUnregisterInterrupts(
418     IN PE1000_ADAPTER Adapter)
419 {
420     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
421 
422     if (Adapter->InterruptRegistered)
423     {
424         NdisMDeregisterInterrupt(&Adapter->Interrupt);
425         Adapter->InterruptRegistered = FALSE;
426     }
427 
428     return NDIS_STATUS_SUCCESS;
429 }
430 
431 NDIS_STATUS
432 NTAPI
433 NICReleaseIoResources(
434     IN PE1000_ADAPTER Adapter)
435 {
436     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
437 
438     if (Adapter->ReceiveDescriptors != NULL)
439     {
440         /* Disassociate our shared buffer before freeing it to avoid NIC-induced memory corruption */
441         if (Adapter->IoBase)
442         {
443             E1000WriteUlong(Adapter, E1000_REG_RDH, 0);
444             E1000WriteUlong(Adapter, E1000_REG_RDT, 0);
445         }
446 
447         NdisMFreeSharedMemory(Adapter->AdapterHandle,
448                               sizeof(E1000_RECEIVE_DESCRIPTOR) * NUM_RECEIVE_DESCRIPTORS,
449                               FALSE,
450                               Adapter->ReceiveDescriptors,
451                               Adapter->ReceiveDescriptorsPa);
452 
453         Adapter->ReceiveDescriptors = NULL;
454     }
455 
456     if (Adapter->ReceiveBuffer != NULL)
457     {
458         NdisMFreeSharedMemory(Adapter->AdapterHandle,
459                               Adapter->ReceiveBufferEntrySize * NUM_RECEIVE_DESCRIPTORS,
460                               FALSE,
461                               Adapter->ReceiveBuffer,
462                               Adapter->ReceiveBufferPa);
463 
464         Adapter->ReceiveBuffer = NULL;
465         Adapter->ReceiveBufferEntrySize = 0;
466     }
467 
468 
469     if (Adapter->TransmitDescriptors != 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_TDH, 0);
475             E1000WriteUlong(Adapter, E1000_REG_TDT, 0);
476         }
477 
478         NdisMFreeSharedMemory(Adapter->AdapterHandle,
479                               sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS,
480                               FALSE,
481                               Adapter->TransmitDescriptors,
482                               Adapter->TransmitDescriptorsPa);
483 
484         Adapter->TransmitDescriptors = NULL;
485     }
486 
487 
488 
489     if (Adapter->IoPort)
490     {
491         NdisMDeregisterIoPortRange(Adapter->AdapterHandle,
492                                    Adapter->IoPortAddress,
493                                    Adapter->IoPortLength,
494                                    Adapter->IoPort);
495     }
496 
497     if (Adapter->IoBase)
498     {
499         NdisMUnmapIoSpace(Adapter->AdapterHandle, Adapter->IoBase, Adapter->IoLength);
500     }
501 
502 
503     return NDIS_STATUS_SUCCESS;
504 }
505 
506 
507 NDIS_STATUS
508 NTAPI
509 NICPowerOn(
510     IN PE1000_ADAPTER Adapter)
511 {
512     NDIS_STATUS Status;
513     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
514 
515     Status = NICSoftReset(Adapter);
516     if (Status != NDIS_STATUS_SUCCESS)
517     {
518         return Status;
519     }
520 
521     if (!E1000ValidateNvmChecksum(Adapter))
522     {
523         return NDIS_STATUS_INVALID_DATA;
524     }
525 
526     return NDIS_STATUS_SUCCESS;
527 }
528 
529 NDIS_STATUS
530 NTAPI
531 NICSoftReset(
532     IN PE1000_ADAPTER Adapter)
533 {
534     ULONG Value, ResetAttempts;
535     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
536 
537     NICDisableInterrupts(Adapter);
538     E1000WriteUlong(Adapter, E1000_REG_RCTL, 0);
539     E1000WriteUlong(Adapter, E1000_REG_TCTL, 0);
540     E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value);
541     /* Write this using IO port, some devices cannot ack this otherwise */
542     E1000WriteIoUlong(Adapter, E1000_REG_CTRL, Value | E1000_CTRL_RST);
543 
544 
545     for (ResetAttempts = 0; ResetAttempts < MAX_RESET_ATTEMPTS; ResetAttempts++)
546     {
547         /* Wait 1us after reset (according to manual) */
548         NdisStallExecution(1);
549         E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value);
550 
551         if (!(Value & E1000_CTRL_RST))
552         {
553             NDIS_DbgPrint(MAX_TRACE, ("Device is back (%u)\n", ResetAttempts));
554 
555             NICDisableInterrupts(Adapter);
556             /* Clear out interrupts (the register is cleared upon read) */
557             E1000ReadUlong(Adapter, E1000_REG_ICR, &Value);
558 
559             E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value);
560             Value &= ~(E1000_CTRL_LRST|E1000_CTRL_VME);
561             Value |= (E1000_CTRL_ASDE|E1000_CTRL_SLU);
562             E1000WriteUlong(Adapter, E1000_REG_CTRL, Value);
563 
564             return NDIS_STATUS_SUCCESS;
565         }
566     }
567 
568     NDIS_DbgPrint(MIN_TRACE, ("Device did not recover\n"));
569     return NDIS_STATUS_FAILURE;
570 }
571 
572 NDIS_STATUS
573 NTAPI
574 NICEnableTxRx(
575     IN PE1000_ADAPTER Adapter)
576 {
577     ULONG Value;
578 
579     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
580     NDIS_DbgPrint(MID_TRACE, ("Setting up transmit.\n"));
581 
582     /* Make sure the thing is disabled first. */
583     E1000WriteUlong(Adapter, E1000_REG_TCTL, 0);
584 
585     /* Transmit descriptor ring buffer */
586     E1000WriteUlong(Adapter, E1000_REG_TDBAH, Adapter->TransmitDescriptorsPa.HighPart);
587     E1000WriteUlong(Adapter, E1000_REG_TDBAL, Adapter->TransmitDescriptorsPa.LowPart);
588 
589     /* Transmit descriptor buffer size */
590     E1000WriteUlong(Adapter, E1000_REG_TDLEN, sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS);
591 
592     /* Transmit descriptor tail / head */
593     E1000WriteUlong(Adapter, E1000_REG_TDH, 0);
594     E1000WriteUlong(Adapter, E1000_REG_TDT, 0);
595     Adapter->CurrentTxDesc = 0;
596 
597     /* Set up interrupt timers */
598     E1000WriteUlong(Adapter, E1000_REG_TADV, 96); // value is in 1.024 of usec
599     E1000WriteUlong(Adapter, E1000_REG_TIDV, 16);
600 
601     E1000WriteUlong(Adapter, E1000_REG_TCTL, E1000_TCTL_EN | E1000_TCTL_PSP);
602 
603     E1000WriteUlong(Adapter, E1000_REG_TIPG, E1000_TIPG_IPGT_DEF | E1000_TIPG_IPGR1_DEF | E1000_TIPG_IPGR2_DEF);
604 
605     NDIS_DbgPrint(MID_TRACE, ("Setting up receive.\n"));
606 
607     /* Make sure the thing is disabled first. */
608     E1000WriteUlong(Adapter, E1000_REG_RCTL, 0);
609 
610     /* Receive descriptor ring buffer */
611     E1000WriteUlong(Adapter, E1000_REG_RDBAH, Adapter->ReceiveDescriptorsPa.HighPart);
612     E1000WriteUlong(Adapter, E1000_REG_RDBAL, Adapter->ReceiveDescriptorsPa.LowPart);
613 
614     /* Receive descriptor buffer size */
615     E1000WriteUlong(Adapter, E1000_REG_RDLEN, sizeof(E1000_RECEIVE_DESCRIPTOR) * NUM_RECEIVE_DESCRIPTORS);
616 
617     /* Receive descriptor tail / head */
618     E1000WriteUlong(Adapter, E1000_REG_RDH, 0);
619     E1000WriteUlong(Adapter, E1000_REG_RDT, NUM_RECEIVE_DESCRIPTORS - 1);
620 
621     /* Set up interrupt timers */
622     E1000WriteUlong(Adapter, E1000_REG_RADV, 96);
623     E1000WriteUlong(Adapter, E1000_REG_RDTR, 16);
624 
625     /* Some defaults */
626     Value = E1000_RCTL_SECRC | E1000_RCTL_EN;
627 
628     /* Receive buffer size */
629     Value |= RcvBufRegisterMask(Adapter->ReceiveBufferType);
630 
631     /* Add our current packet filter */
632     Value |= PacketFilterToMask(Adapter->PacketFilter);
633 
634     E1000WriteUlong(Adapter, E1000_REG_RCTL, Value);
635 
636     return NDIS_STATUS_SUCCESS;
637 }
638 
639 NDIS_STATUS
640 NTAPI
641 NICDisableTxRx(
642     IN PE1000_ADAPTER Adapter)
643 {
644     ULONG Value;
645 
646     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
647 
648     E1000ReadUlong(Adapter, E1000_REG_TCTL, &Value);
649     Value &= ~E1000_TCTL_EN;
650     E1000WriteUlong(Adapter, E1000_REG_TCTL, Value);
651 
652     E1000ReadUlong(Adapter, E1000_REG_RCTL, &Value);
653     Value &= ~E1000_RCTL_EN;
654     E1000WriteUlong(Adapter, E1000_REG_RCTL, Value);
655 
656     return NDIS_STATUS_SUCCESS;
657 }
658 
659 NDIS_STATUS
660 NTAPI
661 NICGetPermanentMacAddress(
662     IN PE1000_ADAPTER Adapter,
663     OUT PUCHAR MacAddress)
664 {
665     USHORT AddrWord;
666     UINT n;
667 
668     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
669 
670     /* Should we read from RAL/RAH first? */
671     for (n = 0; n < (IEEE_802_ADDR_LENGTH / 2); ++n)
672     {
673         if (!E1000ReadEeprom(Adapter, (UCHAR)n, &AddrWord))
674             return NDIS_STATUS_FAILURE;
675         Adapter->PermanentMacAddress[n * 2 + 0] = AddrWord & 0xff;
676         Adapter->PermanentMacAddress[n * 2 + 1] = (AddrWord >> 8) & 0xff;
677     }
678 
679 #if 0
680     NDIS_DbgPrint(MIN_TRACE, ("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
681                               Adapter->PermanentMacAddress[0],
682                               Adapter->PermanentMacAddress[1],
683                               Adapter->PermanentMacAddress[2],
684                               Adapter->PermanentMacAddress[3],
685                               Adapter->PermanentMacAddress[4],
686                               Adapter->PermanentMacAddress[5]));
687 #endif
688     return NDIS_STATUS_SUCCESS;
689 }
690 
691 NDIS_STATUS
692 NTAPI
693 NICUpdateMulticastList(
694     IN PE1000_ADAPTER Adapter)
695 {
696     UINT n;
697     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
698 
699     // FIXME: Use 'Adapter->MulticastListSize'? Check the datasheet
700     for (n = 0; n < MAXIMUM_MULTICAST_ADDRESSES; ++n)
701     {
702         ULONG Ral = *(ULONG *)Adapter->MulticastList[n].MacAddress;
703         ULONG Rah = *(USHORT *)&Adapter->MulticastList[n].MacAddress[4];
704 
705         if (Rah || Ral)
706         {
707             Rah |= E1000_RAH_AV;
708 
709             E1000WriteUlong(Adapter, E1000_REG_RAL + (8*n), Ral);
710             E1000WriteUlong(Adapter, E1000_REG_RAH + (8*n), Rah);
711         }
712         else
713         {
714             E1000WriteUlong(Adapter, E1000_REG_RAH + (8*n), 0);
715             E1000WriteUlong(Adapter, E1000_REG_RAL + (8*n), 0);
716         }
717     }
718 
719     return NDIS_STATUS_SUCCESS;
720 }
721 
722 NDIS_STATUS
723 NTAPI
724 NICApplyPacketFilter(
725     IN PE1000_ADAPTER Adapter)
726 {
727     ULONG FilterMask;
728 
729     E1000ReadUlong(Adapter, E1000_REG_RCTL, &FilterMask);
730 
731     FilterMask &= ~E1000_RCTL_FILTER_BITS;
732     FilterMask |= PacketFilterToMask(Adapter->PacketFilter);
733     E1000WriteUlong(Adapter, E1000_REG_RCTL, FilterMask);
734 
735     return NDIS_STATUS_SUCCESS;
736 }
737 
738 VOID
739 NTAPI
740 NICUpdateLinkStatus(
741     IN PE1000_ADAPTER Adapter)
742 {
743     ULONG DeviceStatus;
744     SIZE_T SpeedIndex;
745     static ULONG SpeedValues[] = { 10, 100, 1000, 1000 };
746 
747     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
748 
749     E1000ReadUlong(Adapter, E1000_REG_STATUS, &DeviceStatus);
750     Adapter->MediaState = (DeviceStatus & E1000_STATUS_LU) ? NdisMediaStateConnected : NdisMediaStateDisconnected;
751     SpeedIndex = (DeviceStatus & E1000_STATUS_SPEEDMASK) >> E1000_STATUS_SPEEDSHIFT;
752     Adapter->LinkSpeedMbps = SpeedValues[SpeedIndex];
753 }
754