Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/mii/mii.c
+++ new/usr/src/uts/common/io/mii/mii.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * mii - MII/PHY support for MAC drivers
28 28 *
29 29 * Utility module to provide a consistent interface to a MAC driver accross
30 30 * different implementations of PHY devices
31 31 */
32 32
33 33 #include <sys/types.h>
34 34 #include <sys/debug.h>
35 35 #include <sys/errno.h>
36 36 #include <sys/param.h>
37 37 #include <sys/kmem.h>
38 38 #include <sys/conf.h>
39 39 #include <sys/ddi.h>
40 40 #include <sys/sunddi.h>
41 41 #include <sys/modctl.h>
42 42 #include <sys/cmn_err.h>
43 43 #include <sys/policy.h>
44 44 #include <sys/note.h>
45 45 #include <sys/strsun.h>
46 46 #include <sys/miiregs.h>
47 47 #include <sys/mac_provider.h>
48 48 #include <sys/mac_ether.h>
49 49 #include <sys/mii.h>
50 50 #include "miipriv.h"
51 51
52 52 #define MII_SECOND 1000000
53 53
54 54 /* indices into error array */
55 55 enum {
56 56 MII_EOK = 0,
57 57 MII_ERESET,
58 58 MII_ESTART,
59 59 MII_ENOPHY,
60 60 MII_ECHECK,
61 61 MII_ELOOP,
62 62 };
63 63
64 64 static const char *mii_errors[] = {
65 65 "",
66 66 "Failure resetting PHY.",
67 67 "Failure starting PHY.",
68 68 "No Ethernet PHY found.",
69 69 "Failure reading PHY (removed?)",
70 70 "Failure setting loopback."
71 71 };
72 72
73 73 /* Indexed by XCVR_ type */
74 74 static const const char *mii_xcvr_types[] = {
75 75 "Undefined",
76 76 "Unknown",
77 77 "10 Mbps",
78 78 "100BASE-T4",
79 79 "100BASE-X",
80 80 "100BASE-T2",
81 81 "1000BASE-X",
82 82 "1000BASE-T"
83 83 };
84 84
85 85 /* state machine */
86 86 typedef enum {
87 87 MII_STATE_PROBE = 0,
88 88 MII_STATE_RESET,
89 89 MII_STATE_START,
90 90 MII_STATE_RUN,
91 91 MII_STATE_LOOPBACK,
92 92 } mii_tstate_t;
93 93
94 94 struct mii_handle {
95 95 dev_info_t *m_dip;
96 96 void *m_private;
97 97 mii_ops_t m_ops;
98 98
99 99 kt_did_t m_tq_id;
100 100 kmutex_t m_lock;
101 101 kcondvar_t m_cv;
102 102 ddi_taskq_t *m_tq;
103 103 int m_flags;
104 104
105 105 boolean_t m_started;
106 106 boolean_t m_suspending;
107 107 boolean_t m_suspended;
108 108 int m_error;
109 109 mii_tstate_t m_tstate;
110 110
111 111 #define MII_FLAG_EXIT 0x1 /* exit the thread */
112 112 #define MII_FLAG_STOP 0x2 /* shutdown MII monitoring */
113 113 #define MII_FLAG_RESET 0x4 /* reset the MII */
114 114 #define MII_FLAG_PROBE 0x8 /* probe for PHYs */
115 115 #define MII_FLAG_NOTIFY 0x10 /* notify about a change */
116 116 #define MII_FLAG_SUSPEND 0x20 /* monitoring suspended */
117 117 #define MII_FLAG_MACRESET 0x40 /* send reset to MAC */
118 118 #define MII_FLAG_PHYSTART 0x80 /* start up the PHY */
119 119
120 120 /* device name for printing, e.g. "hme0" */
121 121 char m_name[MODMAXNAMELEN + 16];
122 122
123 123 int m_addr;
124 124 phy_handle_t m_phys[32];
125 125 phy_handle_t m_bogus_phy;
126 126 phy_handle_t *m_phy;
127 127
128 128 link_state_t m_link;
129 129
130 130 /* these start out undefined, but get values due to mac_prop_set */
131 131 int m_en_aneg;
132 132 int m_en_10_hdx;
133 133 int m_en_10_fdx;
134 134 int m_en_100_t4;
135 135 int m_en_100_hdx;
136 136 int m_en_100_fdx;
137 137 int m_en_1000_hdx;
138 138 int m_en_1000_fdx;
139 139 int m_en_flowctrl;
140 140
141 141 boolean_t m_cap_pause;
142 142 boolean_t m_cap_asmpause;
143 143 };
144 144
145 145
146 146 static void _mii_task(void *);
147 147 static void _mii_probe_phy(phy_handle_t *);
148 148 static void _mii_probe(mii_handle_t);
149 149 static int _mii_reset(mii_handle_t);
150 150 static int _mii_loopback(mii_handle_t);
151 151 static void _mii_notify(mii_handle_t);
152 152 static int _mii_check(mii_handle_t);
153 153 static int _mii_start(mii_handle_t);
154 154
155 155 /*
156 156 * Loadable module structures/entrypoints
↓ open down ↓ |
156 lines elided |
↑ open up ↑ |
157 157 */
158 158
159 159 extern struct mod_ops mod_misc_ops;
160 160
161 161 static struct modlmisc modlmisc = {
162 162 &mod_miscops,
163 163 "802.3 MII support",
164 164 };
165 165
166 166 static struct modlinkage modlinkage = {
167 - MODREV_1, &modlmisc, NULL
167 + MODREV_1, { &modlmisc, NULL }
168 168 };
169 169
170 170 int
171 171 _init(void)
172 172 {
173 173 return (mod_install(&modlinkage));
174 174 }
175 175
176 176 int
177 177 _fini(void)
178 178 {
179 179 return (mod_remove(&modlinkage));
180 180 }
181 181
182 182 int
183 183 _info(struct modinfo *modinfop)
184 184 {
185 185 return (mod_info(&modlinkage, modinfop));
186 186 }
187 187
188 188 void
189 189 _mii_error(mii_handle_t mh, int errno)
190 190 {
191 191 /*
192 192 * This dumps an error message, but it avoids filling the log with
193 193 * repeated error messages.
194 194 */
195 195 if (mh->m_error != errno) {
196 196 cmn_err(CE_WARN, "%s: %s", mh->m_name, mii_errors[errno]);
197 197 mh->m_error = errno;
198 198 }
199 199 }
200 200
201 201 /*
202 202 * Known list of specific PHY probes.
203 203 */
204 204 typedef boolean_t (*phy_probe_t)(phy_handle_t *);
205 205 phy_probe_t _phy_probes[] = {
206 206 phy_natsemi_probe,
207 207 phy_intel_probe,
208 208 phy_qualsemi_probe,
209 209 phy_cicada_probe,
210 210 phy_marvell_probe,
211 211 phy_realtek_probe,
212 212 phy_other_probe,
213 213 NULL
214 214 };
215 215
216 216 /*
217 217 * MII Interface functions
218 218 */
219 219
220 220 mii_handle_t
221 221 mii_alloc_instance(void *private, dev_info_t *dip, int inst, mii_ops_t *ops)
222 222 {
223 223 mii_handle_t mh;
224 224 char tqname[16];
225 225
226 226 if (ops->mii_version != MII_OPS_VERSION) {
227 227 cmn_err(CE_WARN, "%s: incompatible MII version (%d)",
228 228 ddi_driver_name(dip), ops->mii_version);
229 229 return (NULL);
230 230 }
231 231 mh = kmem_zalloc(sizeof (*mh), KM_SLEEP);
232 232
233 233 (void) snprintf(mh->m_name, sizeof (mh->m_name), "%s%d",
234 234 ddi_driver_name(dip), inst);
235 235
236 236 /* DDI will prepend the driver name */
237 237 (void) snprintf(tqname, sizeof (tqname), "mii%d", inst);
238 238
239 239 mh->m_dip = dip;
240 240 mh->m_ops = *ops;
241 241 mh->m_private = private;
242 242 mh->m_suspended = B_FALSE;
243 243 mh->m_started = B_FALSE;
244 244 mh->m_tstate = MII_STATE_PROBE;
245 245 mh->m_link = LINK_STATE_UNKNOWN;
246 246 mh->m_error = MII_EOK;
247 247 mh->m_addr = -1;
248 248 mutex_init(&mh->m_lock, NULL, MUTEX_DRIVER, NULL);
249 249 cv_init(&mh->m_cv, NULL, CV_DRIVER, NULL);
250 250
251 251 mh->m_tq = ddi_taskq_create(dip, tqname, 1, TASKQ_DEFAULTPRI, 0);
252 252 if (mh->m_tq == NULL) {
253 253 cmn_err(CE_WARN, "%s: unable to create MII monitoring task",
254 254 ddi_driver_name(dip));
255 255 cv_destroy(&mh->m_cv);
256 256 mutex_destroy(&mh->m_lock);
257 257 kmem_free(mh, sizeof (*mh));
258 258 return (NULL);
259 259 }
260 260
261 261 /*
262 262 * Initialize user prefs by loading properties. Ultimately,
263 263 * Brussels interfaces would be superior here.
264 264 */
265 265 #define GETPROP(name) ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, name, -1)
266 266 mh->m_en_aneg = GETPROP("adv_autoneg_cap");
267 267 mh->m_en_10_hdx = GETPROP("adv_10hdx_cap");
268 268 mh->m_en_10_fdx = GETPROP("adv_10fdx_cap");
269 269 mh->m_en_100_hdx = GETPROP("adv_100hdx_cap");
270 270 mh->m_en_100_fdx = GETPROP("adv_100fdx_cap");
271 271 mh->m_en_100_t4 = GETPROP("adv_100T4_cap");
272 272 mh->m_en_1000_hdx = GETPROP("adv_1000hdx_cap");
273 273 mh->m_en_1000_fdx = GETPROP("adv_1000fdx_cap");
274 274
275 275 mh->m_cap_pause = B_FALSE;
276 276 mh->m_cap_asmpause = B_FALSE;
277 277
278 278 bzero(&mh->m_bogus_phy, sizeof (mh->m_bogus_phy));
279 279 mh->m_bogus_phy.phy_link = LINK_STATE_UNKNOWN;
280 280 mh->m_bogus_phy.phy_duplex = LINK_DUPLEX_UNKNOWN;
281 281 mh->m_bogus_phy.phy_addr = 0xff;
282 282 mh->m_bogus_phy.phy_type = XCVR_NONE;
283 283 mh->m_bogus_phy.phy_id = (uint32_t)-1;
284 284 mh->m_bogus_phy.phy_loopback = PHY_LB_NONE;
285 285 mh->m_bogus_phy.phy_flowctrl = LINK_FLOWCTRL_NONE;
286 286 mh->m_phy = &mh->m_bogus_phy;
287 287
288 288 for (int i = 0; i < 32; i++) {
289 289 mh->m_phys[i].phy_mii = mh;
290 290 }
291 291 mh->m_bogus_phy.phy_mii = mh;
292 292
293 293 return (mh);
294 294 }
295 295
296 296 mii_handle_t
297 297 mii_alloc(void *private, dev_info_t *dip, mii_ops_t *ops)
298 298 {
299 299 return (mii_alloc_instance(private, dip, ddi_get_instance(dip), ops));
300 300 }
301 301
302 302 void
303 303 mii_set_pauseable(mii_handle_t mh, boolean_t pauseable, boolean_t asymetric)
304 304 {
305 305 phy_handle_t *ph;
306 306
307 307 mutex_enter(&mh->m_lock);
308 308 ph = mh->m_phy;
309 309 ph->phy_cap_pause = mh->m_cap_pause = pauseable;
310 310 ph->phy_cap_asmpause = mh->m_cap_asmpause = asymetric;
311 311 if (pauseable) {
312 312 mh->m_en_flowctrl = LINK_FLOWCTRL_BI;
313 313 } else {
314 314 mh->m_en_flowctrl = LINK_FLOWCTRL_NONE;
315 315 }
316 316 mutex_exit(&mh->m_lock);
317 317 }
318 318
319 319 void
320 320 mii_free(mii_handle_t mh)
321 321 {
322 322 mutex_enter(&mh->m_lock);
323 323 mh->m_started = B_FALSE;
324 324 cv_broadcast(&mh->m_cv);
325 325 mutex_exit(&mh->m_lock);
326 326
327 327 ddi_taskq_destroy(mh->m_tq);
328 328 mutex_destroy(&mh->m_lock);
329 329 cv_destroy(&mh->m_cv);
330 330 kmem_free(mh, sizeof (*mh));
331 331 }
332 332
333 333 void
334 334 mii_reset(mii_handle_t mh)
335 335 {
336 336 mutex_enter(&mh->m_lock);
337 337 if (mh->m_tstate > MII_STATE_RESET)
338 338 mh->m_tstate = MII_STATE_RESET;
339 339 cv_broadcast(&mh->m_cv);
340 340 mutex_exit(&mh->m_lock);
341 341 }
342 342
343 343 void
344 344 mii_suspend(mii_handle_t mh)
345 345 {
346 346 mutex_enter(&mh->m_lock);
347 347 while ((!mh->m_suspended) && (mh->m_started)) {
348 348 mh->m_suspending = B_TRUE;
349 349 cv_broadcast(&mh->m_cv);
350 350 cv_wait(&mh->m_cv, &mh->m_lock);
351 351 }
352 352 mutex_exit(&mh->m_lock);
353 353 }
354 354
355 355 void
356 356 mii_resume(mii_handle_t mh)
357 357 {
358 358 mutex_enter(&mh->m_lock);
359 359
360 360 switch (mh->m_tstate) {
361 361 case MII_STATE_PROBE:
362 362 break;
363 363 case MII_STATE_RESET:
364 364 case MII_STATE_START:
365 365 case MII_STATE_RUN:
366 366 /* let monitor thread deal with this */
367 367 mh->m_tstate = MII_STATE_RESET;
368 368 break;
369 369
370 370 case MII_STATE_LOOPBACK:
371 371 /* loopback is handled synchronously */
372 372 (void) _mii_loopback(mh);
373 373 break;
374 374 }
375 375
376 376 mh->m_suspended = B_FALSE;
377 377 cv_broadcast(&mh->m_cv);
378 378 mutex_exit(&mh->m_lock);
379 379 }
380 380
381 381 void
382 382 mii_start(mii_handle_t mh)
383 383 {
384 384 mutex_enter(&mh->m_lock);
385 385 if (!mh->m_started) {
386 386 mh->m_tstate = MII_STATE_PROBE;
387 387 mh->m_started = B_TRUE;
388 388 if (ddi_taskq_dispatch(mh->m_tq, _mii_task, mh, DDI_NOSLEEP) !=
389 389 DDI_SUCCESS) {
390 390 cmn_err(CE_WARN,
391 391 "%s: unable to start MII monitoring task",
392 392 mh->m_name);
393 393 mh->m_started = B_FALSE;
394 394 }
395 395 }
396 396 cv_broadcast(&mh->m_cv);
397 397 mutex_exit(&mh->m_lock);
398 398 }
399 399
400 400 void
401 401 mii_stop(mii_handle_t mh)
402 402 {
403 403 mutex_enter(&mh->m_lock);
404 404 mh->m_started = B_FALSE;
405 405 /*
406 406 * Reset link state to unknown defaults, since we're not
407 407 * monitoring it anymore. We'll reprobe all link state later.
408 408 */
409 409 mh->m_link = LINK_STATE_UNKNOWN;
410 410 mh->m_phy = &mh->m_bogus_phy;
411 411 cv_broadcast(&mh->m_cv);
412 412 mutex_exit(&mh->m_lock);
413 413 /*
414 414 * Notify the MAC driver. This will allow it to call back
415 415 * into the MAC framework to clear any previous link state.
416 416 */
417 417 _mii_notify(mh);
418 418 }
419 419
420 420 void
421 421 mii_probe(mii_handle_t mh)
422 422 {
423 423 mutex_enter(&mh->m_lock);
424 424 _mii_probe(mh);
425 425 mutex_exit(&mh->m_lock);
426 426 }
427 427
428 428 void
429 429 mii_check(mii_handle_t mh)
430 430 {
431 431 mutex_enter(&mh->m_lock);
432 432 cv_broadcast(&mh->m_cv);
433 433 mutex_exit(&mh->m_lock);
434 434 }
435 435
436 436 int
437 437 mii_get_speed(mii_handle_t mh)
438 438 {
439 439 phy_handle_t *ph = mh->m_phy;
440 440
441 441 return (ph->phy_speed);
442 442 }
443 443
444 444 link_duplex_t
445 445 mii_get_duplex(mii_handle_t mh)
446 446 {
447 447 phy_handle_t *ph = mh->m_phy;
448 448
449 449 return (ph->phy_duplex);
450 450 }
451 451
452 452 link_state_t
453 453 mii_get_state(mii_handle_t mh)
454 454 {
455 455 phy_handle_t *ph = mh->m_phy;
456 456
457 457 return (ph->phy_link);
458 458 }
459 459
460 460 link_flowctrl_t
461 461 mii_get_flowctrl(mii_handle_t mh)
462 462 {
463 463 phy_handle_t *ph = mh->m_phy;
464 464
465 465 return (ph->phy_flowctrl);
466 466 }
467 467
468 468 int
469 469 mii_get_loopmodes(mii_handle_t mh, lb_property_t *modes)
470 470 {
471 471 phy_handle_t *ph = mh->m_phy;
472 472 int cnt = 0;
473 473 lb_property_t lmodes[MII_LOOPBACK_MAX];
474 474
475 475 lmodes[cnt].lb_type = normal;
476 476 (void) strlcpy(lmodes[cnt].key, "normal", sizeof (lmodes[cnt].key));
477 477 lmodes[cnt].value = PHY_LB_NONE;
478 478 cnt++;
479 479
480 480 if (ph->phy_cap_1000_fdx ||
481 481 ph->phy_cap_100_fdx ||
482 482 ph->phy_cap_10_fdx) {
483 483 /* we only support full duplex internal phy testing */
484 484 lmodes[cnt].lb_type = internal;
485 485 (void) strlcpy(lmodes[cnt].key, "PHY",
486 486 sizeof (lmodes[cnt].key));
487 487 lmodes[cnt].value = PHY_LB_INT_PHY;
488 488 cnt++;
489 489 }
490 490
491 491 if (ph->phy_cap_1000_fdx) {
492 492 lmodes[cnt].lb_type = external;
493 493 (void) strlcpy(lmodes[cnt].key, "1000Mbps",
494 494 sizeof (lmodes[cnt].key));
495 495 lmodes[cnt].value = PHY_LB_EXT_1000;
496 496 cnt++;
497 497 }
498 498
499 499 if (ph->phy_cap_100_fdx) {
500 500 lmodes[cnt].lb_type = external;
501 501 (void) strlcpy(lmodes[cnt].key, "100Mbps",
502 502 sizeof (lmodes[cnt].key));
503 503 lmodes[cnt].value = PHY_LB_EXT_100;
504 504 cnt++;
505 505 }
506 506
507 507 if (ph->phy_cap_10_fdx) {
508 508 lmodes[cnt].lb_type = external;
509 509 (void) strlcpy(lmodes[cnt].key, "10Mbps",
510 510 sizeof (lmodes[cnt].key));
511 511 lmodes[cnt].value = PHY_LB_EXT_10;
512 512 cnt++;
513 513 }
514 514
515 515 if (modes) {
516 516 bcopy(lmodes, modes, sizeof (lb_property_t) * cnt);
517 517 }
518 518
519 519 return (cnt);
520 520 }
521 521
522 522 uint32_t
523 523 mii_get_loopback(mii_handle_t mh)
524 524 {
525 525 phy_handle_t *ph = mh->m_phy;
526 526
527 527 return (ph->phy_loopback);
528 528 }
529 529
530 530 int
531 531 mii_set_loopback(mii_handle_t mh, uint32_t loop)
532 532 {
533 533 phy_handle_t *ph;
534 534 int rv;
535 535
536 536 mutex_enter(&mh->m_lock);
537 537 ph = mh->m_phy;
538 538
539 539 if ((!mh->m_started) || (!ph->phy_present) ||
540 540 (loop >= mii_get_loopmodes(mh, NULL))) {
541 541 return (EINVAL);
542 542 }
543 543
544 544 ph->phy_loopback = loop;
545 545 rv = _mii_loopback(mh);
546 546 if (rv == DDI_SUCCESS) {
547 547 mh->m_tstate = MII_STATE_LOOPBACK;
548 548 }
549 549 cv_broadcast(&mh->m_cv);
550 550 mutex_exit(&mh->m_lock);
551 551
552 552 return (rv == DDI_SUCCESS ? 0 : EIO);
553 553 }
554 554
555 555 uint32_t
556 556 mii_get_id(mii_handle_t mh)
557 557 {
558 558 phy_handle_t *ph = mh->m_phy;
559 559
560 560 return (ph->phy_id);
561 561 }
562 562
563 563 int
564 564 mii_get_addr(mii_handle_t mh)
565 565 {
566 566 return (mh->m_addr);
567 567 }
568 568
569 569 /* GLDv3 helpers */
570 570
571 571 boolean_t
572 572 mii_m_loop_ioctl(mii_handle_t mh, queue_t *wq, mblk_t *mp)
573 573 {
574 574 struct iocblk *iocp;
575 575 int rv = 0;
576 576 int cnt;
577 577 lb_property_t modes[MII_LOOPBACK_MAX];
578 578 lb_info_sz_t sz;
579 579 int cmd;
580 580 uint32_t mode;
581 581
582 582 iocp = (void *)mp->b_rptr;
583 583 cmd = iocp->ioc_cmd;
584 584
585 585 switch (cmd) {
586 586 case LB_SET_MODE:
587 587 case LB_GET_INFO_SIZE:
588 588 case LB_GET_INFO:
589 589 case LB_GET_MODE:
590 590 break;
591 591
592 592 default:
593 593 return (B_FALSE);
594 594 }
595 595
596 596 if (mp->b_cont == NULL) {
597 597 miocnak(wq, mp, 0, EINVAL);
598 598 return (B_TRUE);
599 599 }
600 600
601 601 switch (cmd) {
602 602 case LB_GET_INFO_SIZE:
603 603 cnt = mii_get_loopmodes(mh, modes);
604 604 if (iocp->ioc_count != sizeof (sz)) {
605 605 rv = EINVAL;
606 606 } else {
607 607 sz = cnt * sizeof (lb_property_t);
608 608 bcopy(&sz, mp->b_cont->b_rptr, sizeof (sz));
609 609 }
610 610 break;
611 611
612 612 case LB_GET_INFO:
613 613 cnt = mii_get_loopmodes(mh, modes);
614 614 if (iocp->ioc_count != (cnt * sizeof (lb_property_t))) {
615 615 rv = EINVAL;
616 616 } else {
617 617 bcopy(modes, mp->b_cont->b_rptr, iocp->ioc_count);
618 618 }
619 619 break;
620 620
621 621 case LB_GET_MODE:
622 622 if (iocp->ioc_count != sizeof (mode)) {
623 623 rv = EINVAL;
624 624 } else {
625 625 mode = mii_get_loopback(mh);
626 626 bcopy(&mode, mp->b_cont->b_rptr, sizeof (mode));
627 627 }
628 628 break;
629 629
630 630 case LB_SET_MODE:
631 631 rv = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
632 632 if (rv != 0)
633 633 break;
634 634 if (iocp->ioc_count != sizeof (mode)) {
635 635 rv = EINVAL;
636 636 break;
637 637 }
638 638 bcopy(mp->b_cont->b_rptr, &mode, sizeof (mode));
639 639 rv = mii_set_loopback(mh, mode);
640 640 break;
641 641 }
642 642
643 643 if (rv == 0) {
644 644 miocack(wq, mp, iocp->ioc_count, 0);
645 645 } else {
646 646 miocnak(wq, mp, 0, rv);
647 647 }
648 648 return (B_TRUE);
649 649 }
650 650
651 651 int
652 652 mii_m_getprop(mii_handle_t mh, const char *name, mac_prop_id_t num,
653 653 uint_t sz, void *val)
654 654 {
655 655 phy_handle_t *ph;
656 656 int err = 0;
657 657
658 658 _NOTE(ARGUNUSED(name));
659 659
660 660 if (sz < 1)
661 661 return (EINVAL);
662 662
663 663 mutex_enter(&mh->m_lock);
664 664
665 665 ph = mh->m_phy;
666 666
667 667 #define CASE_PROP_ABILITY(PROP, VAR) \
668 668 case MAC_PROP_ADV_##PROP: \
669 669 *(uint8_t *)val = ph->phy_adv_##VAR; \
670 670 break; \
671 671 \
672 672 case MAC_PROP_EN_##PROP: \
673 673 *(uint8_t *)val = ph->phy_en_##VAR; \
674 674 break;
675 675
676 676 switch (num) {
677 677 case MAC_PROP_DUPLEX:
678 678 ASSERT(sz >= sizeof (link_duplex_t));
679 679 bcopy(&ph->phy_duplex, val, sizeof (link_duplex_t));
680 680 break;
681 681
682 682 case MAC_PROP_SPEED: {
683 683 uint64_t speed = ph->phy_speed * 1000000ull;
684 684 ASSERT(sz >= sizeof (uint64_t));
685 685 bcopy(&speed, val, sizeof (speed));
686 686 break;
687 687 }
688 688
689 689 case MAC_PROP_AUTONEG:
690 690 *(uint8_t *)val = ph->phy_adv_aneg;
691 691 break;
692 692
693 693 case MAC_PROP_FLOWCTRL:
694 694 ASSERT(sz >= sizeof (link_flowctrl_t));
695 695 bcopy(&ph->phy_flowctrl, val, sizeof (link_flowctrl_t));
696 696 break;
697 697
698 698 CASE_PROP_ABILITY(1000FDX_CAP, 1000_fdx)
699 699 CASE_PROP_ABILITY(1000HDX_CAP, 1000_hdx)
700 700 CASE_PROP_ABILITY(100T4_CAP, 100_t4)
701 701 CASE_PROP_ABILITY(100FDX_CAP, 100_fdx)
702 702 CASE_PROP_ABILITY(100HDX_CAP, 100_hdx)
703 703 CASE_PROP_ABILITY(10FDX_CAP, 10_fdx)
704 704 CASE_PROP_ABILITY(10HDX_CAP, 10_hdx)
705 705
706 706 default:
707 707 err = ENOTSUP;
708 708 break;
709 709 }
710 710
711 711 mutex_exit(&mh->m_lock);
712 712
713 713 return (err);
714 714 }
715 715
716 716 void
717 717 mii_m_propinfo(mii_handle_t mh, const char *name, mac_prop_id_t num,
718 718 mac_prop_info_handle_t prh)
719 719 {
720 720 phy_handle_t *ph;
721 721
722 722 _NOTE(ARGUNUSED(name));
723 723
724 724 mutex_enter(&mh->m_lock);
725 725
726 726 ph = mh->m_phy;
727 727
728 728 switch (num) {
729 729 case MAC_PROP_DUPLEX:
730 730 case MAC_PROP_SPEED:
731 731 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
732 732 break;
733 733
734 734 case MAC_PROP_AUTONEG:
735 735 mac_prop_info_set_default_uint8(prh, ph->phy_cap_aneg);
736 736 break;
737 737
738 738 #define CASE_PROP_PERM(PROP, VAR) \
739 739 case MAC_PROP_ADV_##PROP: \
740 740 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); \
741 741 mac_prop_info_set_default_uint8(prh, ph->phy_cap_##VAR); \
742 742 break; \
743 743 \
744 744 case MAC_PROP_EN_##PROP: \
745 745 if (!ph->phy_cap_##VAR) \
746 746 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); \
747 747 mac_prop_info_set_default_uint8(prh, ph->phy_cap_##VAR); \
748 748 break;
749 749
750 750 CASE_PROP_PERM(1000FDX_CAP, 1000_fdx)
751 751 CASE_PROP_PERM(1000HDX_CAP, 1000_hdx)
752 752 CASE_PROP_PERM(100T4_CAP, 100_t4)
753 753 CASE_PROP_PERM(100FDX_CAP, 100_fdx)
754 754 CASE_PROP_PERM(100HDX_CAP, 100_hdx)
755 755 CASE_PROP_PERM(10FDX_CAP, 10_fdx)
756 756 CASE_PROP_PERM(10HDX_CAP, 10_hdx)
757 757 }
758 758
759 759 mutex_exit(&mh->m_lock);
760 760 }
761 761
762 762 int
763 763 mii_m_setprop(mii_handle_t mh, const char *name, mac_prop_id_t num,
764 764 uint_t sz, const void *valp)
765 765 {
766 766 phy_handle_t *ph;
767 767 boolean_t *advp = NULL;
768 768 boolean_t *capp = NULL;
769 769 int *macpp = NULL;
770 770 int rv = ENOTSUP;
771 771
772 772 _NOTE(ARGUNUSED(name));
773 773
774 774 if (sz < 1)
775 775 return (EINVAL);
776 776
777 777 mutex_enter(&mh->m_lock);
778 778
779 779 ph = mh->m_phy;
780 780
781 781 /* we don't support changing parameters while in loopback mode */
782 782 if (ph->phy_loopback != PHY_LB_NONE) {
783 783 switch (num) {
784 784 case MAC_PROP_EN_1000FDX_CAP:
785 785 case MAC_PROP_EN_1000HDX_CAP:
786 786 case MAC_PROP_EN_100FDX_CAP:
787 787 case MAC_PROP_EN_100HDX_CAP:
788 788 case MAC_PROP_EN_100T4_CAP:
789 789 case MAC_PROP_EN_10FDX_CAP:
790 790 case MAC_PROP_EN_10HDX_CAP:
791 791 case MAC_PROP_AUTONEG:
792 792 case MAC_PROP_FLOWCTRL:
793 793 return (EBUSY);
794 794 }
795 795 }
796 796
797 797 switch (num) {
798 798 case MAC_PROP_EN_1000FDX_CAP:
799 799 capp = &ph->phy_cap_1000_fdx;
800 800 advp = &ph->phy_en_1000_fdx;
801 801 macpp = &mh->m_en_1000_fdx;
802 802 break;
803 803 case MAC_PROP_EN_1000HDX_CAP:
804 804 capp = &ph->phy_cap_1000_hdx;
805 805 advp = &ph->phy_en_1000_hdx;
806 806 macpp = &mh->m_en_1000_hdx;
807 807 break;
808 808 case MAC_PROP_EN_100FDX_CAP:
809 809 capp = &ph->phy_cap_100_fdx;
810 810 advp = &ph->phy_en_100_fdx;
811 811 macpp = &mh->m_en_100_fdx;
812 812 break;
813 813 case MAC_PROP_EN_100HDX_CAP:
814 814 capp = &ph->phy_cap_100_hdx;
815 815 advp = &ph->phy_en_100_hdx;
816 816 macpp = &mh->m_en_100_hdx;
817 817 break;
818 818 case MAC_PROP_EN_100T4_CAP:
819 819 capp = &ph->phy_cap_100_t4;
820 820 advp = &ph->phy_en_100_t4;
821 821 macpp = &mh->m_en_100_t4;
822 822 break;
823 823 case MAC_PROP_EN_10FDX_CAP:
824 824 capp = &ph->phy_cap_10_fdx;
825 825 advp = &ph->phy_en_10_fdx;
826 826 macpp = &mh->m_en_10_fdx;
827 827 break;
828 828 case MAC_PROP_EN_10HDX_CAP:
829 829 capp = &ph->phy_cap_10_hdx;
830 830 advp = &ph->phy_en_10_hdx;
831 831 macpp = &mh->m_en_10_hdx;
832 832 break;
833 833 case MAC_PROP_AUTONEG:
834 834 capp = &ph->phy_cap_aneg;
835 835 advp = &ph->phy_en_aneg;
836 836 macpp = &mh->m_en_aneg;
837 837 break;
838 838 case MAC_PROP_FLOWCTRL: {
839 839 link_flowctrl_t fc;
840 840 boolean_t chg;
841 841
842 842 ASSERT(sz >= sizeof (link_flowctrl_t));
843 843 bcopy(valp, &fc, sizeof (fc));
844 844
845 845 chg = fc == ph->phy_en_flowctrl ? B_FALSE : B_TRUE;
846 846 switch (fc) {
847 847 case LINK_FLOWCTRL_NONE:
848 848 ph->phy_en_pause = B_FALSE;
849 849 ph->phy_en_asmpause = B_FALSE;
850 850 ph->phy_en_flowctrl = fc;
851 851 break;
852 852 /*
853 853 * Note that while we don't have a way to advertise
854 854 * that we can RX pause (we just won't send pause
855 855 * frames), we advertise full support. The MAC driver
856 856 * will learn of the configuration via the saved value
857 857 * of the tunable.
858 858 */
859 859 case LINK_FLOWCTRL_BI:
860 860 case LINK_FLOWCTRL_RX:
861 861 if (ph->phy_cap_pause) {
862 862 ph->phy_en_pause = B_TRUE;
863 863 ph->phy_en_asmpause = B_TRUE;
864 864 ph->phy_en_flowctrl = fc;
865 865 } else {
866 866 rv = EINVAL;
867 867 }
868 868 break;
869 869
870 870 /*
871 871 * Tell the other side that we can assert pause, but
872 872 * we cannot resend.
873 873 */
874 874 case LINK_FLOWCTRL_TX:
875 875 if (ph->phy_cap_asmpause) {
876 876 ph->phy_en_pause = B_FALSE;
877 877 ph->phy_en_flowctrl = fc;
878 878 ph->phy_en_asmpause = B_TRUE;
879 879 } else {
880 880 rv = EINVAL;
881 881 }
882 882 break;
883 883 default:
884 884 rv = EINVAL;
885 885 break;
886 886 }
887 887 if ((rv == 0) && chg) {
888 888 mh->m_en_flowctrl = fc;
889 889 mh->m_tstate = MII_STATE_RESET;
890 890 cv_broadcast(&mh->m_cv);
891 891 }
892 892 break;
893 893 }
894 894
895 895 default:
896 896 rv = ENOTSUP;
897 897 break;
898 898 }
899 899
900 900 if (capp && advp && macpp) {
901 901 if (sz < sizeof (uint8_t)) {
902 902 rv = EINVAL;
903 903
904 904 } else if (*capp) {
905 905 if (*advp != *(uint8_t *)valp) {
906 906 *advp = *(uint8_t *)valp;
907 907 *macpp = *(uint8_t *)valp;
908 908 mh->m_tstate = MII_STATE_RESET;
909 909 cv_broadcast(&mh->m_cv);
910 910 }
911 911 rv = 0;
912 912 }
913 913 }
914 914
915 915 mutex_exit(&mh->m_lock);
916 916 return (rv);
917 917 }
918 918
919 919 int
920 920 mii_m_getstat(mii_handle_t mh, uint_t stat, uint64_t *val)
921 921 {
922 922 phy_handle_t *ph;
923 923 int rv = 0;
924 924
925 925 mutex_enter(&mh->m_lock);
926 926
927 927 ph = mh->m_phy;
928 928
929 929 switch (stat) {
930 930 case MAC_STAT_IFSPEED:
931 931 *val = ph->phy_speed * 1000000ull;
932 932 break;
933 933 case ETHER_STAT_LINK_DUPLEX:
934 934 *val = ph->phy_duplex;
935 935 break;
936 936 case ETHER_STAT_LINK_AUTONEG:
937 937 *val = !!(ph->phy_adv_aneg && ph->phy_lp_aneg);
938 938 break;
939 939 case ETHER_STAT_XCVR_ID:
940 940 *val = ph->phy_id;
941 941 break;
942 942 case ETHER_STAT_XCVR_INUSE:
943 943 *val = ph->phy_type;
944 944 break;
945 945 case ETHER_STAT_XCVR_ADDR:
946 946 *val = ph->phy_addr;
947 947 break;
948 948 case ETHER_STAT_LINK_ASMPAUSE:
949 949 *val = ph->phy_adv_asmpause && ph->phy_lp_asmpause &&
950 950 ph->phy_adv_pause != ph->phy_lp_pause;
951 951 break;
952 952 case ETHER_STAT_LINK_PAUSE:
953 953 *val = (ph->phy_flowctrl == LINK_FLOWCTRL_BI) ||
954 954 (ph->phy_flowctrl == LINK_FLOWCTRL_RX);
955 955 break;
956 956 case ETHER_STAT_CAP_1000FDX:
957 957 *val = ph->phy_cap_1000_fdx;
958 958 break;
959 959 case ETHER_STAT_CAP_1000HDX:
960 960 *val = ph->phy_cap_1000_hdx;
961 961 break;
962 962 case ETHER_STAT_CAP_100FDX:
963 963 *val = ph->phy_cap_100_fdx;
964 964 break;
965 965 case ETHER_STAT_CAP_100HDX:
966 966 *val = ph->phy_cap_100_hdx;
967 967 break;
968 968 case ETHER_STAT_CAP_10FDX:
969 969 *val = ph->phy_cap_10_fdx;
970 970 break;
971 971 case ETHER_STAT_CAP_10HDX:
972 972 *val = ph->phy_cap_10_hdx;
973 973 break;
974 974 case ETHER_STAT_CAP_100T4:
975 975 *val = ph->phy_cap_100_t4;
976 976 break;
977 977 case ETHER_STAT_CAP_AUTONEG:
978 978 *val = ph->phy_cap_aneg;
979 979 break;
980 980 case ETHER_STAT_CAP_PAUSE:
981 981 *val = ph->phy_cap_pause;
982 982 break;
983 983 case ETHER_STAT_CAP_ASMPAUSE:
984 984 *val = ph->phy_cap_asmpause;
985 985 break;
986 986
987 987 case ETHER_STAT_LP_CAP_1000FDX:
988 988 *val = ph->phy_lp_1000_fdx;
989 989 break;
990 990 case ETHER_STAT_LP_CAP_1000HDX:
991 991 *val = ph->phy_lp_1000_hdx;
992 992 break;
993 993 case ETHER_STAT_LP_CAP_100FDX:
994 994 *val = ph->phy_lp_100_fdx;
995 995 break;
996 996 case ETHER_STAT_LP_CAP_100HDX:
997 997 *val = ph->phy_lp_100_hdx;
998 998 break;
999 999 case ETHER_STAT_LP_CAP_10FDX:
1000 1000 *val = ph->phy_lp_10_fdx;
1001 1001 break;
1002 1002 case ETHER_STAT_LP_CAP_10HDX:
1003 1003 *val = ph->phy_lp_10_hdx;
1004 1004 break;
1005 1005 case ETHER_STAT_LP_CAP_100T4:
1006 1006 *val = ph->phy_lp_100_t4;
1007 1007 break;
1008 1008 case ETHER_STAT_LP_CAP_AUTONEG:
1009 1009 *val = ph->phy_lp_aneg;
1010 1010 break;
1011 1011 case ETHER_STAT_LP_CAP_PAUSE:
1012 1012 *val = ph->phy_lp_pause;
1013 1013 break;
1014 1014 case ETHER_STAT_LP_CAP_ASMPAUSE:
1015 1015 *val = ph->phy_lp_asmpause;
1016 1016 break;
1017 1017
1018 1018 case ETHER_STAT_ADV_CAP_1000FDX:
1019 1019 *val = ph->phy_adv_1000_fdx;
1020 1020 break;
1021 1021 case ETHER_STAT_ADV_CAP_1000HDX:
1022 1022 *val = ph->phy_adv_1000_hdx;
1023 1023 break;
1024 1024 case ETHER_STAT_ADV_CAP_100FDX:
1025 1025 *val = ph->phy_adv_100_fdx;
1026 1026 break;
1027 1027 case ETHER_STAT_ADV_CAP_100HDX:
1028 1028 *val = ph->phy_adv_100_hdx;
1029 1029 break;
1030 1030 case ETHER_STAT_ADV_CAP_10FDX:
1031 1031 *val = ph->phy_adv_10_fdx;
1032 1032 break;
1033 1033 case ETHER_STAT_ADV_CAP_10HDX:
1034 1034 *val = ph->phy_adv_10_hdx;
1035 1035 break;
1036 1036 case ETHER_STAT_ADV_CAP_100T4:
1037 1037 *val = ph->phy_adv_100_t4;
1038 1038 break;
1039 1039 case ETHER_STAT_ADV_CAP_AUTONEG:
1040 1040 *val = ph->phy_adv_aneg;
1041 1041 break;
1042 1042 case ETHER_STAT_ADV_CAP_PAUSE:
1043 1043 *val = ph->phy_adv_pause;
1044 1044 break;
1045 1045 case ETHER_STAT_ADV_CAP_ASMPAUSE:
1046 1046 *val = ph->phy_adv_asmpause;
1047 1047 break;
1048 1048
1049 1049 default:
1050 1050 rv = ENOTSUP;
1051 1051 break;
1052 1052 }
1053 1053 mutex_exit(&mh->m_lock);
1054 1054
1055 1055 return (rv);
1056 1056 }
1057 1057
1058 1058 /*
1059 1059 * PHY support routines. Private to the MII module and the vendor
1060 1060 * specific PHY implementation code.
1061 1061 */
1062 1062 uint16_t
1063 1063 phy_read(phy_handle_t *ph, uint8_t reg)
1064 1064 {
1065 1065 mii_handle_t mh = ph->phy_mii;
1066 1066
1067 1067 return ((*mh->m_ops.mii_read)(mh->m_private, ph->phy_addr, reg));
1068 1068 }
1069 1069
1070 1070 void
1071 1071 phy_write(phy_handle_t *ph, uint8_t reg, uint16_t val)
1072 1072 {
1073 1073 mii_handle_t mh = ph->phy_mii;
1074 1074
1075 1075 (*mh->m_ops.mii_write)(mh->m_private, ph->phy_addr, reg, val);
1076 1076 }
1077 1077
1078 1078 int
1079 1079 phy_reset(phy_handle_t *ph)
1080 1080 {
1081 1081 ASSERT(mutex_owned(&ph->phy_mii->m_lock));
1082 1082
1083 1083 /*
1084 1084 * For our device, make sure its powered up and unisolated.
1085 1085 */
1086 1086 PHY_CLR(ph, MII_CONTROL,
1087 1087 MII_CONTROL_PWRDN | MII_CONTROL_ISOLATE);
1088 1088
1089 1089 /*
1090 1090 * Finally reset it.
1091 1091 */
1092 1092 PHY_SET(ph, MII_CONTROL, MII_CONTROL_RESET);
1093 1093
1094 1094 /*
1095 1095 * Apparently some devices (DP83840A) like to have a little
1096 1096 * bit of a wait before we start accessing anything else on
1097 1097 * the PHY.
1098 1098 */
1099 1099 drv_usecwait(500);
1100 1100
1101 1101 /*
1102 1102 * Wait for reset to complete - probably very fast, but no
1103 1103 * more than 0.5 sec according to spec. It would be nice if
1104 1104 * we could use delay() here, but MAC drivers may call
1105 1105 * functions which hold this lock in interrupt context, so
1106 1106 * sleeping would be a definite no-no. The good news here is
1107 1107 * that it seems to be the case that most devices come back
1108 1108 * within only a few hundred usec.
1109 1109 */
1110 1110 for (int i = 500000; i; i -= 100) {
1111 1111 if ((phy_read(ph, MII_CONTROL) & MII_CONTROL_RESET) == 0) {
1112 1112 /* reset completed */
1113 1113 return (DDI_SUCCESS);
1114 1114 }
1115 1115 drv_usecwait(100);
1116 1116 }
1117 1117
1118 1118 return (DDI_FAILURE);
1119 1119 }
1120 1120
1121 1121 int
1122 1122 phy_stop(phy_handle_t *ph)
1123 1123 {
1124 1124 phy_write(ph, MII_CONTROL, MII_CONTROL_ISOLATE);
1125 1125
1126 1126 return (DDI_SUCCESS);
1127 1127 }
1128 1128
1129 1129 int
1130 1130 phy_loop(phy_handle_t *ph)
1131 1131 {
1132 1132 uint16_t bmcr, gtcr;
1133 1133
1134 1134 ASSERT(mutex_owned(&ph->phy_mii->m_lock));
1135 1135
1136 1136 /*
1137 1137 * Disable everything to start... we'll add in modes as we go.
1138 1138 */
1139 1139 ph->phy_adv_aneg = B_FALSE;
1140 1140 ph->phy_adv_1000_fdx = B_FALSE;
1141 1141 ph->phy_adv_1000_hdx = B_FALSE;
1142 1142 ph->phy_adv_100_fdx = B_FALSE;
1143 1143 ph->phy_adv_100_t4 = B_FALSE;
1144 1144 ph->phy_adv_100_hdx = B_FALSE;
1145 1145 ph->phy_adv_10_fdx = B_FALSE;
1146 1146 ph->phy_adv_10_hdx = B_FALSE;
1147 1147 ph->phy_adv_pause = B_FALSE;
1148 1148 ph->phy_adv_asmpause = B_FALSE;
1149 1149
1150 1150 bmcr = 0;
1151 1151 gtcr = MII_MSCONTROL_MANUAL | MII_MSCONTROL_MASTER;
1152 1152
1153 1153 switch (ph->phy_loopback) {
1154 1154 case PHY_LB_NONE:
1155 1155 /* We shouldn't be here */
1156 1156 ASSERT(0);
1157 1157 break;
1158 1158
1159 1159 case PHY_LB_INT_PHY:
1160 1160 bmcr |= MII_CONTROL_LOOPBACK;
1161 1161 ph->phy_duplex = LINK_DUPLEX_FULL;
1162 1162 if (ph->phy_cap_1000_fdx) {
1163 1163 bmcr |= MII_CONTROL_1GB | MII_CONTROL_FDUPLEX;
1164 1164 ph->phy_speed = 1000;
1165 1165 } else if (ph->phy_cap_100_fdx) {
1166 1166 bmcr |= MII_CONTROL_100MB | MII_CONTROL_FDUPLEX;
1167 1167 ph->phy_speed = 100;
1168 1168 } else if (ph->phy_cap_10_fdx) {
1169 1169 bmcr |= MII_CONTROL_FDUPLEX;
1170 1170 ph->phy_speed = 10;
1171 1171 }
1172 1172 break;
1173 1173
1174 1174 case PHY_LB_EXT_10:
1175 1175 bmcr = MII_CONTROL_FDUPLEX;
1176 1176 ph->phy_speed = 10;
1177 1177 ph->phy_duplex = LINK_DUPLEX_FULL;
1178 1178 break;
1179 1179
1180 1180 case PHY_LB_EXT_100:
1181 1181 bmcr = MII_CONTROL_100MB | MII_CONTROL_FDUPLEX;
1182 1182 ph->phy_speed = 100;
1183 1183 ph->phy_duplex = LINK_DUPLEX_FULL;
1184 1184 break;
1185 1185
1186 1186 case PHY_LB_EXT_1000:
1187 1187 bmcr = MII_CONTROL_1GB | MII_CONTROL_FDUPLEX;
1188 1188 ph->phy_speed = 1000;
1189 1189 ph->phy_duplex = LINK_DUPLEX_FULL;
1190 1190 break;
1191 1191 }
1192 1192
1193 1193 ph->phy_link = LINK_STATE_UP; /* force up for loopback */
1194 1194 ph->phy_flowctrl = LINK_FLOWCTRL_NONE;
1195 1195
1196 1196 switch (ph->phy_type) {
1197 1197 case XCVR_1000T:
1198 1198 case XCVR_1000X:
1199 1199 case XCVR_100T2:
1200 1200 phy_write(ph, MII_MSCONTROL, gtcr);
1201 1201 break;
1202 1202 }
1203 1203
1204 1204 phy_write(ph, MII_CONTROL, bmcr);
1205 1205
1206 1206 return (DDI_SUCCESS);
1207 1207 }
1208 1208
1209 1209 int
1210 1210 phy_start(phy_handle_t *ph)
1211 1211 {
1212 1212 uint16_t bmcr, anar, gtcr;
1213 1213 ASSERT(mutex_owned(&ph->phy_mii->m_lock));
1214 1214
1215 1215 ASSERT(ph->phy_loopback == PHY_LB_NONE);
1216 1216
1217 1217 /*
1218 1218 * No loopback overrides, so try to advertise everything
1219 1219 * that is administratively enabled.
1220 1220 */
1221 1221 ph->phy_adv_aneg = ph->phy_en_aneg;
1222 1222 ph->phy_adv_1000_fdx = ph->phy_en_1000_fdx;
1223 1223 ph->phy_adv_1000_hdx = ph->phy_en_1000_hdx;
1224 1224 ph->phy_adv_100_fdx = ph->phy_en_100_fdx;
1225 1225 ph->phy_adv_100_t4 = ph->phy_en_100_t4;
1226 1226 ph->phy_adv_100_hdx = ph->phy_en_100_hdx;
1227 1227 ph->phy_adv_10_fdx = ph->phy_en_10_fdx;
1228 1228 ph->phy_adv_10_hdx = ph->phy_en_10_hdx;
1229 1229 ph->phy_adv_pause = ph->phy_en_pause;
1230 1230 ph->phy_adv_asmpause = ph->phy_en_asmpause;
1231 1231
1232 1232 /*
1233 1233 * Limit properties to what the hardware can actually support.
1234 1234 */
1235 1235 #define FILTER_ADV(CAP) \
1236 1236 if (!ph->phy_cap_##CAP) \
1237 1237 ph->phy_adv_##CAP = 0
1238 1238
1239 1239 FILTER_ADV(aneg);
1240 1240 FILTER_ADV(1000_fdx);
1241 1241 FILTER_ADV(1000_hdx);
1242 1242 FILTER_ADV(100_fdx);
1243 1243 FILTER_ADV(100_t4);
1244 1244 FILTER_ADV(100_hdx);
1245 1245 FILTER_ADV(10_fdx);
1246 1246 FILTER_ADV(10_hdx);
1247 1247 FILTER_ADV(pause);
1248 1248 FILTER_ADV(asmpause);
1249 1249
1250 1250 #undef FILTER_ADV
1251 1251
1252 1252 /*
1253 1253 * We need at least one valid mode.
1254 1254 */
1255 1255 if ((!ph->phy_adv_1000_fdx) &&
1256 1256 (!ph->phy_adv_1000_hdx) &&
1257 1257 (!ph->phy_adv_100_t4) &&
1258 1258 (!ph->phy_adv_100_fdx) &&
1259 1259 (!ph->phy_adv_100_hdx) &&
1260 1260 (!ph->phy_adv_10_fdx) &&
1261 1261 (!ph->phy_adv_10_hdx)) {
1262 1262
1263 1263 phy_warn(ph,
1264 1264 "No valid link mode selected. Powering down PHY.");
1265 1265
1266 1266 PHY_SET(ph, MII_CONTROL, MII_CONTROL_PWRDN);
1267 1267
1268 1268 ph->phy_link = LINK_STATE_DOWN;
1269 1269 return (DDI_SUCCESS);
1270 1270 }
1271 1271
1272 1272 bmcr = 0;
1273 1273 gtcr = 0;
1274 1274
1275 1275 if (ph->phy_adv_aneg) {
1276 1276 bmcr |= MII_CONTROL_ANE | MII_CONTROL_RSAN;
1277 1277 }
1278 1278
1279 1279 if ((ph->phy_adv_1000_fdx) || (ph->phy_adv_1000_hdx)) {
1280 1280 bmcr |= MII_CONTROL_1GB;
1281 1281
1282 1282 } else if (ph->phy_adv_100_fdx || ph->phy_adv_100_hdx ||
1283 1283 ph->phy_adv_100_t4) {
1284 1284 bmcr |= MII_CONTROL_100MB;
1285 1285 }
1286 1286
1287 1287 if (ph->phy_adv_1000_fdx || ph->phy_adv_100_fdx || ph->phy_adv_10_fdx) {
1288 1288 bmcr |= MII_CONTROL_FDUPLEX;
1289 1289 }
1290 1290
1291 1291 if (ph->phy_type == XCVR_1000X) {
1292 1292 /* 1000BASE-X (usually fiber) */
1293 1293 anar = 0;
1294 1294 if (ph->phy_adv_1000_fdx) {
1295 1295 anar |= MII_ABILITY_X_FD;
1296 1296 }
1297 1297 if (ph->phy_adv_1000_hdx) {
1298 1298 anar |= MII_ABILITY_X_HD;
1299 1299 }
1300 1300 if (ph->phy_adv_pause) {
1301 1301 anar |= MII_ABILITY_X_PAUSE;
1302 1302 }
1303 1303 if (ph->phy_adv_asmpause) {
1304 1304 anar |= MII_ABILITY_X_ASMPAUSE;
1305 1305 }
1306 1306
1307 1307 } else if (ph->phy_type == XCVR_100T2) {
1308 1308 /* 100BASE-T2 */
1309 1309 anar = 0;
1310 1310 if (ph->phy_adv_100_fdx) {
1311 1311 anar |= MII_ABILITY_T2_FD;
1312 1312 }
1313 1313 if (ph->phy_adv_100_hdx) {
1314 1314 anar |= MII_ABILITY_T2_HD;
1315 1315 }
1316 1316
1317 1317 } else {
1318 1318 anar = MII_AN_SELECTOR_8023;
1319 1319
1320 1320 /* 1000BASE-T or 100BASE-X probably */
1321 1321 if (ph->phy_adv_1000_fdx) {
1322 1322 gtcr |= MII_MSCONTROL_1000T_FD;
1323 1323 }
1324 1324 if (ph->phy_adv_1000_hdx) {
1325 1325 gtcr |= MII_MSCONTROL_1000T;
1326 1326 }
1327 1327 if (ph->phy_adv_100_fdx) {
1328 1328 anar |= MII_ABILITY_100BASE_TX_FD;
1329 1329 }
1330 1330 if (ph->phy_adv_100_hdx) {
1331 1331 anar |= MII_ABILITY_100BASE_TX;
1332 1332 }
1333 1333 if (ph->phy_adv_100_t4) {
1334 1334 anar |= MII_ABILITY_100BASE_T4;
1335 1335 }
1336 1336 if (ph->phy_adv_10_fdx) {
1337 1337 anar |= MII_ABILITY_10BASE_T_FD;
1338 1338 }
1339 1339 if (ph->phy_adv_10_hdx) {
1340 1340 anar |= MII_ABILITY_10BASE_T;
1341 1341 }
1342 1342 if (ph->phy_adv_pause) {
1343 1343 anar |= MII_ABILITY_PAUSE;
1344 1344 }
1345 1345 if (ph->phy_adv_asmpause) {
1346 1346 anar |= MII_ABILITY_ASMPAUSE;
1347 1347 }
1348 1348 }
1349 1349
1350 1350 ph->phy_link = LINK_STATE_DOWN;
1351 1351 ph->phy_duplex = LINK_DUPLEX_UNKNOWN;
1352 1352 ph->phy_speed = 0;
1353 1353
1354 1354 phy_write(ph, MII_AN_ADVERT, anar);
1355 1355 phy_write(ph, MII_CONTROL, bmcr & ~(MII_CONTROL_RSAN));
1356 1356
1357 1357 switch (ph->phy_type) {
1358 1358 case XCVR_1000T:
1359 1359 case XCVR_1000X:
1360 1360 case XCVR_100T2:
1361 1361 phy_write(ph, MII_MSCONTROL, gtcr);
1362 1362 }
1363 1363
1364 1364 /*
1365 1365 * Finally, this will start up autoneg if it is enabled, or
1366 1366 * force link settings otherwise.
1367 1367 */
1368 1368 phy_write(ph, MII_CONTROL, bmcr);
1369 1369
1370 1370 return (DDI_SUCCESS);
1371 1371 }
1372 1372
1373 1373
1374 1374 int
1375 1375 phy_check(phy_handle_t *ph)
1376 1376 {
1377 1377 uint16_t control, status, lpar, msstat, anexp;
1378 1378 int debounces = 100;
1379 1379
1380 1380 ASSERT(mutex_owned(&ph->phy_mii->m_lock));
1381 1381
1382 1382 debounce:
1383 1383 status = phy_read(ph, MII_STATUS);
1384 1384 control = phy_read(ph, MII_CONTROL);
1385 1385
1386 1386 if (status & MII_STATUS_EXTENDED) {
1387 1387 lpar = phy_read(ph, MII_AN_LPABLE);
1388 1388 anexp = phy_read(ph, MII_AN_EXPANSION);
1389 1389 } else {
1390 1390 lpar = 0;
1391 1391 anexp = 0;
1392 1392 }
1393 1393
1394 1394 /*
1395 1395 * We reread to clear any latched bits. This also debounces
1396 1396 * any state that might be in transition.
1397 1397 */
1398 1398 drv_usecwait(10);
1399 1399 if ((status != phy_read(ph, MII_STATUS)) && debounces) {
1400 1400 debounces--;
1401 1401 goto debounce;
1402 1402 }
1403 1403
1404 1404 /*
1405 1405 * Detect the situation where the PHY is removed or has died.
1406 1406 * According to spec, at least one bit of status must be set,
1407 1407 * and at least one bit must be clear.
1408 1408 */
1409 1409 if ((status == 0xffff) || (status == 0)) {
1410 1410 ph->phy_speed = 0;
1411 1411 ph->phy_duplex = LINK_DUPLEX_UNKNOWN;
1412 1412 ph->phy_link = LINK_STATE_UNKNOWN;
1413 1413 ph->phy_present = B_FALSE;
1414 1414 return (DDI_FAILURE);
1415 1415 }
1416 1416
1417 1417 /* We only respect the link flag if we are not in loopback. */
1418 1418 if ((ph->phy_loopback != PHY_LB_INT_PHY) &&
1419 1419 ((status & MII_STATUS_LINKUP) == 0)) {
1420 1420 ph->phy_speed = 0;
1421 1421 ph->phy_duplex = LINK_DUPLEX_UNKNOWN;
1422 1422 ph->phy_link = LINK_STATE_DOWN;
1423 1423 return (DDI_SUCCESS);
1424 1424 }
1425 1425
1426 1426 ph->phy_link = LINK_STATE_UP;
1427 1427
1428 1428 if ((control & MII_CONTROL_ANE) == 0) {
1429 1429
1430 1430 ph->phy_lp_aneg = B_FALSE;
1431 1431 ph->phy_lp_10_hdx = B_FALSE;
1432 1432 ph->phy_lp_10_fdx = B_FALSE;
1433 1433 ph->phy_lp_100_t4 = B_FALSE;
1434 1434 ph->phy_lp_100_hdx = B_FALSE;
1435 1435 ph->phy_lp_100_fdx = B_FALSE;
1436 1436 ph->phy_lp_1000_hdx = B_FALSE;
1437 1437 ph->phy_lp_1000_fdx = B_FALSE;
1438 1438
1439 1439 /*
1440 1440 * We have no idea what our link partner might or might
1441 1441 * not be able to support, except that it appears to
1442 1442 * support the same mode that we have forced.
1443 1443 */
1444 1444 if (control & MII_CONTROL_1GB) {
1445 1445 ph->phy_speed = 1000;
1446 1446 } else if (control & MII_CONTROL_100MB) {
1447 1447 ph->phy_speed = 100;
1448 1448 } else {
1449 1449 ph->phy_speed = 10;
1450 1450 }
1451 1451 ph->phy_duplex = control & MII_CONTROL_FDUPLEX ?
1452 1452 LINK_DUPLEX_FULL : LINK_DUPLEX_HALF;
1453 1453
1454 1454 return (DDI_SUCCESS);
1455 1455 }
1456 1456
1457 1457 if (ph->phy_type == XCVR_1000X) {
1458 1458
1459 1459 ph->phy_lp_10_hdx = B_FALSE;
1460 1460 ph->phy_lp_10_fdx = B_FALSE;
1461 1461 ph->phy_lp_100_t4 = B_FALSE;
1462 1462 ph->phy_lp_100_hdx = B_FALSE;
1463 1463 ph->phy_lp_100_fdx = B_FALSE;
1464 1464
1465 1465 /* 1000BASE-X requires autonegotiation */
1466 1466 ph->phy_lp_aneg = B_TRUE;
1467 1467 ph->phy_lp_1000_fdx = !!(lpar & MII_ABILITY_X_FD);
1468 1468 ph->phy_lp_1000_hdx = !!(lpar & MII_ABILITY_X_HD);
1469 1469 ph->phy_lp_pause = !!(lpar & MII_ABILITY_X_PAUSE);
1470 1470 ph->phy_lp_asmpause = !!(lpar & MII_ABILITY_X_ASMPAUSE);
1471 1471
1472 1472 } else if (ph->phy_type == XCVR_100T2) {
1473 1473 ph->phy_lp_10_hdx = B_FALSE;
1474 1474 ph->phy_lp_10_fdx = B_FALSE;
1475 1475 ph->phy_lp_100_t4 = B_FALSE;
1476 1476 ph->phy_lp_1000_hdx = B_FALSE;
1477 1477 ph->phy_lp_1000_fdx = B_FALSE;
1478 1478 ph->phy_lp_pause = B_FALSE;
1479 1479 ph->phy_lp_asmpause = B_FALSE;
1480 1480
1481 1481 /* 100BASE-T2 requires autonegotiation */
1482 1482 ph->phy_lp_aneg = B_TRUE;
1483 1483 ph->phy_lp_100_fdx = !!(lpar & MII_ABILITY_T2_FD);
1484 1484 ph->phy_lp_100_hdx = !!(lpar & MII_ABILITY_T2_HD);
1485 1485
1486 1486 } else if (anexp & MII_AN_EXP_PARFAULT) {
1487 1487 /*
1488 1488 * Parallel detection fault! This happens when the
1489 1489 * peer does not use autonegotiation, and the
1490 1490 * detection logic reports more than one type of legal
1491 1491 * link is available. Note that parallel detection
1492 1492 * can only happen with half duplex 10, 100, and
1493 1493 * 100TX4. We also should not have got here, because
1494 1494 * the link state bit should have failed.
1495 1495 */
1496 1496 #ifdef DEBUG
1497 1497 phy_warn(ph, "Parallel detection fault!");
1498 1498 #endif
1499 1499 ph->phy_lp_10_hdx = B_FALSE;
1500 1500 ph->phy_lp_10_fdx = B_FALSE;
1501 1501 ph->phy_lp_100_t4 = B_FALSE;
1502 1502 ph->phy_lp_100_hdx = B_FALSE;
1503 1503 ph->phy_lp_100_fdx = B_FALSE;
1504 1504 ph->phy_lp_1000_hdx = B_FALSE;
1505 1505 ph->phy_lp_1000_fdx = B_FALSE;
1506 1506 ph->phy_lp_pause = B_FALSE;
1507 1507 ph->phy_lp_asmpause = B_FALSE;
1508 1508 ph->phy_speed = 0;
1509 1509 ph->phy_duplex = LINK_DUPLEX_UNKNOWN;
1510 1510 return (DDI_SUCCESS);
1511 1511
1512 1512 } else {
1513 1513 ph->phy_lp_aneg = !!(anexp & MII_AN_EXP_LPCANAN);
1514 1514
1515 1515 /*
1516 1516 * Note: If the peer doesn't support autonegotiation, then
1517 1517 * according to clause 28.5.4.5, the link partner ability
1518 1518 * register will still have the right bits set. However,
1519 1519 * gigabit modes cannot use legacy parallel detection.
1520 1520 */
1521 1521
1522 1522 if ((ph->phy_type == XCVR_1000T) &
1523 1523 (anexp & MII_AN_EXP_LPCANAN)) {
1524 1524
1525 1525 /* check for gige */
1526 1526 msstat = phy_read(ph, MII_MSSTATUS);
1527 1527
1528 1528 ph->phy_lp_1000_hdx =
1529 1529 !!(msstat & MII_MSSTATUS_LP1000T);
1530 1530
1531 1531 ph->phy_lp_1000_fdx =
1532 1532 !!(msstat & MII_MSSTATUS_LP1000T_FD);
1533 1533 }
1534 1534
1535 1535 ph->phy_lp_100_fdx = !!(lpar & MII_ABILITY_100BASE_TX_FD);
1536 1536 ph->phy_lp_100_hdx = !!(lpar & MII_ABILITY_100BASE_TX);
1537 1537 ph->phy_lp_100_t4 = !!(lpar & MII_ABILITY_100BASE_T4);
1538 1538 ph->phy_lp_10_fdx = !!(lpar & MII_ABILITY_10BASE_T_FD);
1539 1539 ph->phy_lp_10_hdx = !!(lpar & MII_ABILITY_10BASE_T);
1540 1540 ph->phy_lp_pause = !!(lpar & MII_ABILITY_PAUSE);
1541 1541 ph->phy_lp_asmpause = !!(lpar & MII_ABILITY_ASMPAUSE);
1542 1542 }
1543 1543
1544 1544 /* resolve link pause */
1545 1545 if ((ph->phy_en_flowctrl == LINK_FLOWCTRL_BI) &&
1546 1546 (ph->phy_lp_pause)) {
1547 1547 ph->phy_flowctrl = LINK_FLOWCTRL_BI;
1548 1548 } else if ((ph->phy_en_flowctrl == LINK_FLOWCTRL_RX) &&
1549 1549 (ph->phy_lp_pause || ph->phy_lp_asmpause)) {
1550 1550 ph->phy_flowctrl = LINK_FLOWCTRL_RX;
1551 1551 } else if ((ph->phy_en_flowctrl == LINK_FLOWCTRL_TX) &&
1552 1552 (ph->phy_lp_pause)) {
1553 1553 ph->phy_flowctrl = LINK_FLOWCTRL_TX;
1554 1554 } else {
1555 1555 ph->phy_flowctrl = LINK_FLOWCTRL_NONE;
1556 1556 }
1557 1557
1558 1558 if (ph->phy_adv_1000_fdx && ph->phy_lp_1000_fdx) {
1559 1559 ph->phy_speed = 1000;
1560 1560 ph->phy_duplex = LINK_DUPLEX_FULL;
1561 1561
1562 1562 } else if (ph->phy_adv_1000_hdx && ph->phy_lp_1000_hdx) {
1563 1563 ph->phy_speed = 1000;
1564 1564 ph->phy_duplex = LINK_DUPLEX_HALF;
1565 1565
1566 1566 } else if (ph->phy_adv_100_fdx && ph->phy_lp_100_fdx) {
1567 1567 ph->phy_speed = 100;
1568 1568 ph->phy_duplex = LINK_DUPLEX_FULL;
1569 1569
1570 1570 } else if (ph->phy_adv_100_t4 && ph->phy_lp_100_t4) {
1571 1571 ph->phy_speed = 100;
1572 1572 ph->phy_duplex = LINK_DUPLEX_HALF;
1573 1573
1574 1574 } else if (ph->phy_adv_100_hdx && ph->phy_lp_100_hdx) {
1575 1575 ph->phy_speed = 100;
1576 1576 ph->phy_duplex = LINK_DUPLEX_HALF;
1577 1577
1578 1578 } else if (ph->phy_adv_10_fdx && ph->phy_lp_10_fdx) {
1579 1579 ph->phy_speed = 10;
1580 1580 ph->phy_duplex = LINK_DUPLEX_FULL;
1581 1581
1582 1582 } else if (ph->phy_adv_10_hdx && ph->phy_lp_10_hdx) {
1583 1583 ph->phy_speed = 10;
1584 1584 ph->phy_duplex = LINK_DUPLEX_HALF;
1585 1585
1586 1586 } else {
1587 1587 #ifdef DEBUG
1588 1588 phy_warn(ph, "No common abilities.");
1589 1589 #endif
1590 1590 ph->phy_speed = 0;
1591 1591 ph->phy_duplex = LINK_DUPLEX_UNKNOWN;
1592 1592 }
1593 1593
1594 1594 return (DDI_SUCCESS);
1595 1595 }
1596 1596
1597 1597 int
1598 1598 phy_get_prop(phy_handle_t *ph, char *prop, int dflt)
1599 1599 {
1600 1600 mii_handle_t mh = ph->phy_mii;
1601 1601
1602 1602 return (ddi_prop_get_int(DDI_DEV_T_ANY, mh->m_dip, 0, prop, dflt));
1603 1603 }
1604 1604
1605 1605 const char *
1606 1606 phy_get_name(phy_handle_t *ph)
1607 1607 {
1608 1608 mii_handle_t mh = ph->phy_mii;
1609 1609
1610 1610 return (mh->m_name);
1611 1611 }
1612 1612
1613 1613 const char *
1614 1614 phy_get_driver(phy_handle_t *ph)
1615 1615 {
1616 1616 mii_handle_t mh = ph->phy_mii;
1617 1617
1618 1618 return (ddi_driver_name(mh->m_dip));
1619 1619 }
1620 1620
1621 1621 void
1622 1622 phy_warn(phy_handle_t *ph, const char *fmt, ...)
1623 1623 {
1624 1624 va_list va;
1625 1625 char buf[256];
1626 1626
1627 1627 (void) snprintf(buf, sizeof (buf), "%s: %s", phy_get_name(ph), fmt);
1628 1628
1629 1629 va_start(va, fmt);
1630 1630 vcmn_err(CE_WARN, buf, va);
1631 1631 va_end(va);
1632 1632 }
1633 1633
1634 1634 /*
1635 1635 * Internal support routines.
1636 1636 */
1637 1637
1638 1638 void
1639 1639 _mii_notify(mii_handle_t mh)
1640 1640 {
1641 1641 if (mh->m_ops.mii_notify != NULL) {
1642 1642 mh->m_ops.mii_notify(mh->m_private, mh->m_link);
1643 1643 }
1644 1644 }
1645 1645
1646 1646 void
1647 1647 _mii_probe_phy(phy_handle_t *ph)
1648 1648 {
1649 1649 uint16_t bmsr;
1650 1650 uint16_t extsr;
1651 1651 mii_handle_t mh = ph->phy_mii;
1652 1652
1653 1653
1654 1654 /*
1655 1655 * Apparently, PHY 0 is less likely to be physically
1656 1656 * connected, and should always be the last one tried. Most
1657 1657 * single solution NICs use PHY1 for their built-in
1658 1658 * transceiver. NICs with an external MII will often place
1659 1659 * the external PHY at address 1, and use address 0 for the
1660 1660 * internal PHY.
1661 1661 */
1662 1662
1663 1663 ph->phy_id = 0;
1664 1664 ph->phy_model = "PHY";
1665 1665 ph->phy_vendor = "Unknown Vendor";
1666 1666
1667 1667 /* done twice to clear any latched bits */
1668 1668 bmsr = phy_read(ph, MII_STATUS);
1669 1669 bmsr = phy_read(ph, MII_STATUS);
1670 1670 if ((bmsr == 0) || (bmsr == 0xffff)) {
1671 1671 ph->phy_present = B_FALSE;
1672 1672 return;
1673 1673 }
1674 1674
1675 1675 if (bmsr & MII_STATUS_EXTSTAT) {
1676 1676 extsr = phy_read(ph, MII_EXTSTATUS);
1677 1677 } else {
1678 1678 extsr = 0;
1679 1679 }
1680 1680
1681 1681 ph->phy_present = B_TRUE;
1682 1682 ph->phy_id = ((uint32_t)phy_read(ph, MII_PHYIDH) << 16) |
1683 1683 phy_read(ph, MII_PHYIDL);
1684 1684
1685 1685 /* setup default handlers */
1686 1686 ph->phy_reset = phy_reset;
1687 1687 ph->phy_start = phy_start;
1688 1688 ph->phy_stop = phy_stop;
1689 1689 ph->phy_check = phy_check;
1690 1690 ph->phy_loop = phy_loop;
1691 1691
1692 1692 /*
1693 1693 * We ignore the non-existent 100baseT2 stuff -- no
1694 1694 * known products for it exist.
1695 1695 */
1696 1696 ph->phy_cap_aneg = !!(bmsr & MII_STATUS_CANAUTONEG);
1697 1697 ph->phy_cap_100_t4 = !!(bmsr & MII_STATUS_100_BASE_T4);
1698 1698 ph->phy_cap_100_fdx = !!(bmsr & MII_STATUS_100_BASEX_FD);
1699 1699 ph->phy_cap_100_hdx = !!(bmsr & MII_STATUS_100_BASEX);
1700 1700 ph->phy_cap_10_fdx = !!(bmsr & MII_STATUS_10_FD);
1701 1701 ph->phy_cap_10_hdx = !!(bmsr & MII_STATUS_10);
1702 1702 ph->phy_cap_1000_fdx =
1703 1703 !!(extsr & (MII_EXTSTATUS_1000X_FD|MII_EXTSTATUS_1000T_FD));
1704 1704 ph->phy_cap_1000_hdx =
1705 1705 !!(extsr & (MII_EXTSTATUS_1000X | MII_EXTSTATUS_1000T));
1706 1706 ph->phy_cap_pause = mh->m_cap_pause;
1707 1707 ph->phy_cap_asmpause = mh->m_cap_asmpause;
1708 1708
1709 1709 if (bmsr & MII_STATUS_10) {
1710 1710 ph->phy_cap_10_hdx = B_TRUE;
1711 1711 ph->phy_type = XCVR_10;
1712 1712 }
1713 1713 if (bmsr & MII_STATUS_10_FD) {
1714 1714 ph->phy_cap_10_fdx = B_TRUE;
1715 1715 ph->phy_type = XCVR_10;
1716 1716 }
1717 1717 if (bmsr & MII_STATUS_100T2) {
1718 1718 ph->phy_cap_100_hdx = B_TRUE;
1719 1719 ph->phy_type = XCVR_100T2;
1720 1720 }
1721 1721 if (bmsr & MII_STATUS_100T2_FD) {
1722 1722 ph->phy_cap_100_fdx = B_TRUE;
1723 1723 ph->phy_type = XCVR_100T2;
1724 1724 }
1725 1725 if (bmsr & MII_STATUS_100_BASE_T4) {
1726 1726 ph->phy_cap_100_hdx = B_TRUE;
1727 1727 ph->phy_type = XCVR_100T4;
1728 1728 }
1729 1729 if (bmsr & MII_STATUS_100_BASEX) {
1730 1730 ph->phy_cap_100_hdx = B_TRUE;
1731 1731 ph->phy_type = XCVR_100X;
1732 1732 }
1733 1733 if (bmsr & MII_STATUS_100_BASEX_FD) {
1734 1734 ph->phy_cap_100_fdx = B_TRUE;
1735 1735 ph->phy_type = XCVR_100X;
1736 1736 }
1737 1737 if (extsr & MII_EXTSTATUS_1000X) {
1738 1738 ph->phy_cap_1000_hdx = B_TRUE;
1739 1739 ph->phy_type = XCVR_1000X;
1740 1740 }
1741 1741 if (extsr & MII_EXTSTATUS_1000X_FD) {
1742 1742 ph->phy_cap_1000_fdx = B_TRUE;
1743 1743 ph->phy_type = XCVR_1000X;
1744 1744 }
1745 1745 if (extsr & MII_EXTSTATUS_1000T) {
1746 1746 ph->phy_cap_1000_hdx = B_TRUE;
1747 1747 ph->phy_type = XCVR_1000T;
1748 1748 }
1749 1749 if (extsr & MII_EXTSTATUS_1000T_FD) {
1750 1750 ph->phy_cap_1000_fdx = B_TRUE;
1751 1751 ph->phy_type = XCVR_1000T;
1752 1752 }
1753 1753
1754 1754 for (int j = 0; _phy_probes[j] != NULL; j++) {
1755 1755 if ((*_phy_probes[j])(ph)) {
1756 1756 break;
1757 1757 }
1758 1758 }
1759 1759
1760 1760 #define INIT_ENABLE(CAP) \
1761 1761 ph->phy_en_##CAP = (mh->m_en_##CAP > 0) ? \
1762 1762 mh->m_en_##CAP : ph->phy_cap_##CAP
1763 1763
1764 1764 INIT_ENABLE(aneg);
1765 1765 INIT_ENABLE(1000_fdx);
1766 1766 INIT_ENABLE(1000_hdx);
1767 1767 INIT_ENABLE(100_fdx);
1768 1768 INIT_ENABLE(100_t4);
1769 1769 INIT_ENABLE(100_hdx);
1770 1770 INIT_ENABLE(10_fdx);
1771 1771 INIT_ENABLE(10_hdx);
1772 1772
1773 1773 #undef INIT_ENABLE
1774 1774 ph->phy_en_flowctrl = mh->m_en_flowctrl;
1775 1775 switch (ph->phy_en_flowctrl) {
1776 1776 case LINK_FLOWCTRL_BI:
1777 1777 case LINK_FLOWCTRL_RX:
1778 1778 ph->phy_en_pause = B_TRUE;
1779 1779 ph->phy_en_asmpause = B_TRUE;
1780 1780 break;
1781 1781 case LINK_FLOWCTRL_TX:
1782 1782 ph->phy_en_pause = B_FALSE;
1783 1783 ph->phy_en_asmpause = B_TRUE;
1784 1784 break;
1785 1785 default:
1786 1786 ph->phy_en_pause = B_FALSE;
1787 1787 ph->phy_en_asmpause = B_FALSE;
1788 1788 break;
1789 1789 }
1790 1790 }
1791 1791
1792 1792 void
1793 1793 _mii_probe(mii_handle_t mh)
1794 1794 {
1795 1795 uint8_t new_addr;
1796 1796 uint8_t old_addr;
1797 1797 uint8_t user_addr;
1798 1798 uint8_t curr_addr;
1799 1799 phy_handle_t *ph;
1800 1800 int pri = 0;
1801 1801 int first;
1802 1802
1803 1803 user_addr = ddi_prop_get_int(DDI_DEV_T_ANY, mh->m_dip, 0,
1804 1804 "phy-addr", -1);
1805 1805 old_addr = mh->m_addr;
1806 1806 new_addr = 0xff;
1807 1807
1808 1808 /*
1809 1809 * Apparently, PHY 0 is less likely to be physically
1810 1810 * connected, and should always be the last one tried. Most
1811 1811 * single solution NICs use PHY1 for their built-in
1812 1812 * transceiver. NICs with an external MII will often place
1813 1813 * the external PHY at address 1, and use address 0 for the
1814 1814 * internal PHY.
1815 1815 *
1816 1816 * Some devices have a different preference however. They can
1817 1817 * override the default starting point of the search by
1818 1818 * exporting a "first-phy" property.
1819 1819 */
1820 1820
1821 1821 first = ddi_prop_get_int(DDI_DEV_T_ANY, mh->m_dip, 0, "first-phy", 1);
1822 1822 if ((first < 0) || (first > 31)) {
1823 1823 first = 1;
1824 1824 }
1825 1825 for (int i = first; i < (first + 32); i++) {
1826 1826
1827 1827 /*
1828 1828 * This is tricky: it lets us start searching at an
1829 1829 * arbitrary address instead of 0, dealing with the
1830 1830 * wrap-around at address 31 properly.
1831 1831 */
1832 1832 curr_addr = i % 32;
1833 1833
1834 1834 ph = &mh->m_phys[curr_addr];
1835 1835
1836 1836 bzero(ph, sizeof (*ph));
1837 1837 ph->phy_addr = curr_addr;
1838 1838 ph->phy_mii = mh;
1839 1839
1840 1840 _mii_probe_phy(ph);
1841 1841
1842 1842 if (!ph->phy_present)
1843 1843 continue;
1844 1844
1845 1845 if (curr_addr == user_addr) {
1846 1846 /*
1847 1847 * We always try to honor the user configured phy.
1848 1848 */
1849 1849 new_addr = curr_addr;
1850 1850 pri = 4;
1851 1851
1852 1852 }
1853 1853
1854 1854 /* two reads to clear latched bits */
1855 1855 if ((phy_read(ph, MII_STATUS) & MII_STATUS_LINKUP) &&
1856 1856 (phy_read(ph, MII_STATUS) & MII_STATUS_LINKUP) &&
1857 1857 (pri < 3)) {
1858 1858 /*
1859 1859 * Link present is good. We prefer this over
1860 1860 * a possibly disconnected link.
1861 1861 */
1862 1862 new_addr = curr_addr;
1863 1863 pri = 3;
1864 1864 }
1865 1865 if ((curr_addr == old_addr) && (pri < 2)) {
1866 1866 /*
1867 1867 * All else being equal, minimize change.
1868 1868 */
1869 1869 new_addr = curr_addr;
1870 1870 pri = 2;
1871 1871
1872 1872 }
1873 1873 if (pri < 1) {
1874 1874 /*
1875 1875 * But make sure we at least select a present PHY.
1876 1876 */
1877 1877 new_addr = curr_addr;
1878 1878 pri = 1;
1879 1879 }
1880 1880 }
1881 1881
1882 1882 if (new_addr == 0xff) {
1883 1883 mh->m_addr = -1;
1884 1884 mh->m_phy = &mh->m_bogus_phy;
1885 1885 _mii_error(mh, MII_ENOPHY);
1886 1886 } else {
1887 1887 mh->m_addr = new_addr;
1888 1888 mh->m_phy = &mh->m_phys[new_addr];
1889 1889 mh->m_tstate = MII_STATE_RESET;
1890 1890 if (new_addr != old_addr) {
1891 1891 cmn_err(CE_CONT,
1892 1892 "?%s: Using %s Ethernet PHY at %d: %s %s\n",
1893 1893 mh->m_name, mii_xcvr_types[mh->m_phy->phy_type],
1894 1894 mh->m_addr, mh->m_phy->phy_vendor,
1895 1895 mh->m_phy->phy_model);
1896 1896 mh->m_link = LINK_STATE_UNKNOWN;
1897 1897 }
1898 1898 }
1899 1899 }
1900 1900
1901 1901 int
1902 1902 _mii_reset(mii_handle_t mh)
1903 1903 {
1904 1904 phy_handle_t *ph;
1905 1905 boolean_t notify;
1906 1906
1907 1907 ASSERT(mutex_owned(&mh->m_lock));
1908 1908
1909 1909 /*
1910 1910 * Reset logic. We want to isolate all the other
1911 1911 * phys that are not in use.
1912 1912 */
1913 1913 for (int i = 0; i < 32; i++) {
1914 1914 ph = &mh->m_phys[i];
1915 1915
1916 1916 if (!ph->phy_present)
1917 1917 continue;
1918 1918
1919 1919 /* Don't touch our own phy, yet. */
1920 1920 if (ph == mh->m_phy)
1921 1921 continue;
1922 1922
1923 1923 ph->phy_stop(ph);
1924 1924 }
1925 1925
1926 1926 ph = mh->m_phy;
1927 1927
1928 1928 ASSERT(ph->phy_present);
1929 1929
1930 1930 /* If we're resetting the PHY, then we want to notify loss of link */
1931 1931 notify = (mh->m_link != LINK_STATE_DOWN);
1932 1932 mh->m_link = LINK_STATE_DOWN;
1933 1933 ph->phy_link = LINK_STATE_DOWN;
1934 1934 ph->phy_speed = 0;
1935 1935 ph->phy_duplex = LINK_DUPLEX_UNKNOWN;
1936 1936
1937 1937 if (ph->phy_reset(ph) != DDI_SUCCESS) {
1938 1938 _mii_error(mh, MII_ERESET);
1939 1939 return (DDI_FAILURE);
1940 1940 }
1941 1941
1942 1942 /* Perform optional mac layer reset. */
1943 1943 if (mh->m_ops.mii_reset != NULL) {
1944 1944 mh->m_ops.mii_reset(mh->m_private);
1945 1945 }
1946 1946
1947 1947 /* Perform optional mac layer notification. */
1948 1948 if (notify) {
1949 1949 _mii_notify(mh);
1950 1950 }
1951 1951 return (DDI_SUCCESS);
1952 1952 }
1953 1953
1954 1954 int
1955 1955 _mii_loopback(mii_handle_t mh)
1956 1956 {
1957 1957 phy_handle_t *ph;
1958 1958
1959 1959 ASSERT(mutex_owned(&mh->m_lock));
1960 1960
1961 1961 ph = mh->m_phy;
1962 1962
1963 1963 if (_mii_reset(mh) != DDI_SUCCESS) {
1964 1964 return (DDI_FAILURE);
1965 1965 }
1966 1966 if (ph->phy_loopback == PHY_LB_NONE) {
1967 1967 mh->m_tstate = MII_STATE_START;
1968 1968 return (DDI_SUCCESS);
1969 1969 }
1970 1970 if (ph->phy_loop(ph) != DDI_SUCCESS) {
1971 1971 _mii_error(mh, MII_ELOOP);
1972 1972 return (DDI_FAILURE);
1973 1973 }
1974 1974
1975 1975 /* Just force loopback to link up. */
1976 1976 mh->m_link = ph->phy_link = LINK_STATE_UP;
1977 1977 _mii_notify(mh);
1978 1978
1979 1979 return (DDI_SUCCESS);
1980 1980 }
1981 1981
1982 1982 int
1983 1983 _mii_start(mii_handle_t mh)
1984 1984 {
1985 1985 phy_handle_t *ph;
1986 1986
1987 1987 ph = mh->m_phy;
1988 1988
1989 1989 ASSERT(mutex_owned(&mh->m_lock));
1990 1990 ASSERT(ph->phy_present);
1991 1991 ASSERT(ph->phy_loopback == PHY_LB_NONE);
1992 1992
1993 1993 if (ph->phy_start(ph) != DDI_SUCCESS) {
1994 1994 _mii_error(mh, MII_ESTART);
1995 1995 return (DDI_FAILURE);
1996 1996 }
1997 1997 /* clear the error state since we got a good startup! */
1998 1998 mh->m_error = MII_EOK;
1999 1999 return (DDI_SUCCESS);
2000 2000 }
2001 2001
2002 2002 int
2003 2003 _mii_check(mii_handle_t mh)
2004 2004 {
2005 2005 link_state_t olink;
2006 2006 int ospeed;
2007 2007 link_duplex_t oduplex;
2008 2008 link_flowctrl_t ofctrl;
2009 2009 phy_handle_t *ph;
2010 2010
2011 2011 ph = mh->m_phy;
2012 2012
2013 2013 olink = mh->m_link;
2014 2014 ospeed = ph->phy_speed;
2015 2015 oduplex = ph->phy_duplex;
2016 2016 ofctrl = ph->phy_flowctrl;
2017 2017
2018 2018 ASSERT(ph->phy_present);
2019 2019
2020 2020 if (ph->phy_check(ph) == DDI_FAILURE) {
2021 2021 _mii_error(mh, MII_ECHECK);
2022 2022 mh->m_link = LINK_STATE_UNKNOWN;
2023 2023 _mii_notify(mh);
2024 2024 return (DDI_FAILURE);
2025 2025 }
2026 2026
2027 2027 mh->m_link = ph->phy_link;
2028 2028
2029 2029 /* if anything changed, notify! */
2030 2030 if ((mh->m_link != olink) ||
2031 2031 (ph->phy_speed != ospeed) ||
2032 2032 (ph->phy_duplex != oduplex) ||
2033 2033 (ph->phy_flowctrl != ofctrl)) {
2034 2034 _mii_notify(mh);
2035 2035 }
2036 2036
2037 2037 return (DDI_SUCCESS);
2038 2038 }
2039 2039
2040 2040 void
2041 2041 _mii_task(void *_mh)
2042 2042 {
2043 2043 mii_handle_t mh = _mh;
2044 2044 phy_handle_t *ph;
2045 2045 clock_t wait;
2046 2046 clock_t downtime;
2047 2047
2048 2048 mutex_enter(&mh->m_lock);
2049 2049
2050 2050 for (;;) {
2051 2051
2052 2052 /* If detaching, exit the thread. */
2053 2053 if (!mh->m_started) {
2054 2054 break;
2055 2055 }
2056 2056
2057 2057 ph = mh->m_phy;
2058 2058
2059 2059 /*
2060 2060 * If we're suspended or otherwise not supposed to be
2061 2061 * monitoring the link, just go back to sleep.
2062 2062 *
2063 2063 * Theoretically we could power down the PHY, but we
2064 2064 * don't bother. (The link might be used for
2065 2065 * wake-on-lan!) Another option would be to reduce
2066 2066 * power on the PHY if both it and the link partner
2067 2067 * support 10 Mbps mode.
2068 2068 */
2069 2069 if (mh->m_suspending) {
2070 2070 mh->m_suspended = B_TRUE;
2071 2071 cv_broadcast(&mh->m_cv);
2072 2072 }
2073 2073 if (mh->m_suspended) {
2074 2074 mh->m_suspending = B_FALSE;
2075 2075 cv_wait(&mh->m_cv, &mh->m_lock);
2076 2076 continue;
2077 2077 }
2078 2078
2079 2079 switch (mh->m_tstate) {
2080 2080 case MII_STATE_PROBE:
2081 2081 _mii_probe(mh);
2082 2082 ph = mh->m_phy;
2083 2083 if (!ph->phy_present) {
2084 2084 /*
2085 2085 * If no PHY is found, wait a bit before
2086 2086 * trying the probe again. 10 seconds ought
2087 2087 * to be enough.
2088 2088 */
2089 2089 wait = 10 * MII_SECOND;
2090 2090 } else {
2091 2091 wait = 0;
2092 2092 }
2093 2093 break;
2094 2094
2095 2095 case MII_STATE_RESET:
2096 2096 if (_mii_reset(mh) == DDI_SUCCESS) {
2097 2097 mh->m_tstate = MII_STATE_START;
2098 2098 wait = 0;
2099 2099 } else {
2100 2100 /*
2101 2101 * If an error occurred, wait a bit and
2102 2102 * try again later.
2103 2103 */
2104 2104 wait = 10 * MII_SECOND;
2105 2105 }
2106 2106 break;
2107 2107
2108 2108 case MII_STATE_START:
2109 2109 /*
2110 2110 * If an error occurs, we're going to go back to
2111 2111 * probe or reset state. Otherwise we go to run
2112 2112 * state. In all cases we want to wait 1 second
2113 2113 * before doing anything else - either for link to
2114 2114 * settle, or to give other code a chance to run
2115 2115 * while we reset.
2116 2116 */
2117 2117 if (_mii_start(mh) == DDI_SUCCESS) {
2118 2118 /* reset watchdog to latest */
2119 2119 downtime = ddi_get_lbolt();
2120 2120 mh->m_tstate = MII_STATE_RUN;
2121 2121 } else {
2122 2122 mh->m_tstate = MII_STATE_PROBE;
2123 2123 }
2124 2124 wait = 0;
2125 2125 break;
2126 2126
2127 2127 case MII_STATE_LOOPBACK:
2128 2128 /*
2129 2129 * In loopback mode we don't check anything,
2130 2130 * and just wait for some condition to change.
2131 2131 */
2132 2132 wait = (clock_t)-1;
2133 2133 break;
2134 2134
2135 2135 case MII_STATE_RUN:
2136 2136 default:
2137 2137 if (_mii_check(mh) == DDI_FAILURE) {
2138 2138 /*
2139 2139 * On error (PHY removed?), wait a
2140 2140 * short bit before reprobing or
2141 2141 * resetting.
2142 2142 */
2143 2143 wait = MII_SECOND;
2144 2144 mh->m_tstate = MII_STATE_PROBE;
2145 2145
2146 2146 } else if (mh->m_link == LINK_STATE_UP) {
2147 2147 /* got goood link, so reset the watchdog */
2148 2148 downtime = ddi_get_lbolt();
2149 2149 /* rescan again in a second */
2150 2150 wait = MII_SECOND;
2151 2151
2152 2152 } else if ((ddi_get_lbolt() - downtime) >
2153 2153 (drv_usectohz(MII_SECOND * 10))) {
2154 2154
2155 2155 /*
2156 2156 * If we were down for 10 seconds,
2157 2157 * hard reset the PHY.
2158 2158 */
2159 2159 mh->m_tstate = MII_STATE_RESET;
2160 2160 wait = 0;
2161 2161
2162 2162 } else {
2163 2163 /*
2164 2164 * Otherwise, if we are still down,
2165 2165 * rescan the link much more
2166 2166 * frequently. We might be trying to
2167 2167 * autonegotiate.
2168 2168 */
2169 2169 wait = MII_SECOND / 4;
2170 2170 }
2171 2171 break;
2172 2172 }
2173 2173
2174 2174 switch (wait) {
2175 2175 case 0:
2176 2176 break;
2177 2177
2178 2178 case (clock_t)-1:
2179 2179 cv_wait(&mh->m_cv, &mh->m_lock);
2180 2180 break;
2181 2181
2182 2182 default:
2183 2183 (void) cv_reltimedwait(&mh->m_cv, &mh->m_lock,
2184 2184 drv_usectohz(wait), TR_CLOCK_TICK);
2185 2185 }
2186 2186 }
2187 2187
2188 2188 mutex_exit(&mh->m_lock);
2189 2189 }
↓ open down ↓ |
2012 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX