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