mii_physubr.c revision 158649
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 158649 2006-05-16 12:26:00Z oleg $");
42119418Sobrien
4350120Swpaul/*
4450120Swpaul * Subroutines common to all PHYs.
4550120Swpaul */
4650120Swpaul
4750120Swpaul#include <sys/param.h>
4850120Swpaul#include <sys/systm.h>
4950120Swpaul#include <sys/kernel.h>
5050120Swpaul#include <sys/socket.h>
5150120Swpaul#include <sys/errno.h>
5250120Swpaul#include <sys/module.h>
5350120Swpaul#include <sys/bus.h>
5450120Swpaul
5550120Swpaul
5650120Swpaul#include <net/if.h>
5750120Swpaul#include <net/if_media.h>
5850120Swpaul
5950120Swpaul#include <dev/mii/mii.h>
6050120Swpaul#include <dev/mii/miivar.h>
6150120Swpaul
6250120Swpaul#include "miibus_if.h"
6350120Swpaul
6495707Sphk/*
6595707Sphk * Media to register setting conversion table.  Order matters.
6695707Sphk */
6795707Sphkconst struct mii_media mii_media_table[MII_NMEDIA] = {
6895707Sphk	/* None */
6995707Sphk	{ BMCR_ISO,		ANAR_CSMA,
7095707Sphk	  0, },
7195707Sphk
7295707Sphk	/* 10baseT */
7395707Sphk	{ BMCR_S10,		ANAR_CSMA|ANAR_10,
7495707Sphk	  0, },
7595707Sphk
7695707Sphk	/* 10baseT-FDX */
7795707Sphk	{ BMCR_S10|BMCR_FDX,	ANAR_CSMA|ANAR_10_FD,
7895707Sphk	  0, },
7995707Sphk
8095707Sphk	/* 100baseT4 */
8195707Sphk	{ BMCR_S100,		ANAR_CSMA|ANAR_T4,
8295707Sphk	  0, },
8395707Sphk
8495707Sphk	/* 100baseTX */
8595707Sphk	{ BMCR_S100,		ANAR_CSMA|ANAR_TX,
8695707Sphk	  0, },
8795707Sphk
8895707Sphk	/* 100baseTX-FDX */
8995707Sphk	{ BMCR_S100|BMCR_FDX,	ANAR_CSMA|ANAR_TX_FD,
9095707Sphk	  0, },
9195707Sphk
9295707Sphk	/* 1000baseX */
9395707Sphk	{ BMCR_S1000,		ANAR_CSMA,
9495707Sphk	  0, },
9595707Sphk
9695707Sphk	/* 1000baseX-FDX */
9795707Sphk	{ BMCR_S1000|BMCR_FDX,	ANAR_CSMA,
9895707Sphk	  0, },
9995707Sphk
10095707Sphk	/* 1000baseT */
10195707Sphk	{ BMCR_S1000,		ANAR_CSMA,
10295707Sphk	  GTCR_ADV_1000THDX },
10395707Sphk
10495707Sphk	/* 1000baseT-FDX */
10595707Sphk	{ BMCR_S1000,		ANAR_CSMA,
10695707Sphk	  GTCR_ADV_1000TFDX },
10795707Sphk};
10895707Sphk
10995707Sphkvoid
11095707Sphkmii_phy_setmedia(struct mii_softc *sc)
11195707Sphk{
11295707Sphk	struct mii_data *mii = sc->mii_pdata;
11395707Sphk	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
11495707Sphk	int bmcr, anar, gtcr;
11595707Sphk
11695707Sphk	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
11795707Sphk		if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0)
11896026Sphk			(void) mii_phy_auto(sc);
11995707Sphk		return;
12095707Sphk	}
12195707Sphk
12295707Sphk	/*
12395707Sphk	 * Table index is stored in the media entry.
12495707Sphk	 */
12595707Sphk
12695718Sphk	KASSERT(ife->ifm_data >=0 && ife->ifm_data < MII_NMEDIA,
12795718Sphk	    ("invalid ife->ifm_data (0x%x) in mii_phy_setmedia",
12895718Sphk	    ife->ifm_data));
12995707Sphk
13095707Sphk	anar = mii_media_table[ife->ifm_data].mm_anar;
13195707Sphk	bmcr = mii_media_table[ife->ifm_data].mm_bmcr;
13295707Sphk	gtcr = mii_media_table[ife->ifm_data].mm_gtcr;
13395707Sphk
13495707Sphk	if (mii->mii_media.ifm_media & IFM_ETH_MASTER) {
13595707Sphk		switch (IFM_SUBTYPE(ife->ifm_media)) {
13695707Sphk		case IFM_1000_T:
13795707Sphk			gtcr |= GTCR_MAN_MS|GTCR_ADV_MS;
13895707Sphk			break;
13995707Sphk
14095707Sphk		default:
14195707Sphk			panic("mii_phy_setmedia: MASTER on wrong media");
14295707Sphk		}
14395707Sphk	}
14495707Sphk
14595707Sphk	if (ife->ifm_media & IFM_LOOP)
14695707Sphk		bmcr |= BMCR_LOOP;
14795707Sphk
14895707Sphk	PHY_WRITE(sc, MII_ANAR, anar);
14995707Sphk	PHY_WRITE(sc, MII_BMCR, bmcr);
15095707Sphk	if (sc->mii_flags & MIIF_HAVE_GTCR)
15195707Sphk		PHY_WRITE(sc, MII_100T2CR, gtcr);
15295707Sphk}
15395707Sphk
15450120Swpaulint
15596026Sphkmii_phy_auto(struct mii_softc *sc)
15650120Swpaul{
15750120Swpaul
15896026Sphk	/*
15996026Sphk	 * Check for 1000BASE-X.  Autonegotiation is a bit
16096026Sphk	 * different on such devices.
16196026Sphk	 */
16296026Sphk	if (sc->mii_flags & MIIF_IS_1000X) {
16396026Sphk		uint16_t anar = 0;
16495718Sphk
16596026Sphk		if (sc->mii_extcapabilities & EXTSR_1000XFDX)
16696026Sphk			anar |= ANAR_X_FD;
16796026Sphk		if (sc->mii_extcapabilities & EXTSR_1000XHDX)
16896026Sphk			anar |= ANAR_X_HD;
16995718Sphk
17096026Sphk		if (sc->mii_flags & MIIF_DOPAUSE) {
17196026Sphk			/* XXX Asymmetric vs. symmetric? */
17296026Sphk			anar |= ANLPAR_X_PAUSE_TOWARDS;
17396026Sphk		}
17495718Sphk
17596026Sphk		PHY_WRITE(sc, MII_ANAR, anar);
17696026Sphk	} else {
17796026Sphk		uint16_t anar;
17895718Sphk
17996026Sphk		anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) |
18096026Sphk		    ANAR_CSMA;
18196026Sphk		if (sc->mii_flags & MIIF_DOPAUSE)
18296026Sphk			anar |= ANAR_FC;
18396026Sphk		PHY_WRITE(sc, MII_ANAR, anar);
18496026Sphk		if (sc->mii_flags & MIIF_HAVE_GTCR) {
18596026Sphk			uint16_t gtcr = 0;
18695718Sphk
18796026Sphk			if (sc->mii_extcapabilities & EXTSR_1000TFDX)
18896026Sphk				gtcr |= GTCR_ADV_1000TFDX;
18996026Sphk			if (sc->mii_extcapabilities & EXTSR_1000THDX)
19096026Sphk				gtcr |= GTCR_ADV_1000THDX;
19195718Sphk
19296026Sphk			PHY_WRITE(sc, MII_100T2CR, gtcr);
19395718Sphk		}
19450120Swpaul	}
19596026Sphk	PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
19650120Swpaul	return (EJUSTRETURN);
19750120Swpaul}
19850120Swpaul
19984140Sjlemonint
20095718Sphkmii_phy_tick(struct mii_softc *sc)
20184140Sjlemon{
20284140Sjlemon	struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
20384140Sjlemon	struct ifnet *ifp = sc->mii_pdata->mii_ifp;
20484140Sjlemon	int reg;
20584140Sjlemon
20695718Sphk	/* Just bail now if the interface is down. */
20784140Sjlemon	if ((ifp->if_flags & IFF_UP) == 0)
20884140Sjlemon		return (EJUSTRETURN);
20984140Sjlemon
21084140Sjlemon	/*
21184140Sjlemon	 * If we're not doing autonegotiation, we don't need to do
21284140Sjlemon	 * any extra work here.  However, we need to check the link
21384140Sjlemon	 * status so we can generate an announcement if the status
21484140Sjlemon	 * changes.
21584140Sjlemon	 */
21684140Sjlemon	if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
21784140Sjlemon		return (0);
21884140Sjlemon
21995718Sphk	/* Read the status register twice; BMSR_LINK is latch-low. */
22084140Sjlemon	reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
22195718Sphk	if (reg & BMSR_LINK) {
222158649Soleg		sc->mii_ticks = 0;	/* reset autonegotiation timer. */
223158649Soleg		/* See above. */
22484140Sjlemon		return (0);
22595718Sphk	}
22684140Sjlemon
227158649Soleg	/* Announce link loss right after it happens */
228158649Soleg	if (sc->mii_ticks++ == 0)
229128870Sandre		return (0);
230158649Soleg
231158649Soleg	/* XXX: use default value if phy driver did not set mii_anegticks */
232158649Soleg	if (sc->mii_anegticks == 0)
233158649Soleg		sc->mii_anegticks = MII_ANEGTICKS_GIGE;
234158649Soleg
235158649Soleg	/* Only retry autonegotiation every mii_anegticks ticks. */
236158649Soleg	if (sc->mii_ticks <= sc->mii_anegticks)
23784140Sjlemon		return (EJUSTRETURN);
23884140Sjlemon
23984140Sjlemon	sc->mii_ticks = 0;
24084140Sjlemon	mii_phy_reset(sc);
24196026Sphk	mii_phy_auto(sc);
24284140Sjlemon	return (0);
24384140Sjlemon}
24484140Sjlemon
24550120Swpaulvoid
24695718Sphkmii_phy_reset(struct mii_softc *sc)
24750120Swpaul{
24850120Swpaul	int reg, i;
24950120Swpaul
25095718Sphk	if (sc->mii_flags & MIIF_NOISOLATE)
25150120Swpaul		reg = BMCR_RESET;
25250120Swpaul	else
25350120Swpaul		reg = BMCR_RESET | BMCR_ISO;
25495718Sphk	PHY_WRITE(sc, MII_BMCR, reg);
25550120Swpaul
25650120Swpaul	/* Wait 100ms for it to complete. */
25750120Swpaul	for (i = 0; i < 100; i++) {
25895718Sphk		reg = PHY_READ(sc, MII_BMCR);
25950120Swpaul		if ((reg & BMCR_RESET) == 0)
26050120Swpaul			break;
26150120Swpaul		DELAY(1000);
26250120Swpaul	}
26350120Swpaul
26495718Sphk	if (sc->mii_inst != 0 && ((sc->mii_flags & MIIF_NOISOLATE) == 0))
26595718Sphk		PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
26650120Swpaul}
26750120Swpaul
26884140Sjlemonvoid
26995722Sphkmii_phy_down(struct mii_softc *sc)
27084140Sjlemon{
27195722Sphk
27295722Sphk}
27395722Sphk
27495722Sphkvoid
27595722Sphkmii_phy_update(struct mii_softc *sc, int cmd)
27695722Sphk{
27784140Sjlemon	struct mii_data *mii = sc->mii_pdata;
27884140Sjlemon
27995722Sphk	if (sc->mii_media_active != mii->mii_media_active ||
28095722Sphk	    cmd == MII_MEDIACHG) {
28184140Sjlemon		MIIBUS_STATCHG(sc->mii_dev);
28295705Sphk		sc->mii_media_active = mii->mii_media_active;
28384140Sjlemon	}
28495705Sphk	if (sc->mii_media_status != mii->mii_media_status) {
28584140Sjlemon		MIIBUS_LINKCHG(sc->mii_dev);
28695705Sphk		sc->mii_media_status = mii->mii_media_status;
28784140Sjlemon	}
28884140Sjlemon}
28984140Sjlemon
29050120Swpaul/*
29150120Swpaul * Given an ifmedia word, return the corresponding ANAR value.
29250120Swpaul */
29350120Swpaulint
294141937Simpmii_anar(int media)
29550120Swpaul{
29650120Swpaul	int rv;
29750120Swpaul
29850120Swpaul	switch (media & (IFM_TMASK|IFM_NMASK|IFM_FDX)) {
29950120Swpaul	case IFM_ETHER|IFM_10_T:
30050120Swpaul		rv = ANAR_10|ANAR_CSMA;
30150120Swpaul		break;
30250120Swpaul	case IFM_ETHER|IFM_10_T|IFM_FDX:
30350120Swpaul		rv = ANAR_10_FD|ANAR_CSMA;
30450120Swpaul		break;
30550120Swpaul	case IFM_ETHER|IFM_100_TX:
30650120Swpaul		rv = ANAR_TX|ANAR_CSMA;
30750120Swpaul		break;
30850120Swpaul	case IFM_ETHER|IFM_100_TX|IFM_FDX:
30950120Swpaul		rv = ANAR_TX_FD|ANAR_CSMA;
31050120Swpaul		break;
31150120Swpaul	case IFM_ETHER|IFM_100_T4:
31250120Swpaul		rv = ANAR_T4|ANAR_CSMA;
31350120Swpaul		break;
31450120Swpaul	default:
31550120Swpaul		rv = 0;
31650120Swpaul		break;
31750120Swpaul	}
31850120Swpaul
31950120Swpaul	return (rv);
32050120Swpaul}
32150120Swpaul
32250120Swpaul/*
32350120Swpaul * Given a BMCR value, return the corresponding ifmedia word.
32450120Swpaul */
32550120Swpaulint
326141937Simpmii_media_from_bmcr(int bmcr)
32750120Swpaul{
32850120Swpaul	int rv = IFM_ETHER;
32950120Swpaul
33050120Swpaul	if (bmcr & BMCR_S100)
33150120Swpaul		rv |= IFM_100_TX;
33250120Swpaul	else
33350120Swpaul		rv |= IFM_10_T;
33450120Swpaul	if (bmcr & BMCR_FDX)
33550120Swpaul		rv |= IFM_FDX;
33650120Swpaul
33750120Swpaul	return (rv);
33850120Swpaul}
33950120Swpaul
34050120Swpaul/*
34150120Swpaul * Initialize generic PHY media based on BMSR, called when a PHY is
34250120Swpaul * attached.  We expect to be set up to print a comma-separated list
34350120Swpaul * of media names.  Does not print a newline.
34450120Swpaul */
34550120Swpaulvoid
34695667Sphkmii_add_media(struct mii_softc *sc)
34750120Swpaul{
34850120Swpaul	const char *sep = "";
34995667Sphk	struct mii_data *mii;
35050120Swpaul
35195667Sphk	mii = device_get_softc(sc->mii_dev);
35295707Sphk	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) {
35395665Sphk		printf("no media present");
35495665Sphk		return;
35595665Sphk	}
35695665Sphk
35750120Swpaul#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
35850120Swpaul#define	PRINT(s)	printf("%s%s", sep, s); sep = ", "
35950120Swpaul
36095707Sphk	if (sc->mii_capabilities & BMSR_10THDX) {
36195707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), 0);
36250120Swpaul		PRINT("10baseT");
36350120Swpaul	}
36495707Sphk	if (sc->mii_capabilities & BMSR_10TFDX) {
36595707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
36650120Swpaul		    BMCR_FDX);
36750120Swpaul		PRINT("10baseT-FDX");
36850120Swpaul	}
36995707Sphk	if (sc->mii_capabilities & BMSR_100TXHDX) {
37095707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
37150120Swpaul		    BMCR_S100);
37250120Swpaul		PRINT("100baseTX");
37350120Swpaul	}
37495707Sphk	if (sc->mii_capabilities & BMSR_100TXFDX) {
37595707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
37650120Swpaul		    BMCR_S100|BMCR_FDX);
37750120Swpaul		PRINT("100baseTX-FDX");
37850120Swpaul	}
37995707Sphk	if (sc->mii_capabilities & BMSR_100T4) {
38050120Swpaul		/*
38150120Swpaul		 * XXX How do you enable 100baseT4?  I assume we set
38250120Swpaul		 * XXX BMCR_S100 and then assume the PHYs will take
38350120Swpaul		 * XXX watever action is necessary to switch themselves
38450120Swpaul		 * XXX into T4 mode.
38550120Swpaul		 */
38695707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
38750120Swpaul		    BMCR_S100);
38850120Swpaul		PRINT("100baseT4");
38950120Swpaul	}
39095707Sphk	if (sc->mii_capabilities & BMSR_ANEG) {
39195707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
39250120Swpaul		    BMCR_AUTOEN);
39350120Swpaul		PRINT("auto");
39450120Swpaul	}
39595667Sphk
39695667Sphk
39795667Sphk
39850120Swpaul#undef ADD
39950120Swpaul#undef PRINT
40050120Swpaul}
40195718Sphk
40295718Sphk/*
40395718Sphk * Initialize generic PHY media based on BMSR, called when a PHY is
40495718Sphk * attached.  We expect to be set up to print a comma-separated list
40595718Sphk * of media names.  Does not print a newline.
40695718Sphk */
40795718Sphkvoid
40895718Sphkmii_phy_add_media(struct mii_softc *sc)
40995718Sphk{
41095718Sphk	struct mii_data *mii = sc->mii_pdata;
41195718Sphk	const char *sep = "";
41295718Sphk
413158649Soleg	/* Set aneg timer for 10/100 media. Gigabit media handled below. */
414158649Soleg	sc->mii_anegticks = MII_ANEGTICKS;
415158649Soleg
41695718Sphk#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
41795718Sphk#define	PRINT(s)	printf("%s%s", sep, s); sep = ", "
41895718Sphk
41995718Sphk	if ((sc->mii_flags & MIIF_NOISOLATE) == 0)
42095718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
42195718Sphk		    MII_MEDIA_NONE);
42295718Sphk
42395718Sphk	/*
42495718Sphk	 * There are different interpretations for the bits in
42595718Sphk	 * HomePNA PHYs.  And there is really only one media type
42695718Sphk	 * that is supported.
42795718Sphk	 */
42895718Sphk	if (sc->mii_flags & MIIF_IS_HPNA) {
42995718Sphk		if (sc->mii_capabilities & BMSR_10THDX) {
43095718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0,
43195718Sphk					 sc->mii_inst),
43295718Sphk			    MII_MEDIA_10_T);
43395718Sphk			PRINT("HomePNA1");
43495718Sphk		}
43595718Sphk		return;
43695718Sphk	}
43795718Sphk
43895718Sphk	if (sc->mii_capabilities & BMSR_10THDX) {
43995718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
44095718Sphk		    MII_MEDIA_10_T);
44195718Sphk		PRINT("10baseT");
44295718Sphk	}
44395718Sphk	if (sc->mii_capabilities & BMSR_10TFDX) {
44495718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
44595718Sphk		    MII_MEDIA_10_T_FDX);
44695718Sphk		PRINT("10baseT-FDX");
44795718Sphk	}
44895718Sphk	if (sc->mii_capabilities & BMSR_100TXHDX) {
44995718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
45095718Sphk		    MII_MEDIA_100_TX);
45195718Sphk		PRINT("100baseTX");
45295718Sphk	}
45395718Sphk	if (sc->mii_capabilities & BMSR_100TXFDX) {
45495718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
45595718Sphk		    MII_MEDIA_100_TX_FDX);
45695718Sphk		PRINT("100baseTX-FDX");
45795718Sphk	}
45895718Sphk	if (sc->mii_capabilities & BMSR_100T4) {
45995718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
46095718Sphk		    MII_MEDIA_100_T4);
46195718Sphk		PRINT("100baseT4");
46295718Sphk	}
46395718Sphk
46495718Sphk	if (sc->mii_extcapabilities & EXTSR_MEDIAMASK) {
46595718Sphk		/*
46695718Sphk		 * XXX Right now only handle 1000SX and 1000TX.  Need
46795718Sphk		 * XXX to handle 1000LX and 1000CX some how.
46895718Sphk		 */
46995718Sphk		if (sc->mii_extcapabilities & EXTSR_1000XHDX) {
470158649Soleg			sc->mii_anegticks = MII_ANEGTICKS_GIGE;
47195718Sphk			sc->mii_flags |= MIIF_IS_1000X;
47295718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,
47395718Sphk			    sc->mii_inst), MII_MEDIA_1000_X);
47495718Sphk			PRINT("1000baseSX");
47595718Sphk		}
47695718Sphk		if (sc->mii_extcapabilities & EXTSR_1000XFDX) {
477158649Soleg			sc->mii_anegticks = MII_ANEGTICKS_GIGE;
47895718Sphk			sc->mii_flags |= MIIF_IS_1000X;
47995718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
48095718Sphk			    sc->mii_inst), MII_MEDIA_1000_X_FDX);
48195718Sphk			PRINT("1000baseSX-FDX");
48295718Sphk		}
48395718Sphk
48495718Sphk		/*
48595718Sphk		 * 1000baseT media needs to be able to manipulate
48695718Sphk		 * master/slave mode.  We set IFM_ETH_MASTER in
48795718Sphk		 * the "don't care mask" and filter it out when
48895718Sphk		 * the media is set.
48995718Sphk		 *
49095718Sphk		 * All 1000baseT PHYs have a 1000baseT control register.
49195718Sphk		 */
49295718Sphk		if (sc->mii_extcapabilities & EXTSR_1000THDX) {
493158649Soleg			sc->mii_anegticks = MII_ANEGTICKS_GIGE;
49495718Sphk			sc->mii_flags |= MIIF_HAVE_GTCR;
49595718Sphk			mii->mii_media.ifm_mask |= IFM_ETH_MASTER;
49695718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
49795718Sphk			    sc->mii_inst), MII_MEDIA_1000_T);
49895718Sphk			PRINT("1000baseT");
49995718Sphk		}
50095718Sphk		if (sc->mii_extcapabilities & EXTSR_1000TFDX) {
501158649Soleg			sc->mii_anegticks = MII_ANEGTICKS_GIGE;
50295718Sphk			sc->mii_flags |= MIIF_HAVE_GTCR;
50395718Sphk			mii->mii_media.ifm_mask |= IFM_ETH_MASTER;
50495718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,
50595718Sphk			    sc->mii_inst), MII_MEDIA_1000_T_FDX);
50695718Sphk			PRINT("1000baseT-FDX");
50795718Sphk		}
50895718Sphk	}
50995718Sphk
51095718Sphk	if (sc->mii_capabilities & BMSR_ANEG) {
51195718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
51295718Sphk		    MII_NMEDIA);	/* intentionally invalid index */
51395718Sphk		PRINT("auto");
51495718Sphk	}
51595718Sphk#undef ADD
51695718Sphk#undef PRINT
51795718Sphk}
51895718Sphk
51995722Sphkint
52095722Sphkmii_phy_detach(device_t dev)
52195722Sphk{
52295722Sphk	struct mii_softc *sc;
52395722Sphk
52495722Sphk	sc = device_get_softc(dev);
52595722Sphk	mii_phy_down(sc);
52695722Sphk	sc->mii_dev = NULL;
52795722Sphk	LIST_REMOVE(sc, mii_list);
52895722Sphk
52995722Sphk	return(0);
53095722Sphk}
53195724Sphk
53295724Sphkconst struct mii_phydesc *
533150756Simpmii_phy_match_gen(const struct mii_attach_args *ma,
534150756Simp  const struct mii_phydesc *mpd, size_t len)
53595724Sphk{
53695724Sphk
537150756Simp	for (; mpd->mpd_name != NULL;
538150756Simp	     mpd = (const struct mii_phydesc *) ((const char *) mpd + len)) {
53995724Sphk		if (MII_OUI(ma->mii_id1, ma->mii_id2) == mpd->mpd_oui &&
54095724Sphk		    MII_MODEL(ma->mii_id2) == mpd->mpd_model)
54195724Sphk			return (mpd);
54295724Sphk	}
54395724Sphk	return (NULL);
54495724Sphk}
545150756Simp
546150756Simpconst struct mii_phydesc *
547150756Simpmii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd)
548150756Simp{
549150756Simp	return (mii_phy_match_gen(ma, mpd, sizeof(struct mii_phydesc)));
550150756Simp}
551