xref: /reactos/drivers/network/dd/dc21x4/media143.c (revision 4514e91d)
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