xref: /illumos-gate/usr/src/uts/intel/io/dnet/dnet_mii.c (revision 7c478bd9)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * mii - MII/PHY support for MAC drivers
31  *
32  * Utility module to provide a consistent interface to a MAC driver accross
33  * different implementations of PHY devices
34  */
35 
36 #ifndef REALMODE
37 #include <sys/types.h>
38 #include <sys/debug.h>
39 #include <sys/errno.h>
40 #include <sys/param.h>
41 #include <sys/sysmacros.h>
42 #include <sys/stropts.h>
43 #include <sys/stream.h>
44 #include <sys/kmem.h>
45 #include <sys/conf.h>
46 #include <sys/ddi.h>
47 #include <sys/sunddi.h>
48 #include <sys/devops.h>
49 #include <sys/modctl.h>
50 #include <sys/cmn_err.h>
51 #include <sys/mii.h>
52 #include <sys/miipriv.h>
53 #include <sys/miiregs.h>
54 #else
55 #include "../mii/mii.h"
56 #include "../mii/miipriv.h"
57 #include "../mii/miiregs.h"
58 #ifndef	ddi_getprop
59 #define	ddi_getprop(a, b, c, d, def) def
60 #define	ddi_getlongprop(a, b, c, d, e, f) DDI_PROP_FAILURE
61 #define	DDI_PROP_SUCCESS 0
62 #define	DDI_PROP_FAILURE -1
63 #define	kmem_free(p, s) ((void)0)
64 #endif
65 #endif
66 #ifdef DEBUG
67 #define	MIIDEBUG
68 int miidebug = 0;
69 #define	MIITRACE 1
70 #define	MIIDUMP 2
71 #define	MIIPROBE 4
72 #define	MIICOMPAT 8
73 #endif
74 
75 
76 /* Static storage for realmode drivers, instead of allocated memory  */
77 #ifdef REALMODE
78 #define	ddi_get_name(a) "Bootconf"
79 static mii_info_t realmode_mac = {0};
80 #ifndef NULL
81 #define	NULL ((void *)0)
82 #endif
83 #define	MAXPHY 1
84 static struct phydata realmode_phys[MAXPHY];
85 static int current_phy = 0;
86 #endif
87 
88 /* Local functions */
89 static struct phydata *mii_get_valid_phydata(mii_handle_t mac, int phy);
90 static void mii_portmon(mii_handle_t mac);
91 
92 /* Vendor specific callback function prototypes */
93 static void dump_NS83840(mii_handle_t, int);
94 static void dump_ICS1890(struct mii_info *, int);
95 static int getspeed_NS83840(mii_handle_t, int, int *, int *);
96 static int getspeed_82553(mii_handle_t, int, int *, int *);
97 static int getspeed_ICS1890(mii_handle_t, int, int *, int *);
98 static void postreset_ICS1890(mii_handle_t mac, int phy);
99 static void postreset_NS83840(mii_handle_t mac, int phy);
100 
101 #ifdef MII_IS_MODULE
102 /*
103  * Loadable module structures/entrypoints
104  */
105 
106 extern struct mod_ops mod_misc_ops;
107 
108 static struct modlmisc modlmisc = {
109 	&mod_miscops,
110 	"802.3u MII support %I%",
111 };
112 
113 static struct modlinkage modlinkage = {
114 	MODREV_1, &modlmisc, NULL
115 };
116 
117 int
118 _init(void)
119 {
120 	return (mod_install(&modlinkage));
121 }
122 
123 int
124 _fini(void)
125 {
126 	return (mod_remove(&modlinkage));
127 }
128 
129 int
130 _info(struct modinfo *modinfop)
131 {
132 	return (mod_info(&modlinkage, modinfop));
133 }
134 #endif
135 
136 /*
137  * MII Interface functions
138  */
139 
140 /*
141  * Register an instance of an MII interface user
142  */
143 
144 int
145 mii_create(dev_info_t *dip,		/* Passed to read/write functions */
146 	    mii_writefunc_t writefunc, 	/* How to write to a MII register */
147 	    mii_readfunc_t readfunc,	/* How to read from a MII regster */
148 	    mii_handle_t *macp)
149 {
150 	mii_handle_t mac;
151 
152 #ifdef REALMODE
153 	mac = &realmode_mac;
154 #else
155 	/*  Allocate space for the mii structure */
156 	if ((mac = (mii_handle_t)
157 	    kmem_zalloc(sizeof (struct mii_info), KM_NOSLEEP)) == NULL)
158 		return (MII_NOMEM);
159 #endif
160 
161 	mac->mii_write = writefunc;
162 	mac->mii_read = readfunc;
163 	mac->mii_dip = dip;
164 	*macp = mac;
165 	return (MII_SUCCESS);
166 }
167 
168 /*
169  * Returns true if PHY at address phy is accessible. This should be
170  * considered the only function that takes a PHY address that can be called
171  * before mii_init_phy. There should be at least one bit set in the status
172  * register, and at least one clear
173  */
174 int
175 mii_probe_phy(mii_handle_t mac, int phy)
176 {
177 	ushort_t status;
178 	dev_info_t *dip;
179 
180 	if (!mac || phy < 0 || phy > 31)
181 		return (MII_PARAM);
182 
183 	dip = mac->mii_dip;
184 
185 	/* Clear any latched bits by reading twice */
186 	mac->mii_read(dip, phy, MII_STATUS);
187 	status = mac->mii_read(dip, phy, MII_STATUS);
188 
189 #ifdef MIIDEBUG
190 	mac->mii_read(dip, phy, MII_CONTROL);
191 	if (miidebug & MIIPROBE)
192 		cmn_err(CE_NOTE, "PHY Probe: Control=%x, Status=%x",
193 			mac->mii_read(dip, phy, MII_CONTROL), status);
194 #endif
195 	/*
196 	 * At least one bit in status should be clear (one of the error
197 	 * bits), and there must be at least one bit set for the device
198 	 * capabilities. Unconnected devices tend to show 0xffff, but 0x0000
199 	 * has been seen.
200 	 */
201 
202 	if (status == 0xffff || status == 0x0000)
203 		return (MII_PHYNOTPRESENT);
204 	return (MII_SUCCESS);
205 }
206 
207 /*
208  * Initialise PHY, and store info about it in the handle for future
209  * reference when the MAC calls us. PHY Vendor-specific code here isolates
210  * the LAN driver from worrying about different PHY implementations
211  */
212 
213 int
214 mii_init_phy(mii_handle_t mac, int phy)
215 {
216 	ushort_t status;
217 	void *dip;
218 	struct phydata *phydata;
219 
220 	if ((mac == (mii_handle_t)NULL) || phy < 0 || phy > 31)
221 		return (MII_PARAM);
222 
223 	dip = mac->mii_dip;
224 
225 	/* Create a phydata structure for this new phy */
226 	if (mac->phys[phy])
227 		return (MII_PHYPRESENT);
228 #ifdef REALMODE
229 	if (current_phy == MAXPHY)
230 		return (MII_NOMEM);
231 	mac->phys[phy] = phydata = realmode_phys + current_phy++;
232 #else
233 	mac->phys[phy] = phydata = (struct phydata *)
234 			    kmem_zalloc(sizeof (struct phydata), KM_NOSLEEP);
235 
236 	if (!phydata)
237 		return (MII_NOMEM);
238 #endif
239 	phydata->id = (ulong_t)mac->mii_read(dip, phy, MII_PHYIDH) << 16;
240 	phydata->id |= (ulong_t)mac->mii_read(dip, phy, MII_PHYIDL);
241 	phydata->state = phy_state_unknown;
242 
243 	/* Override speed and duplex mode from conf-file if present */
244 	phydata->fix_duplex =
245 	    ddi_getprop(DDI_DEV_T_NONE,
246 	    mac->mii_dip, DDI_PROP_DONTPASS, "full-duplex", 0);
247 
248 	phydata->fix_speed =
249 	    ddi_getprop(DDI_DEV_T_NONE,
250 	    mac->mii_dip, DDI_PROP_DONTPASS, "speed", 0);
251 
252 	status = mac->mii_read(dip, phy, MII_STATUS);
253 
254 	/*
255 	 * when explicitly setting speed or duplex, we must
256 	 * disable autonegotiation
257 	 */
258 	if (!(status & MII_STATUS_CANAUTONEG) ||
259 	    phydata->fix_speed || phydata->fix_duplex) {
260 		/*
261 		 * If local side cannot autonegotiate, we can't try to enable
262 		 * full duplex without the user's consent, because we cannot
263 		 * tell without AN if the partner can support it
264 		 */
265 		if ((status & (MII_STATUS_100_BASEX | MII_STATUS_100_BASEX_FD |
266 		    MII_STATUS_100_BASE_T4)) && phydata->fix_speed == 0) {
267 			phydata->fix_speed = 100;
268 		} else if ((status & (MII_STATUS_10 | MII_STATUS_10_FD)) &&
269 		    phydata->fix_speed == 0) {
270 			phydata->fix_speed = 10;
271 		} else if (phydata->fix_speed == 0) {
272 			/* A very stupid PHY would not be supported */
273 #ifndef REALMODE
274 			kmem_free(mac->phys[phy], sizeof (struct phydata));
275 			mac->phys[phy] = NULL;
276 #endif
277 			return (MII_NOTSUPPORTED);
278 		}
279 		/* mii_sync will sort out the speed selection on the PHY */
280 	} else
281 		phydata->control = MII_CONTROL_ANE;
282 
283 	switch (PHY_MANUFACTURER(phydata->id)) {
284 	case OUI_NATIONAL_SEMICONDUCTOR:
285 		switch (PHY_MODEL(phydata->id)) {
286 		case NS_DP83840:
287 			phydata->phy_postreset = postreset_NS83840;
288 			phydata->phy_dump = dump_NS83840;
289 			phydata->description =
290 				"National Semiconductor DP-83840";
291 			phydata->phy_getspeed = getspeed_NS83840;
292 			break;
293 		default:
294 			phydata->description = "Unknown NS";
295 			break;
296 		}
297 		break;
298 
299 	case OUI_INTEL:
300 		switch (PHY_MODEL(phydata->id)) {
301 		case INTEL_82553_CSTEP:
302 			phydata->description = "Intel 82553 C-step";
303 			phydata->phy_getspeed = getspeed_82553;
304 			break;
305 		case INTEL_82555:
306 			phydata->description = "Intel 82555";
307 			phydata->phy_getspeed = getspeed_82553;
308 			break;
309 		case INTEL_82562_EH:
310 			phydata->description = "Intel 82562 EH";
311 			phydata->phy_getspeed = getspeed_82553;
312 			break;
313 		case INTEL_82562_ET:
314 			phydata->description = "Intel 82562 ET";
315 			phydata->phy_getspeed = getspeed_82553;
316 			break;
317 		default:
318 			phydata->description = "Unknown INTEL";
319 			break;
320 		}
321 		break;
322 
323 	case OUI_ICS:
324 		switch (PHY_MODEL(phydata->id)) {
325 		case ICS_1890:
326 		case ICS_1889:
327 			phydata->phy_postreset = postreset_ICS1890;
328 			phydata->description = "ICS 1890/1889 PHY";
329 			phydata->phy_getspeed = getspeed_ICS1890;
330 			phydata->phy_dump = dump_ICS1890;
331 			break;
332 		default:
333 			phydata->description = "ICS Unknown PHY";
334 			break;
335 		}
336 		break;
337 
338 	default: /* Non-standard PHYs, that encode weird IDs */
339 		phydata->description = "Unknown PHY";
340 		phydata->phy_dump = NULL;
341 		phydata->phy_getspeed = NULL;
342 		break;
343 	}
344 
345 	/* Do all post-reset hacks and user settings */
346 	(void) mii_sync(mac, phy);
347 
348 	if (ddi_getprop(DDI_DEV_T_NONE, mac->mii_dip, DDI_PROP_DONTPASS,
349 	    "dump-phy", 0))
350 		(void) mii_dump_phy(mac, phy);
351 
352 	return (MII_SUCCESS);
353 }
354 
355 /*
356  * Cause a reset on a PHY
357  */
358 
359 int
360 mii_reset_phy(mii_handle_t mac, int phy, enum mii_wait_type wait)
361 {
362 	int i;
363 	struct phydata *phyd;
364 	ushort_t control;
365 	if (!(phyd = mii_get_valid_phydata(mac, phy)))
366 		return (MII_PARAM);
367 
368 	/* Strobe the reset bit in the control register */
369 	mac->mii_write(mac->mii_dip, phy, MII_CONTROL,
370 			phyd->control | MII_CONTROL_RESET);
371 
372 	phyd->state = phy_state_unknown;
373 
374 	/*
375 	 * This is likely to be very fast (ie, by the time we read the
376 	 * control register once, the devices we have seen can have already
377 	 * reset), but according to 802.3u 22.2.4.1.1, it could be up to .5 sec.
378 	 */
379 	if (wait == mii_wait_interrupt || wait == mii_wait_user) {
380 		for (i = 100; i--; ) {
381 			control = mac->mii_read(mac->mii_dip, phy, MII_CONTROL);
382 			if (!(control & MII_CONTROL_RESET))
383 				break;
384 			drv_usecwait(10);
385 		}
386 		if (i)
387 			goto reset_completed;
388 	}
389 
390 	if (wait == mii_wait_user) {
391 		for (i = 50; i--; ) {
392 			control = mac->mii_read(mac->mii_dip, phy, MII_CONTROL);
393 			if (!(control & MII_CONTROL_RESET))
394 				break;
395 #ifdef REALMODE
396 			microseconds(10000);
397 #else
398 			delay(drv_usectohz(10000));
399 #endif
400 		}
401 		if (i)
402 			goto reset_completed;
403 		return (MII_HARDFAIL);	/* It MUST reset within this time */
404 
405 	}
406 	return (MII_TIMEOUT);
407 
408 reset_completed:
409 	(void) mii_sync(mac, phy);
410 	return (MII_SUCCESS);
411 }
412 
413 /*
414  * This routine is called to synchronise the software and the PHY. It should
415  * be called after the PHY is reset, and after initialising the PHY. This
416  * routine is external because devices (DNET) can reset the PHY in ways beyond
417  * the control of the mii interface. Should this happen, the driver is
418  * required to call mii_sync().
419  * If the PHY is resetting still when this is called, it will do nothing,
420  * but, it will be retriggered when the portmon timer expires.
421  */
422 
423 int
424 mii_sync(mii_handle_t mac, int phy)
425 {
426 	struct phydata *phyd = mac->phys[phy];
427 	int len, i, numprop;
428 	struct regprop {
429 		int reg;
430 		int value;
431 	} *regprop;
432 
433 #ifdef MIIDEBUG
434 	if (miidebug & MIITRACE)
435 		cmn_err(CE_NOTE, "mii_sync (phy addr %d)", phy);
436 #endif
437 
438 	len = 0;
439 	/*
440 	 * Conf file can specify a sequence of values to write to
441 	 * the PHY registers if required
442 	 */
443 	if (ddi_getlongprop(DDI_DEV_T_ANY, mac->mii_dip,
444 	    DDI_PROP_DONTPASS, "phy-registers", (caddr_t)&regprop,
445 	    &len) == DDI_PROP_SUCCESS) {
446 		numprop = len / sizeof (struct regprop);
447 		for (i = 0; i < numprop; i++) {
448 			mac->mii_write(mac->mii_dip, phy,
449 			    regprop[i].reg, regprop[i].value);
450 #ifdef MIIDEBUG
451 			if (miidebug & MIITRACE)
452 				cmn_err(CE_NOTE, "PHY Write reg %d=%x",
453 				    regprop[i].reg, regprop[i].value);
454 #endif
455 		}
456 		kmem_free(regprop, len);
457 	} else {
458 		mac->mii_write(mac->mii_dip, phy, MII_CONTROL, phyd->control);
459 		if (phyd->phy_postreset)
460 			phyd->phy_postreset(mac, phy);
461 		if (phyd->fix_speed || phyd->fix_duplex) {
462 			/* XXX function return value ignored */
463 			(void) mii_fixspeed(mac, phy, phyd->fix_speed,
464 			    phyd->fix_duplex);
465 		}
466 	}
467 	return (MII_SUCCESS);
468 }
469 
470 /*
471  * Disable full-duplex negotiation on the PHY. This is useful if the
472  * driver or link-partner is advertising full duplex, but does not support
473  * it properly (as some previous solaris drivers didn't)
474  */
475 
476 int
477 mii_disable_fullduplex(mii_handle_t mac, int phy)
478 {
479 	void *dip = mac->mii_dip;
480 	ushort_t expansion,  miiadvert;
481 	/* dont advertise full duplex capabilites */
482 	const int fullduplex = MII_ABILITY_10BASE_T_FD
483 				| MII_ABILITY_100BASE_TX_FD;
484 
485 	if (!(mac->mii_read(dip, phy, MII_STATUS) & MII_STATUS_CANAUTONEG)) {
486 		/*
487 		 * Local side cannot autonegotiate, so full duplex should
488 		 * never be negotiated. Consider it as a success
489 		 */
490 		return (MII_SUCCESS);
491 	}
492 
493 	/* Change what we advertise if it includes full duplex */
494 
495 	miiadvert = mac->mii_read(dip, phy, MII_AN_ADVERT);
496 	if (miiadvert & fullduplex)
497 		mac->mii_write(dip, phy, MII_AN_ADVERT,
498 				miiadvert & ~fullduplex);
499 
500 	/* See what other end is able to do.  */
501 
502 	expansion = mac->mii_read(dip, phy, MII_AN_EXPANSION);
503 
504 	/*
505 	 * Renegotiate if the link partner supports autonegotiation
506 	 * If it doesn't, we will never have auto-negotiated full duplex
507 	 * anyway
508 	 */
509 
510 	if (expansion & MII_AN_EXP_LPCANAN)
511 		return (mii_rsan(mac, phy, mii_wait_none));
512 	else
513 		return (MII_SUCCESS);
514 }
515 
516 /*
517  * (re)enable autonegotiation on a PHY.
518  */
519 
520 int
521 mii_autoneg_enab(mii_handle_t mac, int phy)
522 {
523 	struct phydata *phyd;
524 	if (!(phyd = mii_get_valid_phydata(mac, phy)))
525 		return (MII_PARAM);
526 	phyd->control |= MII_CONTROL_ANE;
527 	mac->mii_write(mac->mii_dip, phy, MII_CONTROL, phyd->control);
528 	return (MII_SUCCESS);
529 }
530 
531 /*
532  * Check the link status of a PHY connection
533  */
534 int
535 mii_linkup(mii_handle_t mac, int phy)
536 {
537 	ushort_t status;
538 
539 	/*
540 	 * Link status latches, so we need to read it twice, to make sure we
541 	 * get its current status
542 	 */
543 	mac->mii_read(mac->mii_dip, phy, MII_STATUS);
544 	status = mac->mii_read(mac->mii_dip, phy, MII_STATUS);
545 
546 	if (status != 0xffff && (status & MII_STATUS_LINKUP))
547 		return (1);
548 	else
549 		return (0);
550 }
551 
552 /*
553  * Discover what speed the PHY is running at, irrespective of wheather it
554  * autonegotiated this, or was fixed at that rate.
555  */
556 
557 int
558 mii_getspeed(mii_handle_t mac, int phy, int *speed, int *fulld)
559 {
560 	struct phydata *phyd;
561 
562 	if (!(phyd = mii_get_valid_phydata(mac, phy)))
563 		return (MII_PARAM);
564 	if (!(phyd->control & MII_CONTROL_ANE)) {
565 		/*
566 		 * user has requested fixed speed operation, return what we
567 		 * wrote to the control registerfrom control register
568 		 */
569 
570 		*speed = phyd->control & MII_CONTROL_100MB ? 100:10;
571 		*fulld = phyd->control & MII_CONTROL_FDUPLEX ? 1:0;
572 		return (MII_SUCCESS);
573 	}
574 
575 	if (!phyd->phy_getspeed) /* No standard way to do this(!) */
576 		return (MII_NOTSUPPORTED);
577 
578 	return (phyd->phy_getspeed(mac, phy, speed, fulld));
579 }
580 
581 /*
582  * Fix the speed and duplex mode of a PHY
583  */
584 
585 int
586 mii_fixspeed(mii_handle_t mac, int phy, int speed, int fullduplex)
587 {
588 	struct phydata *phyd;
589 
590 #ifdef MIIDEBUG
591 	cmn_err(CE_CONT, "!%s: setting speed to %d, %s duplex",
592 			ddi_get_name(mac->mii_dip), speed,
593 			fullduplex ? "full" : "half");
594 #endif
595 
596 	if (!(phyd = mii_get_valid_phydata(mac, phy)))
597 		return (MII_PARAM);
598 	phyd->control &= ~MII_CONTROL_ANE;
599 
600 	if (speed == 100)
601 		phyd->control |= MII_CONTROL_100MB;
602 	else if (speed == 10)
603 		phyd->control &= ~MII_CONTROL_100MB;
604 	else
605 		cmn_err(CE_NOTE, "%s: mii does not support %d Mb/s speed",
606 			ddi_get_name(mac->mii_dip), speed);
607 
608 	if (fullduplex)
609 		phyd->control |= MII_CONTROL_FDUPLEX;
610 	else
611 		phyd->control &= ~MII_CONTROL_FDUPLEX;
612 
613 	mac->mii_write(mac->mii_dip, phy, MII_CONTROL, phyd->control);
614 	phyd->fix_speed = speed;
615 	phyd->fix_duplex = fullduplex;
616 	return (MII_SUCCESS);
617 }
618 /*
619  * Electrically isolate/unisolate the PHY
620  */
621 
622 int
623 mii_isolate(mii_handle_t mac, int phy)
624 {
625 	struct phydata *phyd;
626 
627 	if (!(phyd = mii_get_valid_phydata(mac, phy)))
628 		return (MII_PARAM);
629 
630 	phyd->control |= MII_CONTROL_ISOLATE;
631 	mac->mii_write(mac->mii_dip, phy, MII_CONTROL, phyd->control);
632 
633 	/* Wait for device to settle */
634 	drv_usecwait(50);
635 	return (MII_SUCCESS);
636 }
637 
638 int
639 mii_unisolate(mii_handle_t mac, int phy)
640 {
641 	struct phydata *phyd;
642 
643 	if (!(phyd = mii_get_valid_phydata(mac, phy)))
644 		return (MII_PARAM);
645 
646 	phyd->control &= ~MII_CONTROL_ISOLATE;
647 	mac->mii_write(mac->mii_dip, phy, MII_CONTROL, phyd->control);
648 	return (MII_SUCCESS);
649 }
650 
651 /*
652  * Restart autonegotiation on a PHY
653  */
654 
655 int
656 mii_rsan(mii_handle_t mac, int phy, enum mii_wait_type wait)
657 {
658 	int i;
659 	void *dip;
660 	struct phydata *phyd;
661 
662 	if (wait == mii_wait_interrupt ||
663 	    !(phyd = mii_get_valid_phydata(mac, phy)))
664 		return (MII_PARAM);
665 
666 	if (phyd->fix_speed)
667 		return (MII_STATE);
668 
669 	dip = mac->mii_dip;
670 
671 	phyd->control |= MII_CONTROL_ANE;
672 	mac->mii_write(dip, phy, MII_CONTROL, phyd->control|MII_CONTROL_RSAN);
673 
674 	/*
675 	 * This can take ages (a second or so). It makes more sense to use
676 	 * the port monitor rather than waiting for completion of this on the
677 	 * PHY. It is pointless doing a busy wait here
678 	 */
679 
680 	if (wait == mii_wait_user) {
681 		for (i = 200; i--; ) {
682 			delay(drv_usectohz(10000));
683 			if (mac->mii_read(dip, phy, MII_STATUS) &
684 			    MII_STATUS_ANDONE)
685 				return (MII_SUCCESS);
686 		}
687 		cmn_err(CE_NOTE,
688 		    "!%s:Timed out waiting for autonegotiation",
689 		    ddi_get_name(mac->mii_dip));
690 		return (MII_TIMEOUT);
691 	}
692 	return (MII_TIMEOUT);
693 }
694 
695 /*
696  * Debuging function to dump contents of PHY registers
697  */
698 int
699 mii_dump_phy(mii_handle_t mac, int phy)
700 {
701 	struct phydata *phydat;
702 
703 	char *miiregs[] = {
704 		"Control             ",
705 		"Status              ",
706 		"PHY Id(H)           ",
707 		"PHY Id(L)           ",
708 		"Advertisement       ",
709 		"Link Partner Ability",
710 		"Expansion           ",
711 		"Next Page Transmit  ",
712 		0
713 	};
714 	int i;
715 
716 	if (!(phydat = mii_get_valid_phydata(mac, phy)))
717 		return (MII_PARAM);
718 
719 	cmn_err(CE_NOTE, "%s: PHY %d, type %s", ddi_get_name(mac->mii_dip), phy,
720 	    phydat->description ? phydat->description: "Unknown");
721 
722 	for (i = 0; miiregs[i]; i++)
723 		cmn_err(CE_NOTE, "%s:\t%x",
724 		    miiregs[i], mac->mii_read(mac->mii_dip, phy, i));
725 
726 	if (phydat->phy_dump)
727 		phydat->phy_dump((struct mii_info *)mac, phy);
728 
729 	return (MII_SUCCESS);
730 }
731 
732 #ifndef REALMODE
733 /*
734  * Start a periodic check to monitor the MII devices attached, and callback
735  * to the MAC driver when the state on a device changes
736  */
737 
738 int
739 mii_start_portmon(mii_handle_t mac, mii_linkfunc_t notify, kmutex_t *lock)
740 {
741 	if (mac->mii_linknotify || mac->portmon_timer)
742 		return (MII_STATE);
743 	mac->mii_linknotify = notify;
744 	/*
745 	 * NOTE: Portmon is normally called through a timeout. In the case
746 	 * of starting off, we assume that the lock is already held
747 	 */
748 	mac->lock = NULL; /* portmon wont try to aquire any lock this time */
749 	mii_portmon(mac);
750 	mac->lock = lock;
751 	return (MII_SUCCESS);
752 }
753 
754 int
755 mii_stop_portmon(mii_handle_t mac)
756 {
757 	if (!mac->mii_linknotify || !mac->portmon_timer)
758 		return (MII_STATE);
759 
760 	mac->mii_linknotify = NULL;
761 	mac->lock = NULL;
762 	(void) untimeout(mac->portmon_timer);
763 	mac->portmon_timer = 0;
764 	return (MII_SUCCESS);
765 }
766 
767 static void
768 mii_portmon(mii_handle_t mac)
769 {
770 	int i;
771 	enum mii_phy_state state;
772 	struct phydata *phydata;
773 
774 	/*
775 	 * There is a potential deadlock between this test and the
776 	 * mutex_enter
777 	 */
778 	if (!mac->mii_linknotify) /* Exiting */
779 		return;
780 
781 	if (mac->lock)
782 		mutex_enter(mac->lock);
783 
784 	/*
785 	 * For each initialised phy, see if the link state has changed, and
786 	 * callback to the mac driver if it has
787 	 */
788 	for (i = 0; i < 32; i++) {
789 		if ((phydata = mac->phys[i]) != 0) {
790 			state = mii_linkup(mac, i) ?
791 				phy_state_linkup : phy_state_linkdown;
792 			if (state != phydata->state) {
793 #ifdef MIIDEBUG
794 				if (miidebug)
795 					cmn_err(CE_NOTE, "%s: PHY %d link %s",
796 					    ddi_get_name(mac->mii_dip), i,
797 					    state == phy_state_linkup ?
798 						"up" : "down");
799 #endif
800 				phydata->state = state;
801 				mac->mii_linknotify(mac->mii_dip, i, state);
802 			}
803 		}
804 	}
805 	/* Check the ports every 5 seconds */
806 	mac->portmon_timer = timeout((void (*)(void*))mii_portmon, (void *)mac,
807 				    (clock_t)(5 * drv_usectohz(1000000)));
808 	if (mac->lock)
809 		mutex_exit(mac->lock);
810 }
811 
812 /*
813  * Close a handle to the MII interface from a registered user
814  */
815 
816 void
817 mii_destroy(mii_handle_t mac)
818 {
819 	/* Free per-PHY information */
820 	int i;
821 
822 	(void) mii_stop_portmon(mac);
823 
824 	for (i = 0; i < 32; i++)
825 		if (mac->phys[i])
826 			kmem_free(mac->phys[i], sizeof (struct phydata));
827 
828 	kmem_free(mac, sizeof (*mac));
829 }
830 
831 #endif
832 /*
833  * Get a PHY data structure from an MII handle, and validate the common
834  * parameters to the MII functions. Used to verify parameters in most MII
835  * functions
836  */
837 static struct phydata *
838 mii_get_valid_phydata(mii_handle_t mac, int phy)
839 {
840 	if (!mac || phy > 31 || phy < 0 || !mac->phys[phy]) {
841 		ASSERT(!"MII: Bad invocation");
842 		return (NULL);
843 	}
844 	return (mac->phys[phy]);
845 }
846 /*
847  * Device-specific routines - National Semiconductor
848  */
849 
850 #define	BIT(bit, value) ((value) & (1<<(bit)))
851 static void
852 dump_NS83840(mii_handle_t mac, int phy)
853 {
854 	ushort_t reg;
855 	void *dip;
856 
857 	dip = mac->mii_dip;
858 	cmn_err(CE_NOTE, "Disconnect count: %x",
859 				mac->mii_read(dip, phy, 0x12));
860 	cmn_err(CE_NOTE, "False Carrier detect count: %x",
861 				mac->mii_read(dip, phy, 0x13));
862 	cmn_err(CE_NOTE, "Receive error count: %x",
863 				mac->mii_read(dip, phy, 0x15));
864 	cmn_err(CE_NOTE, "Silicon revision: %x",
865 				mac->mii_read(dip, phy, 0x16));
866 	cmn_err(CE_NOTE, "PCS Configuration : %x",
867 				mac->mii_read(dip, phy, 0x17));
868 
869 	cmn_err(CE_NOTE, "Loopback, Bypass and Receiver error mask: %x",
870 				mac->mii_read(dip, phy, 0x18));
871 	cmn_err(CE_NOTE, "Wired phy address: %x",
872 				mac->mii_read(dip, phy, 0x19)&0xf);
873 
874 	reg = mac->mii_read(dip, phy, 0x1b);
875 	cmn_err(CE_NOTE, "10 Base T in %s mode",
876 				BIT(9, reg) ? "serial":"nibble");
877 
878 	cmn_err(CE_NOTE, "%slink pulses, %sheartbeat, %s,%s squelch,jabber %s",
879 				BIT(reg, 5) ? "" : "no ",
880 				BIT(reg, 4) ? "" : "no ",
881 				BIT(reg, 3) ? "UTP" : "STP",
882 				BIT(reg, 2) ? "low" : "normal",
883 				BIT(reg, 0) ? "enabled" : "disabled");
884 }
885 
886 static int
887 getspeed_NS83840(mii_handle_t mac, int phy, int *speed, int *fulld)
888 {
889 	int exten =  mac->mii_read(mac->mii_dip, phy, MII_AN_EXPANSION);
890 	if (exten & MII_AN_EXP_LPCANAN) {
891 		/*
892 		 * Link partner can auto-neg, take speed from LP Ability
893 		 * register
894 		 */
895 		int lpable, anadv, mask;
896 
897 		lpable = mac->mii_read(mac->mii_dip, phy, MII_AN_LPABLE);
898 		anadv = mac->mii_read(mac->mii_dip, phy, MII_AN_ADVERT);
899 		mask = anadv & lpable;
900 
901 		if (mask & MII_ABILITY_100BASE_TX_FD) {
902 			*speed = 100;
903 			*fulld = 1;
904 		} else if (mask & MII_ABILITY_100BASE_T4) {
905 			*speed = 100;
906 			*fulld = 0;
907 		} else if (mask & MII_ABILITY_100BASE_TX) {
908 			*speed = 100;
909 			*fulld = 0;
910 		} else if (mask & MII_ABILITY_10BASE_T_FD) {
911 			*speed = 10;
912 			*fulld = 1;
913 		} else if (mask & MII_ABILITY_10BASE_T) {
914 			*speed = 10;
915 			*fulld = 0;
916 		}
917 	} else {
918 		int addr = mac->mii_read(mac->mii_dip, phy, MII_83840_ADDR);
919 		*speed = (addr & NS83840_ADDR_SPEED10) ? 10:100;
920 		/* No fullduplex without autonegotiation on link partner */
921 		*fulld = 0;
922 	}
923 	return (0);
924 }
925 
926 /*
927  * Device-specific routines - INTEL
928  */
929 
930 static int
931 getspeed_82553(mii_handle_t mac, int phy, int *speed, int *fulld)
932 {
933 	int ex0 = mac->mii_read(mac->mii_dip, phy, MII_82553_EX0);
934 	*fulld = (ex0 & I82553_EX0_FDUPLEX) ? 1:0;
935 	*speed = (ex0 & I82553_EX0_100MB) ? 100:10;
936 	return (0);
937 }
938 
939 /*
940  * Device-specific routines - ICS
941  */
942 
943 static int
944 getspeed_ICS1890(mii_handle_t mac, int phy, int *speed, int *fulld)
945 {
946 	ushort_t quickpoll = mac->mii_read(mac->mii_dip, phy, ICS_QUICKPOLL);
947 	*speed = (quickpoll & ICS_QUICKPOLL_100MB) ? 100 : 10;
948 	*fulld = (quickpoll & ICS_QUICKPOLL_FDUPLEX) ? 1 : 0;
949 	return (0);
950 }
951 
952 static void
953 dump_ICS1890(mii_handle_t mac, int phy)
954 {
955 	ushort_t quickpoll = mac->mii_read(mac->mii_dip, phy, ICS_QUICKPOLL);
956 	cmn_err(CE_NOTE, "QuickPoll:%x (Speed:%d FullDuplex:%c) ",
957 				quickpoll,
958 				quickpoll & ICS_QUICKPOLL_100MB ? 100:10,
959 				quickpoll & ICS_QUICKPOLL_FDUPLEX ? 'Y' : 'N');
960 }
961 
962 static void
963 postreset_NS83840(mii_handle_t mac, int phy)
964 {
965 	ushort_t reg;
966 	struct phydata *phyd = mac->phys[phy];
967 	/*
968 	 * As per INTEL "PRO/100B Adapter Software Technical
969 	 * Reference Manual", set bit 10 of MII register 23.
970 	 * National Semiconductor documentation shows this as
971 	 * "reserved, write to as zero". We also set the
972 	 * "f_connect" bit, also as requested by the PRO/100B
973 	 * doc
974 	 */
975 
976 	reg = mac->mii_read(mac->mii_dip, phy, 23) | (1<<10) | (1<<5);
977 	mac->mii_write(mac->mii_dip, phy, 23, reg);
978 
979 	/*
980 	 * Some of thses PHYs seem to reset with the wrong value in the
981 	 * AN advertisment register. It should containt 1e1, indicating that
982 	 * the device can do 802.3 10BASE-T, 10BASE-T Full duplex, 100BASE-TX,
983 	 * and 100 BASE-TX full duplex. Instead it seems to advertise only
984 	 * 100BASE-TX Full duplex. The result of this is that the device will
985 	 * NOT autonegotiate at all against a 10MB only or 100MB/Half duplex
986 	 * autonegotiating hub
987 	 * NEEDSWORK:
988 	 * There is possibly a time-dependancy here.
989 	 * If the autonegotiation has completed BEFORE we get to here
990 	 * (after the reset) then this could possibly have not effect
991 	 */
992 	if (!phyd->fix_speed) {
993 #ifdef MIIDEBUG
994 		if (miidebug & MIICOMPAT)
995 			cmn_err(CE_NOTE, "Reset value of AN_ADV reg:%x",
996 			    mac->mii_read(mac->mii_dip, phy, MII_AN_ADVERT));
997 #endif
998 		mac->mii_write(mac->mii_dip, phy, MII_AN_ADVERT, 0x1e1);
999 	}
1000 }
1001 
1002 void
1003 postreset_ICS1890(mii_handle_t mac, int phy)
1004 {
1005 	/* This device comes up isolated if no link is found */
1006 	(void) mii_unisolate(mac, phy);
1007 }
1008