1 /* 2 * PROJECT: ReactOS nVidia nForce Ethernet Controller Driver 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: PHY layer setup and management 5 * COPYRIGHT: Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com> 6 */ 7 8 /* 9 * HW access code was taken from the Linux forcedeth driver 10 * Copyright (C) 2003,4,5 Manfred Spraul 11 * Copyright (C) 2004 Andrew de Quincey 12 * Copyright (C) 2004 Carl-Daniel Hailfinger 13 * Copyright (c) 2004,2005,2006,2007,2008,2009 NVIDIA Corporation 14 */ 15 16 /* INCLUDES *******************************************************************/ 17 18 #include "nvnet.h" 19 20 #define NDEBUG 21 #include "debug.h" 22 23 /* GLOBALS ********************************************************************/ 24 25 BOOLEAN 26 MiiWrite( 27 _In_ PNVNET_ADAPTER Adapter, 28 _In_ ULONG PhyAddress, 29 _In_ ULONG RegAddress, 30 _In_ ULONG Data) 31 { 32 ULONG i; 33 34 NV_WRITE(Adapter, NvRegMIIStatus, NVREG_MIISTAT_MASK_RW); 35 36 if (NV_READ(Adapter, NvRegMIIControl) & NVREG_MIICTL_INUSE) 37 { 38 NV_WRITE(Adapter, NvRegMIIControl, NVREG_MIICTL_INUSE); 39 NdisStallExecution(NV_MIIBUSY_DELAY); 40 } 41 42 NV_WRITE(Adapter, NvRegMIIData, Data); 43 NV_WRITE(Adapter, NvRegMIIControl, 44 NVREG_MIICTL_WRITE | (PhyAddress << NVREG_MIICTL_ADDRSHIFT) | RegAddress); 45 46 for (i = NV_MIIPHY_DELAYMAX; i > 0; --i) 47 { 48 NdisStallExecution(NV_MIIPHY_DELAY); 49 50 if (!(NV_READ(Adapter, NvRegMIIControl) & NVREG_MIICTL_INUSE)) 51 break; 52 } 53 if (i == 0) 54 { 55 return FALSE; 56 } 57 58 return TRUE; 59 } 60 61 BOOLEAN 62 MiiRead( 63 _In_ PNVNET_ADAPTER Adapter, 64 _In_ ULONG PhyAddress, 65 _In_ ULONG RegAddress, 66 _Out_ PULONG Data) 67 { 68 ULONG i; 69 70 NV_WRITE(Adapter, NvRegMIIStatus, NVREG_MIISTAT_MASK_RW); 71 72 if (NV_READ(Adapter, NvRegMIIControl) & NVREG_MIICTL_INUSE) 73 { 74 NV_WRITE(Adapter, NvRegMIIControl, NVREG_MIICTL_INUSE); 75 NdisStallExecution(NV_MIIBUSY_DELAY); 76 } 77 78 NV_WRITE(Adapter, NvRegMIIControl, (PhyAddress << NVREG_MIICTL_ADDRSHIFT) | RegAddress); 79 80 for (i = NV_MIIPHY_DELAYMAX; i > 0; --i) 81 { 82 NdisStallExecution(NV_MIIPHY_DELAY); 83 84 if (!(NV_READ(Adapter, NvRegMIIControl) & NVREG_MIICTL_INUSE)) 85 break; 86 } 87 if (i == 0) 88 { 89 *Data = 0; 90 return FALSE; 91 } 92 93 if (NV_READ(Adapter, NvRegMIIStatus) & NVREG_MIISTAT_ERROR) 94 { 95 *Data = 0; 96 return FALSE; 97 } 98 99 *Data = NV_READ(Adapter, NvRegMIIData); 100 return TRUE; 101 } 102 103 static 104 CODE_SEG("PAGE") 105 BOOLEAN 106 PhyInitRealtek8211b( 107 _In_ PNVNET_ADAPTER Adapter) 108 { 109 ULONG i; 110 const struct 111 { 112 ULONG Register; 113 ULONG Data; 114 } Sequence[] = 115 { 116 { PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1 }, 117 { PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2 }, 118 { PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3 }, 119 { PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4 }, 120 { PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5 }, 121 { PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6 }, 122 { PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1 } 123 }; 124 125 PAGED_CODE(); 126 127 NDIS_DbgPrint(MIN_TRACE, ("()\n")); 128 129 for (i = 0; i < RTL_NUMBER_OF(Sequence); ++i) 130 { 131 if (!MiiWrite(Adapter, Adapter->PhyAddress, Sequence[i].Register, Sequence[i].Data)) 132 return FALSE; 133 } 134 135 return TRUE; 136 } 137 138 static 139 CODE_SEG("PAGE") 140 BOOLEAN 141 PhyInitRealtek8211c( 142 _In_ PNVNET_ADAPTER Adapter) 143 { 144 ULONG PowerState, MiiRegister; 145 146 PAGED_CODE(); 147 148 NDIS_DbgPrint(MIN_TRACE, ("()\n")); 149 150 PowerState = NV_READ(Adapter, NvRegPowerState2); 151 152 NV_WRITE(Adapter, NvRegPowerState2, PowerState | NVREG_POWERSTATE2_PHY_RESET); 153 NdisMSleep(25000); 154 155 NV_WRITE(Adapter, NvRegPowerState2, PowerState); 156 NdisMSleep(25000); 157 158 MiiRead(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG6, &MiiRegister); 159 MiiRegister |= PHY_REALTEK_INIT9; 160 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG6, MiiRegister)) 161 return FALSE; 162 163 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT10)) 164 return FALSE; 165 166 MiiRead(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG7, &MiiRegister); 167 if (!(MiiRegister & PHY_REALTEK_INIT11)) 168 { 169 MiiRegister |= PHY_REALTEK_INIT11; 170 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG7, MiiRegister)) 171 return FALSE; 172 } 173 174 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) 175 return FALSE; 176 177 return TRUE; 178 } 179 180 static 181 CODE_SEG("PAGE") 182 BOOLEAN 183 PhyInitRealtek8201( 184 _In_ PNVNET_ADAPTER Adapter, 185 _In_ BOOLEAN DisableCrossoverDetection) 186 { 187 ULONG MiiRegister; 188 189 PAGED_CODE(); 190 191 NDIS_DbgPrint(MIN_TRACE, ("()\n")); 192 193 if (Adapter->Features & DEV_NEED_PHY_INIT_FIX) 194 { 195 MiiRead(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG6, &MiiRegister); 196 MiiRegister |= PHY_REALTEK_INIT7; 197 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG6, MiiRegister)) 198 return FALSE; 199 } 200 201 if (DisableCrossoverDetection) 202 { 203 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) 204 return FALSE; 205 206 MiiRead(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG2, &MiiRegister); 207 MiiRegister &= ~PHY_REALTEK_INIT_MSK1; 208 MiiRegister |= PHY_REALTEK_INIT3; 209 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG2, MiiRegister)) 210 return FALSE; 211 212 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) 213 return FALSE; 214 } 215 216 return TRUE; 217 } 218 219 static 220 CODE_SEG("PAGE") 221 BOOLEAN 222 PhyInitCicadaSemiconductor( 223 _In_ PNVNET_ADAPTER Adapter, 224 _In_ ULONG PhyInterface) 225 { 226 ULONG MiiRegister; 227 228 PAGED_CODE(); 229 230 NDIS_DbgPrint(MIN_TRACE, ("()\n")); 231 232 if (PhyInterface & PHY_RGMII) 233 { 234 MiiRead(Adapter, Adapter->PhyAddress, PHY_CICADA_INIT_REG2, &MiiRegister); 235 MiiRegister &= ~(PHY_CICADA_INIT1 | PHY_CICADA_INIT2); 236 MiiRegister |= (PHY_CICADA_INIT3 | PHY_CICADA_INIT4); 237 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_CICADA_INIT_REG2, MiiRegister)) 238 return FALSE; 239 240 MiiRead(Adapter, Adapter->PhyAddress, PHY_CICADA_INIT_REG3, &MiiRegister); 241 MiiRegister |= PHY_CICADA_INIT5; 242 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_CICADA_INIT_REG3, MiiRegister)) 243 return FALSE; 244 } 245 246 MiiRead(Adapter, Adapter->PhyAddress, PHY_CICADA_INIT_REG1, &MiiRegister); 247 MiiRegister |= PHY_CICADA_INIT6; 248 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_CICADA_INIT_REG1, MiiRegister)) 249 return FALSE; 250 251 return TRUE; 252 } 253 254 static 255 CODE_SEG("PAGE") 256 BOOLEAN 257 PhyInitVitesseSemiconductor( 258 _In_ PNVNET_ADAPTER Adapter) 259 { 260 ULONG MiiRegister; 261 262 PAGED_CODE(); 263 264 NDIS_DbgPrint(MIN_TRACE, ("()\n")); 265 266 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG1, PHY_VITESSE_INIT1)) 267 return FALSE; 268 269 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT2)) 270 return FALSE; 271 272 MiiRead(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG4, &MiiRegister); 273 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG4, MiiRegister)) 274 return FALSE; 275 276 MiiRead(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG3, &MiiRegister); 277 MiiRegister &= ~PHY_VITESSE_INIT_MSK1; 278 MiiRegister |= PHY_VITESSE_INIT3; 279 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG3, MiiRegister)) 280 return FALSE; 281 282 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT4)) 283 return FALSE; 284 285 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT5)) 286 return FALSE; 287 288 MiiRead(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG4, &MiiRegister); 289 MiiRegister &= ~PHY_VITESSE_INIT_MSK1; 290 MiiRegister |= PHY_VITESSE_INIT3; 291 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG4, MiiRegister)) 292 return FALSE; 293 294 MiiRead(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG3, &MiiRegister); 295 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG3, MiiRegister)) 296 return FALSE; 297 298 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT6)) 299 return FALSE; 300 301 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT7)) 302 return FALSE; 303 304 MiiRead(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG4, &MiiRegister); 305 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG4, MiiRegister)) 306 return FALSE; 307 308 MiiRead(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG3, &MiiRegister); 309 MiiRegister &= ~PHY_VITESSE_INIT_MSK2; 310 MiiRegister |= PHY_VITESSE_INIT8; 311 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG3, MiiRegister)) 312 return FALSE; 313 314 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT9)) 315 return FALSE; 316 317 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_VITESSE_INIT_REG1, PHY_VITESSE_INIT10)) 318 return FALSE; 319 320 return TRUE; 321 } 322 323 static 324 CODE_SEG("PAGE") 325 BOOLEAN 326 PhyReset( 327 _In_ PNVNET_ADAPTER Adapter, 328 _In_ ULONG ControlSetup) 329 { 330 ULONG Tries = 0, MiiControl = MII_CR_RESET | ControlSetup; 331 332 PAGED_CODE(); 333 334 NDIS_DbgPrint(MIN_TRACE, ("()\n")); 335 336 if (!MiiWrite(Adapter, Adapter->PhyAddress, MII_CONTROL, MiiControl)) 337 return FALSE; 338 339 NdisMSleep(500000); 340 341 do 342 { 343 NdisMSleep(10000); 344 345 MiiRead(Adapter, Adapter->PhyAddress, MII_CONTROL, &MiiControl); 346 347 if (Tries++ > 100) 348 return FALSE; 349 } 350 while (MiiControl & MII_CR_RESET); 351 352 return TRUE; 353 } 354 355 static 356 CODE_SEG("PAGE") 357 NDIS_STATUS 358 PhyInit( 359 _In_ PNVNET_ADAPTER Adapter) 360 { 361 ULONG PhyInterface, MiiRegister, MiiStatus, MiiControl; 362 363 PAGED_CODE(); 364 365 NDIS_DbgPrint(MIN_TRACE, ("()\n")); 366 367 /* PHY errata for E3016 PHY */ 368 if (Adapter->PhyModel == PHY_MODEL_MARVELL_E3016) 369 { 370 MiiRead(Adapter, Adapter->PhyAddress, PHY_MARVELL_INIT_REG1, &MiiRegister); 371 MiiRegister &= ~PHY_MARVELL_E3016_INITMASK; 372 if (!MiiWrite(Adapter, Adapter->PhyAddress, PHY_MARVELL_INIT_REG1, MiiRegister)) 373 { 374 NDIS_DbgPrint(MAX_TRACE, ("PHY init failed\n")); 375 return NDIS_STATUS_FAILURE; 376 } 377 } 378 379 if (Adapter->PhyOui == PHY_OUI_REALTEK) 380 { 381 if (Adapter->PhyModel == PHY_MODEL_REALTEK_8211 && 382 Adapter->PhyRevision == PHY_REV_REALTEK_8211B) 383 { 384 if (!PhyInitRealtek8211b(Adapter)) 385 { 386 NDIS_DbgPrint(MAX_TRACE, ("PHY init failed\n")); 387 return NDIS_STATUS_FAILURE; 388 } 389 } 390 else if (Adapter->PhyModel == PHY_MODEL_REALTEK_8211 && 391 Adapter->PhyRevision == PHY_REV_REALTEK_8211C) 392 { 393 if (!PhyInitRealtek8211c(Adapter)) 394 { 395 NDIS_DbgPrint(MAX_TRACE, ("PHY init failed\n")); 396 return NDIS_STATUS_FAILURE; 397 } 398 } 399 else if (Adapter->PhyModel == PHY_MODEL_REALTEK_8201) 400 { 401 if (!PhyInitRealtek8201(Adapter, FALSE)) 402 { 403 NDIS_DbgPrint(MAX_TRACE, ("PHY init failed\n")); 404 return NDIS_STATUS_FAILURE; 405 } 406 } 407 } 408 409 /* Set advertise register */ 410 MiiRead(Adapter, Adapter->PhyAddress, MII_AUTONEG_ADVERTISE, &MiiRegister); 411 if (Adapter->Flags & NV_FORCE_SPEED_AND_DUPLEX) 412 { 413 MiiRegister &= ~(MII_ADV_10T_HD | MII_ADV_10T_FD | MII_ADV_100T_HD | MII_ADV_100T_FD | 414 MII_ADV_100T4 | MII_ADV_PAUSE_SYM | MII_ADV_PAUSE_ASYM); 415 416 if (Adapter->Flags & NV_USER_SPEED_100) 417 { 418 if (Adapter->Flags & NV_FORCE_FULL_DUPLEX) 419 MiiRegister |= MII_ADV_100T_FD; 420 else 421 MiiRegister |= MII_ADV_100T_HD; 422 } 423 else 424 { 425 if (Adapter->Flags & NV_FORCE_FULL_DUPLEX) 426 MiiRegister |= MII_ADV_10T_FD; 427 else 428 MiiRegister |= MII_ADV_10T_HD; 429 } 430 431 Adapter->PauseFlags &= ~(NV_PAUSEFRAME_AUTONEG | NV_PAUSEFRAME_RX_ENABLE | 432 NV_PAUSEFRAME_TX_ENABLE); 433 if (Adapter->PauseFlags & NV_PAUSEFRAME_RX_REQ) 434 { 435 /* For RX we set both advertisements but disable TX pause */ 436 MiiRegister |= MII_ADV_PAUSE_SYM | MII_ADV_PAUSE_ASYM; 437 Adapter->PauseFlags |= NV_PAUSEFRAME_RX_ENABLE; 438 } 439 if (Adapter->PauseFlags & NV_PAUSEFRAME_TX_REQ) 440 { 441 MiiRegister |= MII_ADV_PAUSE_ASYM; 442 Adapter->PauseFlags |= NV_PAUSEFRAME_TX_ENABLE; 443 } 444 } 445 else 446 { 447 MiiRegister |= MII_ADV_10T_HD | MII_ADV_10T_FD | MII_ADV_100T_HD | 448 MII_ADV_100T_FD | MII_ADV_PAUSE_SYM | MII_ADV_PAUSE_ASYM; 449 } 450 if (!MiiWrite(Adapter, Adapter->PhyAddress, MII_AUTONEG_ADVERTISE, MiiRegister)) 451 { 452 NDIS_DbgPrint(MAX_TRACE, ("PHY init failed!\n")); 453 return NDIS_STATUS_FAILURE; 454 } 455 456 /* Get PHY interface type */ 457 PhyInterface = NV_READ(Adapter, NvRegPhyInterface); 458 459 /* See if gigabit PHY */ 460 MiiRead(Adapter, Adapter->PhyAddress, MII_STATUS, &MiiStatus); 461 if (MiiStatus & PHY_GIGABIT) 462 { 463 ULONG MiiControl1000; 464 465 Adapter->Flags |= NV_GIGABIT_PHY; 466 467 MiiRead(Adapter, Adapter->PhyAddress, MII_MASTER_SLAVE_CONTROL, &MiiControl1000); 468 MiiControl1000 &= ~MII_MS_CR_1000T_HD; 469 if ((PhyInterface & PHY_RGMII) && !(Adapter->Flags & NV_FORCE_SPEED_AND_DUPLEX)) 470 MiiControl1000 |= MII_MS_CR_1000T_FD; 471 else 472 MiiControl1000 &= ~MII_MS_CR_1000T_FD; 473 if (!MiiWrite(Adapter, Adapter->PhyAddress, MII_MASTER_SLAVE_CONTROL, MiiControl1000)) 474 { 475 NDIS_DbgPrint(MAX_TRACE, ("PHY init failed\n")); 476 return NDIS_STATUS_FAILURE; 477 } 478 } 479 else 480 { 481 Adapter->Flags &= ~NV_GIGABIT_PHY; 482 } 483 484 MiiRead(Adapter, Adapter->PhyAddress, MII_CONTROL, &MiiControl); 485 MiiControl |= MII_CR_AUTONEG; 486 if (Adapter->PhyOui == PHY_OUI_REALTEK && 487 Adapter->PhyModel == PHY_MODEL_REALTEK_8211 && 488 Adapter->PhyRevision == PHY_REV_REALTEK_8211C) 489 { 490 /* Start auto-negation since we already performed HW reset above */ 491 MiiControl |= MII_CR_AUTONEG_RESTART; 492 if (!MiiWrite(Adapter, Adapter->PhyAddress, MII_CONTROL, MiiControl)) 493 { 494 NDIS_DbgPrint(MAX_TRACE, ("PHY init failed\n")); 495 return NDIS_STATUS_FAILURE; 496 } 497 } 498 else 499 { 500 /* Reset the PHY (certain PHYs need BMCR to be setup with reset) */ 501 if (!PhyReset(Adapter, MiiControl)) 502 { 503 NDIS_DbgPrint(MAX_TRACE, ("PHY reset failed\n")); 504 return NDIS_STATUS_FAILURE; 505 } 506 } 507 508 /* PHY vendor specific configuration */ 509 if (Adapter->PhyOui == PHY_OUI_CICADA) 510 { 511 if (!PhyInitCicadaSemiconductor(Adapter, PhyInterface)) 512 { 513 NDIS_DbgPrint(MAX_TRACE, ("PHY init failed\n")); 514 return NDIS_STATUS_FAILURE; 515 } 516 } 517 else if (Adapter->PhyOui == PHY_OUI_VITESSE) 518 { 519 if (!PhyInitVitesseSemiconductor(Adapter)) 520 { 521 NDIS_DbgPrint(MAX_TRACE, ("PHY init failed\n")); 522 return NDIS_STATUS_FAILURE; 523 } 524 } 525 else if (Adapter->PhyOui == PHY_OUI_REALTEK) 526 { 527 if (Adapter->PhyModel == PHY_MODEL_REALTEK_8211 && 528 Adapter->PhyRevision == PHY_REV_REALTEK_8211B) 529 { 530 /* Reset could have cleared these out, set them back */ 531 if (!PhyInitRealtek8211b(Adapter)) 532 { 533 NDIS_DbgPrint(MAX_TRACE, ("PHY init failed\n")); 534 return NDIS_STATUS_FAILURE; 535 } 536 } 537 else if (Adapter->PhyModel == PHY_MODEL_REALTEK_8201) 538 { 539 if (!PhyInitRealtek8201(Adapter, TRUE)) 540 { 541 NDIS_DbgPrint(MAX_TRACE, ("PHY init failed\n")); 542 return NDIS_STATUS_FAILURE; 543 } 544 } 545 } 546 547 /* Some PHYs clear out pause advertisement on reset, set it back */ 548 MiiWrite(Adapter, Adapter->PhyAddress, MII_AUTONEG_ADVERTISE, MiiRegister); 549 550 /* Restart auto-negotiation */ 551 MiiRead(Adapter, Adapter->PhyAddress, MII_CONTROL, &MiiControl); 552 MiiControl |= (MII_CR_AUTONEG_RESTART | MII_CR_AUTONEG); 553 if (!MiiWrite(Adapter, Adapter->PhyAddress, MII_CONTROL, MiiControl)) 554 return NDIS_STATUS_FAILURE; 555 556 return NDIS_STATUS_SUCCESS; 557 } 558 559 static 560 CODE_SEG("PAGE") 561 BOOLEAN 562 FindPhyDevice( 563 _Inout_ PNVNET_ADAPTER Adapter) 564 { 565 ULONG Phy; 566 567 PAGED_CODE(); 568 569 NDIS_DbgPrint(MIN_TRACE, ("()\n")); 570 571 for (Phy = 1; Phy <= 32; ++Phy) 572 { 573 ULONG PhyAddress = Phy & 0x1F; /* Check the PHY 0 last */ 574 ULONG PhyIdLow, PhyIdHigh; 575 576 if (!MiiRead(Adapter, PhyAddress, MII_PHY_ID1, &PhyIdLow)) 577 continue; 578 if (PhyIdLow == 0xFFFF) 579 continue; 580 581 if (!MiiRead(Adapter, PhyAddress, MII_PHY_ID2, &PhyIdHigh)) 582 continue; 583 if (PhyIdHigh == 0xFFFF) 584 continue; 585 586 Adapter->PhyAddress = PhyAddress; 587 Adapter->PhyModel = PhyIdHigh & PHYID2_MODEL_MASK; 588 Adapter->PhyOui = ((PhyIdLow & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT) | 589 ((PhyIdHigh & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT); 590 591 /* Realtek hardcoded PhyIdLow to all zero's on certain PHYs */ 592 if (Adapter->PhyOui == PHY_OUI_REALTEK2) 593 Adapter->PhyOui = PHY_OUI_REALTEK; 594 595 /* Setup PHY revision for Realtek */ 596 if (Adapter->PhyOui == PHY_OUI_REALTEK && Adapter->PhyModel == PHY_MODEL_REALTEK_8211) 597 { 598 ULONG PhyRevision; 599 600 MiiRead(Adapter, PhyAddress, PHY_REALTEK_REVISION, &PhyRevision); 601 Adapter->PhyRevision = PhyRevision & PHY_REV_MASK; 602 } 603 604 NDIS_DbgPrint(MIN_TRACE, ("Found PHY %X %X %X\n", 605 Adapter->PhyAddress, 606 Adapter->PhyModel, 607 Adapter->PhyOui)); 608 break; 609 } 610 if (Phy == 33) 611 { 612 return FALSE; 613 } 614 615 return TRUE; 616 } 617 618 static 619 CODE_SEG("PAGE") 620 BOOLEAN 621 SidebandUnitAcquireSemaphore( 622 _Inout_ PNVNET_ADAPTER Adapter) 623 { 624 ULONG i; 625 626 PAGED_CODE(); 627 628 NDIS_DbgPrint(MIN_TRACE, ("()\n")); 629 630 for (i = 10; i > 0; --i) 631 { 632 if ((NV_READ(Adapter, NvRegTransmitterControl) & NVREG_XMITCTL_MGMT_SEMA_MASK) == 633 NVREG_XMITCTL_MGMT_SEMA_FREE) 634 { 635 break; 636 } 637 638 NdisMSleep(500000); 639 } 640 if (i == 0) 641 { 642 return FALSE; 643 } 644 645 for (i = 0; i < 2; ++i) 646 { 647 ULONG TxControl = NV_READ(Adapter, NvRegTransmitterControl); 648 649 NV_WRITE(Adapter, NvRegTransmitterControl, TxControl | NVREG_XMITCTL_HOST_SEMA_ACQ); 650 651 /* Verify that the semaphore was acquired */ 652 TxControl = NV_READ(Adapter, NvRegTransmitterControl); 653 if (((TxControl & NVREG_XMITCTL_HOST_SEMA_MASK) == NVREG_XMITCTL_HOST_SEMA_ACQ) && 654 ((TxControl & NVREG_XMITCTL_MGMT_SEMA_MASK) == NVREG_XMITCTL_MGMT_SEMA_FREE)) 655 { 656 Adapter->Flags |= NV_UNIT_SEMAPHORE_ACQUIRED; 657 return TRUE; 658 } 659 660 NdisStallExecution(50); 661 } 662 663 return FALSE; 664 } 665 666 VOID 667 SidebandUnitReleaseSemaphore( 668 _In_ PNVNET_ADAPTER Adapter) 669 { 670 if (Adapter->Flags & NV_UNIT_SEMAPHORE_ACQUIRED) 671 { 672 ULONG TxControl; 673 674 TxControl = NV_READ(Adapter, NvRegTransmitterControl); 675 TxControl &= ~NVREG_XMITCTL_HOST_SEMA_ACQ; 676 NV_WRITE(Adapter, NvRegTransmitterControl, TxControl); 677 } 678 } 679 680 static 681 CODE_SEG("PAGE") 682 BOOLEAN 683 SidebandUnitGetVersion( 684 _In_ PNVNET_ADAPTER Adapter, 685 _Out_ PULONG Version) 686 { 687 ULONG i, DataReady, DataReady2; 688 689 PAGED_CODE(); 690 691 NDIS_DbgPrint(MIN_TRACE, ("()\n")); 692 693 DataReady = NV_READ(Adapter, NvRegTransmitterControl); 694 695 NV_WRITE(Adapter, NvRegMgmtUnitGetVersion, NVREG_MGMTUNITGETVERSION); 696 NV_WRITE(Adapter, NvRegTransmitterControl, DataReady ^ NVREG_XMITCTL_DATA_START); 697 698 for (i = 100000; i > 0; --i) 699 { 700 DataReady2 = NV_READ(Adapter, NvRegTransmitterControl); 701 702 if ((DataReady & NVREG_XMITCTL_DATA_READY) != (DataReady2 & NVREG_XMITCTL_DATA_READY)) 703 { 704 break; 705 } 706 707 NdisStallExecution(50); 708 } 709 if (i == 0 || DataReady2 & NVREG_XMITCTL_DATA_ERROR) 710 { 711 return FALSE; 712 } 713 714 *Version = NV_READ(Adapter, NvRegMgmtUnitVersion) & NVREG_MGMTUNITVERSION; 715 716 return TRUE; 717 } 718 719 static 720 BOOLEAN 721 MiiGetSpeedAndDuplex( 722 _In_ PNVNET_ADAPTER Adapter, 723 _Out_ PULONG MiiAdvertise, 724 _Out_ PULONG MiiLinkPartnerAbility, 725 _Out_ PULONG LinkSpeed, 726 _Out_ PBOOLEAN FullDuplex) 727 { 728 ULONG MiiStatus, AdvLpa; 729 730 *MiiAdvertise = 0; 731 *MiiLinkPartnerAbility = 0; 732 733 /* Link status is a latched-low bit, read it twice */ 734 MiiRead(Adapter, Adapter->PhyAddress, MII_STATUS, &MiiStatus); 735 MiiRead(Adapter, Adapter->PhyAddress, MII_STATUS, &MiiStatus); 736 737 /* Check link status */ 738 if (!(MiiStatus & MII_SR_LINK_STATUS)) 739 { 740 /* No link detected - configure NIC for 10 MB HD */ 741 *LinkSpeed = NVREG_LINKSPEED_10; 742 *FullDuplex = FALSE; 743 return FALSE; 744 } 745 746 /* If we are forcing speed and duplex */ 747 if (Adapter->Flags & NV_FORCE_SPEED_AND_DUPLEX) 748 { 749 if (Adapter->Flags & NV_USER_SPEED_100) 750 { 751 *LinkSpeed = NVREG_LINKSPEED_100; 752 } 753 else 754 { 755 *LinkSpeed = NVREG_LINKSPEED_10; 756 } 757 *FullDuplex = !!(Adapter->Flags & NV_FORCE_FULL_DUPLEX); 758 return TRUE; 759 } 760 761 /* Check auto-negotiation is complete */ 762 if (!(MiiStatus & MII_SR_AUTONEG_COMPLETE)) 763 { 764 /* Still in auto-negotiation - configure NIC for 10 MBit HD and wait */ 765 *LinkSpeed = NVREG_LINKSPEED_10; 766 *FullDuplex = FALSE; 767 return FALSE; 768 } 769 770 MiiRead(Adapter, Adapter->PhyAddress, MII_AUTONEG_ADVERTISE, MiiAdvertise); 771 MiiRead(Adapter, Adapter->PhyAddress, MII_AUTONEG_LINK_PARTNER, MiiLinkPartnerAbility); 772 773 /* Gigabit ethernet */ 774 if (Adapter->Flags & NV_GIGABIT_PHY) 775 { 776 ULONG MiiControl1000, MiiStatus1000; 777 778 MiiRead(Adapter, Adapter->PhyAddress, MII_MASTER_SLAVE_CONTROL, &MiiControl1000); 779 MiiRead(Adapter, Adapter->PhyAddress, MII_MASTER_SLAVE_STATUS, &MiiStatus1000); 780 781 if ((MiiControl1000 & MII_MS_CR_1000T_FD) && (MiiStatus1000 & MII_MS_SR_1000T_FD)) 782 { 783 *LinkSpeed = NVREG_LINKSPEED_1000; 784 *FullDuplex = TRUE; 785 return TRUE; 786 } 787 } 788 789 AdvLpa = (*MiiAdvertise) & (*MiiLinkPartnerAbility); 790 if (AdvLpa & MII_LP_100T_FD) 791 { 792 *LinkSpeed = NVREG_LINKSPEED_100; 793 *FullDuplex = TRUE; 794 } 795 else if (AdvLpa & MII_LP_100T_HD) 796 { 797 *LinkSpeed = NVREG_LINKSPEED_100; 798 *FullDuplex = FALSE; 799 } 800 else if (AdvLpa & MII_LP_10T_FD) 801 { 802 *LinkSpeed = NVREG_LINKSPEED_10; 803 *FullDuplex = TRUE; 804 } 805 else if (AdvLpa & MII_LP_10T_HD) 806 { 807 *LinkSpeed = NVREG_LINKSPEED_10; 808 *FullDuplex = FALSE; 809 } 810 else 811 { 812 *LinkSpeed = NVREG_LINKSPEED_10; 813 *FullDuplex = FALSE; 814 } 815 816 return TRUE; 817 } 818 819 static 820 VOID 821 NvNetSetSpeedAndDuplex( 822 _In_ PNVNET_ADAPTER Adapter, 823 _In_ ULONG MiiAdvertise, 824 _In_ ULONG MiiLinkPartnerAbility) 825 { 826 ULONG PhyRegister, TxDeferral, PauseFlags, MiiExpansion; 827 BOOLEAN RestartTransmitter = FALSE, RestartReceiver = FALSE; 828 829 /* The transmitter and receiver must be restarted for safe update */ 830 if (NV_READ(Adapter, NvRegTransmitterControl) & NVREG_XMITCTL_START) 831 { 832 RestartTransmitter = TRUE; 833 NvNetStopTransmitter(Adapter); 834 } 835 if (NV_READ(Adapter, NvRegReceiverControl) & NVREG_RCVCTL_START) 836 { 837 RestartReceiver = TRUE; 838 NvNetStopReceiver(Adapter); 839 } 840 841 if (Adapter->Flags & NV_GIGABIT_PHY) 842 { 843 PhyRegister = NV_READ(Adapter, NvRegSlotTime); 844 PhyRegister &= ~NVREG_SLOTTIME_1000_FULL; 845 if ((Adapter->LinkSpeed == NVREG_LINKSPEED_10) || 846 (Adapter->LinkSpeed == NVREG_LINKSPEED_100)) 847 { 848 PhyRegister |= NVREG_SLOTTIME_10_100_FULL; 849 } 850 else if (Adapter->LinkSpeed == NVREG_LINKSPEED_1000) 851 { 852 PhyRegister |= NVREG_SLOTTIME_1000_FULL; 853 } 854 NV_WRITE(Adapter, NvRegSlotTime, PhyRegister); 855 } 856 857 PhyRegister = NV_READ(Adapter, NvRegPhyInterface); 858 PhyRegister &= ~(PHY_HALF | PHY_100 | PHY_1000); 859 if (!Adapter->FullDuplex) 860 { 861 PhyRegister |= PHY_HALF; 862 } 863 if (Adapter->LinkSpeed == NVREG_LINKSPEED_100) 864 PhyRegister |= PHY_100; 865 else if (Adapter->LinkSpeed == NVREG_LINKSPEED_1000) 866 PhyRegister |= PHY_1000; 867 NV_WRITE(Adapter, NvRegPhyInterface, PhyRegister); 868 869 /* Setup the deferral register */ 870 MiiRead(Adapter, Adapter->PhyAddress, MII_AUTONEG_EXPANSION, &MiiExpansion); 871 if (PhyRegister & PHY_RGMII) 872 { 873 if (Adapter->LinkSpeed == NVREG_LINKSPEED_1000) 874 { 875 TxDeferral = NVREG_TX_DEFERRAL_RGMII_1000; 876 } 877 else 878 { 879 if (!(MiiExpansion & MII_EXP_LP_AUTONEG) && !Adapter->FullDuplex && 880 (Adapter->Features & DEV_HAS_COLLISION_FIX)) 881 { 882 TxDeferral = NVREG_TX_DEFERRAL_RGMII_STRETCH_10; 883 } 884 else 885 { 886 TxDeferral = NVREG_TX_DEFERRAL_RGMII_STRETCH_100; 887 } 888 } 889 } 890 else 891 { 892 if (!(MiiExpansion & MII_EXP_LP_AUTONEG) && !Adapter->FullDuplex && 893 (Adapter->Features & DEV_HAS_COLLISION_FIX)) 894 { 895 TxDeferral = NVREG_TX_DEFERRAL_MII_STRETCH; 896 } 897 else 898 { 899 TxDeferral = NVREG_TX_DEFERRAL_DEFAULT; 900 } 901 } 902 NV_WRITE(Adapter, NvRegTxDeferral, TxDeferral); 903 904 /* Setup the watermark register */ 905 if (Adapter->Features & (DEV_HAS_HIGH_DMA | DEV_HAS_LARGEDESC)) 906 { 907 if (Adapter->LinkSpeed == NVREG_LINKSPEED_1000) 908 NV_WRITE(Adapter, NvRegTxWatermark, NVREG_TX_WM_DESC2_3_1000); 909 else 910 NV_WRITE(Adapter, NvRegTxWatermark, NVREG_TX_WM_DESC2_3_DEFAULT); 911 } 912 else 913 { 914 NV_WRITE(Adapter, NvRegTxWatermark, NVREG_TX_WM_DESC1_DEFAULT); 915 } 916 917 NV_WRITE(Adapter, NvRegMisc1, NVREG_MISC1_FORCE | (Adapter->FullDuplex ? 0 : NVREG_MISC1_HD)); 918 NV_WRITE(Adapter, NvRegLinkSpeed, Adapter->LinkSpeed | NVREG_LINKSPEED_FORCE); 919 920 PauseFlags = 0; 921 922 /* Setup pause frames */ 923 if (Adapter->FullDuplex) 924 { 925 if (!(Adapter->Flags & NV_FORCE_SPEED_AND_DUPLEX) && 926 (Adapter->PauseFlags & NV_PAUSEFRAME_AUTONEG)) 927 { 928 ULONG AdvPause = MiiAdvertise & (MII_ADV_PAUSE_SYM | MII_ADV_PAUSE_ASYM); 929 ULONG LpaPause = MiiLinkPartnerAbility & (MII_LP_PAUSE_SYM | MII_LP_PAUSE_ASYM); 930 931 switch (AdvPause) 932 { 933 case MII_ADV_PAUSE_SYM: 934 { 935 if (LpaPause & MII_LP_PAUSE_SYM) 936 { 937 PauseFlags |= NV_PAUSEFRAME_RX_ENABLE; 938 939 if (Adapter->PauseFlags & NV_PAUSEFRAME_TX_REQ) 940 PauseFlags |= NV_PAUSEFRAME_TX_ENABLE; 941 } 942 break; 943 } 944 case MII_ADV_PAUSE_ASYM: 945 { 946 if (LpaPause == (MII_LP_PAUSE_SYM | MII_LP_PAUSE_ASYM)) 947 { 948 PauseFlags |= NV_PAUSEFRAME_TX_ENABLE; 949 } 950 break; 951 } 952 case (MII_ADV_PAUSE_SYM | MII_ADV_PAUSE_ASYM): 953 { 954 if (LpaPause & MII_LP_PAUSE_SYM) 955 { 956 PauseFlags |= NV_PAUSEFRAME_RX_ENABLE; 957 958 if (Adapter->PauseFlags & NV_PAUSEFRAME_TX_REQ) 959 PauseFlags |= NV_PAUSEFRAME_TX_ENABLE; 960 } 961 if (LpaPause == MII_LP_PAUSE_ASYM) 962 { 963 PauseFlags |= NV_PAUSEFRAME_RX_ENABLE; 964 } 965 break; 966 } 967 968 default: 969 break; 970 } 971 } 972 else 973 { 974 PauseFlags = Adapter->PauseFlags; 975 } 976 } 977 NvNetUpdatePauseFrame(Adapter, PauseFlags); 978 979 if (RestartTransmitter) 980 { 981 NvNetStartTransmitter(Adapter); 982 } 983 if (RestartReceiver) 984 { 985 NvNetStartReceiver(Adapter); 986 } 987 } 988 989 BOOLEAN 990 NvNetUpdateLinkSpeed( 991 _In_ PNVNET_ADAPTER Adapter) 992 { 993 ULONG MiiAdvertise, MiiLinkPartnerAbility, LinkSpeed; 994 BOOLEAN FullDuplex, LinkUp; 995 996 NDIS_DbgPrint(MIN_TRACE, ("()\n")); 997 998 LinkUp = MiiGetSpeedAndDuplex(Adapter, 999 &MiiAdvertise, 1000 &MiiLinkPartnerAbility, 1001 &LinkSpeed, 1002 &FullDuplex); 1003 if (Adapter->FullDuplex == FullDuplex && Adapter->LinkSpeed == LinkSpeed) 1004 { 1005 return LinkUp; 1006 } 1007 1008 NDIS_DbgPrint(MIN_TRACE, ("Configuring MAC from '%lx %s-duplex' to '%lx %s-duplex'\n", 1009 Adapter->LinkSpeed, 1010 Adapter->FullDuplex ? "full" : "half", 1011 LinkSpeed, 1012 FullDuplex ? "full" : "half")); 1013 1014 Adapter->FullDuplex = FullDuplex; 1015 Adapter->LinkSpeed = LinkSpeed; 1016 1017 if (Adapter->Flags & NV_ACTIVE) 1018 { 1019 NdisDprAcquireSpinLock(&Adapter->Send.Lock); 1020 NdisDprAcquireSpinLock(&Adapter->Receive.Lock); 1021 } 1022 1023 NvNetSetSpeedAndDuplex(Adapter, MiiAdvertise, MiiLinkPartnerAbility); 1024 1025 if (Adapter->Flags & NV_ACTIVE) 1026 { 1027 NdisDprReleaseSpinLock(&Adapter->Receive.Lock); 1028 NdisDprReleaseSpinLock(&Adapter->Send.Lock); 1029 } 1030 1031 return LinkUp; 1032 } 1033 1034 CODE_SEG("PAGE") 1035 NDIS_STATUS 1036 NvNetPhyInit( 1037 _In_ PNVNET_ADAPTER Adapter) 1038 { 1039 ULONG PhyState; 1040 BOOLEAN RestorePhyState = FALSE, PhyInitialized = FALSE; 1041 1042 PAGED_CODE(); 1043 1044 NDIS_DbgPrint(MIN_TRACE, ("()\n")); 1045 1046 /* Take PHY and NIC out of low power mode */ 1047 if (Adapter->Features & DEV_HAS_POWER_CNTRL) 1048 { 1049 ULONG PowerState = NV_READ(Adapter, NvRegPowerState2); 1050 1051 PowerState &= ~NVREG_POWERSTATE2_POWERUP_MASK; 1052 if ((Adapter->Features & DEV_NEED_LOW_POWER_FIX) && Adapter->RevisionId >= 0xA3) 1053 { 1054 PowerState |= NVREG_POWERSTATE2_POWERUP_REV_A3; 1055 } 1056 NV_WRITE(Adapter, NvRegPowerState2, PowerState); 1057 } 1058 1059 /* Clear PHY state and temporarily halt PHY interrupts */ 1060 NV_WRITE(Adapter, NvRegMIIMask, 0); 1061 PhyState = NV_READ(Adapter, NvRegAdapterControl); 1062 if (PhyState & NVREG_ADAPTCTL_RUNNING) 1063 { 1064 RestorePhyState = TRUE; 1065 1066 PhyState &= ~NVREG_ADAPTCTL_RUNNING; 1067 NV_WRITE(Adapter, NvRegAdapterControl, PhyState); 1068 } 1069 NV_WRITE(Adapter, NvRegMIIStatus, NVREG_MIISTAT_MASK_ALL); 1070 1071 if (Adapter->Features & DEV_HAS_MGMT_UNIT) 1072 { 1073 ULONG UnitVersion; 1074 1075 /* Management unit running on the MAC? */ 1076 if ((NV_READ(Adapter, NvRegTransmitterControl) & NVREG_XMITCTL_MGMT_ST) && 1077 (NV_READ(Adapter, NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_PHY_INIT) && 1078 SidebandUnitAcquireSemaphore(Adapter) && 1079 SidebandUnitGetVersion(Adapter, &UnitVersion)) 1080 { 1081 if (UnitVersion > 0) 1082 { 1083 if (NV_READ(Adapter, NvRegMgmtUnitControl) & NVREG_MGMTUNITCONTROL_INUSE) 1084 Adapter->Flags |= NV_MAC_IN_USE; 1085 else 1086 Adapter->Flags &= ~NV_MAC_IN_USE; 1087 } 1088 else 1089 { 1090 Adapter->Flags |= NV_MAC_IN_USE; 1091 } 1092 1093 NDIS_DbgPrint(MIN_TRACE, ("Management unit is running. MAC in use\n")); 1094 1095 /* Management unit setup the PHY already? */ 1096 if ((Adapter->Flags & NV_MAC_IN_USE) && 1097 ((NV_READ(Adapter, NvRegTransmitterControl) & NVREG_XMITCTL_SYNC_MASK) == 1098 NVREG_XMITCTL_SYNC_PHY_INIT)) 1099 { 1100 /* PHY is inited by management unit */ 1101 PhyInitialized = TRUE; 1102 1103 NDIS_DbgPrint(MIN_TRACE, ("PHY already initialized by management unit\n")); 1104 } 1105 } 1106 } 1107 1108 /* Find a suitable PHY */ 1109 if (!FindPhyDevice(Adapter)) 1110 { 1111 NDIS_DbgPrint(MAX_TRACE, ("Could not find a valid PHY\n")); 1112 goto Failure; 1113 } 1114 1115 /* We need to init the PHY */ 1116 if (!PhyInitialized) 1117 { 1118 if (!PhyInit(Adapter)) 1119 { 1120 /* It's not critical for init, continue */ 1121 } 1122 } 1123 else 1124 { 1125 ULONG MiiStatus; 1126 1127 /* See if it is a gigabit PHY */ 1128 MiiRead(Adapter, Adapter->PhyAddress, MII_STATUS, &MiiStatus); 1129 if (MiiStatus & PHY_GIGABIT) 1130 { 1131 Adapter->Flags |= NV_GIGABIT_PHY; 1132 } 1133 } 1134 1135 return NDIS_STATUS_SUCCESS; 1136 1137 Failure: 1138 if (RestorePhyState) 1139 { 1140 NV_WRITE(Adapter, NvRegAdapterControl, PhyState | NVREG_ADAPTCTL_RUNNING); 1141 } 1142 1143 return NDIS_STATUS_FAILURE; 1144 } 1145