xref: /illumos-gate/usr/src/uts/common/io/mii/mii.c (revision 9b9d39d2a32ff806d2431dbcc50968ef1e6d46b2)
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
175 _init(void)
176 {
177 	return (mod_install(&modlinkage));
178 }
179 
180 int
181 _fini(void)
182 {
183 	return (mod_remove(&modlinkage));
184 }
185 
186 int
187 _info(struct modinfo *modinfop)
188 {
189 	return (mod_info(&modlinkage, modinfop));
190 }
191 
192 void
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
568 mii_get_addr(mii_handle_t mh)
569 {
570 	return (mh->m_addr);
571 }
572 
573 /* GLDv3 helpers */
574 
575 boolean_t
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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 *
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
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
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
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
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
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
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
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
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
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