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