1 /* 2 * PROJECT: ReactOS DC21x4 Driver 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: 21142/21143/21145 media support code 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 static 17 VOID 18 Media143SelectNextSerialMedia( 19 _In_ PDC21X4_ADAPTER Adapter) 20 { 21 ULONG MediaNumber; 22 23 MediaNumber = Adapter->MediaNumber; 24 25 /* The HMR media isn't checked as HMR boards use it instead of AUI and BNC */ 26 if (MediaNumber == MEDIA_AUI || MediaNumber == MEDIA_BNC) 27 { 28 if (MediaNumber == MEDIA_AUI) 29 Adapter->ModeFlags |= DC_MODE_AUI_FAILED; 30 else if (MediaNumber == MEDIA_BNC) 31 Adapter->ModeFlags |= DC_MODE_BNC_FAILED; 32 33 if ((Adapter->ModeFlags & (DC_MODE_AUI_FAILED | DC_MODE_BNC_FAILED)) != 34 (DC_MODE_AUI_FAILED | DC_MODE_BNC_FAILED)) 35 { 36 MediaNumber = (MEDIA_BNC + MEDIA_AUI) - MediaNumber; 37 38 if (Adapter->MediaBitmap & (1 << MediaNumber)) 39 { 40 Adapter->MediaNumber = MediaNumber; 41 MediaSiaSelect(Adapter); 42 return; 43 } 44 } 45 } 46 47 if (Adapter->Features & DC_HAS_MII) 48 { 49 Adapter->MediaNumber = MEDIA_MII; 50 51 DcStopTxRxProcess(Adapter); 52 MediaSelectMiiPort(Adapter, FALSE); 53 MediaMiiSelect(Adapter); 54 } 55 else 56 { 57 Adapter->MediaNumber = MEDIA_10T; 58 MediaSiaSelect(Adapter); 59 } 60 } 61 62 static 63 VOID 64 Media143SelectNextMedia( 65 _In_ PDC21X4_ADAPTER Adapter, 66 _In_ ULONG SiaStatus) 67 { 68 ULONG MediaBitmap, MediaNumber; 69 70 MediaIndicateConnect(Adapter, FALSE); 71 72 MediaBitmap = Adapter->MediaBitmap; 73 74 if (MediaBitmap & (1 << MEDIA_HMR)) 75 { 76 MediaNumber = MEDIA_HMR; 77 } 78 else if ((MediaBitmap & MEDIA_AUI_BNC_MASK) == MEDIA_AUI_BNC_MASK) 79 { 80 if (SiaStatus & DC_SIA_STATUS_AUI_ACTIVITY) 81 { 82 MediaNumber = MEDIA_AUI; 83 } 84 else 85 { 86 MediaNumber = MEDIA_BNC; 87 } 88 } 89 else if (MediaBitmap & (1 << MEDIA_AUI)) 90 { 91 MediaNumber = MEDIA_AUI; 92 } 93 else if (MediaBitmap & (1 << MEDIA_BNC)) 94 { 95 MediaNumber = MEDIA_BNC; 96 } 97 else 98 { 99 MediaNumber = MEDIA_10T; 100 } 101 102 Adapter->ModeFlags &= ~DC_MODE_AUTONEG_MASK; 103 Adapter->ModeFlags |= DC_MODE_AUTONEG_NONE; 104 NdisMSetTimer(&Adapter->MediaMonitorTimer, 3000); 105 106 if (Adapter->MediaNumber != MediaNumber) 107 { 108 Adapter->MediaNumber = MediaNumber; 109 MediaSiaSelect(Adapter); 110 } 111 112 Adapter->ModeFlags &= ~(DC_MODE_TEST_PACKET | 113 DC_MODE_AUI_FAILED | 114 DC_MODE_BNC_FAILED); 115 Adapter->LastReceiveActivity = (ULONG)Adapter->Statistics.ReceiveOk; 116 } 117 118 static 119 VOID 120 Media143Handle10LinkFail( 121 _In_ PDC21X4_ADAPTER Adapter, 122 _In_ ULONG SiaStatus) 123 { 124 INFO_VERB("Link failed, CSR12 %08lx\n", SiaStatus); 125 126 /* 10Base-T link is down */ 127 MediaIndicateConnect(Adapter, FALSE); 128 129 /* Select the other port */ 130 if (!MEDIA_IS_FIXED(Adapter)) 131 { 132 Media143SelectNextMedia(Adapter, SiaStatus); 133 } 134 } 135 136 static 137 VOID 138 Media143Handle10LinkPass( 139 _In_ PDC21X4_ADAPTER Adapter, 140 _In_ ULONG SiaStatus) 141 { 142 INFO_VERB("Link passed, CSR12 %08lx\n", SiaStatus); 143 144 /* 10Base-T is the active port now */ 145 if (!MEDIA_IS_10T(Adapter->MediaNumber)) 146 { 147 /* Switch to TP medium */ 148 if (!MEDIA_IS_FIXED(Adapter)) 149 { 150 Adapter->MediaNumber = MEDIA_10T; 151 MediaSiaSelect(Adapter); 152 153 /* Wait for a link pass interrupt to signal the link test completed */ 154 Adapter->ModeFlags &= ~DC_MODE_AUTONEG_MASK; 155 Adapter->ModeFlags |= DC_MODE_AUTONEG_WAIT_INTERRUPT; 156 NdisMSetTimer(&Adapter->MediaMonitorTimer, 3000); 157 } 158 } 159 else 160 { 161 /* 10Base-T link is up */ 162 MediaIndicateConnect(Adapter, TRUE); 163 } 164 } 165 166 static 167 VOID 168 Media143Handle100LinkChange( 169 _In_ PDC21X4_ADAPTER Adapter, 170 _In_ ULONG SiaStatus) 171 { 172 BOOLEAN LinkUp; 173 174 INFO_VERB("Link changed, CSR12 %08lx\n", SiaStatus); 175 176 LinkUp = !(SiaStatus & DC_SIA_STATUS_100T_LINK_FAIL); 177 178 if (MEDIA_IS_FIXED(Adapter)) 179 { 180 MediaIndicateConnect(Adapter, LinkUp); 181 } 182 else 183 { 184 /* Select the other port */ 185 if (!LinkUp) 186 { 187 Media143SelectNextMedia(Adapter, SiaStatus); 188 } 189 else 190 { 191 /* Ignore this hint */ 192 } 193 } 194 } 195 196 static 197 VOID 198 Media143HandleNWayComplete( 199 _In_ PDC21X4_ADAPTER Adapter, 200 _In_ ULONG SiaStatus) 201 { 202 ULONG MediaNumber, AdvLpa; 203 204 /* Select media according to auto-negotiation result */ 205 if (SiaStatus & DC_SIA_STATUS_LP_AUTONED_SUPPORTED) 206 { 207 INFO_VERB("Auto-negotiation has completed, LPA %08lx ADV %08lx\n", 208 SiaStatus, Adapter->SymAdvertising); 209 210 AdvLpa = (SiaStatus >> DC_SIA_STATUS_LP_CODE_WORD_SHIFT) & Adapter->SymAdvertising; 211 if (AdvLpa & MII_ADV_100T_FD) 212 { 213 MediaNumber = MEDIA_100TX_FD; 214 } 215 else if (AdvLpa & MII_ADV_100T4) 216 { 217 MediaNumber = MEDIA_100T4; 218 } 219 else if (AdvLpa & MII_ADV_100T_HD) 220 { 221 MediaNumber = MEDIA_100TX_HD; 222 } 223 else if (AdvLpa & MII_ADV_10T_FD) 224 { 225 MediaNumber = MEDIA_10T_FD; 226 } 227 else if (AdvLpa & MII_ADV_10T_HD) 228 { 229 MediaNumber = MEDIA_10T; 230 } 231 else 232 { 233 INFO_VERB("No common mode\n"); 234 235 /* No common mode, select the other port */ 236 Media143SelectNextMedia(Adapter, SiaStatus); 237 return; 238 } 239 } 240 else 241 { 242 INFO_VERB("Link partner does not support auto-negotiation, CSR12 %08lx\n", SiaStatus); 243 244 /* Check the results of parallel detection */ 245 if (!(SiaStatus & DC_SIA_STATUS_100T_LINK_FAIL)) 246 { 247 MediaNumber = MEDIA_100TX_HD; 248 } 249 else if (!(SiaStatus & DC_SIA_STATUS_10T_LINK_FAIL)) 250 { 251 MediaNumber = MEDIA_10T; 252 } 253 else 254 { 255 /* No link detected, select the other port */ 256 Media143SelectNextMedia(Adapter, SiaStatus); 257 return; 258 } 259 } 260 261 if (MEDIA_IS_10T(MediaNumber) && (MediaNumber != Adapter->MediaNumber)) 262 { 263 /* Set the time limit for auto-negotiation */ 264 Adapter->ModeFlags &= ~DC_MODE_AUTONEG_MASK; 265 Adapter->ModeFlags |= DC_MODE_AUTONEG_WAIT_INTERRUPT; 266 NdisMSetTimer(&Adapter->MediaMonitorTimer, 5000); 267 } 268 else 269 { 270 /* Wait for the link integrity test to complete before we can read the link status */ 271 Adapter->ModeFlags &= ~DC_MODE_AUTONEG_MASK; 272 Adapter->ModeFlags |= DC_MODE_AUTONEG_LINK_STATUS_CHECK; 273 NdisMSetTimer(&Adapter->MediaMonitorTimer, 1000); 274 } 275 276 if (Adapter->MediaNumber != MediaNumber) 277 { 278 Adapter->MediaNumber = MediaNumber; 279 MediaSiaSelect(Adapter); 280 } 281 } 282 283 VOID 284 MediaLinkStateChange21143( 285 _In_ PDC21X4_ADAPTER Adapter, 286 _In_ ULONG InterruptStatus) 287 { 288 ULONG SiaStatus; 289 290 INFO_VERB("Link interrupt, CSR5 %08lx\n", InterruptStatus); 291 292 NdisDprAcquireSpinLock(&Adapter->ModeLock); 293 294 /* Ignore link changes caused by media being estabilished */ 295 if ((Adapter->ModeFlags & DC_MODE_AUTONEG_MASK) == DC_MODE_AUTONEG_LINK_STATUS_CHECK) 296 { 297 NdisDprReleaseSpinLock(&Adapter->ModeLock); 298 return; 299 } 300 301 SiaStatus = DC_READ(Adapter, DcCsr12_SiaStatus); 302 303 if ((InterruptStatus & DC_IRQ_LINK_FAIL) && MEDIA_IS_10T(Adapter->MediaNumber)) 304 { 305 /* Link has failed */ 306 Media143Handle10LinkFail(Adapter, SiaStatus); 307 } 308 else if (InterruptStatus & DC_IRQ_LINK_PASS) 309 { 310 if (DC_READ(Adapter, DcCsr14_SiaTxRx) & DC_SIA_TXRX_AUTONEG) 311 { 312 /* Auto-negotiation has completed */ 313 Media143HandleNWayComplete(Adapter, SiaStatus); 314 } 315 else 316 { 317 /* Link has passed */ 318 Media143Handle10LinkPass(Adapter, SiaStatus); 319 } 320 } 321 else 322 { 323 /* NOTE: The Link Changed bit is reserved on the 21142 and always reads as 1 */ 324 if (InterruptStatus & Adapter->LinkStateChangeMask & DC_IRQ_LINK_CHANGED) 325 { 326 /* Link has changed */ 327 Media143Handle100LinkChange(Adapter, SiaStatus); 328 } 329 } 330 331 NdisDprReleaseSpinLock(&Adapter->ModeLock); 332 } 333 334 static 335 BOOLEAN 336 Media143CheckLink( 337 _In_ PDC21X4_ADAPTER Adapter, 338 _In_ ULONG SiaStatus) 339 { 340 if (MEDIA_IS_100(Adapter->MediaNumber)) 341 { 342 if (SiaStatus & DC_SIA_STATUS_100T_LINK_FAIL) 343 return FALSE; 344 } 345 else 346 { 347 /* The auto-negotiation process can be restarted upon link failure in 10Base-T mode */ 348 if ((SiaStatus & DC_SIA_STATUS_ANS_MASK) != DC_SIA_STATUS_ANS_AUTONEG_COMPLETE) 349 return FALSE; 350 351 if (SiaStatus & DC_SIA_STATUS_10T_LINK_FAIL) 352 return FALSE; 353 } 354 355 return TRUE; 356 } 357 358 static 359 VOID 360 MediaMonitor143( 361 _In_ PDC21X4_ADAPTER Adapter) 362 { 363 ULONG SiaStatus; 364 BOOLEAN LinkUp; 365 366 SiaStatus = DC_READ(Adapter, DcCsr12_SiaStatus); 367 368 switch (Adapter->ModeFlags & DC_MODE_AUTONEG_MASK) 369 { 370 case DC_MODE_AUTONEG_WAIT_INTERRUPT: 371 { 372 /* Timeout, select the other port */ 373 Media143SelectNextMedia(Adapter, SiaStatus); 374 break; 375 } 376 377 case DC_MODE_AUTONEG_LINK_STATUS_CHECK: 378 { 379 /* Check the link status */ 380 LinkUp = Media143CheckLink(Adapter, SiaStatus); 381 if (LinkUp) 382 { 383 Adapter->ModeFlags &= ~DC_MODE_AUTONEG_MASK; 384 Adapter->ModeFlags |= DC_MODE_AUTONEG_NONE; 385 386 MediaIndicateConnect(Adapter, TRUE); 387 } 388 else 389 { 390 /* No link detected, select the other port */ 391 Media143SelectNextMedia(Adapter, SiaStatus); 392 } 393 break; 394 } 395 396 case DC_MODE_AUTONEG_NONE: 397 { 398 break; 399 } 400 401 default: 402 ASSERT(FALSE); 403 UNREACHABLE; 404 break; 405 } 406 } 407 408 VOID 409 NTAPI 410 MediaMonitor21143Dpc( 411 _In_ PVOID SystemSpecific1, 412 _In_ PVOID FunctionContext, 413 _In_ PVOID SystemSpecific2, 414 _In_ PVOID SystemSpecific3) 415 { 416 PDC21X4_ADAPTER Adapter = FunctionContext; 417 ULONG DelayMs; 418 BOOLEAN LinkUp; 419 420 UNREFERENCED_PARAMETER(SystemSpecific1); 421 UNREFERENCED_PARAMETER(SystemSpecific2); 422 UNREFERENCED_PARAMETER(SystemSpecific3); 423 424 if (!(Adapter->Flags & DC_ACTIVE)) 425 return; 426 427 NdisDprAcquireSpinLock(&Adapter->ModeLock); 428 429 switch (Adapter->MediaNumber) 430 { 431 case MEDIA_MII: 432 { 433 LinkUp = MediaMiiCheckLink(Adapter); 434 435 MediaIndicateConnect(Adapter, LinkUp); 436 437 NdisMSetTimer(&Adapter->MediaMonitorTimer, 5000); 438 break; 439 } 440 441 case MEDIA_AUI: 442 case MEDIA_BNC: 443 case MEDIA_HMR: 444 { 445 ULONG ReceiveActivity = (ULONG)Adapter->Statistics.ReceiveOk; 446 447 if (!(Adapter->ModeFlags & DC_MODE_TEST_PACKET)) 448 { 449 if ((Adapter->MediaNumber == MEDIA_AUI || Adapter->MediaNumber == MEDIA_HMR) && 450 (DC_READ(Adapter, DcCsr12_SiaStatus) & DC_SIA_STATUS_AUI_ACTIVITY)) 451 { 452 /* Clear the AUI/HMR port activity bit */ 453 DC_WRITE(Adapter, DcCsr12_SiaStatus, DC_SIA_STATUS_AUI_ACTIVITY); 454 455 MediaIndicateConnect(Adapter, TRUE); 456 457 DelayMs = 5000; 458 } 459 /* Check for any received packets */ 460 else if (ReceiveActivity != Adapter->LastReceiveActivity) 461 { 462 MediaIndicateConnect(Adapter, TRUE); 463 464 DelayMs = 3000; 465 } 466 else 467 { 468 /* Send a loopback packet */ 469 NdisDprAcquireSpinLock(&Adapter->SendLock); 470 DcTestPacket(Adapter); 471 NdisDprReleaseSpinLock(&Adapter->SendLock); 472 473 DelayMs = 3000; 474 } 475 } 476 else 477 { 478 Adapter->ModeFlags &= ~DC_MODE_TEST_PACKET; 479 480 LinkUp = !!Adapter->MediaTestStatus; 481 482 MediaIndicateConnect(Adapter, LinkUp); 483 484 /* Select the other port */ 485 if (!LinkUp && !MEDIA_IS_FIXED(Adapter)) 486 { 487 Media143SelectNextSerialMedia(Adapter); 488 489 DelayMs = 3000; 490 } 491 else 492 { 493 DelayMs = 5000; 494 } 495 } 496 Adapter->LastReceiveActivity = ReceiveActivity; 497 498 NdisMSetTimer(&Adapter->MediaMonitorTimer, DelayMs); 499 break; 500 } 501 502 default: 503 { 504 MediaMonitor143(Adapter); 505 break; 506 } 507 } 508 509 NdisDprReleaseSpinLock(&Adapter->ModeLock); 510 } 511