mii_physubr.c revision 217414
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 * 2050120Swpaul * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2150120Swpaul * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2250120Swpaul * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2350120Swpaul * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2450120Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2550120Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2650120Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2750120Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2850120Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2950120Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3050120Swpaul * POSSIBILITY OF SUCH DAMAGE. 3150120Swpaul */ 3250120Swpaul 33119418Sobrien#include <sys/cdefs.h> 34119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/mii/mii_physubr.c 217414 2011-01-14 19:33:58Z marius $"); 35119418Sobrien 3650120Swpaul/* 3750120Swpaul * Subroutines common to all PHYs. 3850120Swpaul */ 3950120Swpaul 4050120Swpaul#include <sys/param.h> 4150120Swpaul#include <sys/systm.h> 4250120Swpaul#include <sys/kernel.h> 4350120Swpaul#include <sys/socket.h> 4450120Swpaul#include <sys/errno.h> 4550120Swpaul#include <sys/module.h> 4650120Swpaul#include <sys/bus.h> 4750120Swpaul 4850120Swpaul#include <net/if.h> 4950120Swpaul#include <net/if_media.h> 5050120Swpaul 5150120Swpaul#include <dev/mii/mii.h> 5250120Swpaul#include <dev/mii/miivar.h> 5350120Swpaul 5450120Swpaul#include "miibus_if.h" 5550120Swpaul 5695707Sphk/* 5795707Sphk * Media to register setting conversion table. Order matters. 5895707Sphk */ 59214265Smariusstatic const struct mii_media mii_media_table[MII_NMEDIA] = { 6095707Sphk /* None */ 6195707Sphk { BMCR_ISO, ANAR_CSMA, 6295707Sphk 0, }, 6395707Sphk 6495707Sphk /* 10baseT */ 6595707Sphk { BMCR_S10, ANAR_CSMA|ANAR_10, 6695707Sphk 0, }, 6795707Sphk 6895707Sphk /* 10baseT-FDX */ 6995707Sphk { BMCR_S10|BMCR_FDX, ANAR_CSMA|ANAR_10_FD, 7095707Sphk 0, }, 7195707Sphk 7295707Sphk /* 100baseT4 */ 7395707Sphk { BMCR_S100, ANAR_CSMA|ANAR_T4, 7495707Sphk 0, }, 7595707Sphk 7695707Sphk /* 100baseTX */ 7795707Sphk { BMCR_S100, ANAR_CSMA|ANAR_TX, 7895707Sphk 0, }, 7995707Sphk 8095707Sphk /* 100baseTX-FDX */ 8195707Sphk { BMCR_S100|BMCR_FDX, ANAR_CSMA|ANAR_TX_FD, 8295707Sphk 0, }, 8395707Sphk 8495707Sphk /* 1000baseX */ 8595707Sphk { BMCR_S1000, ANAR_CSMA, 8695707Sphk 0, }, 8795707Sphk 8895707Sphk /* 1000baseX-FDX */ 8995707Sphk { BMCR_S1000|BMCR_FDX, ANAR_CSMA, 9095707Sphk 0, }, 9195707Sphk 9295707Sphk /* 1000baseT */ 9395707Sphk { BMCR_S1000, ANAR_CSMA, 9495707Sphk GTCR_ADV_1000THDX }, 9595707Sphk 9695707Sphk /* 1000baseT-FDX */ 9795707Sphk { BMCR_S1000, ANAR_CSMA, 9895707Sphk GTCR_ADV_1000TFDX }, 9995707Sphk}; 10095707Sphk 10195707Sphkvoid 10295707Sphkmii_phy_setmedia(struct mii_softc *sc) 10395707Sphk{ 10495707Sphk struct mii_data *mii = sc->mii_pdata; 10595707Sphk struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 10695707Sphk int bmcr, anar, gtcr; 10795707Sphk 10895707Sphk if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { 109215297Smarius /* 110215297Smarius * Force renegotiation if MIIF_DOPAUSE or MIIF_FORCEANEG. 111215297Smarius * The former is necessary as we might switch from flow- 112215297Smarius * control advertisment being off to on or vice versa. 113215297Smarius */ 114164702Smarius if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0 || 115215297Smarius (sc->mii_flags & (MIIF_DOPAUSE | MIIF_FORCEANEG)) != 0) 116214606Smarius (void)mii_phy_auto(sc); 11795707Sphk return; 11895707Sphk } 11995707Sphk 12095707Sphk /* 12195707Sphk * Table index is stored in the media entry. 12295707Sphk */ 12395707Sphk 12495718Sphk KASSERT(ife->ifm_data >=0 && ife->ifm_data < MII_NMEDIA, 12595718Sphk ("invalid ife->ifm_data (0x%x) in mii_phy_setmedia", 12695718Sphk ife->ifm_data)); 12795707Sphk 12895707Sphk anar = mii_media_table[ife->ifm_data].mm_anar; 12995707Sphk bmcr = mii_media_table[ife->ifm_data].mm_bmcr; 13095707Sphk gtcr = mii_media_table[ife->ifm_data].mm_gtcr; 13195707Sphk 132215297Smarius if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { 133215297Smarius gtcr |= GTCR_MAN_MS; 134215297Smarius if ((ife->ifm_media & IFM_ETH_MASTER) != 0) 135215297Smarius gtcr |= GTCR_ADV_MS; 136215297Smarius } 13795707Sphk 138217414Smarius if ((ife->ifm_media & IFM_FDX) != 0 && 139217414Smarius ((ife->ifm_media & IFM_FLOW) != 0 || 140217414Smarius (sc->mii_flags & MIIF_FORCEPAUSE) != 0)) { 141215297Smarius if ((sc->mii_flags & MIIF_IS_1000X) != 0) 142215297Smarius anar |= ANAR_X_PAUSE_TOWARDS; 143215297Smarius else { 144215297Smarius anar |= ANAR_FC; 145215297Smarius /* XXX Only 1000BASE-T has PAUSE_ASYM? */ 146215297Smarius if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0 && 147215297Smarius (sc->mii_extcapabilities & 148215297Smarius (EXTSR_1000THDX | EXTSR_1000TFDX)) != 0) 149215297Smarius anar |= ANAR_X_PAUSE_ASYM; 15095707Sphk } 15195707Sphk } 15295707Sphk 153214606Smarius if ((ife->ifm_media & IFM_LOOP) != 0) 15495707Sphk bmcr |= BMCR_LOOP; 15595707Sphk 15695707Sphk PHY_WRITE(sc, MII_ANAR, anar); 15795707Sphk PHY_WRITE(sc, MII_BMCR, bmcr); 158214606Smarius if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) 15995707Sphk PHY_WRITE(sc, MII_100T2CR, gtcr); 16095707Sphk} 16195707Sphk 16250120Swpaulint 16396026Sphkmii_phy_auto(struct mii_softc *sc) 16450120Swpaul{ 165215297Smarius struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur; 166214606Smarius int anar, gtcr; 16750120Swpaul 16896026Sphk /* 16996026Sphk * Check for 1000BASE-X. Autonegotiation is a bit 17096026Sphk * different on such devices. 17196026Sphk */ 172214606Smarius if ((sc->mii_flags & MIIF_IS_1000X) != 0) { 173214606Smarius anar = 0; 174214606Smarius if ((sc->mii_extcapabilities & EXTSR_1000XFDX) != 0) 17596026Sphk anar |= ANAR_X_FD; 176214606Smarius if ((sc->mii_extcapabilities & EXTSR_1000XHDX) != 0) 17796026Sphk anar |= ANAR_X_HD; 17895718Sphk 179215297Smarius if ((ife->ifm_media & IFM_FLOW) != 0 || 180215297Smarius (sc->mii_flags & MIIF_FORCEPAUSE) != 0) 181215297Smarius anar |= ANAR_X_PAUSE_TOWARDS; 18296026Sphk PHY_WRITE(sc, MII_ANAR, anar); 18396026Sphk } else { 18496026Sphk anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | 18596026Sphk ANAR_CSMA; 186215297Smarius if ((ife->ifm_media & IFM_FLOW) != 0 || 187215297Smarius (sc->mii_flags & MIIF_FORCEPAUSE) != 0) { 188217414Smarius if ((sc->mii_capabilities & 189217414Smarius (BMSR_10TFDX | BMSR_100TXFDX)) != 0) 190215297Smarius anar |= ANAR_FC; 191215297Smarius /* XXX Only 1000BASE-T has PAUSE_ASYM? */ 192215297Smarius if (((sc->mii_flags & MIIF_HAVE_GTCR) != 0) && 193215297Smarius (sc->mii_extcapabilities & 194215297Smarius (EXTSR_1000THDX | EXTSR_1000TFDX)) != 0) 195215297Smarius anar |= ANAR_X_PAUSE_ASYM; 196215297Smarius } 19796026Sphk PHY_WRITE(sc, MII_ANAR, anar); 198214606Smarius if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) { 199214606Smarius gtcr = 0; 200214606Smarius if ((sc->mii_extcapabilities & EXTSR_1000TFDX) != 0) 20196026Sphk gtcr |= GTCR_ADV_1000TFDX; 202214606Smarius if ((sc->mii_extcapabilities & EXTSR_1000THDX) != 0) 20396026Sphk gtcr |= GTCR_ADV_1000THDX; 20496026Sphk PHY_WRITE(sc, MII_100T2CR, gtcr); 20595718Sphk } 20650120Swpaul } 20796026Sphk PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); 20850120Swpaul return (EJUSTRETURN); 20950120Swpaul} 21050120Swpaul 21184140Sjlemonint 21295718Sphkmii_phy_tick(struct mii_softc *sc) 21384140Sjlemon{ 21484140Sjlemon struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur; 21584140Sjlemon struct ifnet *ifp = sc->mii_pdata->mii_ifp; 21684140Sjlemon int reg; 21784140Sjlemon 21895718Sphk /* Just bail now if the interface is down. */ 21984140Sjlemon if ((ifp->if_flags & IFF_UP) == 0) 22084140Sjlemon return (EJUSTRETURN); 22184140Sjlemon 22284140Sjlemon /* 22384140Sjlemon * If we're not doing autonegotiation, we don't need to do 22484140Sjlemon * any extra work here. However, we need to check the link 22584140Sjlemon * status so we can generate an announcement if the status 22684140Sjlemon * changes. 22784140Sjlemon */ 228160082Soleg if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { 229160082Soleg sc->mii_ticks = 0; /* reset autonegotiation timer. */ 23084140Sjlemon return (0); 231160082Soleg } 23284140Sjlemon 23395718Sphk /* Read the status register twice; BMSR_LINK is latch-low. */ 23484140Sjlemon reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 235214606Smarius if ((reg & BMSR_LINK) != 0) { 236158649Soleg sc->mii_ticks = 0; /* reset autonegotiation timer. */ 237158649Soleg /* See above. */ 23884140Sjlemon return (0); 23995718Sphk } 24084140Sjlemon 241158649Soleg /* Announce link loss right after it happens */ 242158649Soleg if (sc->mii_ticks++ == 0) 243128870Sandre return (0); 244158649Soleg 245158649Soleg /* XXX: use default value if phy driver did not set mii_anegticks */ 246158649Soleg if (sc->mii_anegticks == 0) 247158649Soleg sc->mii_anegticks = MII_ANEGTICKS_GIGE; 248158649Soleg 249158649Soleg /* Only retry autonegotiation every mii_anegticks ticks. */ 250158649Soleg if (sc->mii_ticks <= sc->mii_anegticks) 25184140Sjlemon return (EJUSTRETURN); 25284140Sjlemon 25384140Sjlemon sc->mii_ticks = 0; 25484140Sjlemon mii_phy_reset(sc); 25596026Sphk mii_phy_auto(sc); 25684140Sjlemon return (0); 25784140Sjlemon} 25884140Sjlemon 25950120Swpaulvoid 26095718Sphkmii_phy_reset(struct mii_softc *sc) 26150120Swpaul{ 262164702Smarius struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur; 26350120Swpaul int reg, i; 26450120Swpaul 265214606Smarius if ((sc->mii_flags & MIIF_NOISOLATE) != 0) 26650120Swpaul reg = BMCR_RESET; 26750120Swpaul else 26850120Swpaul reg = BMCR_RESET | BMCR_ISO; 26995718Sphk PHY_WRITE(sc, MII_BMCR, reg); 27050120Swpaul 27150120Swpaul /* Wait 100ms for it to complete. */ 27250120Swpaul for (i = 0; i < 100; i++) { 273164702Smarius reg = PHY_READ(sc, MII_BMCR); 27450120Swpaul if ((reg & BMCR_RESET) == 0) 27550120Swpaul break; 27650120Swpaul DELAY(1000); 27750120Swpaul } 27850120Swpaul 279164702Smarius if ((sc->mii_flags & MIIF_NOISOLATE) == 0) { 280164702Smarius if ((ife == NULL && sc->mii_inst != 0) || 281164702Smarius (ife != NULL && IFM_INST(ife->ifm_media) != sc->mii_inst)) 282164702Smarius PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 283164702Smarius } 28450120Swpaul} 28550120Swpaul 28684140Sjlemonvoid 28795722Sphkmii_phy_down(struct mii_softc *sc) 28884140Sjlemon{ 28995722Sphk 29095722Sphk} 29195722Sphk 29295722Sphkvoid 29395722Sphkmii_phy_update(struct mii_softc *sc, int cmd) 29495722Sphk{ 29584140Sjlemon struct mii_data *mii = sc->mii_pdata; 29684140Sjlemon 29795722Sphk if (sc->mii_media_active != mii->mii_media_active || 29895722Sphk cmd == MII_MEDIACHG) { 29984140Sjlemon MIIBUS_STATCHG(sc->mii_dev); 30095705Sphk sc->mii_media_active = mii->mii_media_active; 30184140Sjlemon } 30295705Sphk if (sc->mii_media_status != mii->mii_media_status) { 30384140Sjlemon MIIBUS_LINKCHG(sc->mii_dev); 30495705Sphk sc->mii_media_status = mii->mii_media_status; 30584140Sjlemon } 30684140Sjlemon} 30784140Sjlemon 30850120Swpaul/* 30950120Swpaul * Initialize generic PHY media based on BMSR, called when a PHY is 31050120Swpaul * attached. We expect to be set up to print a comma-separated list 31150120Swpaul * of media names. Does not print a newline. 31250120Swpaul */ 31350120Swpaulvoid 31495718Sphkmii_phy_add_media(struct mii_softc *sc) 31595718Sphk{ 31695718Sphk struct mii_data *mii = sc->mii_pdata; 31795718Sphk const char *sep = ""; 318215297Smarius int fdx = 0; 31995718Sphk 320164703Smarius if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 && 321164703Smarius (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) { 322164703Smarius printf("no media present"); 323164703Smarius return; 324164703Smarius } 325164703Smarius 326214606Smarius /* 327214606Smarius * Set the autonegotiation timer for 10/100 media. Gigabit media is 328214606Smarius * handled below. 329214606Smarius */ 330158649Soleg sc->mii_anegticks = MII_ANEGTICKS; 331158649Soleg 33295718Sphk#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 33395718Sphk#define PRINT(s) printf("%s%s", sep, s); sep = ", " 33495718Sphk 33595718Sphk if ((sc->mii_flags & MIIF_NOISOLATE) == 0) 33695718Sphk ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), 33795718Sphk MII_MEDIA_NONE); 33895718Sphk 33995718Sphk /* 34095718Sphk * There are different interpretations for the bits in 34195718Sphk * HomePNA PHYs. And there is really only one media type 34295718Sphk * that is supported. 34395718Sphk */ 344214606Smarius if ((sc->mii_flags & MIIF_IS_HPNA) != 0) { 345214606Smarius if ((sc->mii_capabilities & BMSR_10THDX) != 0) { 34695718Sphk ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, 347214606Smarius sc->mii_inst), MII_MEDIA_10_T); 34895718Sphk PRINT("HomePNA1"); 34995718Sphk } 35095718Sphk return; 35195718Sphk } 35295718Sphk 353214606Smarius if ((sc->mii_capabilities & BMSR_10THDX) != 0) { 35495718Sphk ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), 35595718Sphk MII_MEDIA_10_T); 35695718Sphk PRINT("10baseT"); 35795718Sphk } 358214606Smarius if ((sc->mii_capabilities & BMSR_10TFDX) != 0) { 35995718Sphk ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), 36095718Sphk MII_MEDIA_10_T_FDX); 36195718Sphk PRINT("10baseT-FDX"); 362215297Smarius if ((sc->mii_flags & MIIF_DOPAUSE) != 0 && 363215297Smarius (sc->mii_flags & MIIF_NOMANPAUSE) == 0) { 364215297Smarius ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 365215297Smarius IFM_FDX | IFM_FLOW, sc->mii_inst), 366215297Smarius MII_MEDIA_10_T_FDX); 367215297Smarius PRINT("10baseT-FDX-flow"); 368215297Smarius } 369215297Smarius fdx = 1; 37095718Sphk } 371214606Smarius if ((sc->mii_capabilities & BMSR_100TXHDX) != 0) { 37295718Sphk ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), 37395718Sphk MII_MEDIA_100_TX); 37495718Sphk PRINT("100baseTX"); 37595718Sphk } 376214606Smarius if ((sc->mii_capabilities & BMSR_100TXFDX) != 0) { 37795718Sphk ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), 37895718Sphk MII_MEDIA_100_TX_FDX); 37995718Sphk PRINT("100baseTX-FDX"); 380215297Smarius if ((sc->mii_flags & MIIF_DOPAUSE) != 0 && 381215297Smarius (sc->mii_flags & MIIF_NOMANPAUSE) == 0) { 382215297Smarius ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 383215297Smarius IFM_FDX | IFM_FLOW, sc->mii_inst), 384215297Smarius MII_MEDIA_100_TX_FDX); 385215297Smarius PRINT("100baseTX-FDX-flow"); 386215297Smarius } 387215297Smarius fdx = 1; 38895718Sphk } 389214606Smarius if ((sc->mii_capabilities & BMSR_100T4) != 0) { 39095718Sphk ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst), 39195718Sphk MII_MEDIA_100_T4); 39295718Sphk PRINT("100baseT4"); 39395718Sphk } 39495718Sphk 395214606Smarius if ((sc->mii_extcapabilities & EXTSR_MEDIAMASK) != 0) { 39695718Sphk /* 39795718Sphk * XXX Right now only handle 1000SX and 1000TX. Need 398214606Smarius * XXX to handle 1000LX and 1000CX somehow. 39995718Sphk */ 400214606Smarius if ((sc->mii_extcapabilities & EXTSR_1000XHDX) != 0) { 401158649Soleg sc->mii_anegticks = MII_ANEGTICKS_GIGE; 40295718Sphk sc->mii_flags |= MIIF_IS_1000X; 40395718Sphk ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, 40495718Sphk sc->mii_inst), MII_MEDIA_1000_X); 40595718Sphk PRINT("1000baseSX"); 40695718Sphk } 407214606Smarius if ((sc->mii_extcapabilities & EXTSR_1000XFDX) != 0) { 408158649Soleg sc->mii_anegticks = MII_ANEGTICKS_GIGE; 40995718Sphk sc->mii_flags |= MIIF_IS_1000X; 41095718Sphk ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, 41195718Sphk sc->mii_inst), MII_MEDIA_1000_X_FDX); 41295718Sphk PRINT("1000baseSX-FDX"); 413215297Smarius if ((sc->mii_flags & MIIF_DOPAUSE) != 0 && 414215297Smarius (sc->mii_flags & MIIF_NOMANPAUSE) == 0) { 415215297Smarius ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 416215297Smarius IFM_FDX | IFM_FLOW, sc->mii_inst), 417215297Smarius MII_MEDIA_1000_X_FDX); 418215297Smarius PRINT("1000baseSX-FDX-flow"); 419215297Smarius } 420215297Smarius fdx = 1; 42195718Sphk } 42295718Sphk 42395718Sphk /* 42495718Sphk * 1000baseT media needs to be able to manipulate 425215297Smarius * master/slave mode. 42695718Sphk * 42795718Sphk * All 1000baseT PHYs have a 1000baseT control register. 42895718Sphk */ 429214606Smarius if ((sc->mii_extcapabilities & EXTSR_1000THDX) != 0) { 430158649Soleg sc->mii_anegticks = MII_ANEGTICKS_GIGE; 43195718Sphk sc->mii_flags |= MIIF_HAVE_GTCR; 43295718Sphk ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, 43395718Sphk sc->mii_inst), MII_MEDIA_1000_T); 43495718Sphk PRINT("1000baseT"); 435215297Smarius ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 436215297Smarius IFM_ETH_MASTER, sc->mii_inst), MII_MEDIA_1000_T); 437215297Smarius PRINT("1000baseT-master"); 43895718Sphk } 439214606Smarius if ((sc->mii_extcapabilities & EXTSR_1000TFDX) != 0) { 440158649Soleg sc->mii_anegticks = MII_ANEGTICKS_GIGE; 44195718Sphk sc->mii_flags |= MIIF_HAVE_GTCR; 44295718Sphk ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, 44395718Sphk sc->mii_inst), MII_MEDIA_1000_T_FDX); 44495718Sphk PRINT("1000baseT-FDX"); 445215297Smarius ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 446215297Smarius IFM_FDX | IFM_ETH_MASTER, sc->mii_inst), 447215297Smarius MII_MEDIA_1000_T_FDX); 448215297Smarius PRINT("1000baseT-FDX-master"); 449215297Smarius if ((sc->mii_flags & MIIF_DOPAUSE) != 0 && 450215297Smarius (sc->mii_flags & MIIF_NOMANPAUSE) == 0) { 451215297Smarius ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 452215297Smarius IFM_FDX | IFM_FLOW, sc->mii_inst), 453215297Smarius MII_MEDIA_1000_T_FDX); 454215297Smarius PRINT("1000baseT-FDX-flow"); 455215297Smarius ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 456215297Smarius IFM_FDX | IFM_FLOW | IFM_ETH_MASTER, 457215297Smarius sc->mii_inst), MII_MEDIA_1000_T_FDX); 458215297Smarius PRINT("1000baseT-FDX-flow-master"); 459215297Smarius } 460215297Smarius fdx = 1; 46195718Sphk } 46295718Sphk } 46395718Sphk 464214606Smarius if ((sc->mii_capabilities & BMSR_ANEG) != 0) { 465215297Smarius /* intentionally invalid index */ 46695718Sphk ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 467215297Smarius MII_NMEDIA); 46895718Sphk PRINT("auto"); 469215297Smarius if (fdx != 0 && (sc->mii_flags & MIIF_DOPAUSE) != 0) { 470215297Smarius ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, IFM_FLOW, 471215297Smarius sc->mii_inst), MII_NMEDIA); 472215297Smarius PRINT("auto-flow"); 473215297Smarius } 47495718Sphk } 47595718Sphk#undef ADD 47695718Sphk#undef PRINT 47795718Sphk} 47895718Sphk 47995722Sphkint 48095722Sphkmii_phy_detach(device_t dev) 48195722Sphk{ 48295722Sphk struct mii_softc *sc; 48395722Sphk 48495722Sphk sc = device_get_softc(dev); 48595722Sphk mii_phy_down(sc); 48695722Sphk sc->mii_dev = NULL; 48795722Sphk LIST_REMOVE(sc, mii_list); 488214606Smarius return (0); 48995722Sphk} 49095724Sphk 49195724Sphkconst struct mii_phydesc * 492150756Simpmii_phy_match_gen(const struct mii_attach_args *ma, 493150756Simp const struct mii_phydesc *mpd, size_t len) 49495724Sphk{ 49595724Sphk 496150756Simp for (; mpd->mpd_name != NULL; 497215297Smarius mpd = (const struct mii_phydesc *)((const char *)mpd + len)) { 49895724Sphk if (MII_OUI(ma->mii_id1, ma->mii_id2) == mpd->mpd_oui && 49995724Sphk MII_MODEL(ma->mii_id2) == mpd->mpd_model) 50095724Sphk return (mpd); 50195724Sphk } 50295724Sphk return (NULL); 50395724Sphk} 504150756Simp 505150756Simpconst struct mii_phydesc * 506150756Simpmii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd) 507150756Simp{ 508164702Smarius 509150756Simp return (mii_phy_match_gen(ma, mpd, sizeof(struct mii_phydesc))); 510150756Simp} 511164827Smarius 512164827Smariusint 513164827Smariusmii_phy_dev_probe(device_t dev, const struct mii_phydesc *mpd, int mrv) 514164827Smarius{ 515164827Smarius 516164827Smarius mpd = mii_phy_match(device_get_ivars(dev), mpd); 517164827Smarius if (mpd != NULL) { 518164827Smarius device_set_desc(dev, mpd->mpd_name); 519164827Smarius return (mrv); 520164827Smarius } 521164827Smarius return (ENXIO); 522164827Smarius} 523215297Smarius 524215297Smarius/* 525215297Smarius * Return the flow control status flag from MII_ANAR & MII_ANLPAR. 526215297Smarius */ 527215297Smariusu_int 528215297Smariusmii_phy_flowstatus(struct mii_softc *sc) 529215297Smarius{ 530215297Smarius int anar, anlpar; 531215297Smarius 532215297Smarius if ((sc->mii_flags & MIIF_DOPAUSE) == 0) 533215297Smarius return (0); 534215297Smarius 535215297Smarius anar = PHY_READ(sc, MII_ANAR); 536215297Smarius anlpar = PHY_READ(sc, MII_ANLPAR); 537215297Smarius 538215297Smarius /* 539215297Smarius * Check for 1000BASE-X. Autonegotiation is a bit 540215297Smarius * different on such devices. 541215297Smarius */ 542215297Smarius if ((sc->mii_flags & MIIF_IS_1000X) != 0) { 543215297Smarius anar <<= 3; 544215297Smarius anlpar <<= 3; 545215297Smarius } 546215297Smarius 547215297Smarius if ((anar & ANAR_PAUSE_SYM) != 0 && (anlpar & ANLPAR_PAUSE_SYM) != 0) 548215297Smarius return (IFM_FLOW | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE); 549215297Smarius 550215297Smarius if ((anar & ANAR_PAUSE_SYM) == 0) { 551215297Smarius if ((anar & ANAR_PAUSE_ASYM) != 0 && 552215297Smarius (anlpar & ANLPAR_PAUSE_TOWARDS) != 0) 553215297Smarius return (IFM_FLOW | IFM_ETH_TXPAUSE); 554215297Smarius else 555215297Smarius return (0); 556215297Smarius } 557215297Smarius 558215297Smarius if ((anar & ANAR_PAUSE_ASYM) == 0) { 559215297Smarius if ((anlpar & ANLPAR_PAUSE_SYM) != 0) 560215297Smarius return (IFM_FLOW | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE); 561215297Smarius else 562215297Smarius return (0); 563215297Smarius } 564215297Smarius 565215297Smarius switch ((anlpar & ANLPAR_PAUSE_TOWARDS)) { 566215297Smarius case ANLPAR_PAUSE_NONE: 567215297Smarius return (0); 568215297Smarius case ANLPAR_PAUSE_ASYM: 569215297Smarius return (IFM_FLOW | IFM_ETH_RXPAUSE); 570215297Smarius default: 571215297Smarius return (IFM_FLOW | IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE); 572215297Smarius } 573215297Smarius /* NOTREACHED */ 574215297Smarius} 575