]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
23 | * Copyright (c) 1996 NeXT Software, Inc. All rights reserved. | |
24 | * | |
25 | * i82557PHY.cpp | |
26 | * | |
27 | */ | |
28 | ||
29 | #include "i82557.h" | |
30 | #include "i82557PHY.h" | |
31 | ||
32 | //--------------------------------------------------------------------------- | |
33 | // Function: _logMDIStatus | |
34 | // | |
35 | // Purpose: | |
36 | // Dump the contents of the MDI status register. | |
37 | ||
38 | static inline void | |
39 | _logMDIStatus(mdi_reg_t reg) | |
40 | { | |
41 | if (reg & MDI_STATUS_T4) | |
42 | IOLog("PHY: T4 capable\n"); | |
43 | if (reg & MDI_STATUS_TX_FD) | |
44 | IOLog("PHY: 100Base-TX full duplex capable\n"); | |
45 | if (reg & MDI_STATUS_TX_HD) | |
46 | IOLog("PHY: 100Base-TX half duplex capable\n"); | |
47 | if (reg & MDI_STATUS_10_FD) | |
48 | IOLog("PHY: 10Base-T full duplex capable\n"); | |
49 | if (reg & MDI_STATUS_10_HD) | |
50 | IOLog("PHY: 10Base-T half duplex capable\n"); | |
51 | if (reg & MDI_STATUS_EXTENDED_CAPABILITY) | |
52 | IOLog("PHY: has extended capability registers\n"); | |
53 | if (reg & MDI_STATUS_JABBER_DETECTED) | |
54 | IOLog("PHY: jabberDetect set\n"); | |
55 | if (reg & MDI_STATUS_AUTONEG_CAPABLE) | |
56 | IOLog("PHY: auto negotiation capable\n"); | |
57 | IOLog("PHY: link is %s\n", (reg & MDI_STATUS_LINK_STATUS) ? "UP" : "DOWN"); | |
58 | return; | |
59 | } | |
60 | ||
61 | //--------------------------------------------------------------------------- | |
62 | // Function: _getModelId | |
63 | // | |
64 | // Purpose: | |
65 | // Read the MDI ID registers and form a single 32-bit id. | |
66 | ||
67 | UInt32 Intel82557::_phyGetID() | |
68 | { | |
69 | UInt16 id1, id2; | |
70 | _mdiReadPHY(phyAddr, MDI_REG_PHYID_WORD_1, &id1); | |
71 | _mdiReadPHY(phyAddr, MDI_REG_PHYID_WORD_2, &id2); | |
72 | return ((id2 << 16) | id1); | |
73 | } | |
74 | ||
75 | //--------------------------------------------------------------------------- | |
76 | // Function: _phySetMedium | |
77 | // | |
78 | // Purpose: | |
79 | // Setup the PHY to the medium type given. | |
80 | // Returns true on success. | |
81 | ||
82 | bool Intel82557::_phySetMedium(mediumType_t medium) | |
83 | { | |
84 | mdi_reg_t status; | |
85 | mdi_reg_t control; | |
86 | mediumType_t phyMedium = medium; | |
87 | UInt32 mediumCapableMask; | |
88 | ||
89 | // Reset PHY before changing medium selection. | |
90 | // | |
91 | _phyReset(); | |
92 | ||
93 | // Get local capability. | |
94 | // | |
95 | _mdiReadPHY(phyAddr, MDI_REG_STATUS, &status); | |
96 | ||
97 | // Create a medium capable mask. | |
98 | // | |
99 | mediumCapableMask = (status >> 11) & 0x1f; | |
100 | ||
101 | // Force the PHY's data rate and duplex settings if the medium type | |
102 | // chosen is not AUTO. | |
103 | // | |
104 | if (phyMedium != MEDIUM_TYPE_AUTO) { | |
105 | if ((MEDIUM_TYPE_TO_MASK(phyMedium) & mediumCapableMask) == 0) { | |
106 | // Hardware is not capable of selecting the user-selected | |
107 | // medium. | |
108 | // | |
109 | return false; | |
110 | } | |
111 | else { | |
112 | // Medium chosen is valid, go ahead and set PHY. | |
113 | // | |
114 | bool speed100 = false; | |
115 | bool fullDuplex = false; | |
116 | ||
117 | if ((medium == MEDIUM_TYPE_TX_HD) || | |
118 | (medium == MEDIUM_TYPE_TX_FD) || | |
119 | (medium == MEDIUM_TYPE_T4)) | |
120 | speed100 = true; | |
121 | ||
122 | if ((medium == MEDIUM_TYPE_10_FD) || (medium == MEDIUM_TYPE_TX_FD)) | |
123 | fullDuplex = true; | |
124 | ||
125 | // Disable auto-negotiation function and force speed + duplex. | |
126 | // | |
127 | IOSleep(300); | |
128 | ||
129 | control = ((speed100 ? MDI_CONTROL_100 : 0) | | |
130 | (fullDuplex ? MDI_CONTROL_FULL_DUPLEX : 0)); | |
131 | ||
132 | _mdiWritePHY(phyAddr, MDI_REG_CONTROL, control); | |
133 | ||
134 | VPRINT("%s: user forced %s Mbit/s%s mode\n", getName(), | |
135 | speed100 ? "100" : "10", | |
136 | fullDuplex ? " full duplex" : ""); | |
137 | ||
138 | IOSleep(50); | |
139 | } | |
140 | } | |
141 | else { | |
142 | // For MEDIUM_TYPE_AUTO, enable and restart auto-negotiation. | |
143 | // | |
144 | control = MDI_CONTROL_AUTONEG_ENABLE; | |
145 | _mdiWritePHY(phyAddr, MDI_REG_CONTROL, control); | |
146 | IOSleep(1); | |
147 | control |= MDI_CONTROL_RESTART_AUTONEG; | |
148 | _mdiWritePHY(phyAddr, MDI_REG_CONTROL, control); | |
149 | } | |
150 | ||
151 | // Some special bit twiddling for NSC83840. | |
152 | // | |
153 | if (phyID == PHY_MODEL_NSC83840) { | |
154 | /* set-up National Semiconductor 83840 specific registers */ | |
155 | ||
156 | mdi_reg_t reg; | |
157 | ||
158 | VPRINT("%s: setting NSC83840-specific registers\n", getName()); | |
159 | _mdiReadPHY(phyAddr, NSC83840_REG_PCR, ®); | |
160 | ||
161 | /* | |
162 | * This bit MUST be set, otherwise the card may not transmit at | |
163 | * all in 100Mb/s mode. This is specially true for 82557 cards | |
164 | * with the DP83840 PHY. | |
165 | * | |
166 | * In the NSC documentation, bit 10 of PCS register is labeled | |
167 | * as a reserved bit. What is the real function of this bit? | |
168 | */ | |
169 | reg |= (NSC83840_PCR_TXREADY | NSC83840_PCR_CIM_DIS); | |
170 | ||
171 | _mdiWritePHY(phyAddr, NSC83840_REG_PCR, reg); | |
172 | } | |
173 | ||
174 | currentMediumType = medium; | |
175 | ||
176 | return true; | |
177 | } | |
178 | ||
179 | //--------------------------------------------------------------------------- | |
180 | // Function: _phyAddMediumType | |
181 | // | |
182 | // Purpose: | |
183 | // Add a single medium object to the medium dictionary. | |
184 | // Also add the medium object to an array for fast lookup. | |
185 | ||
186 | bool Intel82557::_phyAddMediumType(UInt32 type, UInt32 speed, UInt32 code) | |
187 | { | |
188 | IONetworkMedium * medium; | |
189 | bool ret = false; | |
190 | ||
191 | medium = IONetworkMedium::medium(type, speed, 0, code); | |
192 | if (medium) { | |
193 | ret = IONetworkMedium::addMedium(mediumDict, medium); | |
194 | if (ret) | |
195 | mediumTable[code] = medium; | |
196 | medium->release(); | |
197 | } | |
198 | return ret; | |
199 | } | |
200 | ||
201 | //--------------------------------------------------------------------------- | |
202 | // Function: _phyPublishMedia | |
203 | // | |
204 | // Purpose: | |
205 | // Examine the PHY capabilities and advertise all supported medium types. | |
206 | // | |
207 | // FIXME: Non PHY medium types are not probed. | |
208 | ||
209 | #define MBPS 1000000 | |
210 | ||
211 | void Intel82557::_phyPublishMedia() | |
212 | { | |
213 | mdi_reg_t status; | |
214 | ||
215 | // Read the PHY's media capability. | |
216 | // | |
217 | _mdiReadPHY(phyAddr, MDI_REG_STATUS, &status); | |
218 | ||
219 | _phyAddMediumType(kIOMediumEthernetAuto, | |
220 | 0, | |
221 | MEDIUM_TYPE_AUTO); | |
222 | ||
223 | if (status & MDI_STATUS_10_HD) | |
224 | _phyAddMediumType(kIOMediumEthernet10BaseT | kIOMediumOptionHalfDuplex, | |
225 | 10 * MBPS, | |
226 | MEDIUM_TYPE_10_HD); | |
227 | ||
228 | if (status & MDI_STATUS_10_FD) | |
229 | _phyAddMediumType(kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex, | |
230 | 10 * MBPS, | |
231 | MEDIUM_TYPE_10_FD); | |
232 | ||
233 | if (status & MDI_STATUS_TX_HD) | |
234 | _phyAddMediumType( | |
235 | kIOMediumEthernet100BaseTX | kIOMediumOptionHalfDuplex, | |
236 | 100 * MBPS, | |
237 | MEDIUM_TYPE_TX_HD); | |
238 | ||
239 | if (status & MDI_STATUS_TX_FD) | |
240 | _phyAddMediumType( | |
241 | kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex, | |
242 | 100 * MBPS, | |
243 | MEDIUM_TYPE_TX_FD); | |
244 | ||
245 | if (status & MDI_STATUS_T4) | |
246 | _phyAddMediumType(kIOMediumEthernet100BaseT4, | |
247 | 100 * MBPS, | |
248 | MEDIUM_TYPE_T4); | |
249 | } | |
250 | ||
251 | //--------------------------------------------------------------------------- | |
252 | // Function: _phyReset | |
253 | // | |
254 | // Purpose: | |
255 | // Reset the PHY. | |
256 | ||
257 | #define PHY_RESET_TIMEOUT 100 // ms | |
258 | #define PHY_RESET_DELAY 10 // ms | |
259 | #define PHY_POST_RESET_DELAY 300 // us | |
260 | ||
261 | bool Intel82557::_phyReset() | |
262 | { | |
263 | int i = PHY_RESET_TIMEOUT; | |
264 | mdi_reg_t control; | |
265 | ||
266 | if (!_mdiReadPHY(phyAddr, MDI_REG_CONTROL, &control)) | |
267 | return false; | |
268 | ||
269 | // Set the reset bit in the PHY Control register | |
270 | // | |
271 | _mdiWritePHY(phyAddr, MDI_REG_CONTROL, control | MDI_CONTROL_RESET); | |
272 | ||
273 | // Wait till reset process is complete (MDI_CONTROL_RESET returns to zero) | |
274 | // | |
275 | while (i > 0) { | |
276 | if (!_mdiReadPHY(phyAddr, MDI_REG_CONTROL, &control)) | |
277 | return false; | |
278 | if ((control & MDI_CONTROL_RESET) == 0) { | |
279 | IODelay(PHY_POST_RESET_DELAY); | |
280 | return true; | |
281 | } | |
282 | IOSleep(PHY_RESET_DELAY); | |
283 | i -= PHY_RESET_DELAY; | |
284 | } | |
285 | return false; | |
286 | } | |
287 | ||
288 | //--------------------------------------------------------------------------- | |
289 | // Function: _phyWaitAutoNegotiation | |
290 | // | |
291 | // Purpose: | |
292 | // Wait until auto-negotiation is complete. | |
293 | ||
294 | #define PHY_NWAY_TIMEOUT 5000 // ms | |
295 | #define PHY_NWAY_DELAY 20 // ms | |
296 | ||
297 | bool Intel82557::_phyWaitAutoNegotiation() | |
298 | { | |
299 | int i = PHY_NWAY_TIMEOUT; | |
300 | mdi_reg_t status; | |
301 | ||
302 | while (i > 0) { | |
303 | if (!_mdiReadPHY(phyAddr, MDI_REG_STATUS, &status)) | |
304 | return false; | |
305 | ||
306 | if (status & MDI_STATUS_AUTONEG_COMPLETE) | |
307 | return true; | |
308 | ||
309 | IOSleep(PHY_NWAY_DELAY); | |
310 | i -= PHY_NWAY_DELAY; | |
311 | } | |
312 | return false; | |
313 | } | |
314 | ||
315 | //--------------------------------------------------------------------------- | |
316 | // Function: _phyProbe | |
317 | // | |
318 | // Purpose: | |
319 | // Find out which PHY is active. | |
320 | // | |
321 | #define AUTONEGOTIATE_TIMEOUT 35 | |
322 | ||
323 | bool Intel82557::_phyProbe() | |
324 | { | |
325 | bool foundPhy1 = false; | |
326 | mdi_reg_t control; | |
327 | mdi_reg_t status; | |
328 | ||
329 | if (phyAddr == PHY_ADDRESS_I82503) { | |
330 | VPRINT("%s: overriding to use Intel 82503", getName()); | |
331 | return true; | |
332 | } | |
333 | ||
334 | if (phyAddr > 0 && phyAddr < PHY_ADDRESS_MAX) { | |
335 | VPRINT("%s: looking for Phy 1 at address %d\n", getName(), phyAddr); | |
336 | _mdiReadPHY(phyAddr, MDI_REG_CONTROL, &control); | |
337 | _mdiReadPHY(phyAddr, MDI_REG_STATUS, &status); // do it twice | |
338 | _mdiReadPHY(phyAddr, MDI_REG_STATUS, &status); | |
339 | if (control == 0xffff || (status == 0 && control == 0)) | |
340 | { | |
341 | VPRINT("%s: Phy 1 at address %d does not exist\n", getName(), | |
342 | phyAddr); | |
343 | } | |
344 | else { | |
345 | VPRINT("%s: Phy 1 at address %d exists\n", getName(), phyAddr); | |
346 | foundPhy1 = true; | |
347 | if (status & MDI_STATUS_LINK_STATUS) { | |
348 | VPRINT("%s: found Phy 1 at address %d with link\n", | |
349 | getName(), phyAddr); | |
350 | return true; // use PHY1 | |
351 | } | |
352 | } | |
353 | } | |
354 | ||
355 | // PHY1 does not exist, or it does not have valid link. | |
356 | // Try PHY0 at address 0. | |
357 | // | |
358 | _mdiReadPHY(PHY_ADDRESS_0, MDI_REG_CONTROL, &control); | |
359 | _mdiReadPHY(PHY_ADDRESS_0, MDI_REG_STATUS, &status); | |
360 | ||
361 | if (control == 0xffff || (status == 0 && control == 0)) { | |
362 | if (phyAddr == 0) { /* if address forced to 0, then fail */ | |
363 | IOLog("%s: phy0 not detected\n", getName()); | |
364 | return false; | |
365 | } | |
366 | if (foundPhy1 == true) { | |
367 | VPRINT("%s: no Phy at address 0, using Phy 1 without link\n", | |
368 | getName()); | |
369 | return true; // use PHY1 without a valid link | |
370 | } | |
371 | VPRINT("%s: no Phy at address 0, defaulting to 82503\n", getName()); | |
372 | phyAddr = PHY_ADDRESS_I82503; | |
373 | return true; | |
374 | } | |
375 | ||
376 | // must isolate PHY1 electrically before using PHY0. | |
377 | // | |
378 | if (foundPhy1 == true) { | |
379 | control = MDI_CONTROL_ISOLATE; | |
380 | _mdiWritePHY(phyAddr, MDI_REG_CONTROL, control); | |
381 | IOSleep(1); | |
382 | } | |
383 | ||
384 | // Enable and restart auto-negotiation on PHY0. | |
385 | // | |
386 | VPRINT("%s: starting auto-negotiation on Phy 0", getName()); | |
387 | control = MDI_CONTROL_AUTONEG_ENABLE; | |
388 | _mdiWritePHY(PHY_ADDRESS_0, MDI_REG_CONTROL, control); | |
389 | IOSleep(1); | |
390 | control |= MDI_CONTROL_RESTART_AUTONEG; | |
391 | _mdiWritePHY(PHY_ADDRESS_0, MDI_REG_CONTROL, control); | |
392 | ||
393 | for (int i = 0; i < AUTONEGOTIATE_TIMEOUT; i++) { | |
394 | _mdiReadPHY(PHY_ADDRESS_0, MDI_REG_STATUS, &status); | |
395 | if (status & MDI_STATUS_AUTONEG_COMPLETE) | |
396 | break; | |
397 | IOSleep(100); | |
398 | } | |
399 | _mdiReadPHY(PHY_ADDRESS_0, MDI_REG_STATUS, &status); | |
400 | _mdiReadPHY(PHY_ADDRESS_0, MDI_REG_STATUS, &status); | |
401 | _mdiReadPHY(PHY_ADDRESS_0, MDI_REG_STATUS, &status); | |
402 | if ((status & MDI_STATUS_LINK_STATUS) || foundPhy1 == false) { | |
403 | VPRINT("%s: using Phy 0 at address 0\n", getName()); | |
404 | phyAddr = 0; | |
405 | return true; | |
406 | } | |
407 | ||
408 | // Isolate PHY0. | |
409 | // | |
410 | VPRINT("%s: using Phy 1 without link\n", getName()); | |
411 | control = MDI_CONTROL_ISOLATE; | |
412 | _mdiWritePHY(PHY_ADDRESS_0, MDI_REG_CONTROL, control); | |
413 | IOSleep(1); | |
414 | ||
415 | // Enable and restart auto-negotiation on PHY1. | |
416 | // | |
417 | control = MDI_CONTROL_AUTONEG_ENABLE; | |
418 | _mdiWritePHY(phyAddr, MDI_REG_CONTROL, control); | |
419 | IOSleep(1); | |
420 | control |= MDI_CONTROL_RESTART_AUTONEG; | |
421 | _mdiWritePHY(phyAddr, MDI_REG_CONTROL, control); | |
422 | ||
423 | phyID = _phyGetID(); | |
424 | VPRINT("%s: PHY model id is 0x%08lx\n", getName(), phyID); | |
425 | phyID &= PHY_MODEL_MASK; | |
426 | ||
427 | return true; | |
428 | } | |
429 | ||
430 | //--------------------------------------------------------------------------- | |
431 | // Function: _phyGetMediumTypeFromBits | |
432 | // | |
433 | // Purpose: | |
434 | // Return the medium type that correspond to the given specifiers. | |
435 | ||
436 | mediumType_t Intel82557::_phyGetMediumTypeFromBits(bool rate100, | |
437 | bool fullDuplex, | |
438 | bool t4) | |
439 | { | |
440 | mediumType_t mediumType; | |
441 | ||
442 | if (t4) { | |
443 | mediumType = MEDIUM_TYPE_T4; | |
444 | } | |
445 | else if (rate100) { | |
446 | if (fullDuplex) | |
447 | mediumType = MEDIUM_TYPE_TX_FD; | |
448 | else | |
449 | mediumType = MEDIUM_TYPE_TX_HD; | |
450 | } | |
451 | else { | |
452 | if (fullDuplex) | |
453 | mediumType = MEDIUM_TYPE_10_FD; | |
454 | else | |
455 | mediumType = MEDIUM_TYPE_10_HD; | |
456 | } | |
457 | ||
458 | return mediumType; | |
459 | } | |
460 | ||
461 | //--------------------------------------------------------------------------- | |
462 | // Function: _phyGetMediumWithCode | |
463 | // | |
464 | // Purpose: | |
465 | // Returns the IONetworkMedium object associated with the given type. | |
466 | ||
467 | IONetworkMedium * Intel82557::_phyGetMediumWithType(UInt32 type) | |
468 | { | |
469 | if (type < MEDIUM_TYPE_INVALID) | |
470 | return mediumTable[type]; | |
471 | else | |
472 | return 0; | |
473 | } | |
474 | ||
475 | //--------------------------------------------------------------------------- | |
476 | // Function: _phyReportLinkStatus | |
477 | // | |
478 | // Purpose: | |
479 | // Called periodically to monitor for link changes. When a change | |
480 | // is detected, determine the current link and report it to the | |
481 | // upper layers by calling IONetworkController::setLinkStatus(). | |
482 | ||
483 | void Intel82557::_phyReportLinkStatus( bool firstPoll = false ) | |
484 | { | |
485 | UInt16 phyStatus; | |
486 | UInt16 phyStatusChange; | |
487 | ||
488 | // Read PHY status register. | |
489 | ||
490 | _mdiReadPHY( phyAddr, MDI_REG_STATUS, &phyStatus ); | |
491 | ||
492 | // Detect a change in the two link related bits. | |
493 | // Remember that the link status bit will latch a link fail | |
494 | // condition (should not miss a link down event). | |
495 | ||
496 | phyStatusChange = ( phyStatusPrev ^ phyStatus ) & | |
497 | ( MDI_STATUS_LINK_STATUS | | |
498 | MDI_STATUS_AUTONEG_COMPLETE ); | |
499 | ||
500 | if ( phyStatusChange || firstPoll ) | |
501 | { | |
502 | if ( firstPoll ) | |
503 | { | |
504 | // For the initial link status poll, wait a bit, then | |
505 | // re-read the status register to clear any latched bits. | |
506 | ||
507 | _phyWaitAutoNegotiation(); | |
508 | _mdiReadPHY( phyAddr, MDI_REG_STATUS, &phyStatus ); | |
509 | _mdiReadPHY( phyAddr, MDI_REG_STATUS, &phyStatus ); | |
510 | } | |
511 | ||
512 | // IOLog("PhyStatus: %04x\n", phyStatus); | |
513 | ||
514 | // Determine the link status. | |
515 | ||
516 | if ( ( phyStatus & MDI_STATUS_LINK_STATUS ) && | |
517 | ( phyStatus & MDI_STATUS_AUTONEG_COMPLETE ) ) | |
518 | { | |
519 | // Excellent, link is up. | |
520 | ||
521 | IONetworkMedium * activeMedium; | |
522 | ||
523 | activeMedium = _phyGetMediumWithType( _phyGetActiveMedium() ); | |
524 | ||
525 | setLinkStatus( kIONetworkLinkValid | kIONetworkLinkActive, | |
526 | activeMedium ); | |
527 | ||
528 | // IOLog("link is up %lx\n", | |
529 | // activeMedium ? activeMedium->getType() : 0); | |
530 | } | |
531 | else | |
532 | { | |
533 | // Link is down. | |
534 | ||
535 | setLinkStatus( kIONetworkLinkValid, 0 ); | |
536 | ||
537 | // IOLog("link is down\n"); | |
538 | } | |
539 | ||
540 | // Save phyStatus for the next run. | |
541 | ||
542 | phyStatusPrev = phyStatus; | |
543 | } | |
544 | } | |
545 | ||
546 | //--------------------------------------------------------------------------- | |
547 | // Function: _phyGetActiveMedium | |
548 | // | |
549 | // Purpose: | |
550 | // Once the PHY reports that the link is up, this method can be called | |
551 | // to return the type of link that was established. | |
552 | ||
553 | mediumType_t Intel82557::_phyGetActiveMedium() | |
554 | { | |
555 | mdi_reg_t reg; | |
556 | mediumType_t medium; | |
557 | ||
558 | do { | |
559 | // For the simple case where the media selection is not | |
560 | // automatic (e.g. forced to 100BaseTX). | |
561 | ||
562 | if ( currentMediumType != MEDIUM_TYPE_AUTO ) | |
563 | { | |
564 | medium = currentMediumType; | |
565 | break; | |
566 | } | |
567 | ||
568 | // i82553 has a special register for determining the speed and | |
569 | // duplex mode settings. | |
570 | ||
571 | if ( ( phyID == PHY_MODEL_I82553_A_B ) || | |
572 | ( phyID == PHY_MODEL_I82553_C ) ) | |
573 | { | |
574 | _mdiReadPHY( phyAddr, I82553_REG_SCR, ® ); | |
575 | ||
576 | medium = _phyGetMediumTypeFromBits( reg & I82553_SCR_100, | |
577 | reg & I82553_SCR_FULL_DUPLEX, | |
578 | reg & I82553_SCR_T4 ); | |
579 | break; | |
580 | } | |
581 | else if ( phyID == PHY_MODEL_NSC83840 ) | |
582 | { | |
583 | // For NSC83840, we use the 83840 specific register to determine | |
584 | // the link speed and duplex mode setting. Early 83840 devices | |
585 | // did not seem to report the remote capabilities when the link | |
586 | // partner does not support NWay. | |
587 | ||
588 | mdi_reg_t exp; | |
589 | ||
590 | _mdiReadPHY( phyAddr, MDI_REG_ANEX, &exp ); | |
591 | ||
592 | if ( ( exp & MDI_ANEX_LP_AUTONEGOTIABLE ) == 0 ) | |
593 | { | |
594 | _mdiReadPHY( phyAddr, NSC83840_REG_PAR, ® ); | |
595 | ||
596 | medium = _phyGetMediumTypeFromBits( | |
597 | !(reg & NSC83840_PAR_SPEED_10), | |
598 | (reg & NSC83840_PAR_DUPLEX_STAT), | |
599 | 0 ); | |
600 | break; | |
601 | } | |
602 | } | |
603 | ||
604 | // For generic PHY, use the standard PHY registers. | |
605 | // | |
606 | // Use the local and remote capability words to determine the | |
607 | // current active medium. | |
608 | ||
609 | mdi_reg_t lpa; | |
610 | mdi_reg_t mya; | |
611 | ||
612 | _mdiReadPHY( phyAddr, MDI_REG_ANLP, &lpa ); | |
613 | _mdiReadPHY( phyAddr, MDI_REG_ANAR, &mya ); | |
614 | ||
615 | mya &= lpa; // obtain common capabilities mask. | |
616 | ||
617 | // Observe PHY medium precedence. | |
618 | ||
619 | if ( mya & MDI_ANAR_TX_FD ) medium = MEDIUM_TYPE_TX_FD; | |
620 | else if ( mya & MDI_ANAR_T4 ) medium = MEDIUM_TYPE_T4; | |
621 | else if ( mya & MDI_ANAR_TX_HD ) medium = MEDIUM_TYPE_TX_HD; | |
622 | else if ( mya & MDI_ANAR_10_FD ) medium = MEDIUM_TYPE_10_FD; | |
623 | else medium = MEDIUM_TYPE_10_HD; | |
624 | } | |
625 | while ( false ); | |
626 | ||
627 | return medium; | |
628 | } |