[E1000] Finished an implementation of the driver.
[reactos.git] / drivers / network / dd / e1000 / hardware.c
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 }