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
MiiWrite(_In_ PNVNET_ADAPTER Adapter,_In_ ULONG PhyAddress,_In_ ULONG RegAddress,_In_ ULONG Data)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
MiiRead(_In_ PNVNET_ADAPTER Adapter,_In_ ULONG PhyAddress,_In_ ULONG RegAddress,_Out_ PULONG Data)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
PhyInitRealtek8211b(_In_ PNVNET_ADAPTER Adapter)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
PhyInitRealtek8211c(_In_ PNVNET_ADAPTER Adapter)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
PhyInitRealtek8201(_In_ PNVNET_ADAPTER Adapter,_In_ BOOLEAN DisableCrossoverDetection)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
PhyInitCicadaSemiconductor(_In_ PNVNET_ADAPTER Adapter,_In_ ULONG PhyInterface)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
PhyInitVitesseSemiconductor(_In_ PNVNET_ADAPTER Adapter)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
PhyReset(_In_ PNVNET_ADAPTER Adapter,_In_ ULONG ControlSetup)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
PhyInit(_In_ PNVNET_ADAPTER Adapter)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
FindPhyDevice(_Inout_ PNVNET_ADAPTER Adapter)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
SidebandUnitAcquireSemaphore(_Inout_ PNVNET_ADAPTER Adapter)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
SidebandUnitReleaseSemaphore(_In_ PNVNET_ADAPTER Adapter)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
SidebandUnitGetVersion(_In_ PNVNET_ADAPTER Adapter,_Out_ PULONG Version)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
MiiGetSpeedAndDuplex(_In_ PNVNET_ADAPTER Adapter,_Out_ PULONG MiiAdvertise,_Out_ PULONG MiiLinkPartnerAbility,_Out_ PULONG LinkSpeed,_Out_ PBOOLEAN FullDuplex)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
NvNetSetSpeedAndDuplex(_In_ PNVNET_ADAPTER Adapter,_In_ ULONG MiiAdvertise,_In_ ULONG MiiLinkPartnerAbility)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
NvNetUpdateLinkSpeed(_In_ PNVNET_ADAPTER Adapter)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
NvNetPhyInit(_In_ PNVNET_ADAPTER Adapter)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