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