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 return NDIS_STATUS_SUCCESS; 263 } 264 265 NDIS_STATUS 266 NTAPI 267 NICRegisterInterrupts( 268 IN PE1000_ADAPTER Adapter) 269 { 270 NDIS_STATUS Status; 271 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 272 273 Status = NdisMRegisterInterrupt(&Adapter->Interrupt, 274 Adapter->AdapterHandle, 275 Adapter->InterruptVector, 276 Adapter->InterruptLevel, 277 TRUE, // We always want ISR calls 278 Adapter->InterruptShared, 279 (Adapter->InterruptFlags & CM_RESOURCE_INTERRUPT_LATCHED) ? 280 NdisInterruptLatched : NdisInterruptLevelSensitive); 281 282 if (Status == NDIS_STATUS_SUCCESS) 283 { 284 Adapter->InterruptRegistered = TRUE; 285 } 286 287 return Status; 288 } 289 290 NDIS_STATUS 291 NTAPI 292 NICUnregisterInterrupts( 293 IN PE1000_ADAPTER Adapter) 294 { 295 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 296 297 if (Adapter->InterruptRegistered) 298 { 299 NdisMDeregisterInterrupt(&Adapter->Interrupt); 300 Adapter->InterruptRegistered = FALSE; 301 } 302 303 return NDIS_STATUS_SUCCESS; 304 } 305 306 NDIS_STATUS 307 NTAPI 308 NICReleaseIoResources( 309 IN PE1000_ADAPTER Adapter) 310 { 311 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 312 313 if (Adapter->IoPort) 314 { 315 NdisMDeregisterIoPortRange(Adapter->AdapterHandle, 316 Adapter->IoPortAddress, 317 Adapter->IoPortLength, 318 Adapter->IoPort); 319 } 320 321 if (Adapter->IoBase) 322 { 323 NdisMUnmapIoSpace(Adapter->AdapterHandle, Adapter->IoBase, Adapter->IoLength); 324 } 325 326 327 return NDIS_STATUS_SUCCESS; 328 } 329 330 331 NDIS_STATUS 332 NTAPI 333 NICPowerOn( 334 IN PE1000_ADAPTER Adapter) 335 { 336 NDIS_STATUS Status; 337 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 338 339 Status = NICSoftReset(Adapter); 340 if (Status != NDIS_STATUS_SUCCESS) 341 { 342 return Status; 343 } 344 345 if (!E1000ValidateNvmChecksum(Adapter)) 346 { 347 return NDIS_STATUS_INVALID_DATA; 348 } 349 350 return NDIS_STATUS_SUCCESS; 351 } 352 353 NDIS_STATUS 354 NTAPI 355 NICSoftReset( 356 IN PE1000_ADAPTER Adapter) 357 { 358 ULONG Value, ResetAttempts; 359 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 360 361 //em_get_hw_control(adapter); 362 363 NICDisableInterrupts(Adapter); 364 E1000WriteUlong(Adapter, E1000_REG_RCTL, 0); 365 E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value); 366 /* Write this using IO port, some devices cannot ack this otherwise */ 367 E1000WriteIoUlong(Adapter, E1000_REG_CTRL, Value | E1000_CTRL_RST); 368 369 370 for (ResetAttempts = 0; ResetAttempts < MAX_RESET_ATTEMPTS; ResetAttempts++) 371 { 372 NdisStallExecution(100); 373 E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value); 374 375 if (!(Value & E1000_CTRL_RST)) 376 { 377 NDIS_DbgPrint(MAX_TRACE, ("Device is back (%u)\n", ResetAttempts)); 378 379 NICDisableInterrupts(Adapter); 380 /* Clear out interrupts */ 381 E1000ReadUlong(Adapter, E1000_REG_ICR, &Value); 382 383 //NdisWriteRegisterUlong(Adapter->IoBase + E1000_REG_WUFC, 0); 384 //NdisWriteRegisterUlong(Adapter->IoBase + E1000_REG_VET, E1000_VET_VLAN); 385 386 return NDIS_STATUS_SUCCESS; 387 } 388 } 389 390 NDIS_DbgPrint(MIN_TRACE, ("Device did not recover\n")); 391 return NDIS_STATUS_FAILURE; 392 } 393 394 NDIS_STATUS 395 NTAPI 396 NICEnableTxRx( 397 IN PE1000_ADAPTER Adapter) 398 { 399 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 400 401 return NDIS_STATUS_SUCCESS; 402 } 403 404 NDIS_STATUS 405 NTAPI 406 NICDisableTxRx( 407 IN PE1000_ADAPTER Adapter) 408 { 409 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 410 411 return NDIS_STATUS_SUCCESS; 412 } 413 414 NDIS_STATUS 415 NTAPI 416 NICGetPermanentMacAddress( 417 IN PE1000_ADAPTER Adapter, 418 OUT PUCHAR MacAddress) 419 { 420 USHORT AddrWord; 421 UINT n; 422 423 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 424 425 /* Should we read from RAL/RAH first? */ 426 for (n = 0; n < (IEEE_802_ADDR_LENGTH / 2); ++n) 427 { 428 if (!E1000ReadEeprom(Adapter, (UCHAR)n, &AddrWord)) 429 return NDIS_STATUS_FAILURE; 430 Adapter->PermanentMacAddress[n * 2 + 0] = AddrWord & 0xff; 431 Adapter->PermanentMacAddress[n * 2 + 1] = (AddrWord >> 8) & 0xff; 432 } 433 434 NDIS_DbgPrint(MIN_TRACE, ("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 435 Adapter->PermanentMacAddress[0], 436 Adapter->PermanentMacAddress[1], 437 Adapter->PermanentMacAddress[2], 438 Adapter->PermanentMacAddress[3], 439 Adapter->PermanentMacAddress[4], 440 Adapter->PermanentMacAddress[5])); 441 return NDIS_STATUS_SUCCESS; 442 } 443 444 NDIS_STATUS 445 NTAPI 446 NICUpdateMulticastList( 447 IN PE1000_ADAPTER Adapter) 448 { 449 UINT n; 450 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 451 452 for (n = 0; n < MAXIMUM_MULTICAST_ADDRESSES; ++n) 453 { 454 ULONG Ral = *(ULONG *)Adapter->MulticastList[n].MacAddress; 455 ULONG Rah = *(USHORT *)&Adapter->MulticastList[n].MacAddress[4]; 456 457 if (Rah || Ral) 458 { 459 Rah |= E1000_RAH_AV; 460 461 E1000WriteUlong(Adapter, E1000_REG_RAL + (8*n), Ral); 462 E1000WriteUlong(Adapter, E1000_REG_RAH + (8*n), Rah); 463 } 464 else 465 { 466 E1000WriteUlong(Adapter, E1000_REG_RAH + (8*n), 0); 467 E1000WriteUlong(Adapter, E1000_REG_RAL + (8*n), 0); 468 } 469 } 470 471 return NDIS_STATUS_SUCCESS; 472 } 473 474 NDIS_STATUS 475 NTAPI 476 NICApplyPacketFilter( 477 IN PE1000_ADAPTER Adapter) 478 { 479 ULONG FilterMask = 0; 480 481 E1000ReadUlong(Adapter, E1000_REG_RCTL, &FilterMask); 482 483 FilterMask &= ~E1000_RCTL_FILTER_BITS; 484 485 if (Adapter->PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) 486 { 487 /* Multicast Promiscuous Enabled */ 488 FilterMask |= E1000_RCTL_MPE; 489 } 490 if (Adapter->PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) 491 { 492 /* Unicast Promiscuous Enabled */ 493 FilterMask |= E1000_RCTL_UPE; 494 /* Multicast Promiscuous Enabled */ 495 FilterMask |= E1000_RCTL_MPE; 496 } 497 if (Adapter->PacketFilter & NDIS_PACKET_TYPE_MAC_FRAME) 498 { 499 /* Pass MAC Control Frames */ 500 FilterMask |= E1000_RCTL_PMCF; 501 } 502 if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST) 503 { 504 /* Broadcast Accept Mode */ 505 FilterMask |= E1000_RCTL_BAM; 506 } 507 508 E1000WriteUlong(Adapter, E1000_REG_RCTL, FilterMask); 509 510 return NDIS_STATUS_SUCCESS; 511 } 512 513 NDIS_STATUS 514 NTAPI 515 NICApplyInterruptMask( 516 IN PE1000_ADAPTER Adapter) 517 { 518 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 519 520 E1000WriteUlong(Adapter, E1000_REG_IMS, Adapter->InterruptMask); 521 return NDIS_STATUS_SUCCESS; 522 } 523 524 NDIS_STATUS 525 NTAPI 526 NICDisableInterrupts( 527 IN PE1000_ADAPTER Adapter) 528 { 529 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 530 531 E1000WriteUlong(Adapter, E1000_REG_IMC, ~0); 532 return NDIS_STATUS_SUCCESS; 533 } 534 535 USHORT 536 NTAPI 537 NICInterruptRecognized( 538 IN PE1000_ADAPTER Adapter, 539 OUT PBOOLEAN InterruptRecognized) 540 { 541 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 542 543 return 0; 544 } 545 546 VOID 547 NTAPI 548 NICAcknowledgeInterrupts( 549 IN PE1000_ADAPTER Adapter) 550 { 551 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 552 } 553 554 VOID 555 NTAPI 556 NICUpdateLinkStatus( 557 IN PE1000_ADAPTER Adapter) 558 { 559 ULONG SpeedIndex; 560 USHORT PhyStatus; 561 static ULONG SpeedValues[] = { 10, 100, 1000, 1000 }; 562 563 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 564 565 #if 0 566 /* This does not work */ 567 E1000ReadUlong(Adapter, E1000_REG_STATUS, &DeviceStatus); 568 E1000ReadUlong(Adapter, E1000_REG_STATUS, &DeviceStatus); 569 Adapter->MediaState = (DeviceStatus & E1000_STATUS_LU) ? NdisMediaStateConnected : NdisMediaStateDisconnected; 570 SpeedIndex = (DeviceStatus & E1000_STATUS_SPEEDMASK) >> E1000_STATUS_SPEEDSHIFT; 571 Adapter->LinkSpeedMbps = SpeedValues[SpeedIndex]; 572 #else 573 /* Link bit can be sticky on some boards, read it twice */ 574 if (!E1000ReadMdic(Adapter, E1000_PHY_STATUS, &PhyStatus)) 575 NdisStallExecution(100); 576 577 Adapter->MediaState = NdisMediaStateDisconnected; 578 Adapter->LinkSpeedMbps = 0; 579 580 if (!E1000ReadMdic(Adapter, E1000_PHY_STATUS, &PhyStatus)) 581 return; 582 583 if (!(PhyStatus & E1000_PS_LINK_STATUS)) 584 return; 585 586 Adapter->MediaState = NdisMediaStateConnected; 587 588 if (E1000ReadMdic(Adapter, E1000_PHY_SPECIFIC_STATUS, &PhyStatus)) 589 { 590 if (PhyStatus & E1000_PSS_SPEED_AND_DUPLEX) 591 { 592 SpeedIndex = (PhyStatus & E1000_PSS_SPEEDMASK) >> E1000_PSS_SPEEDSHIFT; 593 Adapter->LinkSpeedMbps = SpeedValues[SpeedIndex]; 594 } 595 else 596 { 597 NDIS_DbgPrint(MIN_TRACE, ("Speed and duplex not yet resolved, retry?.\n")); 598 } 599 } 600 #endif 601 } 602 603 NDIS_STATUS 604 NTAPI 605 NICTransmitPacket( 606 IN PE1000_ADAPTER Adapter, 607 IN UCHAR TxDesc, 608 IN ULONG PhysicalAddress, 609 IN ULONG Length) 610 { 611 NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); 612 613 return NDIS_STATUS_FAILURE; 614 } 615