1 /* 2 * PROJECT: ReactOS DC21x4 Driver 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Hardware specific functions 5 * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com> 6 */ 7 8 /* INCLUDES *******************************************************************/ 9 10 #include "dc21x4.h" 11 12 #include <debug.h> 13 14 /* FUNCTIONS ******************************************************************/ 15 16 VOID 17 DcDisableHw( 18 _In_ PDC21X4_ADAPTER Adapter) 19 { 20 ULONG OpMode; 21 22 /* Disable interrupts */ 23 DC_WRITE(Adapter, DcCsr7_IrqMask, 0); 24 25 /* Stop DMA */ 26 OpMode = Adapter->OpMode; 27 OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE); 28 DC_WRITE(Adapter, DcCsr6_OpMode, OpMode); 29 30 /* Put the adapter to snooze mode */ 31 DcPowerSave(Adapter, TRUE); 32 33 /* Perform a software reset */ 34 DC_WRITE(Adapter, DcCsr0_BusMode, DC_BUS_MODE_SOFT_RESET); 35 } 36 37 VOID 38 DcStopTxRxProcess( 39 _In_ PDC21X4_ADAPTER Adapter) 40 { 41 ULONG i, OpMode, Status; 42 43 OpMode = Adapter->OpMode; 44 OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE); 45 DC_WRITE(Adapter, DcCsr6_OpMode, OpMode); 46 47 for (i = 0; i < 5000; ++i) 48 { 49 Status = DC_READ(Adapter, DcCsr5_Status); 50 51 if (((Status & DC_STATUS_TX_STATE_MASK) == DC_STATUS_TX_STATE_STOPPED) && 52 ((Status & DC_STATUS_RX_STATE_MASK) == DC_STATUS_RX_STATE_STOPPED)) 53 { 54 return; 55 } 56 57 NdisStallExecution(10); 58 } 59 60 WARN("Failed to stop the TX/RX process 0x%08lx\n", Status); 61 } 62 63 VOID 64 DcWriteGpio( 65 _In_ PDC21X4_ADAPTER Adapter, 66 _In_ ULONG Value) 67 { 68 ULONG Data, Register; 69 70 /* Some chips don't have a separate GPIO register */ 71 if (Adapter->Features & DC_SIA_GPIO) 72 { 73 Data = Adapter->SiaSetting; 74 Data &= 0x0000FFFF; /* SIA */ 75 Data |= Value << 16; /* GPIO */ 76 Adapter->SiaSetting = Data; 77 78 Register = DcCsr15_SiaGeneral; 79 } 80 else 81 { 82 Data = Value; 83 Register = DcCsr12_Gpio; 84 } 85 DC_WRITE(Adapter, Register, Data); 86 } 87 88 VOID 89 DcWriteSia( 90 _In_ PDC21X4_ADAPTER Adapter, 91 _In_ ULONG Csr13, 92 _In_ ULONG Csr14, 93 _In_ ULONG Csr15) 94 { 95 ULONG SiaConn, SiaGen; 96 97 TRACE("CSR13 %08lx, CSR14 %08lx, CSR15 %08lx\n", Csr13, Csr14, Csr15); 98 99 SiaConn = 0; 100 101 /* The 21145 comes with 16 new bits in CSR13 */ 102 if (Adapter->Features & DC_SIA_ANALOG_CONTROL) 103 { 104 SiaConn = Adapter->AnalogControl; 105 } 106 107 /* Reset the transceiver */ 108 DC_WRITE(Adapter, DcCsr13_SiaConnectivity, SiaConn | DC_SIA_CONN_RESET); 109 NdisStallExecution(20); 110 111 /* Some chips don't have a separate GPIO register */ 112 if (Adapter->Features & DC_SIA_GPIO) 113 { 114 SiaGen = Adapter->SiaSetting; 115 SiaGen &= 0xFFFF0000; /* GPIO */ 116 SiaGen |= Csr15; /* SIA */ 117 Adapter->SiaSetting = SiaGen; 118 } 119 else 120 { 121 SiaGen = Csr15; 122 } 123 124 DC_WRITE(Adapter, DcCsr14_SiaTxRx, Csr14); 125 DC_WRITE(Adapter, DcCsr15_SiaGeneral, SiaGen); 126 127 /* Don't reset the transceiver twice */ 128 if (Csr13 == DC_SIA_CONN_RESET) 129 return; 130 131 DC_WRITE(Adapter, DcCsr13_SiaConnectivity, SiaConn | Csr13); 132 } 133 134 VOID 135 DcTestPacket( 136 _In_ PDC21X4_ADAPTER Adapter) 137 { 138 PDC_TCB Tcb; 139 PDC_TBD Tbd; 140 ULONG FrameNumber; 141 142 Adapter->MediaTestStatus = FALSE; 143 Adapter->ModeFlags |= DC_MODE_TEST_PACKET; 144 145 if (!Adapter->LoopbackFrameSlots) 146 { 147 ERR("Failed to complete test packets, CSR12 %08lx, CSR5 %08lx\n", 148 DC_READ(Adapter, DcCsr12_SiaStatus), 149 DC_READ(Adapter, DcCsr5_Status)); 150 151 /* Try to recover the lost TX buffers */ 152 NdisScheduleWorkItem(&Adapter->TxRecoveryWorkItem); 153 return; 154 } 155 156 --Adapter->LoopbackFrameSlots; 157 158 FrameNumber = (Adapter->LoopbackFrameNumber++) % DC_LOOPBACK_FRAMES; 159 160 Tbd = Adapter->CurrentTbd; 161 Adapter->CurrentTbd = DC_NEXT_TBD(Adapter, Tbd); 162 163 Tcb = Adapter->CurrentTcb; 164 Adapter->CurrentTcb = DC_NEXT_TCB(Adapter, Tcb); 165 166 Tcb->Tbd = Tbd; 167 Tcb->Packet = NULL; 168 169 ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED)); 170 171 /* Put the loopback frame on the transmit ring */ 172 Tbd->Address1 = Adapter->LoopbackFramePhys[FrameNumber]; 173 Tbd->Address2 = 0; 174 Tbd->Control &= DC_TBD_CONTROL_END_OF_RING; 175 Tbd->Control |= DC_LOOPBACK_FRAME_SIZE | 176 DC_TBD_CONTROL_FIRST_FRAGMENT | 177 DC_TBD_CONTROL_LAST_FRAGMENT | 178 DC_TBD_CONTROL_REQUEST_INTERRUPT; 179 DC_WRITE_BARRIER(); 180 Tbd->Status = DC_TBD_STATUS_OWNED; 181 182 /* Send the loopback packet to verify connectivity of a media */ 183 DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL); 184 } 185 186 BOOLEAN 187 DcSetupFrameDownload( 188 _In_ PDC21X4_ADAPTER Adapter, 189 _In_ BOOLEAN WaitForCompletion) 190 { 191 PDC_TCB Tcb; 192 PDC_TBD Tbd; 193 ULONG i, Control; 194 195 Tbd = Adapter->CurrentTbd; 196 197 /* Ensure correct setup frame processing */ 198 if (Tbd != Adapter->HeadTbd) 199 { 200 ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED)); 201 202 /* Put the null frame on the transmit ring */ 203 Tbd->Control &= DC_TBD_CONTROL_END_OF_RING; 204 Tbd->Address1 = 0; 205 Tbd->Address2 = 0; 206 DC_WRITE_BARRIER(); 207 Tbd->Status = DC_TBD_STATUS_OWNED; 208 209 Tbd = DC_NEXT_TBD(Adapter, Tbd); 210 } 211 212 Adapter->CurrentTbd = DC_NEXT_TBD(Adapter, Tbd); 213 214 Tcb = Adapter->CurrentTcb; 215 Adapter->CurrentTcb = DC_NEXT_TCB(Adapter, Tcb); 216 217 Tcb->Tbd = Tbd; 218 Tcb->Packet = NULL; 219 220 ASSERT(!(Tbd->Status & DC_TBD_STATUS_OWNED)); 221 222 /* Prepare the setup frame */ 223 Tbd->Address1 = Adapter->SetupFramePhys; 224 Tbd->Address2 = 0; 225 Tbd->Control &= DC_TBD_CONTROL_END_OF_RING; 226 Control = DC_SETUP_FRAME_SIZE | DC_TBD_CONTROL_SETUP_FRAME; 227 if (!WaitForCompletion) 228 Control |= DC_TBD_CONTROL_REQUEST_INTERRUPT; 229 if (Adapter->ProgramHashPerfectFilter) 230 Control |= DC_TBD_CONTROL_HASH_PERFECT_FILTER; 231 Tbd->Control |= Control; 232 DC_WRITE_BARRIER(); 233 Tbd->Status = DC_TBD_STATUS_OWNED; 234 235 DC_WRITE(Adapter, DcCsr1_TxPoll, DC_TX_POLL_DOORBELL); 236 237 if (!WaitForCompletion) 238 return TRUE; 239 240 /* Wait up to 500 ms for the chip to process the setup frame */ 241 for (i = 50000; i > 0; --i) 242 { 243 NdisStallExecution(10); 244 245 KeMemoryBarrierWithoutFence(); 246 if (!(Tbd->Status & DC_TBD_STATUS_OWNED)) 247 break; 248 } 249 if (i == 0) 250 { 251 ERR("Failed to complete setup frame %08lx\n", Tbd->Status); 252 return FALSE; 253 } 254 255 return TRUE; 256 } 257 258 CODE_SEG("PAGE") 259 VOID 260 DcSetupFrameInitialize( 261 _In_ PDC21X4_ADAPTER Adapter) 262 { 263 PULONG SetupFrame, SetupFrameStart; 264 PUSHORT MacAddress; 265 ULONG i; 266 267 PAGED_CODE(); 268 269 SetupFrame = Adapter->SetupFrame; 270 271 /* Add the physical address entry */ 272 MacAddress = (PUSHORT)Adapter->CurrentMacAddress; 273 *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]); 274 *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]); 275 *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]); 276 277 /* Pad to 16 addresses */ 278 SetupFrameStart = Adapter->SetupFrame; 279 for (i = 1; i < DC_SETUP_FRAME_PERFECT_FILTER_ADDRESSES; ++i) 280 { 281 *SetupFrame++ = SetupFrameStart[0]; 282 *SetupFrame++ = SetupFrameStart[1]; 283 *SetupFrame++ = SetupFrameStart[2]; 284 } 285 } 286 287 static 288 VOID 289 DcSetupFramePerfectFiltering( 290 _In_ PDC21X4_ADAPTER Adapter) 291 { 292 PULONG SetupFrame, SetupFrameStart; 293 PUSHORT MacAddress; 294 ULONG i; 295 296 SetupFrame = Adapter->SetupFrame; 297 298 /* Add the physical address entry */ 299 MacAddress = (PUSHORT)Adapter->CurrentMacAddress; 300 *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]); 301 *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]); 302 *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]); 303 304 /* Store multicast addresses */ 305 for (i = 0; i < Adapter->MulticastCount; ++i) 306 { 307 MacAddress = (PUSHORT)Adapter->MulticastList[i].MacAddress; 308 309 *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[0]); 310 *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[1]); 311 *SetupFrame++ = DC_SETUP_FRAME_ENTRY(MacAddress[2]); 312 } 313 314 ++i; 315 316 /* Add the broadcast address entry */ 317 if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST) 318 { 319 *SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF); 320 *SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF); 321 *SetupFrame++ = DC_SETUP_FRAME_ENTRY(0x0000FFFF); 322 323 ++i; 324 } 325 326 /* Pad to 16 addresses */ 327 SetupFrameStart = Adapter->SetupFrame; 328 while (i < DC_SETUP_FRAME_PERFECT_FILTER_ADDRESSES) 329 { 330 *SetupFrame++ = SetupFrameStart[0]; 331 *SetupFrame++ = SetupFrameStart[1]; 332 *SetupFrame++ = SetupFrameStart[2]; 333 334 ++i; 335 } 336 } 337 338 static 339 VOID 340 DcSetupFrameImperfectFiltering( 341 _In_ PDC21X4_ADAPTER Adapter) 342 { 343 PULONG SetupFrame = Adapter->SetupFrame; 344 PUSHORT MacAddress; 345 ULONG Hash, i; 346 347 RtlZeroMemory(SetupFrame, DC_SETUP_FRAME_SIZE); 348 349 /* Fill up the 512-bit multicast hash table */ 350 for (i = 0; i < Adapter->MulticastCount; ++i) 351 { 352 MacAddress = (PUSHORT)Adapter->MulticastList[i].MacAddress; 353 354 /* Only need lower 9 bits of the hash */ 355 Hash = DcEthernetCrc(MacAddress, ETH_LENGTH_OF_ADDRESS); 356 Hash &= 512 - 1; 357 SetupFrame[Hash / 16] |= 1 << (Hash % 16); 358 } 359 360 /* Insert the broadcast address hash to the bin */ 361 if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST) 362 { 363 Hash = DC_SETUP_FRAME_BROADCAST_HASH; 364 SetupFrame[Hash / 16] |= 1 << (Hash % 16); 365 } 366 367 /* Add the physical address entry */ 368 MacAddress = (PUSHORT)Adapter->CurrentMacAddress; 369 SetupFrame[39] = DC_SETUP_FRAME_ENTRY(MacAddress[0]); 370 SetupFrame[40] = DC_SETUP_FRAME_ENTRY(MacAddress[1]); 371 SetupFrame[41] = DC_SETUP_FRAME_ENTRY(MacAddress[2]); 372 } 373 374 NDIS_STATUS 375 DcUpdateMulticastList( 376 _In_ PDC21X4_ADAPTER Adapter) 377 { 378 BOOLEAN UsePerfectFiltering; 379 380 /* If more than 14 addresses are requested, switch to hash filtering mode */ 381 UsePerfectFiltering = (Adapter->MulticastCount <= DC_SETUP_FRAME_ADDRESSES); 382 383 Adapter->ProgramHashPerfectFilter = UsePerfectFiltering; 384 Adapter->OidPending = TRUE; 385 386 if (UsePerfectFiltering) 387 DcSetupFramePerfectFiltering(Adapter); 388 else 389 DcSetupFrameImperfectFiltering(Adapter); 390 391 NdisAcquireSpinLock(&Adapter->SendLock); 392 393 DcSetupFrameDownload(Adapter, FALSE); 394 395 NdisReleaseSpinLock(&Adapter->SendLock); 396 397 return NDIS_STATUS_PENDING; 398 } 399 400 NDIS_STATUS 401 DcApplyPacketFilter( 402 _In_ PDC21X4_ADAPTER Adapter, 403 _In_ ULONG PacketFilter) 404 { 405 ULONG OpMode, OldPacketFilter; 406 407 INFO("Packet filter value 0x%lx\n", PacketFilter); 408 409 NdisAcquireSpinLock(&Adapter->ModeLock); 410 411 /* Update the filtering mode */ 412 OpMode = Adapter->OpMode; 413 OpMode &= ~(DC_OPMODE_RX_PROMISCUOUS | DC_OPMODE_RX_ALL_MULTICAST); 414 if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) 415 { 416 OpMode |= DC_OPMODE_RX_PROMISCUOUS; 417 } 418 else if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) 419 { 420 OpMode |= DC_OPMODE_RX_ALL_MULTICAST; 421 } 422 Adapter->OpMode = OpMode; 423 DC_WRITE(Adapter, DcCsr6_OpMode, OpMode); 424 425 NdisReleaseSpinLock(&Adapter->ModeLock); 426 427 OldPacketFilter = Adapter->PacketFilter; 428 Adapter->PacketFilter = PacketFilter; 429 430 /* Program the NIC to receive or reject broadcast frames */ 431 if ((OldPacketFilter ^ PacketFilter) & NDIS_PACKET_TYPE_BROADCAST) 432 { 433 return DcUpdateMulticastList(Adapter); 434 } 435 436 return NDIS_STATUS_SUCCESS; 437 } 438 439 static 440 CODE_SEG("PAGE") 441 VOID 442 DcSoftReset( 443 _In_ PDC21X4_ADAPTER Adapter) 444 { 445 PAGED_CODE(); 446 447 /* Linux driver does this */ 448 if (Adapter->Features & DC_HAS_MII) 449 { 450 /* Select the MII/SYM port */ 451 DC_WRITE(Adapter, DcCsr6_OpMode, DC_OPMODE_PORT_SELECT); 452 } 453 454 /* Perform a software reset */ 455 DC_WRITE(Adapter, DcCsr0_BusMode, DC_BUS_MODE_SOFT_RESET); 456 NdisMSleep(100); 457 DC_WRITE(Adapter, DcCsr0_BusMode, Adapter->BusMode); 458 } 459 460 CODE_SEG("PAGE") 461 NDIS_STATUS 462 DcSetupAdapter( 463 _In_ PDC21X4_ADAPTER Adapter) 464 { 465 PAGED_CODE(); 466 467 DcInitTxRing(Adapter); 468 DcInitRxRing(Adapter); 469 470 /* Initial values */ 471 if (!MEDIA_IS_FIXED(Adapter)) 472 { 473 Adapter->LinkSpeedMbps = 10; 474 } 475 Adapter->MediaNumber = Adapter->DefaultMedia; 476 Adapter->ModeFlags &= ~(DC_MODE_PORT_AUTOSENSE | DC_MODE_AUI_FAILED | DC_MODE_BNC_FAILED | 477 DC_MODE_TEST_PACKET | DC_MODE_AUTONEG_MASK); 478 479 DcSoftReset(Adapter); 480 481 /* Receive descriptor ring buffer */ 482 DC_WRITE(Adapter, DcCsr3_RxRingAddress, Adapter->RbdPhys); 483 484 /* Transmit descriptor ring buffer */ 485 DC_WRITE(Adapter, DcCsr4_TxRingAddress, Adapter->TbdPhys); 486 487 switch (Adapter->ChipType) 488 { 489 case DC21040: 490 { 491 DcWriteSia(Adapter, 492 Adapter->Media[Adapter->MediaNumber].Csr13, 493 Adapter->Media[Adapter->MediaNumber].Csr14, 494 Adapter->Media[Adapter->MediaNumber].Csr15); 495 496 /* Explicitly specifed by user */ 497 if (Adapter->MediaNumber == MEDIA_10T_FD) 498 { 499 Adapter->OpMode |= DC_OPMODE_FULL_DUPLEX; 500 } 501 break; 502 } 503 504 case DC21041: 505 { 506 MediaSiaSelect(Adapter); 507 break; 508 } 509 510 case DC21140: 511 { 512 if (Adapter->MediaNumber == MEDIA_MII) 513 { 514 MediaSelectMiiPort(Adapter, !(Adapter->Flags & DC_FIRST_SETUP)); 515 MediaMiiSelect(Adapter); 516 } 517 else 518 { 519 /* All media use the same GPIO directon */ 520 DC_WRITE(Adapter, DcCsr12_Gpio, Adapter->Media[Adapter->MediaNumber].GpioCtrl); 521 NdisStallExecution(10); 522 523 MediaGprSelect(Adapter); 524 } 525 break; 526 } 527 528 case DC21143: 529 case DC21145: 530 { 531 /* Init the HPNA PHY */ 532 if ((Adapter->MediaBitmap & (1 << MEDIA_HMR)) && Adapter->HpnaInitBitmap) 533 { 534 HpnaPhyInit(Adapter); 535 } 536 537 if (Adapter->MediaNumber == MEDIA_MII) 538 { 539 MediaSelectMiiPort(Adapter, !(Adapter->Flags & DC_FIRST_SETUP)); 540 MediaMiiSelect(Adapter); 541 break; 542 } 543 544 /* If the current media is FX, assume we have a link */ 545 if (MEDIA_IS_FX(Adapter->MediaNumber)) 546 { 547 Adapter->LinkUp = TRUE; 548 549 NdisMIndicateStatus(Adapter->AdapterHandle, 550 NDIS_STATUS_MEDIA_CONNECT, 551 NULL, 552 0); 553 NdisMIndicateStatusComplete(Adapter->AdapterHandle); 554 } 555 556 MediaSiaSelect(Adapter); 557 break; 558 } 559 560 default: 561 ASSERT(FALSE); 562 UNREACHABLE; 563 break; 564 } 565 566 /* Start the TX process */ 567 Adapter->OpMode |= DC_OPMODE_TX_ENABLE; 568 DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode); 569 570 /* Load the address recognition RAM */ 571 if (!DcSetupFrameDownload(Adapter, TRUE)) 572 { 573 /* This normally should not happen */ 574 ASSERT(FALSE); 575 576 NdisWriteErrorLogEntry(Adapter->AdapterHandle, 577 NDIS_ERROR_CODE_HARDWARE_FAILURE, 578 1, 579 __LINE__); 580 581 return NDIS_STATUS_HARD_ERRORS; 582 } 583 584 return NDIS_STATUS_SUCCESS; 585 } 586