brgphy.c revision 84145
159477Swpaul/*
259477Swpaul * Copyright (c) 2000
359477Swpaul *	Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
459477Swpaul *
559477Swpaul * Redistribution and use in source and binary forms, with or without
659477Swpaul * modification, are permitted provided that the following conditions
759477Swpaul * are met:
859477Swpaul * 1. Redistributions of source code must retain the above copyright
959477Swpaul *    notice, this list of conditions and the following disclaimer.
1059477Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1159477Swpaul *    notice, this list of conditions and the following disclaimer in the
1259477Swpaul *    documentation and/or other materials provided with the distribution.
1359477Swpaul * 3. All advertising materials mentioning features or use of this software
1459477Swpaul *    must display the following acknowledgement:
1559477Swpaul *	This product includes software developed by Bill Paul.
1659477Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1759477Swpaul *    may be used to endorse or promote products derived from this software
1859477Swpaul *    without specific prior written permission.
1959477Swpaul *
2059477Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2159477Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2259477Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2359477Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2459477Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2559477Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2659477Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2759477Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2859477Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2959477Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3059477Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
3159477Swpaul *
3259477Swpaul * $FreeBSD: head/sys/dev/mii/brgphy.c 84145 2001-09-29 19:18:52Z jlemon $
3359477Swpaul */
3459477Swpaul
3559477Swpaul/*
3659477Swpaul * Driver for the Broadcom BCR5400 1000baseTX PHY. Speed is always
3759477Swpaul * 1000mbps; all we need to negotiate here is full or half duplex.
3859477Swpaul */
3959477Swpaul
4059477Swpaul#include <sys/param.h>
4159477Swpaul#include <sys/systm.h>
4259477Swpaul#include <sys/kernel.h>
4359477Swpaul#include <sys/malloc.h>
4459477Swpaul#include <sys/socket.h>
4559477Swpaul#include <sys/bus.h>
4659477Swpaul
4783029Swpaul#include <machine/clock.h>
4859477Swpaul
4959477Swpaul#include <net/if.h>
5059477Swpaul#include <net/if_media.h>
5159477Swpaul
5259477Swpaul#include <dev/mii/mii.h>
5359477Swpaul#include <dev/mii/miivar.h>
5459477Swpaul#include <dev/mii/miidevs.h>
5559477Swpaul
5659477Swpaul#include <dev/mii/brgphyreg.h>
5759477Swpaul
5859477Swpaul#include "miibus_if.h"
5959477Swpaul
6059477Swpaul#if !defined(lint)
6159477Swpaulstatic const char rcsid[] =
6259477Swpaul  "$FreeBSD: head/sys/dev/mii/brgphy.c 84145 2001-09-29 19:18:52Z jlemon $";
6359477Swpaul#endif
6459477Swpaul
6559477Swpaulstatic int brgphy_probe		__P((device_t));
6659477Swpaulstatic int brgphy_attach		__P((device_t));
6759477Swpaulstatic int brgphy_detach		__P((device_t));
6859477Swpaul
6959477Swpaulstatic device_method_t brgphy_methods[] = {
7059477Swpaul	/* device interface */
7159477Swpaul	DEVMETHOD(device_probe,		brgphy_probe),
7259477Swpaul	DEVMETHOD(device_attach,	brgphy_attach),
7359477Swpaul	DEVMETHOD(device_detach,	brgphy_detach),
7459477Swpaul	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
7559477Swpaul	{ 0, 0 }
7659477Swpaul};
7759477Swpaul
7859477Swpaulstatic devclass_t brgphy_devclass;
7959477Swpaul
8059477Swpaulstatic driver_t brgphy_driver = {
8159477Swpaul	"brgphy",
8259477Swpaul	brgphy_methods,
8359477Swpaul	sizeof(struct mii_softc)
8459477Swpaul};
8559477Swpaul
8659477SwpaulDRIVER_MODULE(brgphy, miibus, brgphy_driver, brgphy_devclass, 0, 0);
8759477Swpaul
8884145Sjlemonstatic int	brgphy_service(struct mii_softc *, struct mii_data *, int);
8984145Sjlemonstatic void	brgphy_status(struct mii_softc *);
9059477Swpaulstatic int	brgphy_mii_phy_auto __P((struct mii_softc *, int));
9159477Swpaulextern void	mii_phy_auto_timeout __P((void *));
9259477Swpaul
9359477Swpaulstatic int brgphy_probe(dev)
9459477Swpaul	device_t		dev;
9559477Swpaul{
9659477Swpaul	struct mii_attach_args *ma;
9759477Swpaul
9859477Swpaul	ma = device_get_ivars(dev);
9959477Swpaul
10083029Swpaul	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
10183029Swpaul	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5400) {
10283029Swpaul		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5400);
10383029Swpaul		return(0);
10483029Swpaul	}
10559477Swpaul
10683029Swpaul	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
10783029Swpaul	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5401) {
10883029Swpaul		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5401);
10983029Swpaul		return(0);
11083029Swpaul	}
11159477Swpaul
11283029Swpaul	if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxBROADCOM &&
11383029Swpaul	    MII_MODEL(ma->mii_id2) == MII_MODEL_xxBROADCOM_BCM5411) {
11483029Swpaul		device_set_desc(dev, MII_STR_xxBROADCOM_BCM5411);
11583029Swpaul		return(0);
11683029Swpaul	}
11783029Swpaul
11883029Swpaul	return(ENXIO);
11959477Swpaul}
12059477Swpaul
12159477Swpaulstatic int brgphy_attach(dev)
12259477Swpaul	device_t		dev;
12359477Swpaul{
12459477Swpaul	struct mii_softc *sc;
12559477Swpaul	struct mii_attach_args *ma;
12659477Swpaul	struct mii_data *mii;
12759477Swpaul	const char *sep = "";
12859477Swpaul
12959477Swpaul	sc = device_get_softc(dev);
13059477Swpaul	ma = device_get_ivars(dev);
13159477Swpaul	sc->mii_dev = device_get_parent(dev);
13259477Swpaul	mii = device_get_softc(sc->mii_dev);
13359477Swpaul	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
13459477Swpaul
13559477Swpaul	sc->mii_inst = mii->mii_instance;
13659477Swpaul	sc->mii_phy = ma->mii_phyno;
13759477Swpaul	sc->mii_service = brgphy_service;
13859477Swpaul	sc->mii_pdata = mii;
13959477Swpaul
14059477Swpaul	sc->mii_flags |= MIIF_NOISOLATE;
14159477Swpaul	mii->mii_instance++;
14259477Swpaul
14359477Swpaul#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
14459477Swpaul#define PRINT(s)	printf("%s%s", sep, s); sep = ", "
14559477Swpaul
14659477Swpaul	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
14759477Swpaul	    BMCR_ISO);
14859477Swpaul#if 0
14959477Swpaul	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
15059477Swpaul	    BMCR_LOOP|BMCR_S100);
15159477Swpaul#endif
15259477Swpaul
15359477Swpaul	mii_phy_reset(sc);
15459477Swpaul
15583029Swpaul
15683029Swpaul	sc->mii_capabilities =
15783029Swpaul	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
15859477Swpaul	device_printf(dev, " ");
15983029Swpaul	if (sc->mii_capabilities & BMSR_MEDIAMASK)
16083029Swpaul		mii_add_media(mii, (sc->mii_capabilities & ~BMSR_ANEG),
16183029Swpaul		    sc->mii_inst);
16259477Swpaul	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_TX, 0, sc->mii_inst),
16359477Swpaul	    BRGPHY_BMCR_FDX);
16483029Swpaul	PRINT(", 1000baseTX");
16559477Swpaul	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_TX, IFM_FDX, sc->mii_inst), 0);
16659477Swpaul	PRINT("1000baseTX-FDX");
16759477Swpaul	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
16859477Swpaul	PRINT("auto");
16959477Swpaul
17059477Swpaul	printf("\n");
17159477Swpaul#undef ADD
17259477Swpaul#undef PRINT
17359477Swpaul
17459477Swpaul	MIIBUS_MEDIAINIT(sc->mii_dev);
17559477Swpaul	return(0);
17659477Swpaul}
17759477Swpaul
17859477Swpaulstatic int brgphy_detach(dev)
17959477Swpaul	device_t		dev;
18059477Swpaul{
18159477Swpaul	struct mii_softc *sc;
18259477Swpaul	struct mii_data *mii;
18359477Swpaul
18459477Swpaul	sc = device_get_softc(dev);
18559477Swpaul	mii = device_get_softc(device_get_parent(dev));
18669925Swpaul	if (sc->mii_flags & MIIF_DOINGAUTO)
18769925Swpaul		untimeout(mii_phy_auto_timeout, sc, sc->mii_auto_ch);
18883029Swpaul
18959477Swpaul	sc->mii_dev = NULL;
19059477Swpaul	LIST_REMOVE(sc, mii_list);
19159477Swpaul
19259477Swpaul	return(0);
19359477Swpaul}
19484145Sjlemon
19584145Sjlemonstatic int
19659477Swpaulbrgphy_service(sc, mii, cmd)
19759477Swpaul	struct mii_softc *sc;
19859477Swpaul	struct mii_data *mii;
19959477Swpaul	int cmd;
20059477Swpaul{
20159477Swpaul	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
20283029Swpaul	int reg, speed;
20359477Swpaul
20459477Swpaul	switch (cmd) {
20559477Swpaul	case MII_POLLSTAT:
20659477Swpaul		/*
20759477Swpaul		 * If we're not polling our PHY instance, just return.
20859477Swpaul		 */
20959477Swpaul		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
21059477Swpaul			return (0);
21159477Swpaul		break;
21259477Swpaul
21359477Swpaul	case MII_MEDIACHG:
21459477Swpaul		/*
21559477Swpaul		 * If the media indicates a different PHY instance,
21659477Swpaul		 * isolate ourselves.
21759477Swpaul		 */
21859477Swpaul		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
21959477Swpaul			reg = PHY_READ(sc, MII_BMCR);
22059477Swpaul			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
22159477Swpaul			return (0);
22259477Swpaul		}
22359477Swpaul
22459477Swpaul		/*
22559477Swpaul		 * If the interface is not up, don't do anything.
22659477Swpaul		 */
22759477Swpaul		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
22859477Swpaul			break;
22959477Swpaul
23059477Swpaul		PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
23159477Swpaul		    BRGPHY_PHY_EXTCTL_HIGH_LA|BRGPHY_PHY_EXTCTL_EN_LTR);
23259477Swpaul		PHY_WRITE(sc, BRGPHY_MII_AUXCTL,
23359477Swpaul		    BRGPHY_AUXCTL_LONG_PKT|BRGPHY_AUXCTL_TX_TST);
23459477Swpaul		PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
23559477Swpaul
23659477Swpaul		switch (IFM_SUBTYPE(ife->ifm_media)) {
23759477Swpaul		case IFM_AUTO:
23859477Swpaul#ifdef foo
23959477Swpaul			/*
24059477Swpaul			 * If we're already in auto mode, just return.
24159477Swpaul			 */
24259477Swpaul			if (PHY_READ(sc, BRGPHY_MII_BMCR) & BRGPHY_BMCR_AUTOEN)
24359477Swpaul				return (0);
24459477Swpaul#endif
24559477Swpaul			(void) brgphy_mii_phy_auto(sc, 1);
24659477Swpaul			break;
24759477Swpaul		case IFM_1000_TX:
24883029Swpaul			speed = BRGPHY_S1000;
24983029Swpaul			goto setit;
25083029Swpaul		case IFM_100_TX:
25183029Swpaul			speed = BRGPHY_S100;
25283029Swpaul			goto setit;
25383029Swpaul		case IFM_10_T:
25483029Swpaul			speed = BRGPHY_S10;
25583029Swpaulsetit:
25659477Swpaul			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
25759477Swpaul				PHY_WRITE(sc, BRGPHY_MII_BMCR,
25883029Swpaul				    BRGPHY_BMCR_FDX|speed);
25959477Swpaul			} else {
26083029Swpaul				PHY_WRITE(sc, BRGPHY_MII_BMCR, speed);
26159477Swpaul			}
26259477Swpaul			PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE);
26359477Swpaul
26483029Swpaul			if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_TX)
26583029Swpaul				break;
26683029Swpaul
26759477Swpaul			/*
26859477Swpaul			 * When settning the link manually, one side must
26959477Swpaul			 * be the master and the other the slave. However
27059477Swpaul			 * ifmedia doesn't give us a good way to specify
27159477Swpaul			 * this, so we fake it by using one of the LINK
27259477Swpaul			 * flags. If LINK0 is set, we program the PHY to
27359477Swpaul			 * be a master, otherwise it's a slave.
27459477Swpaul			 */
27559477Swpaul			if ((mii->mii_ifp->if_flags & IFF_LINK0)) {
27659477Swpaul				PHY_WRITE(sc, BRGPHY_MII_1000CTL,
27759477Swpaul				    BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC);
27859477Swpaul			} else {
27959477Swpaul				PHY_WRITE(sc, BRGPHY_MII_1000CTL,
28059477Swpaul				    BRGPHY_1000CTL_MSE);
28159477Swpaul			}
28259477Swpaul			break;
28383597Swpaul#ifdef foo
28483597Swpaul		case IFM_NONE:
28583597Swpaul			PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN);
28683597Swpaul			break;
28783597Swpaul#endif
28859477Swpaul		case IFM_100_T4:
28959477Swpaul		default:
29059477Swpaul			return (EINVAL);
29159477Swpaul		}
29259477Swpaul		break;
29359477Swpaul
29459477Swpaul	case MII_TICK:
29559477Swpaul		/*
29659477Swpaul		 * If we're not currently selected, just return.
29759477Swpaul		 */
29859477Swpaul		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
29959477Swpaul			return (0);
30059477Swpaul
30159477Swpaul		/*
30259477Swpaul		 * Is the interface even up?
30359477Swpaul		 */
30459477Swpaul		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
30559477Swpaul			return (0);
30659477Swpaul
30759477Swpaul		/*
30884145Sjlemon		 * Only used for autonegotiation.
30959477Swpaul		 */
31084145Sjlemon		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
31184145Sjlemon			break;
31259477Swpaul
31359477Swpaul		/*
31459477Swpaul		 * Check to see if we have link.  If we do, we don't
31559477Swpaul		 * need to restart the autonegotiation process.  Read
31659477Swpaul		 * the BMSR twice in case it's latched.
31759477Swpaul		 */
31859477Swpaul		reg = PHY_READ(sc, BRGPHY_MII_AUXSTS);
31959477Swpaul		if (reg & BRGPHY_AUXSTS_LINK)
32059477Swpaul			break;
32159477Swpaul
32284145Sjlemon		/*
32384145Sjlemon		 * Only retry autonegotiation every 5 seconds.
32484145Sjlemon		 */
32584145Sjlemon		if (++sc->mii_ticks != 5)
32684145Sjlemon			return (0);
32784145Sjlemon
32884145Sjlemon		sc->mii_ticks = 0;
32959477Swpaul		mii_phy_reset(sc);
33059477Swpaul		if (brgphy_mii_phy_auto(sc, 0) == EJUSTRETURN)
33184145Sjlemon			return (0);
33259477Swpaul		break;
33359477Swpaul	}
33459477Swpaul
33559477Swpaul	/* Update the media status. */
33659477Swpaul	brgphy_status(sc);
33759477Swpaul
33859477Swpaul	/* Callback if something changed. */
33984145Sjlemon	mii_phy_update(sc, cmd);
34059477Swpaul	return (0);
34159477Swpaul}
34259477Swpaul
34384145Sjlemonstatic void
34459477Swpaulbrgphy_status(sc)
34559477Swpaul	struct mii_softc *sc;
34659477Swpaul{
34759477Swpaul	struct mii_data *mii = sc->mii_pdata;
34883029Swpaul	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
34983029Swpaul	int bmsr, bmcr;
35059477Swpaul
35159477Swpaul	mii->mii_media_status = IFM_AVALID;
35259477Swpaul	mii->mii_media_active = IFM_ETHER;
35359477Swpaul
35459477Swpaul	bmsr = PHY_READ(sc, BRGPHY_MII_BMSR);
35559477Swpaul	if (PHY_READ(sc, BRGPHY_MII_AUXSTS) & BRGPHY_AUXSTS_LINK)
35659477Swpaul		mii->mii_media_status |= IFM_ACTIVE;
35759477Swpaul
35859477Swpaul	bmcr = PHY_READ(sc, BRGPHY_MII_BMCR);
35959477Swpaul
36059477Swpaul	if (bmcr & BRGPHY_BMCR_LOOP)
36159477Swpaul		mii->mii_media_active |= IFM_LOOP;
36259477Swpaul
36359477Swpaul	if (bmcr & BRGPHY_BMCR_AUTOEN) {
36459477Swpaul		if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) {
36559477Swpaul			/* Erg, still trying, I guess... */
36659477Swpaul			mii->mii_media_active |= IFM_NONE;
36759477Swpaul			return;
36859477Swpaul		}
36959477Swpaul
37083029Swpaul		switch (PHY_READ(sc, BRGPHY_MII_AUXSTS) &
37183029Swpaul		    BRGPHY_AUXSTS_AN_RES) {
37283029Swpaul		case BRGPHY_RES_1000FD:
37383029Swpaul			mii->mii_media_active |= IFM_1000_TX | IFM_FDX;
37483029Swpaul			break;
37583029Swpaul		case BRGPHY_RES_1000HD:
37683029Swpaul			mii->mii_media_active |= IFM_1000_TX | IFM_HDX;
37783029Swpaul			break;
37883029Swpaul		case BRGPHY_RES_100FD:
37983029Swpaul			mii->mii_media_active |= IFM_100_TX | IFM_FDX;
38083029Swpaul			break;
38183029Swpaul		case BRGPHY_RES_100T4:
38283029Swpaul			mii->mii_media_active |= IFM_100_T4;
38383029Swpaul			break;
38483029Swpaul		case BRGPHY_RES_100HD:
38583029Swpaul			mii->mii_media_active |= IFM_100_TX | IFM_HDX;
38683029Swpaul			break;
38783029Swpaul		case BRGPHY_RES_10FD:
38883029Swpaul			mii->mii_media_active |= IFM_10_T | IFM_FDX;
38983029Swpaul			break;
39083029Swpaul		case BRGPHY_RES_10HD:
39183029Swpaul			mii->mii_media_active |= IFM_10_T | IFM_HDX;
39283029Swpaul			break;
39383029Swpaul		default:
39483029Swpaul			mii->mii_media_active |= IFM_NONE;
39583029Swpaul			break;
39683029Swpaul		}
39759477Swpaul		return;
39859477Swpaul	}
39959477Swpaul
40083029Swpaul	mii->mii_media_active = ife->ifm_media;
40159477Swpaul
40259477Swpaul	return;
40359477Swpaul}
40459477Swpaul
40559477Swpaul
40659477Swpaulstatic int
40759477Swpaulbrgphy_mii_phy_auto(mii, waitfor)
40859477Swpaul	struct mii_softc *mii;
40959477Swpaul	int waitfor;
41059477Swpaul{
41183597Swpaul	int bmsr, ktcr = 0, i;
41259477Swpaul
41359477Swpaul	if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
41483597Swpaul		mii_phy_reset(mii);
41583597Swpaul		PHY_WRITE(mii, BRGPHY_MII_BMCR, 0);
41683597Swpaul		DELAY(1000);
41783597Swpaul		ktcr = PHY_READ(mii, BRGPHY_MII_1000CTL);
41883597Swpaul		PHY_WRITE(mii, BRGPHY_MII_1000CTL, ktcr |
41959477Swpaul		    BRGPHY_1000CTL_AFD|BRGPHY_1000CTL_AHD);
42083597Swpaul		ktcr = PHY_READ(mii, BRGPHY_MII_1000CTL);
42183597Swpaul		DELAY(1000);
42283597Swpaul		PHY_WRITE(mii, BRGPHY_MII_ANAR,
42383597Swpaul		    BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA);
42483597Swpaul		DELAY(1000);
42559477Swpaul		PHY_WRITE(mii, BRGPHY_MII_BMCR,
42659477Swpaul		    BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG);
42759477Swpaul		PHY_WRITE(mii, BRGPHY_MII_IMR, 0xFF00);
42859477Swpaul	}
42959477Swpaul
43059477Swpaul	if (waitfor) {
43159477Swpaul		/* Wait 500ms for it to complete. */
43259477Swpaul		for (i = 0; i < 500; i++) {
43359477Swpaul			if ((bmsr = PHY_READ(mii, BRGPHY_MII_BMSR)) &
43459477Swpaul			    BRGPHY_BMSR_ACOMP)
43559477Swpaul				return (0);
43659477Swpaul			DELAY(1000);
43759477Swpaul#if 0
43859477Swpaul		if ((bmsr & BMSR_ACOMP) == 0)
43959477Swpaul			printf("%s: autonegotiation failed to complete\n",
44059477Swpaul			    mii->mii_dev.dv_xname);
44159477Swpaul#endif
44259477Swpaul		}
44359477Swpaul
44459477Swpaul		/*
44559477Swpaul		 * Don't need to worry about clearing MIIF_DOINGAUTO.
44659477Swpaul		 * If that's set, a timeout is pending, and it will
44759477Swpaul		 * clear the flag.
44859477Swpaul		 */
44959477Swpaul		return (EIO);
45059477Swpaul	}
45159477Swpaul
45259477Swpaul	/*
45359477Swpaul	 * Just let it finish asynchronously.  This is for the benefit of
45459477Swpaul	 * the tick handler driving autonegotiation.  Don't want 500ms
45559477Swpaul	 * delays all the time while the system is running!
45659477Swpaul	 */
45759477Swpaul	if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
45859477Swpaul		mii->mii_flags |= MIIF_DOINGAUTO;
45969925Swpaul		mii->mii_auto_ch = timeout(mii_phy_auto_timeout, mii, hz >> 1);
46059477Swpaul	}
46159477Swpaul	return (EJUSTRETURN);
46259477Swpaul}
463