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