mii_physubr.c revision 164702
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 164702 2006-11-27 23:37:59Z marius $");
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) {
117164702Smarius		if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0 ||
118164702Smarius		    (sc->mii_flags & MIIF_FORCEANEG))
11996026Sphk			(void) mii_phy_auto(sc);
12095707Sphk		return;
12195707Sphk	}
12295707Sphk
12395707Sphk	/*
12495707Sphk	 * Table index is stored in the media entry.
12595707Sphk	 */
12695707Sphk
12795718Sphk	KASSERT(ife->ifm_data >=0 && ife->ifm_data < MII_NMEDIA,
12895718Sphk	    ("invalid ife->ifm_data (0x%x) in mii_phy_setmedia",
12995718Sphk	    ife->ifm_data));
13095707Sphk
13195707Sphk	anar = mii_media_table[ife->ifm_data].mm_anar;
13295707Sphk	bmcr = mii_media_table[ife->ifm_data].mm_bmcr;
13395707Sphk	gtcr = mii_media_table[ife->ifm_data].mm_gtcr;
13495707Sphk
13595707Sphk	if (mii->mii_media.ifm_media & IFM_ETH_MASTER) {
13695707Sphk		switch (IFM_SUBTYPE(ife->ifm_media)) {
13795707Sphk		case IFM_1000_T:
13895707Sphk			gtcr |= GTCR_MAN_MS|GTCR_ADV_MS;
13995707Sphk			break;
14095707Sphk
14195707Sphk		default:
14295707Sphk			panic("mii_phy_setmedia: MASTER on wrong media");
14395707Sphk		}
14495707Sphk	}
14595707Sphk
14695707Sphk	if (ife->ifm_media & IFM_LOOP)
14795707Sphk		bmcr |= BMCR_LOOP;
14895707Sphk
14995707Sphk	PHY_WRITE(sc, MII_ANAR, anar);
15095707Sphk	PHY_WRITE(sc, MII_BMCR, bmcr);
15195707Sphk	if (sc->mii_flags & MIIF_HAVE_GTCR)
15295707Sphk		PHY_WRITE(sc, MII_100T2CR, gtcr);
15395707Sphk}
15495707Sphk
15550120Swpaulint
15696026Sphkmii_phy_auto(struct mii_softc *sc)
15750120Swpaul{
15850120Swpaul
15996026Sphk	/*
16096026Sphk	 * Check for 1000BASE-X.  Autonegotiation is a bit
16196026Sphk	 * different on such devices.
16296026Sphk	 */
16396026Sphk	if (sc->mii_flags & MIIF_IS_1000X) {
16496026Sphk		uint16_t anar = 0;
16595718Sphk
16696026Sphk		if (sc->mii_extcapabilities & EXTSR_1000XFDX)
16796026Sphk			anar |= ANAR_X_FD;
16896026Sphk		if (sc->mii_extcapabilities & EXTSR_1000XHDX)
16996026Sphk			anar |= ANAR_X_HD;
17095718Sphk
17196026Sphk		if (sc->mii_flags & MIIF_DOPAUSE) {
17296026Sphk			/* XXX Asymmetric vs. symmetric? */
17396026Sphk			anar |= ANLPAR_X_PAUSE_TOWARDS;
17496026Sphk		}
17595718Sphk
17696026Sphk		PHY_WRITE(sc, MII_ANAR, anar);
17796026Sphk	} else {
17896026Sphk		uint16_t anar;
17995718Sphk
18096026Sphk		anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) |
18196026Sphk		    ANAR_CSMA;
18296026Sphk		if (sc->mii_flags & MIIF_DOPAUSE)
18396026Sphk			anar |= ANAR_FC;
18496026Sphk		PHY_WRITE(sc, MII_ANAR, anar);
18596026Sphk		if (sc->mii_flags & MIIF_HAVE_GTCR) {
18696026Sphk			uint16_t gtcr = 0;
18795718Sphk
18896026Sphk			if (sc->mii_extcapabilities & EXTSR_1000TFDX)
18996026Sphk				gtcr |= GTCR_ADV_1000TFDX;
19096026Sphk			if (sc->mii_extcapabilities & EXTSR_1000THDX)
19196026Sphk				gtcr |= GTCR_ADV_1000THDX;
19295718Sphk
19396026Sphk			PHY_WRITE(sc, MII_100T2CR, gtcr);
19495718Sphk		}
19550120Swpaul	}
19696026Sphk	PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
19750120Swpaul	return (EJUSTRETURN);
19850120Swpaul}
19950120Swpaul
20084140Sjlemonint
20195718Sphkmii_phy_tick(struct mii_softc *sc)
20284140Sjlemon{
20384140Sjlemon	struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
20484140Sjlemon	struct ifnet *ifp = sc->mii_pdata->mii_ifp;
20584140Sjlemon	int reg;
20684140Sjlemon
20795718Sphk	/* Just bail now if the interface is down. */
20884140Sjlemon	if ((ifp->if_flags & IFF_UP) == 0)
20984140Sjlemon		return (EJUSTRETURN);
21084140Sjlemon
21184140Sjlemon	/*
21284140Sjlemon	 * If we're not doing autonegotiation, we don't need to do
21384140Sjlemon	 * any extra work here.  However, we need to check the link
21484140Sjlemon	 * status so we can generate an announcement if the status
21584140Sjlemon	 * changes.
21684140Sjlemon	 */
217160082Soleg	if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
218160082Soleg		sc->mii_ticks = 0;	/* reset autonegotiation timer. */
21984140Sjlemon		return (0);
220160082Soleg	}
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) {
225158649Soleg		sc->mii_ticks = 0;	/* reset autonegotiation timer. */
226158649Soleg		/* See above. */
22784140Sjlemon		return (0);
22895718Sphk	}
22984140Sjlemon
230158649Soleg	/* Announce link loss right after it happens */
231158649Soleg	if (sc->mii_ticks++ == 0)
232128870Sandre		return (0);
233158649Soleg
234158649Soleg	/* XXX: use default value if phy driver did not set mii_anegticks */
235158649Soleg	if (sc->mii_anegticks == 0)
236158649Soleg		sc->mii_anegticks = MII_ANEGTICKS_GIGE;
237158649Soleg
238158649Soleg	/* Only retry autonegotiation every mii_anegticks ticks. */
239158649Soleg	if (sc->mii_ticks <= sc->mii_anegticks)
24084140Sjlemon		return (EJUSTRETURN);
24184140Sjlemon
24284140Sjlemon	sc->mii_ticks = 0;
24384140Sjlemon	mii_phy_reset(sc);
24496026Sphk	mii_phy_auto(sc);
24584140Sjlemon	return (0);
24684140Sjlemon}
24784140Sjlemon
24850120Swpaulvoid
24995718Sphkmii_phy_reset(struct mii_softc *sc)
25050120Swpaul{
251164702Smarius	struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
25250120Swpaul	int reg, i;
25350120Swpaul
25495718Sphk	if (sc->mii_flags & MIIF_NOISOLATE)
25550120Swpaul		reg = BMCR_RESET;
25650120Swpaul	else
25750120Swpaul		reg = BMCR_RESET | BMCR_ISO;
25895718Sphk	PHY_WRITE(sc, MII_BMCR, reg);
25950120Swpaul
26050120Swpaul	/* Wait 100ms for it to complete. */
26150120Swpaul	for (i = 0; i < 100; i++) {
262164702Smarius		reg = PHY_READ(sc, MII_BMCR);
26350120Swpaul		if ((reg & BMCR_RESET) == 0)
26450120Swpaul			break;
26550120Swpaul		DELAY(1000);
26650120Swpaul	}
26750120Swpaul
268164702Smarius	if ((sc->mii_flags & MIIF_NOISOLATE) == 0) {
269164702Smarius		if ((ife == NULL && sc->mii_inst != 0) ||
270164702Smarius		    (ife != NULL && IFM_INST(ife->ifm_media) != sc->mii_inst))
271164702Smarius			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
272164702Smarius	}
27350120Swpaul}
27450120Swpaul
27584140Sjlemonvoid
27695722Sphkmii_phy_down(struct mii_softc *sc)
27784140Sjlemon{
27895722Sphk
27995722Sphk}
28095722Sphk
28195722Sphkvoid
28295722Sphkmii_phy_update(struct mii_softc *sc, int cmd)
28395722Sphk{
28484140Sjlemon	struct mii_data *mii = sc->mii_pdata;
28584140Sjlemon
28695722Sphk	if (sc->mii_media_active != mii->mii_media_active ||
28795722Sphk	    cmd == MII_MEDIACHG) {
28884140Sjlemon		MIIBUS_STATCHG(sc->mii_dev);
28995705Sphk		sc->mii_media_active = mii->mii_media_active;
29084140Sjlemon	}
29195705Sphk	if (sc->mii_media_status != mii->mii_media_status) {
29284140Sjlemon		MIIBUS_LINKCHG(sc->mii_dev);
29395705Sphk		sc->mii_media_status = mii->mii_media_status;
29484140Sjlemon	}
29584140Sjlemon}
29684140Sjlemon
29750120Swpaul/*
29850120Swpaul * Given an ifmedia word, return the corresponding ANAR value.
29950120Swpaul */
30050120Swpaulint
301141937Simpmii_anar(int media)
30250120Swpaul{
30350120Swpaul	int rv;
30450120Swpaul
30550120Swpaul	switch (media & (IFM_TMASK|IFM_NMASK|IFM_FDX)) {
30650120Swpaul	case IFM_ETHER|IFM_10_T:
30750120Swpaul		rv = ANAR_10|ANAR_CSMA;
30850120Swpaul		break;
30950120Swpaul	case IFM_ETHER|IFM_10_T|IFM_FDX:
31050120Swpaul		rv = ANAR_10_FD|ANAR_CSMA;
31150120Swpaul		break;
31250120Swpaul	case IFM_ETHER|IFM_100_TX:
31350120Swpaul		rv = ANAR_TX|ANAR_CSMA;
31450120Swpaul		break;
31550120Swpaul	case IFM_ETHER|IFM_100_TX|IFM_FDX:
31650120Swpaul		rv = ANAR_TX_FD|ANAR_CSMA;
31750120Swpaul		break;
31850120Swpaul	case IFM_ETHER|IFM_100_T4:
31950120Swpaul		rv = ANAR_T4|ANAR_CSMA;
32050120Swpaul		break;
32150120Swpaul	default:
32250120Swpaul		rv = 0;
32350120Swpaul		break;
32450120Swpaul	}
32550120Swpaul
32650120Swpaul	return (rv);
32750120Swpaul}
32850120Swpaul
32950120Swpaul/*
33050120Swpaul * Given a BMCR value, return the corresponding ifmedia word.
33150120Swpaul */
33250120Swpaulint
333141937Simpmii_media_from_bmcr(int bmcr)
33450120Swpaul{
33550120Swpaul	int rv = IFM_ETHER;
33650120Swpaul
33750120Swpaul	if (bmcr & BMCR_S100)
33850120Swpaul		rv |= IFM_100_TX;
33950120Swpaul	else
34050120Swpaul		rv |= IFM_10_T;
34150120Swpaul	if (bmcr & BMCR_FDX)
34250120Swpaul		rv |= IFM_FDX;
34350120Swpaul
34450120Swpaul	return (rv);
34550120Swpaul}
34650120Swpaul
34750120Swpaul/*
34850120Swpaul * Initialize generic PHY media based on BMSR, called when a PHY is
34950120Swpaul * attached.  We expect to be set up to print a comma-separated list
35050120Swpaul * of media names.  Does not print a newline.
35150120Swpaul */
35250120Swpaulvoid
35395667Sphkmii_add_media(struct mii_softc *sc)
35450120Swpaul{
35550120Swpaul	const char *sep = "";
35695667Sphk	struct mii_data *mii;
35750120Swpaul
35895667Sphk	mii = device_get_softc(sc->mii_dev);
35995707Sphk	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) {
36095665Sphk		printf("no media present");
36195665Sphk		return;
36295665Sphk	}
36395665Sphk
36450120Swpaul#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
36550120Swpaul#define	PRINT(s)	printf("%s%s", sep, s); sep = ", "
36650120Swpaul
36795707Sphk	if (sc->mii_capabilities & BMSR_10THDX) {
36895707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), 0);
36950120Swpaul		PRINT("10baseT");
37050120Swpaul	}
37195707Sphk	if (sc->mii_capabilities & BMSR_10TFDX) {
37295707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
37350120Swpaul		    BMCR_FDX);
37450120Swpaul		PRINT("10baseT-FDX");
37550120Swpaul	}
37695707Sphk	if (sc->mii_capabilities & BMSR_100TXHDX) {
37795707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
37850120Swpaul		    BMCR_S100);
37950120Swpaul		PRINT("100baseTX");
38050120Swpaul	}
38195707Sphk	if (sc->mii_capabilities & BMSR_100TXFDX) {
38295707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
38350120Swpaul		    BMCR_S100|BMCR_FDX);
38450120Swpaul		PRINT("100baseTX-FDX");
38550120Swpaul	}
38695707Sphk	if (sc->mii_capabilities & BMSR_100T4) {
38750120Swpaul		/*
38850120Swpaul		 * XXX How do you enable 100baseT4?  I assume we set
38950120Swpaul		 * XXX BMCR_S100 and then assume the PHYs will take
39050120Swpaul		 * XXX watever action is necessary to switch themselves
39150120Swpaul		 * XXX into T4 mode.
39250120Swpaul		 */
39395707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
39450120Swpaul		    BMCR_S100);
39550120Swpaul		PRINT("100baseT4");
39650120Swpaul	}
39795707Sphk	if (sc->mii_capabilities & BMSR_ANEG) {
39895707Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
39950120Swpaul		    BMCR_AUTOEN);
40050120Swpaul		PRINT("auto");
40150120Swpaul	}
40295667Sphk
40395667Sphk
40495667Sphk
40550120Swpaul#undef ADD
40650120Swpaul#undef PRINT
40750120Swpaul}
40895718Sphk
40995718Sphk/*
41095718Sphk * Initialize generic PHY media based on BMSR, called when a PHY is
41195718Sphk * attached.  We expect to be set up to print a comma-separated list
41295718Sphk * of media names.  Does not print a newline.
41395718Sphk */
41495718Sphkvoid
41595718Sphkmii_phy_add_media(struct mii_softc *sc)
41695718Sphk{
41795718Sphk	struct mii_data *mii = sc->mii_pdata;
41895718Sphk	const char *sep = "";
41995718Sphk
420158649Soleg	/* Set aneg timer for 10/100 media. Gigabit media handled below. */
421158649Soleg	sc->mii_anegticks = MII_ANEGTICKS;
422158649Soleg
42395718Sphk#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
42495718Sphk#define	PRINT(s)	printf("%s%s", sep, s); sep = ", "
42595718Sphk
42695718Sphk	if ((sc->mii_flags & MIIF_NOISOLATE) == 0)
42795718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
42895718Sphk		    MII_MEDIA_NONE);
42995718Sphk
43095718Sphk	/*
43195718Sphk	 * There are different interpretations for the bits in
43295718Sphk	 * HomePNA PHYs.  And there is really only one media type
43395718Sphk	 * that is supported.
43495718Sphk	 */
43595718Sphk	if (sc->mii_flags & MIIF_IS_HPNA) {
43695718Sphk		if (sc->mii_capabilities & BMSR_10THDX) {
43795718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0,
43895718Sphk					 sc->mii_inst),
43995718Sphk			    MII_MEDIA_10_T);
44095718Sphk			PRINT("HomePNA1");
44195718Sphk		}
44295718Sphk		return;
44395718Sphk	}
44495718Sphk
44595718Sphk	if (sc->mii_capabilities & BMSR_10THDX) {
44695718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
44795718Sphk		    MII_MEDIA_10_T);
44895718Sphk		PRINT("10baseT");
44995718Sphk	}
45095718Sphk	if (sc->mii_capabilities & BMSR_10TFDX) {
45195718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
45295718Sphk		    MII_MEDIA_10_T_FDX);
45395718Sphk		PRINT("10baseT-FDX");
45495718Sphk	}
45595718Sphk	if (sc->mii_capabilities & BMSR_100TXHDX) {
45695718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
45795718Sphk		    MII_MEDIA_100_TX);
45895718Sphk		PRINT("100baseTX");
45995718Sphk	}
46095718Sphk	if (sc->mii_capabilities & BMSR_100TXFDX) {
46195718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
46295718Sphk		    MII_MEDIA_100_TX_FDX);
46395718Sphk		PRINT("100baseTX-FDX");
46495718Sphk	}
46595718Sphk	if (sc->mii_capabilities & BMSR_100T4) {
46695718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
46795718Sphk		    MII_MEDIA_100_T4);
46895718Sphk		PRINT("100baseT4");
46995718Sphk	}
47095718Sphk
47195718Sphk	if (sc->mii_extcapabilities & EXTSR_MEDIAMASK) {
47295718Sphk		/*
47395718Sphk		 * XXX Right now only handle 1000SX and 1000TX.  Need
47495718Sphk		 * XXX to handle 1000LX and 1000CX some how.
47595718Sphk		 */
47695718Sphk		if (sc->mii_extcapabilities & EXTSR_1000XHDX) {
477158649Soleg			sc->mii_anegticks = MII_ANEGTICKS_GIGE;
47895718Sphk			sc->mii_flags |= MIIF_IS_1000X;
47995718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,
48095718Sphk			    sc->mii_inst), MII_MEDIA_1000_X);
48195718Sphk			PRINT("1000baseSX");
48295718Sphk		}
48395718Sphk		if (sc->mii_extcapabilities & EXTSR_1000XFDX) {
484158649Soleg			sc->mii_anegticks = MII_ANEGTICKS_GIGE;
48595718Sphk			sc->mii_flags |= MIIF_IS_1000X;
48695718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
48795718Sphk			    sc->mii_inst), MII_MEDIA_1000_X_FDX);
48895718Sphk			PRINT("1000baseSX-FDX");
48995718Sphk		}
49095718Sphk
49195718Sphk		/*
49295718Sphk		 * 1000baseT media needs to be able to manipulate
49395718Sphk		 * master/slave mode.  We set IFM_ETH_MASTER in
49495718Sphk		 * the "don't care mask" and filter it out when
49595718Sphk		 * the media is set.
49695718Sphk		 *
49795718Sphk		 * All 1000baseT PHYs have a 1000baseT control register.
49895718Sphk		 */
49995718Sphk		if (sc->mii_extcapabilities & EXTSR_1000THDX) {
500158649Soleg			sc->mii_anegticks = MII_ANEGTICKS_GIGE;
50195718Sphk			sc->mii_flags |= MIIF_HAVE_GTCR;
50295718Sphk			mii->mii_media.ifm_mask |= IFM_ETH_MASTER;
50395718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
50495718Sphk			    sc->mii_inst), MII_MEDIA_1000_T);
50595718Sphk			PRINT("1000baseT");
50695718Sphk		}
50795718Sphk		if (sc->mii_extcapabilities & EXTSR_1000TFDX) {
508158649Soleg			sc->mii_anegticks = MII_ANEGTICKS_GIGE;
50995718Sphk			sc->mii_flags |= MIIF_HAVE_GTCR;
51095718Sphk			mii->mii_media.ifm_mask |= IFM_ETH_MASTER;
51195718Sphk			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,
51295718Sphk			    sc->mii_inst), MII_MEDIA_1000_T_FDX);
51395718Sphk			PRINT("1000baseT-FDX");
51495718Sphk		}
51595718Sphk	}
51695718Sphk
51795718Sphk	if (sc->mii_capabilities & BMSR_ANEG) {
51895718Sphk		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
51995718Sphk		    MII_NMEDIA);	/* intentionally invalid index */
52095718Sphk		PRINT("auto");
52195718Sphk	}
52295718Sphk#undef ADD
52395718Sphk#undef PRINT
52495718Sphk}
52595718Sphk
52695722Sphkint
52795722Sphkmii_phy_detach(device_t dev)
52895722Sphk{
52995722Sphk	struct mii_softc *sc;
53095722Sphk
53195722Sphk	sc = device_get_softc(dev);
53295722Sphk	mii_phy_down(sc);
53395722Sphk	sc->mii_dev = NULL;
53495722Sphk	LIST_REMOVE(sc, mii_list);
53595722Sphk
53695722Sphk	return(0);
53795722Sphk}
53895724Sphk
53995724Sphkconst struct mii_phydesc *
540150756Simpmii_phy_match_gen(const struct mii_attach_args *ma,
541150756Simp  const struct mii_phydesc *mpd, size_t len)
54295724Sphk{
54395724Sphk
544150756Simp	for (; mpd->mpd_name != NULL;
545150756Simp	     mpd = (const struct mii_phydesc *) ((const char *) mpd + len)) {
54695724Sphk		if (MII_OUI(ma->mii_id1, ma->mii_id2) == mpd->mpd_oui &&
54795724Sphk		    MII_MODEL(ma->mii_id2) == mpd->mpd_model)
54895724Sphk			return (mpd);
54995724Sphk	}
55095724Sphk	return (NULL);
55195724Sphk}
552150756Simp
553150756Simpconst struct mii_phydesc *
554150756Simpmii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd)
555150756Simp{
556164702Smarius
557150756Simp	return (mii_phy_match_gen(ma, mpd, sizeof(struct mii_phydesc)));
558150756Simp}
559