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: Copyright 2018 Mark Jansen (mark.jansen@reactos.org) 6 */ 7 8 #include "nic.h" 9 10 #include <debug.h> 11 12 13 static USHORT SupportedDevices[] = 14 { 15 0x100f, // Intel 82545EM (VMWare E1000) 16 }; 17 18 19 static ULONG E1000WriteFlush(IN PE1000_ADAPTER Adapter) 20 { 21 volatile ULONG Value; 22 23 NdisReadRegisterUlong(Adapter->IoBase + E1000_REG_STATUS, &Value); 24 return Value; 25 } 26 27 static VOID E1000WriteUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, IN ULONG Value) 28 { 29 NdisWriteRegisterUlong((PULONG)(Adapter->IoBase + Address), Value); 30 } 31 32 static VOID E1000ReadUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, OUT PULONG Value) 33 { 34 NdisReadRegisterUlong((PULONG)(Adapter->IoBase + Address), Value); 35 } 36 37 static VOID E1000WriteIoUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, IN ULONG Value) 38 { 39 NdisRawWritePortUlong((PULONG)(Adapter->IoPort), Address); 40 E1000WriteFlush(Adapter); 41 NdisRawWritePortUlong((PULONG)(Adapter->IoPort + 4), Value); 42 } 43 44 static BOOLEAN E1000ReadMdic(IN PE1000_ADAPTER Adapter, IN ULONG Address, USHORT *Result) 45 { 46 ULONG ResultAddress; 47 ULONG Mdic; 48 UINT n; 49 50 if (Address > MAX_PHY_REG_ADDRESS) 51 { 52 NDIS_DbgPrint(MIN_TRACE, ("PHY Address %d is invalid\n", Address)); 53 return 1; 54 } 55 56 Mdic = (Address << E1000_MDIC_REGADD_SHIFT); 57 Mdic |= (E1000_MDIC_PHYADD_GIGABIT << E1000_MDIC_PHYADD_SHIFT); 58 Mdic |= E1000_MDIC_OP_READ; 59 60 E1000WriteUlong(Adapter, E1000_REG_MDIC, Mdic); 61 62 for (n = 0; n < MAX_PHY_READ_ATTEMPTS; n++) 63 { 64 NdisStallExecution(50); 65 E1000ReadUlong(Adapter, E1000_REG_MDIC, &Mdic); 66 if (Mdic & E1000_MDIC_R) 67 break; 68 } 69 if (!(Mdic & E1000_MDIC_R)) 70 { 71 NDIS_DbgPrint(MIN_TRACE, ("MDI Read incomplete\n")); 72 return FALSE; 73 } 74 if (Mdic & E1000_MDIC_E) 75 { 76 NDIS_DbgPrint(MIN_TRACE, ("MDI Read error\n")); 77 return FALSE; 78 } 79 80 ResultAddress = (Mdic >> E1000_MDIC_REGADD_SHIFT) & MAX_PHY_REG_ADDRESS; 81 82 if (ResultAddress!= Address) 83 { 84 /* Add locking? */ 85 NDIS_DbgPrint(MIN_TRACE, ("MDI Read got wrong address (%d instead of %d)\n", 86 ResultAddress, Address)); 87 return FALSE; 88 } 89 *Result = (USHORT) Mdic; 90 return TRUE; 91 } 92 93 94 static BOOLEAN E1000ReadEeprom(IN PE1000_ADAPTER Adapter, IN UCHAR Address, USHORT *Result) 95 { 96 UINT Value; 97 UINT n; 98 99 E1000WriteUlong(Adapter, E1000_REG_EERD, E1000_EERD_START | ((UINT)Address << E1000_EERD_ADDR_SHIFT)); 100 101 for (n = 0; n < MAX_EEPROM_READ_ATTEMPTS; ++n) 102 { 103 NdisStallExecution(5); 104 105 E1000ReadUlong(Adapter, E1000_REG_EERD, &Value); 106 107 if (Value & E1000_EERD_DONE) 108 break; 109 } 110 if (!(Value & E1000_EERD_DONE)) 111 { 112 NDIS_DbgPrint(MIN_TRACE, ("EEPROM Read incomplete\n")); 113 return FALSE; 114 } 115 *Result = (USHORT)(Value >> E1000_EERD_DATA_SHIFT); 116 return TRUE; 117 } 118 119 BOOLEAN E1000ValidateNvmChecksum(IN PE1000_ADAPTER Adapter) 120 { 121 USHORT Checksum = 0, Data; 122 UINT n; 123 124 /* 5.6.35 Checksum Word Calculation (Word 3Fh) */ 125 for (n = 0; n <= E1000_NVM_REG_CHECKSUM; n++) 126 { 127 if (!E1000ReadEeprom(Adapter, n, &Data)) 128 { 129 return FALSE; 130 } 131 Checksum += Data; 132 } 133 134 if (Checksum != NVM_MAGIC_SUM) 135 { 136 NDIS_DbgPrint(MIN_TRACE, ("EEPROM has an invalid checksum of 0x%x\n", (ULONG)Checksum)); 137 return FALSE; 138 } 139 140 return TRUE; 141 } 142 143 144 BOOLEAN 145 NTAPI 146 NICRecognizeHardware( 147 IN PE1000_ADAPTER Adapter) 148 { 149 UINT n; 150 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 151 152 if (Adapter->VendorID != HW_VENDOR_INTEL) 153 { 154 NDIS_DbgPrint(MIN_TRACE, ("Unknown vendor: 0x%x\n", Adapter->VendorID)); 155 return FALSE; 156 } 157 158 for (n = 0; n < ARRAYSIZE(SupportedDevices); ++n) 159 { 160 if (SupportedDevices[n] == Adapter->DeviceID) 161 { 162 return TRUE; 163 } 164 } 165 166 NDIS_DbgPrint(MIN_TRACE, ("Unknown device: 0x%x\n", Adapter->DeviceID)); 167 168 return FALSE; 169 } 170 171 NDIS_STATUS 172 NTAPI 173 NICInitializeAdapterResources( 174 IN PE1000_ADAPTER Adapter, 175 IN PNDIS_RESOURCE_LIST ResourceList) 176 { 177 UINT n; 178 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 179 180 for (n = 0; n < ResourceList->Count; n++) 181 { 182 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor = ResourceList->PartialDescriptors + n; 183 184 switch (ResourceDescriptor->Type) 185 { 186 case CmResourceTypePort: 187 ASSERT(Adapter->IoPortAddress == 0); 188 ASSERT(ResourceDescriptor->u.Port.Start.HighPart == 0); 189 190 Adapter->IoPortAddress = ResourceDescriptor->u.Port.Start.LowPart; 191 Adapter->IoPortLength = ResourceDescriptor->u.Port.Length; 192 193 NDIS_DbgPrint(MID_TRACE, ("I/O port range is %p to %p\n", 194 Adapter->IoPortAddress, 195 Adapter->IoPortAddress + Adapter->IoPortLength)); 196 break; 197 case CmResourceTypeInterrupt: 198 ASSERT(Adapter->InterruptVector == 0); 199 ASSERT(Adapter->InterruptLevel == 0); 200 201 Adapter->InterruptVector = ResourceDescriptor->u.Interrupt.Vector; 202 Adapter->InterruptLevel = ResourceDescriptor->u.Interrupt.Level; 203 Adapter->InterruptShared = (ResourceDescriptor->ShareDisposition == CmResourceShareShared); 204 Adapter->InterruptFlags = ResourceDescriptor->Flags; 205 206 NDIS_DbgPrint(MID_TRACE, ("IRQ vector is %d\n", Adapter->InterruptVector)); 207 break; 208 case CmResourceTypeMemory: 209 /* Internal registers and memories (including PHY) */ 210 if (ResourceDescriptor->u.Memory.Length == (128 * 1024)) 211 { 212 ASSERT(Adapter->IoAddress.LowPart == 0); 213 ASSERT(ResourceDescriptor->u.Port.Start.HighPart == 0); 214 215 216 Adapter->IoAddress.QuadPart = ResourceDescriptor->u.Memory.Start.QuadPart; 217 Adapter->IoLength = ResourceDescriptor->u.Memory.Length; 218 NDIS_DbgPrint(MID_TRACE, ("Memory range is %I64x to %I64x\n", 219 Adapter->IoAddress.QuadPart, 220 Adapter->IoAddress.QuadPart + Adapter->IoLength)); 221 } 222 break; 223 224 default: 225 NDIS_DbgPrint(MIN_TRACE, ("Unrecognized resource type: 0x%x\n", ResourceDescriptor->Type)); 226 break; 227 } 228 } 229 230 if (Adapter->IoAddress.QuadPart == 0 || Adapter->IoPortAddress == 0 || Adapter->InterruptVector == 0) 231 { 232 NDIS_DbgPrint(MIN_TRACE, ("Adapter didn't receive enough resources\n")); 233 return NDIS_STATUS_RESOURCES; 234 } 235 236 return NDIS_STATUS_SUCCESS; 237 } 238 239 NDIS_STATUS 240 NTAPI 241 NICAllocateIoResources( 242 IN PE1000_ADAPTER Adapter) 243 { 244 NDIS_STATUS Status; 245 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 246 247 Status = NdisMRegisterIoPortRange((PVOID*)&Adapter->IoPort, 248 Adapter->AdapterHandle, 249 Adapter->IoPortAddress, 250 Adapter->IoPortLength); 251 if (Status != NDIS_STATUS_SUCCESS) 252 { 253 NDIS_DbgPrint(MIN_TRACE, ("Unable to register IO port range (0x%x)\n", Status)); 254 return NDIS_STATUS_RESOURCES; 255 } 256 257 Status = NdisMMapIoSpace((PVOID*)&Adapter->IoBase, 258 Adapter->AdapterHandle, 259 Adapter->IoAddress, 260 Adapter->IoLength); 261 262 263 NdisMAllocateSharedMemory(Adapter->AdapterHandle, 264 sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS, 265 FALSE, 266 (PVOID*)&Adapter->TransmitDescriptors, 267 &Adapter->TransmitDescriptorsPa); 268 if (Adapter->TransmitDescriptors == NULL) 269 { 270 NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate transmit descriptors\n")); 271 return NDIS_STATUS_RESOURCES; 272 } 273 274 275 return NDIS_STATUS_SUCCESS; 276 } 277 278 NDIS_STATUS 279 NTAPI 280 NICRegisterInterrupts( 281 IN PE1000_ADAPTER Adapter) 282 { 283 NDIS_STATUS Status; 284 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 285 286 Status = NdisMRegisterInterrupt(&Adapter->Interrupt, 287 Adapter->AdapterHandle, 288 Adapter->InterruptVector, 289 Adapter->InterruptLevel, 290 TRUE, // We always want ISR calls 291 Adapter->InterruptShared, 292 (Adapter->InterruptFlags & CM_RESOURCE_INTERRUPT_LATCHED) ? 293 NdisInterruptLatched : NdisInterruptLevelSensitive); 294 295 if (Status == NDIS_STATUS_SUCCESS) 296 { 297 Adapter->InterruptRegistered = TRUE; 298 } 299 300 return Status; 301 } 302 303 NDIS_STATUS 304 NTAPI 305 NICUnregisterInterrupts( 306 IN PE1000_ADAPTER Adapter) 307 { 308 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 309 310 if (Adapter->InterruptRegistered) 311 { 312 NdisMDeregisterInterrupt(&Adapter->Interrupt); 313 Adapter->InterruptRegistered = FALSE; 314 } 315 316 return NDIS_STATUS_SUCCESS; 317 } 318 319 NDIS_STATUS 320 NTAPI 321 NICReleaseIoResources( 322 IN PE1000_ADAPTER Adapter) 323 { 324 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 325 326 if (Adapter->TransmitDescriptors != NULL) 327 { 328 /* Disassociate our shared buffer before freeing it to avoid NIC-induced memory corruption */ 329 //E1000WriteUlong(Adapter, E1000_REG_TDH, 0); 330 //E1000WriteUlong(Adapter, E1000_REG_TDT, 0); 331 332 NdisMFreeSharedMemory(Adapter->AdapterHandle, 333 sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS, 334 FALSE, 335 Adapter->TransmitDescriptors, 336 Adapter->TransmitDescriptorsPa); 337 338 Adapter->TransmitDescriptors = NULL; 339 } 340 341 342 343 if (Adapter->IoPort) 344 { 345 NdisMDeregisterIoPortRange(Adapter->AdapterHandle, 346 Adapter->IoPortAddress, 347 Adapter->IoPortLength, 348 Adapter->IoPort); 349 } 350 351 if (Adapter->IoBase) 352 { 353 NdisMUnmapIoSpace(Adapter->AdapterHandle, Adapter->IoBase, Adapter->IoLength); 354 } 355 356 357 return NDIS_STATUS_SUCCESS; 358 } 359 360 361 NDIS_STATUS 362 NTAPI 363 NICPowerOn( 364 IN PE1000_ADAPTER Adapter) 365 { 366 NDIS_STATUS Status; 367 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 368 369 Status = NICSoftReset(Adapter); 370 if (Status != NDIS_STATUS_SUCCESS) 371 { 372 return Status; 373 } 374 375 if (!E1000ValidateNvmChecksum(Adapter)) 376 { 377 return NDIS_STATUS_INVALID_DATA; 378 } 379 380 return NDIS_STATUS_SUCCESS; 381 } 382 383 NDIS_STATUS 384 NTAPI 385 NICSoftReset( 386 IN PE1000_ADAPTER Adapter) 387 { 388 ULONG Value, ResetAttempts; 389 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 390 391 //em_get_hw_control(adapter); 392 393 NICDisableInterrupts(Adapter); 394 E1000WriteUlong(Adapter, E1000_REG_RCTL, 0); 395 E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value); 396 /* Write this using IO port, some devices cannot ack this otherwise */ 397 E1000WriteIoUlong(Adapter, E1000_REG_CTRL, Value | E1000_CTRL_RST); 398 399 400 for (ResetAttempts = 0; ResetAttempts < MAX_RESET_ATTEMPTS; ResetAttempts++) 401 { 402 NdisStallExecution(100); 403 E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value); 404 405 if (!(Value & E1000_CTRL_RST)) 406 { 407 NDIS_DbgPrint(MAX_TRACE, ("Device is back (%u)\n", ResetAttempts)); 408 409 NICDisableInterrupts(Adapter); 410 /* Clear out interrupts */ 411 E1000ReadUlong(Adapter, E1000_REG_ICR, &Value); 412 413 //NdisWriteRegisterUlong(Adapter->IoBase + E1000_REG_WUFC, 0); 414 //NdisWriteRegisterUlong(Adapter->IoBase + E1000_REG_VET, E1000_VET_VLAN); 415 416 return NDIS_STATUS_SUCCESS; 417 } 418 } 419 420 NDIS_DbgPrint(MIN_TRACE, ("Device did not recover\n")); 421 return NDIS_STATUS_FAILURE; 422 } 423 424 NDIS_STATUS 425 NTAPI 426 NICEnableTxRx( 427 IN PE1000_ADAPTER Adapter) 428 { 429 ULONG Value; 430 431 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 432 433 /* Transmit descriptor ring buffer */ 434 E1000WriteUlong(Adapter, E1000_REG_TDBAH, Adapter->TransmitDescriptorsPa.HighPart); 435 E1000WriteUlong(Adapter, E1000_REG_TDBAL, Adapter->TransmitDescriptorsPa.LowPart); 436 437 /* Transmit descriptor buffer size */ 438 E1000WriteUlong(Adapter, E1000_REG_TDLEN, sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS); 439 440 /* Transmit descriptor tail / head */ 441 E1000WriteUlong(Adapter, E1000_REG_TDH, 0); 442 E1000WriteUlong(Adapter, E1000_REG_TDT, 0); 443 Adapter->CurrentTxDesc = 0; 444 445 446 Value = E1000_TCTL_EN | E1000_TCTL_PSP; 447 E1000WriteUlong(Adapter, E1000_REG_TCTL, Value); 448 449 450 451 452 //E1000ReadUlong(Adapter, E1000_REG_RCTL, &Value); 453 //Value = E1000_RCTL_BSIZE_2048 | E1000_RCTL_SECRC | E1000_RCTL_EN; 454 //E1000WriteUlong(Adapter, E1000_REG_RCTL, Value); 455 456 457 return NDIS_STATUS_SUCCESS; 458 } 459 460 NDIS_STATUS 461 NTAPI 462 NICDisableTxRx( 463 IN PE1000_ADAPTER Adapter) 464 { 465 ULONG Value; 466 467 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 468 469 E1000ReadUlong(Adapter, E1000_REG_TCTL, &Value); 470 Value &= ~E1000_TCTL_EN; 471 E1000WriteUlong(Adapter, E1000_REG_TCTL, Value); 472 473 //E1000ReadUlong(Adapter, E1000_REG_RCTL, &Value); 474 //Value &= ~E1000_RCTL_EN; 475 //E1000WriteUlong(Adapter, E1000_REG_RCTL, Value); 476 477 return NDIS_STATUS_SUCCESS; 478 } 479 480 NDIS_STATUS 481 NTAPI 482 NICGetPermanentMacAddress( 483 IN PE1000_ADAPTER Adapter, 484 OUT PUCHAR MacAddress) 485 { 486 USHORT AddrWord; 487 UINT n; 488 489 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 490 491 /* Should we read from RAL/RAH first? */ 492 for (n = 0; n < (IEEE_802_ADDR_LENGTH / 2); ++n) 493 { 494 if (!E1000ReadEeprom(Adapter, (UCHAR)n, &AddrWord)) 495 return NDIS_STATUS_FAILURE; 496 Adapter->PermanentMacAddress[n * 2 + 0] = AddrWord & 0xff; 497 Adapter->PermanentMacAddress[n * 2 + 1] = (AddrWord >> 8) & 0xff; 498 } 499 500 NDIS_DbgPrint(MIN_TRACE, ("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 501 Adapter->PermanentMacAddress[0], 502 Adapter->PermanentMacAddress[1], 503 Adapter->PermanentMacAddress[2], 504 Adapter->PermanentMacAddress[3], 505 Adapter->PermanentMacAddress[4], 506 Adapter->PermanentMacAddress[5])); 507 return NDIS_STATUS_SUCCESS; 508 } 509 510 NDIS_STATUS 511 NTAPI 512 NICUpdateMulticastList( 513 IN PE1000_ADAPTER Adapter) 514 { 515 UINT n; 516 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 517 518 for (n = 0; n < MAXIMUM_MULTICAST_ADDRESSES; ++n) 519 { 520 ULONG Ral = *(ULONG *)Adapter->MulticastList[n].MacAddress; 521 ULONG Rah = *(USHORT *)&Adapter->MulticastList[n].MacAddress[4]; 522 523 if (Rah || Ral) 524 { 525 Rah |= E1000_RAH_AV; 526 527 E1000WriteUlong(Adapter, E1000_REG_RAL + (8*n), Ral); 528 E1000WriteUlong(Adapter, E1000_REG_RAH + (8*n), Rah); 529 } 530 else 531 { 532 E1000WriteUlong(Adapter, E1000_REG_RAH + (8*n), 0); 533 E1000WriteUlong(Adapter, E1000_REG_RAL + (8*n), 0); 534 } 535 } 536 537 return NDIS_STATUS_SUCCESS; 538 } 539 540 NDIS_STATUS 541 NTAPI 542 NICApplyPacketFilter( 543 IN PE1000_ADAPTER Adapter) 544 { 545 ULONG FilterMask = 0; 546 547 E1000ReadUlong(Adapter, E1000_REG_RCTL, &FilterMask); 548 549 FilterMask &= ~E1000_RCTL_FILTER_BITS; 550 551 if (Adapter->PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) 552 { 553 /* Multicast Promiscuous Enabled */ 554 FilterMask |= E1000_RCTL_MPE; 555 } 556 if (Adapter->PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) 557 { 558 /* Unicast Promiscuous Enabled */ 559 FilterMask |= E1000_RCTL_UPE; 560 /* Multicast Promiscuous Enabled */ 561 FilterMask |= E1000_RCTL_MPE; 562 } 563 if (Adapter->PacketFilter & NDIS_PACKET_TYPE_MAC_FRAME) 564 { 565 /* Pass MAC Control Frames */ 566 FilterMask |= E1000_RCTL_PMCF; 567 } 568 if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST) 569 { 570 /* Broadcast Accept Mode */ 571 FilterMask |= E1000_RCTL_BAM; 572 } 573 574 E1000WriteUlong(Adapter, E1000_REG_RCTL, FilterMask); 575 576 return NDIS_STATUS_SUCCESS; 577 } 578 579 NDIS_STATUS 580 NTAPI 581 NICApplyInterruptMask( 582 IN PE1000_ADAPTER Adapter) 583 { 584 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 585 586 E1000WriteUlong(Adapter, E1000_REG_IMS, Adapter->InterruptMask); 587 return NDIS_STATUS_SUCCESS; 588 } 589 590 NDIS_STATUS 591 NTAPI 592 NICDisableInterrupts( 593 IN PE1000_ADAPTER Adapter) 594 { 595 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 596 597 E1000WriteUlong(Adapter, E1000_REG_IMC, ~0); 598 return NDIS_STATUS_SUCCESS; 599 } 600 601 ULONG 602 NTAPI 603 NICInterruptRecognized( 604 IN PE1000_ADAPTER Adapter, 605 OUT PBOOLEAN InterruptRecognized) 606 { 607 ULONG Value; 608 609 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 610 611 /* Reading the interrupt acknowledges them */ 612 E1000ReadUlong(Adapter, E1000_REG_ICR, &Value); 613 614 *InterruptRecognized = (Value & Adapter->InterruptMask) != 0; 615 616 return (Value & Adapter->InterruptMask); 617 } 618 619 VOID 620 NTAPI 621 NICUpdateLinkStatus( 622 IN PE1000_ADAPTER Adapter) 623 { 624 ULONG SpeedIndex; 625 USHORT PhyStatus; 626 static ULONG SpeedValues[] = { 10, 100, 1000, 1000 }; 627 628 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 629 630 #if 0 631 /* This does not work */ 632 E1000ReadUlong(Adapter, E1000_REG_STATUS, &DeviceStatus); 633 E1000ReadUlong(Adapter, E1000_REG_STATUS, &DeviceStatus); 634 Adapter->MediaState = (DeviceStatus & E1000_STATUS_LU) ? NdisMediaStateConnected : NdisMediaStateDisconnected; 635 SpeedIndex = (DeviceStatus & E1000_STATUS_SPEEDMASK) >> E1000_STATUS_SPEEDSHIFT; 636 Adapter->LinkSpeedMbps = SpeedValues[SpeedIndex]; 637 #else 638 /* Link bit can be sticky on some boards, read it twice */ 639 if (!E1000ReadMdic(Adapter, E1000_PHY_STATUS, &PhyStatus)) 640 NdisStallExecution(100); 641 642 Adapter->MediaState = NdisMediaStateDisconnected; 643 Adapter->LinkSpeedMbps = 0; 644 645 if (!E1000ReadMdic(Adapter, E1000_PHY_STATUS, &PhyStatus)) 646 return; 647 648 if (!(PhyStatus & E1000_PS_LINK_STATUS)) 649 return; 650 651 Adapter->MediaState = NdisMediaStateConnected; 652 653 if (E1000ReadMdic(Adapter, E1000_PHY_SPECIFIC_STATUS, &PhyStatus)) 654 { 655 if (PhyStatus & E1000_PSS_SPEED_AND_DUPLEX) 656 { 657 SpeedIndex = (PhyStatus & E1000_PSS_SPEEDMASK) >> E1000_PSS_SPEEDSHIFT; 658 Adapter->LinkSpeedMbps = SpeedValues[SpeedIndex]; 659 } 660 else 661 { 662 NDIS_DbgPrint(MIN_TRACE, ("Speed and duplex not yet resolved, retry?.\n")); 663 } 664 } 665 #endif 666 } 667 668 NDIS_STATUS 669 NTAPI 670 NICTransmitPacket( 671 IN PE1000_ADAPTER Adapter, 672 IN ULONG PhysicalAddress, 673 IN ULONG Length) 674 { 675 volatile PE1000_TRANSMIT_DESCRIPTOR TransmitDescriptor; 676 677 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 678 679 TransmitDescriptor = Adapter->TransmitDescriptors + Adapter->CurrentTxDesc; 680 TransmitDescriptor->Address = PhysicalAddress; 681 TransmitDescriptor->Length = Length; 682 TransmitDescriptor->ChecksumOffset = 0; 683 TransmitDescriptor->Command = E1000_TDESC_CMD_RS | E1000_TDESC_CMD_IFCS | E1000_TDESC_CMD_EOP; 684 TransmitDescriptor->Status = 0; 685 TransmitDescriptor->ChecksumStartField = 0; 686 TransmitDescriptor->Special = 0; 687 688 Adapter->CurrentTxDesc = (Adapter->CurrentTxDesc + 1) % NUM_TRANSMIT_DESCRIPTORS; 689 690 E1000WriteUlong(Adapter, E1000_REG_TDT, Adapter->CurrentTxDesc); 691 692 NDIS_DbgPrint(MAX_TRACE, ("CurrentTxDesc:%u, LastTxDesc:%u\n", Adapter->CurrentTxDesc, Adapter->LastTxDesc)); 693 694 if (Adapter->CurrentTxDesc == Adapter->LastTxDesc) 695 { 696 NDIS_DbgPrint(MID_TRACE, ("All TX descriptors are full now\n")); 697 Adapter->TxFull = TRUE; 698 } 699 700 return NDIS_STATUS_SUCCESS; 701 } 702