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