xref: /reactos/drivers/network/dd/nvnet/phy.c (revision bbccad0e)
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