mii_physubr.c revision 128870
150120Swpaul/*	$NetBSD: mii_physubr.c,v 1.5 1999/08/03 19:41:49 drochner Exp $	*/
250120Swpaul
350120Swpaul/*-
495718Sphk * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
550120Swpaul * All rights reserved.
650120Swpaul *
750120Swpaul * This code is derived from software contributed to The NetBSD Foundation
850120Swpaul * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
950120Swpaul * NASA Ames Research Center.
1050120Swpaul *
1150120Swpaul * Redistribution and use in source and binary forms, with or without
1250120Swpaul * modification, are permitted provided that the following conditions
1350120Swpaul * are met:
1450120Swpaul * 1. Redistributions of source code must retain the above copyright
1550120Swpaul *    notice, this list of conditions and the following disclaimer.
1650120Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1750120Swpaul *    notice, this list of conditions and the following disclaimer in the
1850120Swpaul *    documentation and/or other materials provided with the distribution.
1950120Swpaul * 3. All advertising materials mentioning features or use of this software
2050120Swpaul *    must display the following acknowledgement:
2150120Swpaul *	This product includes software developed by the NetBSD
2250120Swpaul *	Foundation, Inc. and its contributors.
2350120Swpaul * 4. Neither the name of The NetBSD Foundation nor the names of its
2450120Swpaul *    contributors may be used to endorse or promote products derived
2550120Swpaul *    from this software without specific prior written permission.
2650120Swpaul *
2750120Swpaul * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2850120Swpaul * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2950120Swpaul * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
3050120Swpaul * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
3150120Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3250120Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3350120Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3450120Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3550120Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3650120Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3750120Swpaul * POSSIBILITY OF SUCH DAMAGE.
3850120Swpaul */
3950120Swpaul
40119418Sobrien#include <sys/cdefs.h>
41119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/mii/mii_physubr.c 128870 2004-05-03 13:01:34Z andre $");
42119418Sobrien
4350120Swpaul/*
4450120Swpaul * Subroutines common to all PHYs.
4550120Swpaul */
4650120Swpaul
47113038Sobrien#include <sys/cdefs.h>
48113038Sobrien__FBSDID("$FreeBSD: head/sys/dev/mii/mii_physubr.c 128870 2004-05-03 13:01:34Z andre $");
49113038Sobrien
5050120Swpaul#include <sys/param.h>
5150120Swpaul#include <sys/systm.h>
5250120Swpaul#include <sys/kernel.h>
5350120Swpaul#include <sys/socket.h>
5450120Swpaul#include <sys/errno.h>
5550120Swpaul#include <sys/module.h>
5650120Swpaul#include <sys/bus.h>
5750120Swpaul
5850120Swpaul
5950120Swpaul#include <net/if.h>
6050120Swpaul#include <net/if_media.h>
6150120Swpaul
6250120Swpaul#include <dev/mii/mii.h>
6350120Swpaul#include <dev/mii/miivar.h>
6450120Swpaul
6550120Swpaul#include "miibus_if.h"
6650120Swpaul
6795707Sphk/*
6895707Sphk * Media to register setting conversion table.  Order matters.
6995707Sphk */
7095707Sphkconst struct mii_media mii_media_table[MII_NMEDIA] = {
7195707Sphk	/* None */
7295707Sphk	{ BMCR_ISO,		ANAR_CSMA,
7395707Sphk	  0, },
7495707Sphk
7595707Sphk	/* 10baseT */
7695707Sphk	{ BMCR_S10,		ANAR_CSMA|ANAR_10,
7795707Sphk	  0, },
7895707Sphk
7995707Sphk	/* 10baseT-FDX */
8095707Sphk	{ BMCR_S10|BMCR_FDX,	ANAR_CSMA|ANAR_10_FD,
8195707Sphk	  0, },
8295707Sphk
8395707Sphk	/* 100baseT4 */
8495707Sphk	{ BMCR_S100,		ANAR_CSMA|ANAR_T4,
8595707Sphk	  0, },
8695707Sphk
8795707Sphk	/* 100baseTX */
8895707Sphk	{ BMCR_S100,		ANAR_CSMA|ANAR_TX,
8995707Sphk	  0, },
9095707Sphk
9195707Sphk	/* 100baseTX-FDX */
9295707Sphk	{ BMCR_S100|BMCR_FDX,	ANAR_CSMA|ANAR_TX_FD,
9395707Sphk	  0, },
9495707Sphk
9595707Sphk	/* 1000baseX */
9695707Sphk	{ BMCR_S1000,		ANAR_CSMA,
9795707Sphk	  0, },
9895707Sphk
9995707Sphk	/* 1000baseX-FDX */
10095707Sphk	{ BMCR_S1000|BMCR_FDX,	ANAR_CSMA,
10195707Sphk	  0, },
10295707Sphk
10395707Sphk	/* 1000baseT */
10495707Sphk	{ BMCR_S1000,		ANAR_CSMA,
10595707Sphk	  GTCR_ADV_1000THDX },
10695707Sphk
10795707Sphk	/* 1000baseT-FDX */
10895707Sphk	{ BMCR_S1000,		ANAR_CSMA,
10995707Sphk	  GTCR_ADV_1000TFDX },
11095707Sphk};
11195707Sphk
11295707Sphkvoid
11395707Sphkmii_phy_setmedia(struct mii_softc *sc)
11495707Sphk{
11595707Sphk	struct mii_data *mii = sc->mii_pdata;
11695707Sphk	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
11795707Sphk	int bmcr, anar, gtcr;
11895707Sphk
11995707Sphk	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
12095707Sphk		if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0)
12196026Sphk			(void) mii_phy_auto(sc);
12295707Sphk		return;
12395707Sphk	}
12495707Sphk
12595707Sphk	/*
12695707Sphk	 * Table index is stored in the media entry.
12795707Sphk	 */
12895707Sphk
12995718Sphk	KASSERT(ife->ifm_data >=0 && ife->ifm_data < MII_NMEDIA,
13095718Sphk	    ("invalid ife->ifm_data (0x%x) in mii_phy_setmedia",
13195718Sphk	    ife->ifm_data));
13295707Sphk
13395707Sphk	anar = mii_media_table[ife->ifm_data].mm_anar;
13495707Sphk	bmcr = mii_media_table[ife->ifm_data].mm_bmcr;
13595707Sphk	gtcr = mii_media_table[ife->ifm_data].mm_gtcr;
13695707Sphk
13795707Sphk	if (mii->mii_media.ifm_media & IFM_ETH_MASTER) {
13895707Sphk		switch (IFM_SUBTYPE(ife->ifm_media)) {
13995707Sphk		case IFM_1000_T:
14095707Sphk			gtcr |= GTCR_MAN_MS|GTCR_ADV_MS;
14195707Sphk			break;
14295707Sphk
14395707Sphk		default:
14495707Sphk			panic("mii_phy_setmedia: MASTER on wrong media");
14595707Sphk		}
14695707Sphk	}
14795707Sphk
14895707Sphk	if (ife->ifm_media & IFM_LOOP)
14995707Sphk		bmcr |= BMCR_LOOP;
15095707Sphk
15195707Sphk	PHY_WRITE(sc, MII_ANAR, anar);
15295707Sphk	PHY_WRITE(sc, MII_BMCR, bmcr);
15395707Sphk	if (sc->mii_flags & MIIF_HAVE_GTCR)
15495707Sphk		PHY_WRITE(sc, MII_100T2CR, gtcr);
15595707Sphk}
15695707Sphk
15750120Swpaulint
15896026Sphkmii_phy_auto(struct mii_softc *sc)
15950120Swpaul{
16050120Swpaul
16196026Sphk	/*
16296026Sphk	 * Check for 1000BASE-X.  Autonegotiation is a bit
16396026Sphk	 * different on such devices.
16496026Sphk	 */
16596026Sphk	if (sc->mii_flags & MIIF_IS_1000X) {
16696026Sphk		uint16_t anar = 0;
16795718Sphk
16896026Sphk		if (sc->mii_extcapabilities & EXTSR_1000XFDX)
16996026Sphk			anar |= ANAR_X_FD;
17096026Sphk		if (sc->mii_extcapabilities & EXTSR_1000XHDX)
17196026Sphk			anar |= ANAR_X_HD;
17295718Sphk
17396026Sphk		if (sc->mii_flags & MIIF_DOPAUSE) {
17496026Sphk			/* XXX Asymmetric vs. symmetric? */
17596026Sphk			anar |= ANLPAR_X_PAUSE_TOWARDS;
17696026Sphk		}
17795718Sphk
17896026Sphk		PHY_WRITE(sc, MII_ANAR, anar);
17996026Sphk	} else {
18096026Sphk		uint16_t anar;
18195718Sphk
18296026Sphk		anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) |
18396026Sphk		    ANAR_CSMA;
18496026Sphk		if (sc->mii_flags & MIIF_DOPAUSE)
18596026Sphk			anar |= ANAR_FC;
18696026Sphk		PHY_WRITE(sc, MII_ANAR, anar);
18796026Sphk		if (sc->mii_flags & MIIF_HAVE_GTCR) {
18896026Sphk			uint16_t gtcr = 0;
18995718Sphk
19096026Sphk			if (sc->mii_extcapabilities & EXTSR_1000TFDX)
19196026Sphk				gtcr |= GTCR_ADV_1000TFDX;
19296026Sphk			if (sc->mii_extcapabilities & EXTSR_1000THDX)
19396026Sphk				gtcr |= GTCR_ADV_1000THDX;
19495718Sphk
19596026Sphk			PHY_WRITE(sc, MII_100T2CR, gtcr);
19695718Sphk		}
19750120Swpaul	}
19896026Sphk	PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
19950120Swpaul	return (EJUSTRETURN);
20050120Swpaul}
20150120Swpaul
20284140Sjlemonint
20395718Sphkmii_phy_tick(struct mii_softc *sc)
20484140Sjlemon{
20584140Sjlemon	struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
20684140Sjlemon	struct ifnet *ifp = sc->mii_pdata->mii_ifp;
20784140Sjlemon	int reg;
20884140Sjlemon
20995718Sphk	/* Just bail now if the interface is down. */
21084140Sjlemon	if ((ifp->if_flags & IFF_UP) == 0)
21184140Sjlemon		return (EJUSTRETURN);
21284140Sjlemon
21384140Sjlemon	/*
21484140Sjlemon	 * If we're not doing autonegotiation, we don't need to do
21584140Sjlemon	 * any extra work here.  However, we need to check the link
21684140Sjlemon	 * status so we can generate an announcement if the status
21784140Sjlemon	 * changes.
21884140Sjlemon	 */
21984140Sjlemon	if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
22084140Sjlemon		return (0);
22184140Sjlemon
22295718Sphk	/* Read the status register twice; BMSR_LINK is latch-low. */
22384140Sjlemon	reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
22495718Sphk	if (reg & BMSR_LINK) {
22595718Sphk		/*
22695718Sphk		 * See above.
22795718Sphk		 */
22884140Sjlemon		return (0);
22995718Sphk	}
23084140Sjlemon
23184140Sjlemon	/*
23295718Sphk	 * Only retry autonegotiation every N seconds.
23384140Sjlemon	 */
234128870Sandre	if (sc->mii_anegticks == 0) {
23596027Sphk		sc->mii_anegticks = 17;
236128870Sandre		return (0);
237128870Sandre	}
238128870Sandre	if (++sc->mii_ticks <= sc->mii_anegticks)
23984140Sjlemon		return (EJUSTRETURN);
24084140Sjlemon
24184140Sjlemon	sc->mii_ticks = 0;
24284140Sjlemon	mii_phy_reset(sc);
24396026Sphk	mii_phy_auto(sc);
24484140Sjlemon	return (0);
24584140Sjlemon}
24684140Sjlemon
24750120Swpaulvoid
24895718Sphkmii_phy_reset(struct mii_softc *sc)
24950120Swpaul{
25050120Swpaul	int reg, i;
25150120Swpaul
25295718Sphk	if (sc->mii_flags & MIIF_NOISOLATE)
25350120Swpaul		reg = BMCR_RESET;
25450120Swpaul	else
25550120Swpaul		reg = BMCR_RESET | BMCR_ISO;
25695718Sphk	PHY_WRITE(sc, MII_BMCR, reg);
25750120Swpaul
25850120Swpaul	/* Wait 100ms for it to complete. */
25950120Swpaul	for (i = 0; i < 100; i++) {
26095718Sphk		reg = PHY_READ(sc, MII_BMCR);
26150120Swpaul		if ((reg & BMCR_RESET) == 0)
26250120Swpaul			break;
26350120Swpaul		DELAY(1000);
26450120Swpaul	}
26550120Swpaul
26695718Sphk	if (sc->mii_inst != 0 && ((sc->mii_flags & MIIF_NOISOLATE) == 0))
26795718Sphk		PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
26850120Swpaul}
26950120Swpaul
27084140Sjlemonvoid
27195722Sphkmii_phy_down(struct mii_softc *sc)
27284140Sjlemon{
27395722Sphk
27495722Sphk}
27595722Sphk
27695722Sphkvoid
27795722Sphkmii_phy_update(struct mii_softc *sc, int cmd)
27895722Sphk{
27984140Sjlemon	struct mii_data *mii = sc->mii_pdata;
28084140Sjlemon
28195722Sphk	if (sc->mii_media_active != mii->mii_media_active ||
28295722Sphk	    cmd == MII_MEDIACHG) {
28384140Sjlemon		MIIBUS_STATCHG(sc->mii_dev);
28495705Sphk		sc->mii_media_active = mii->mii_media_active;
28584140Sjlemon	}
28695705Sphk	if (sc->mii_media_status != mii->mii_media_status) {
28784140Sjlemon		MIIBUS_LINKCHG(sc->mii_dev);
28895705Sphk		sc->mii_media_status = mii->mii_media_status;
28984140Sjlemon	}
29084140Sjlemon}
29184140Sjlemon
29250120Swpaul/*
29350120Swpaul * Given an ifmedia word, return the corresponding ANAR value.
29450120Swpaul */
29550120Swpaulint
29650120Swpaulmii_anar(media)
29750120Swpaul	int media;
29850120Swpaul{
29950120Swpaul	int rv;
30050120Swpaul
30150120Swpaul	switch (media & (IFM_TMASK|IFM_NMASK|IFM_FDX)) {
30250120Swpaul	case IFM_ETHER|IFM_10_T:
30350120Swpaul		rv = ANAR_10|ANAR_CSMA;
30450120Swpaul		break;
30550120Swpaul	case IFM_ETHER|IFM_10_T|IFM_FDX:
30650120Swpaul		rv = ANAR_10_FD|ANAR_CSMA;
30750120Swpaul		break;
30850120Swpaul	case IFM_ETHER|IFM_100_TX:
30950120Swpaul		rv = ANAR_TX|ANAR_CSMA;
31050120Swpaul		break;
31150120Swpaul	case IFM_ETHER|IFM_100_TX|IFM_FDX:
31250120Swpaul		rv = ANAR_TX_FD|ANAR_CSMA;
31350120Swpaul		break;
31450120Swpaul	case IFM_ETHER|IFM_100_T4:
31550120Swpaul		rv = ANAR_T4|ANAR_CSMA;
31650120Swpaul		break;
31750120Swpaul	default:
31850120Swpaul		rv = 0;
31950120Swpaul		break;
32050120Swpaul	}
32150120Swpaul
32250120Swpaul	return (rv);
32350120Swpaul}
32450120Swpaul
32550120Swpaul/*
32650120Swpaul * Given a BMCR value, return the corresponding ifmedia word.
32750120Swpaul */
32850120Swpaulint
32950120Swpaulmii_media_from_bmcr(bmcr)
33050120Swpaul	int bmcr;
33150120Swpaul{
33250120Swpaul	int rv = IFM_ETHER;
33350120Swpaul
33450120Swpaul	if (bmcr & BMCR_S100)
33550120Swpaul		rv |= IFM_100_TX;
33650120Swpaul	else
33750120Swpaul		rv |= IFM_10_T;
33850120Swpaul	if (bmcr & BMCR_FDX)
33950120Swpaul		rv |= IFM_FDX;
34050120Swpaul
34150120Swpaul	return (rv);
34250120Swpaul}
34350120Swpaul
34450120Swpaul/*
34550120Swpaul * Initialize generic PHY media based on BMSR, called when a PHY is
34650120Swpaul * attached.  We expect to be set up to print a comma-separated list
34750120Swpaul * of media names.  Does not print a newline.
34850120Swpaul */
34950120Swpaulvoid
35095667Sphkmii_add_media(struct mii_softc *sc)
35150120Swpaul{
35250120Swpaul	const char *sep = "";
35395667Sphk	struct mii_data *mii;
35450120Swpaul
35595667Sphk	mii = device_get_softc(sc->mii_dev);
35695707Sphk	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) {
35795665Sphk		printf("no media present");
35895665Sphk		return;
35995665Sphk	}
36095665Sphk
36150120Swpaul#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
36250120Swpaul#define	PRINT(s)	printf("%s%s", sep, s); sep = ", "
36350120Swpaul
36495707Sphk	if (sc->mii_capabilities & BMSR_10THDX) {
36595707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), 0);
36650120Swpaul		PRINT("10baseT");
36750120Swpaul	}
36895707Sphk	if (sc->mii_capabilities & BMSR_10TFDX) {
36995707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
37050120Swpaul		    BMCR_FDX);
37150120Swpaul		PRINT("10baseT-FDX");
37250120Swpaul	}
37395707Sphk	if (sc->mii_capabilities & BMSR_100TXHDX) {
37495707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
37550120Swpaul		    BMCR_S100);
37650120Swpaul		PRINT("100baseTX");
37750120Swpaul	}
37895707Sphk	if (sc->mii_capabilities & BMSR_100TXFDX) {
37995707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
38050120Swpaul		    BMCR_S100|BMCR_FDX);
38150120Swpaul		PRINT("100baseTX-FDX");
38250120Swpaul	}
38395707Sphk	if (sc->mii_capabilities & BMSR_100T4) {
38450120Swpaul		/*
38550120Swpaul		 * XXX How do you enable 100baseT4?  I assume we set
38650120Swpaul		 * XXX BMCR_S100 and then assume the PHYs will take
38750120Swpaul		 * XXX watever action is necessary to switch themselves
38850120Swpaul		 * XXX into T4 mode.
38950120Swpaul		 */
39095707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
39150120Swpaul		    BMCR_S100);
39250120Swpaul		PRINT("100baseT4");
39350120Swpaul	}
39495707Sphk	if (sc->mii_capabilities & BMSR_ANEG) {
39595707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
39650120Swpaul		    BMCR_AUTOEN);
39750120Swpaul		PRINT("auto");
39850120Swpaul	}
39995667Sphk
40095667Sphk
40195667Sphk
40250120Swpaul#undef ADD
40350120Swpaul#undef PRINT
40450120Swpaul}
40595718Sphk
40695718Sphk/*
40795718Sphk * Initialize generic PHY media based on BMSR, called when a PHY is
40895718Sphk * attached.  We expect to be set up to print a comma-separated list
40995718Sphk * of media names.  Does not print a newline.
41095718Sphk */
41195718Sphkvoid
41295718Sphkmii_phy_add_media(struct mii_softc *sc)
41395718Sphk{
41495718Sphk	struct mii_data *mii = sc->mii_pdata;
41595718Sphk	const char *sep = "";
41695718Sphk
41795718Sphk#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
41895718Sphk#define	PRINT(s)	printf("%s%s", sep, s); sep = ", "
41995718Sphk
42095718Sphk	if ((sc->mii_flags & MIIF_NOISOLATE) == 0)
42195718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
42295718Sphk		    MII_MEDIA_NONE);
42395718Sphk
42495718Sphk	/*
42595718Sphk	 * There are different interpretations for the bits in
42695718Sphk	 * HomePNA PHYs.  And there is really only one media type
42795718Sphk	 * that is supported.
42895718Sphk	 */
42995718Sphk	if (sc->mii_flags & MIIF_IS_HPNA) {
43095718Sphk		if (sc->mii_capabilities & BMSR_10THDX) {
43195718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0,
43295718Sphk					 sc->mii_inst),
43395718Sphk			    MII_MEDIA_10_T);
43495718Sphk			PRINT("HomePNA1");
43595718Sphk		}
43695718Sphk		return;
43795718Sphk	}
43895718Sphk
43995718Sphk	if (sc->mii_capabilities & BMSR_10THDX) {
44095718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
44195718Sphk		    MII_MEDIA_10_T);
44295718Sphk		PRINT("10baseT");
44395718Sphk	}
44495718Sphk	if (sc->mii_capabilities & BMSR_10TFDX) {
44595718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
44695718Sphk		    MII_MEDIA_10_T_FDX);
44795718Sphk		PRINT("10baseT-FDX");
44895718Sphk	}
44995718Sphk	if (sc->mii_capabilities & BMSR_100TXHDX) {
45095718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
45195718Sphk		    MII_MEDIA_100_TX);
45295718Sphk		PRINT("100baseTX");
45395718Sphk	}
45495718Sphk	if (sc->mii_capabilities & BMSR_100TXFDX) {
45595718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
45695718Sphk		    MII_MEDIA_100_TX_FDX);
45795718Sphk		PRINT("100baseTX-FDX");
45895718Sphk	}
45995718Sphk	if (sc->mii_capabilities & BMSR_100T4) {
46095718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
46195718Sphk		    MII_MEDIA_100_T4);
46295718Sphk		PRINT("100baseT4");
46395718Sphk	}
46495718Sphk
46595718Sphk	if (sc->mii_extcapabilities & EXTSR_MEDIAMASK) {
46695718Sphk		/*
46795718Sphk		 * XXX Right now only handle 1000SX and 1000TX.  Need
46895718Sphk		 * XXX to handle 1000LX and 1000CX some how.
46995718Sphk		 *
47095718Sphk		 * Note since it can take 5 seconds to auto-negotiate
47195718Sphk		 * a gigabit link, we make anegticks 10 seconds for
47295718Sphk		 * all the gigabit media types.
47395718Sphk		 */
47495718Sphk		if (sc->mii_extcapabilities & EXTSR_1000XHDX) {
47596027Sphk			sc->mii_anegticks = 17;
47695718Sphk			sc->mii_flags |= MIIF_IS_1000X;
47795718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,
47895718Sphk			    sc->mii_inst), MII_MEDIA_1000_X);
47995718Sphk			PRINT("1000baseSX");
48095718Sphk		}
48195718Sphk		if (sc->mii_extcapabilities & EXTSR_1000XFDX) {
48296027Sphk			sc->mii_anegticks = 17;
48395718Sphk			sc->mii_flags |= MIIF_IS_1000X;
48495718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
48595718Sphk			    sc->mii_inst), MII_MEDIA_1000_X_FDX);
48695718Sphk			PRINT("1000baseSX-FDX");
48795718Sphk		}
48895718Sphk
48995718Sphk		/*
49095718Sphk		 * 1000baseT media needs to be able to manipulate
49195718Sphk		 * master/slave mode.  We set IFM_ETH_MASTER in
49295718Sphk		 * the "don't care mask" and filter it out when
49395718Sphk		 * the media is set.
49495718Sphk		 *
49595718Sphk		 * All 1000baseT PHYs have a 1000baseT control register.
49695718Sphk		 */
49795718Sphk		if (sc->mii_extcapabilities & EXTSR_1000THDX) {
49896027Sphk			sc->mii_anegticks = 17;
49995718Sphk			sc->mii_flags |= MIIF_HAVE_GTCR;
50095718Sphk			mii->mii_media.ifm_mask |= IFM_ETH_MASTER;
50195718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
50295718Sphk			    sc->mii_inst), MII_MEDIA_1000_T);
50395718Sphk			PRINT("1000baseT");
50495718Sphk		}
50595718Sphk		if (sc->mii_extcapabilities & EXTSR_1000TFDX) {
50696027Sphk			sc->mii_anegticks = 17;
50795718Sphk			sc->mii_flags |= MIIF_HAVE_GTCR;
50895718Sphk			mii->mii_media.ifm_mask |= IFM_ETH_MASTER;
50995718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,
51095718Sphk			    sc->mii_inst), MII_MEDIA_1000_T_FDX);
51195718Sphk			PRINT("1000baseT-FDX");
51295718Sphk		}
51395718Sphk	}
51495718Sphk
51595718Sphk	if (sc->mii_capabilities & BMSR_ANEG) {
51695718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
51795718Sphk		    MII_NMEDIA);	/* intentionally invalid index */
51895718Sphk		PRINT("auto");
51995718Sphk	}
52095718Sphk#undef ADD
52195718Sphk#undef PRINT
52295718Sphk}
52395718Sphk
52495722Sphkint
52595722Sphkmii_phy_detach(device_t dev)
52695722Sphk{
52795722Sphk	struct mii_softc *sc;
52895722Sphk
52995722Sphk	sc = device_get_softc(dev);
53095722Sphk	mii_phy_down(sc);
53195722Sphk	sc->mii_dev = NULL;
53295722Sphk	LIST_REMOVE(sc, mii_list);
53395722Sphk
53495722Sphk	return(0);
53595722Sphk}
53695724Sphk
53795724Sphkconst struct mii_phydesc *
53895724Sphkmii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd)
53995724Sphk{
54095724Sphk
54195724Sphk	for (; mpd->mpd_name != NULL; mpd++) {
54295724Sphk		if (MII_OUI(ma->mii_id1, ma->mii_id2) == mpd->mpd_oui &&
54395724Sphk		    MII_MODEL(ma->mii_id2) == mpd->mpd_model)
54495724Sphk			return (mpd);
54595724Sphk	}
54695724Sphk	return (NULL);
54795724Sphk}
548