diff options
author | dim <dim@FreeBSD.org> | 2010-11-14 20:47:30 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2010-11-14 20:47:30 +0000 |
commit | b355314642d1e24edf4e05d08b793f8b9ea76458 (patch) | |
tree | 06fb324a8697fbee8ca1e10b6e5ed702632baffc /sys/dev | |
parent | 466abdddb672857d5af81ed2471904a9b734a52b (diff) | |
download | FreeBSD-src-b355314642d1e24edf4e05d08b793f8b9ea76458.zip FreeBSD-src-b355314642d1e24edf4e05d08b793f8b9ea76458.tar.gz |
Sync: merge r215273 through r215318 from ^/head.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/arcmsr/arcmsr.c | 4 | ||||
-rw-r--r-- | sys/dev/bce/if_bce.c | 7 | ||||
-rw-r--r-- | sys/dev/bge/if_bge.c | 34 | ||||
-rw-r--r-- | sys/dev/mii/atphy.c | 36 | ||||
-rw-r--r-- | sys/dev/mii/brgphy.c | 202 | ||||
-rw-r--r-- | sys/dev/mii/ciphy.c | 30 | ||||
-rw-r--r-- | sys/dev/mii/e1000phy.c | 82 | ||||
-rw-r--r-- | sys/dev/mii/gentbi.c | 3 | ||||
-rw-r--r-- | sys/dev/mii/ip1000phy.c | 63 | ||||
-rw-r--r-- | sys/dev/mii/jmphy.c | 37 | ||||
-rw-r--r-- | sys/dev/mii/mii.h | 9 | ||||
-rw-r--r-- | sys/dev/mii/mii_physubr.c | 162 | ||||
-rw-r--r-- | sys/dev/mii/miivar.h | 4 | ||||
-rw-r--r-- | sys/dev/mii/nsgphy.c | 3 | ||||
-rw-r--r-- | sys/dev/mii/rgephy.c | 78 | ||||
-rw-r--r-- | sys/dev/mii/smcphy.c | 10 | ||||
-rw-r--r-- | sys/dev/mii/ukphy_subr.c | 7 | ||||
-rw-r--r-- | sys/dev/mii/xmphy.c | 5 | ||||
-rw-r--r-- | sys/dev/msk/if_msk.c | 12 | ||||
-rw-r--r-- | sys/dev/nfe/if_nfe.c | 8 | ||||
-rw-r--r-- | sys/dev/stge/if_stge.c | 6 |
21 files changed, 407 insertions, 395 deletions
diff --git a/sys/dev/arcmsr/arcmsr.c b/sys/dev/arcmsr/arcmsr.c index c175522..fe7c90b 100644 --- a/sys/dev/arcmsr/arcmsr.c +++ b/sys/dev/arcmsr/arcmsr.c @@ -2470,11 +2470,15 @@ static void arcmsr_action(struct cam_sim * psim, union ccb * pccb) splx(s); } else { /* Buffer is physical */ +#ifdef PAE + panic("arcmsr: CAM_DATA_PHYS not supported"); +#else struct bus_dma_segment seg; seg.ds_addr = (bus_addr_t)pccb->csio.data_ptr; seg.ds_len = pccb->csio.dxfer_len; arcmsr_execute_srb(srb, &seg, 1, 0); +#endif } } else { /* Scatter/gather list */ diff --git a/sys/dev/bce/if_bce.c b/sys/dev/bce/if_bce.c index 2d38b8e..c9200f3 100644 --- a/sys/dev/bce/if_bce.c +++ b/sys/dev/bce/if_bce.c @@ -1143,7 +1143,7 @@ bce_attach(device_t dev) /* MII child bus by attaching the PHY. */ rc = mii_attach(dev, &sc->bce_miibus, ifp, bce_ifmedia_upd, bce_ifmedia_sts, BMSR_DEFCAPMASK, sc->bce_phy_addr, - MII_OFFSET_ANY, 0); + MII_OFFSET_ANY, MIIF_DOPAUSE); if (rc != 0) { BCE_PRINTF("%s(%d): attaching PHYs failed\n", __FILE__, __LINE__); @@ -1769,8 +1769,7 @@ bce_miibus_statchg(device_t dev) REG_WR(sc, BCE_EMAC_MODE, val); - /* FLAG0 is set if RX is enabled and FLAG1 if TX is enabled */ - if (mii->mii_media_active & IFM_FLAG0) { + if ((mii->mii_media_active & IFM_ETH_RXPAUSE) != 0) { DBPRINT(sc, BCE_INFO_PHY, "%s(): Enabling RX flow control.\n", __FUNCTION__); BCE_SETBIT(sc, BCE_EMAC_RX_MODE, BCE_EMAC_RX_MODE_FLOW_EN); @@ -1780,7 +1779,7 @@ bce_miibus_statchg(device_t dev) BCE_CLRBIT(sc, BCE_EMAC_RX_MODE, BCE_EMAC_RX_MODE_FLOW_EN); } - if (mii->mii_media_active & IFM_FLAG1) { + if ((mii->mii_media_active & IFM_ETH_TXPAUSE) != 0) { DBPRINT(sc, BCE_INFO_PHY, "%s(): Enabling TX flow control.\n", __FUNCTION__); BCE_SETBIT(sc, BCE_EMAC_TX_MODE, BCE_EMAC_TX_MODE_FLOW_EN); diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c index 59ce673..c3bdcaf 100644 --- a/sys/dev/bge/if_bge.c +++ b/sys/dev/bge/if_bge.c @@ -914,11 +914,13 @@ bge_miibus_statchg(device_t dev) if (IFM_OPTIONS(mii->mii_media_active & IFM_FDX) != 0) { BGE_CLRBIT(sc, BGE_MAC_MODE, BGE_MACMODE_HALF_DUPLEX); - if (IFM_OPTIONS(mii->mii_media_active) & IFM_FLAG1) + if ((IFM_OPTIONS(mii->mii_media_active) & + IFM_ETH_TXPAUSE) != 0) BGE_SETBIT(sc, BGE_TX_MODE, BGE_TXMODE_FLOWCTL_ENABLE); else BGE_CLRBIT(sc, BGE_TX_MODE, BGE_TXMODE_FLOWCTL_ENABLE); - if (IFM_OPTIONS(mii->mii_media_active) & IFM_FLAG0) + if ((IFM_OPTIONS(mii->mii_media_active) & + IFM_ETH_RXPAUSE) != 0) BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_FLOWCTL_ENABLE); else BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_FLOWCTL_ENABLE); @@ -2638,7 +2640,7 @@ bge_attach(device_t dev) struct bge_softc *sc; uint32_t hwcfg = 0, misccfg; u_char eaddr[ETHER_ADDR_LEN]; - int error, f, msicount, phy_addr, reg, rid, trys; + int capmask, error, f, msicount, phy_addr, reg, rid, trys; sc = device_get_softc(dev); sc->bge_dev = dev; @@ -2822,13 +2824,31 @@ bge_attach(device_t dev) if (BGE_IS_5755_PLUS(sc) == 0) sc->bge_flags |= BGE_FLAG_4G_BNDRY_BUG; + misccfg = CSR_READ_4(sc, BGE_MISC_CFG) & BGE_MISCCFG_BOARD_ID; if (sc->bge_asicrev == BGE_ASICREV_BCM5705) { - misccfg = CSR_READ_4(sc, BGE_MISC_CFG) & BGE_MISCCFG_BOARD_ID; if (misccfg == BGE_MISCCFG_BOARD_ID_5788 || misccfg == BGE_MISCCFG_BOARD_ID_5788M) sc->bge_flags |= BGE_FLAG_5788; } + capmask = BMSR_DEFCAPMASK; + if ((sc->bge_asicrev == BGE_ASICREV_BCM5703 && + (misccfg == 0x4000 || misccfg == 0x8000)) || + (sc->bge_asicrev == BGE_ASICREV_BCM5705 && + pci_get_vendor(dev) == BCOM_VENDORID && + (pci_get_device(dev) == BCOM_DEVICEID_BCM5901 || + pci_get_device(dev) == BCOM_DEVICEID_BCM5901A2 || + pci_get_device(dev) == BCOM_DEVICEID_BCM5705F)) || + (pci_get_vendor(dev) == BCOM_VENDORID && + (pci_get_device(dev) == BCOM_DEVICEID_BCM5751F || + pci_get_device(dev) == BCOM_DEVICEID_BCM5753F || + pci_get_device(dev) == BCOM_DEVICEID_BCM5787F)) || + pci_get_device(dev) == BCOM_DEVICEID_BCM57790 || + sc->bge_asicrev == BGE_ASICREV_BCM5906) { + /* These chips are 10/100 only. */ + capmask &= ~BMSR_EXTSTAT; + } + /* * Some controllers seem to require a special firmware to use * TSO. But the firmware is not available to FreeBSD and Linux @@ -3102,9 +3122,9 @@ bge_attach(device_t dev) again: bge_asf_driver_up(sc); - error = (mii_attach(dev, &sc->bge_miibus, ifp, - bge_ifmedia_upd, bge_ifmedia_sts, BMSR_DEFCAPMASK, - phy_addr, MII_OFFSET_ANY, 0)); + error = mii_attach(dev, &sc->bge_miibus, ifp, bge_ifmedia_upd, + bge_ifmedia_sts, capmask, phy_addr, MII_OFFSET_ANY, + MIIF_DOPAUSE); if (error != 0) { if (trys++ < 4) { device_printf(sc->bge_dev, "Try again\n"); diff --git a/sys/dev/mii/atphy.c b/sys/dev/mii/atphy.c index 41cd72c..cfabd21 100644 --- a/sys/dev/mii/atphy.c +++ b/sys/dev/mii/atphy.c @@ -82,7 +82,7 @@ static int atphy_service(struct mii_softc *, struct mii_data *, int); static void atphy_status(struct mii_softc *); static void atphy_reset(struct mii_softc *); static uint16_t atphy_anar(struct ifmedia_entry *); -static int atphy_auto(struct mii_softc *); +static int atphy_setmedia(struct mii_softc *, int); static const struct mii_phydesc atphys[] = { MII_PHY_DESC(ATHEROS, F1), @@ -158,7 +158,7 @@ atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO || IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { - atphy_auto(sc); + atphy_setmedia(sc, ife->ifm_media); break; } @@ -175,7 +175,7 @@ atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) /* * XXX * Due to an unknown reason powering down PHY resulted - * in unexpected results such as inaccessbility of + * in unexpected results such as inaccessibility of * hardware of freshly rebooted system. Disable * powering down PHY until I got more information for * Attansic/Atheros PHY hardwares. @@ -189,8 +189,9 @@ atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) anar = atphy_anar(ife); if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) { bmcr |= BMCR_FDX; - /* Enable pause. */ - anar |= (3 << 10); + if (((ife->ifm_media & IFM_GMASK) & IFM_FLOW) != 0 || + (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + anar |= ANAR_PAUSE_TOWARDS; } if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | @@ -222,7 +223,7 @@ done: } /* - * check for link. + * Check for link. * Read the status register twice; BMSR_LINK is latch-low. */ bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); @@ -238,7 +239,7 @@ done: return (0); sc->mii_ticks = 0; - atphy_auto(sc); + atphy_setmedia(sc, ife->ifm_media); break; } @@ -284,7 +285,7 @@ atphy_status(struct mii_softc *sc) case ATPHY_SSR_1000MBS: mii->mii_media_active |= IFM_1000_T; /* - * atphy(4) got a valid link so reset mii_ticks. + * atphy(4) has a valid link so reset mii_ticks. * Resetting mii_ticks is needed in order to * detect link loss after auto-negotiation. */ @@ -304,11 +305,13 @@ atphy_status(struct mii_softc *sc) } if ((ssr & ATPHY_SSR_DUPLEX) != 0) - mii->mii_media_active |= IFM_FDX; + mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; - /* XXX Master/Slave, Flow-control */ + if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) && + (PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES) != 0) + mii->mii_media_active |= IFM_ETH_MASTER; } static void @@ -336,7 +339,7 @@ atphy_reset(struct mii_softc *sc) PHY_WRITE(sc, ATPHY_SCR, reg); /* Workaround F1 bug to reset phy. */ - atphy_auto(sc); + atphy_setmedia(sc, sc->mii_pdata->mii_media.ifm_cur->ifm_media); for (i = 0; i < 1000; i++) { DELAY(1); @@ -378,12 +381,17 @@ atphy_anar(struct ifmedia_entry *ife) } static int -atphy_auto(struct mii_softc *sc) +atphy_setmedia(struct mii_softc *sc, int media) { uint16_t anar; - anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities); - PHY_WRITE(sc, MII_ANAR, anar | (3 << 10) | ANAR_CSMA); + anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; + if (((IFM_SUBTYPE(media) == IFM_AUTO || + ((media & IFM_GMASK) & IFM_FDX) != 0) && + ((media & IFM_GMASK) & IFM_FLOW) != 0) || + (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + anar |= ANAR_PAUSE_TOWARDS; + PHY_WRITE(sc, MII_ANAR, anar); if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) PHY_WRITE(sc, MII_100T2CR, GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX); diff --git a/sys/dev/mii/brgphy.c b/sys/dev/mii/brgphy.c index 62fcd8f..96947d4 100644 --- a/sys/dev/mii/brgphy.c +++ b/sys/dev/mii/brgphy.c @@ -99,9 +99,9 @@ static driver_t brgphy_driver = { DRIVER_MODULE(brgphy, miibus, brgphy_driver, brgphy_devclass, 0, 0); static int brgphy_service(struct mii_softc *, struct mii_data *, int); -static void brgphy_setmedia(struct mii_softc *, int, int); +static void brgphy_setmedia(struct mii_softc *, int); static void brgphy_status(struct mii_softc *); -static void brgphy_mii_phy_auto(struct mii_softc *); +static void brgphy_mii_phy_auto(struct mii_softc *, int); static void brgphy_reset(struct mii_softc *); static void brgphy_enable_loopback(struct mii_softc *); static void bcm5401_load_dspcode(struct mii_softc *); @@ -169,6 +169,7 @@ detect_hs21(struct bce_softc *bce_sc) static int brgphy_probe(device_t dev) { + return (mii_phy_dev_probe(dev, brgphys, BUS_PROBE_DEFAULT)); } @@ -183,7 +184,6 @@ brgphy_attach(device_t dev) struct mii_attach_args *ma; struct mii_data *mii; struct ifnet *ifp; - int fast_ether; bsc = device_get_softc(dev); sc = &bsc->mii_sc; @@ -203,8 +203,7 @@ brgphy_attach(device_t dev) * At least some variants wedge when isolating, at least some also * don't support loopback. */ - sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; - sc->mii_anegticks = MII_ANEGTICKS_GIGE; + sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP | MIIF_NOMANPAUSE; /* Initialize brgphy_softc structure */ bsc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2); @@ -212,8 +211,6 @@ brgphy_attach(device_t dev) bsc->mii_rev = MII_REV(ma->mii_id2); bsc->serdes_flags = 0; - fast_ether = 0; - if (bootverbose) device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n", bsc->mii_oui, bsc->mii_model, bsc->mii_rev); @@ -271,18 +268,6 @@ brgphy_attach(device_t dev) bce_sc = ifp->if_softc; } - /* Todo: Need to add additional controllers such as 5906 & 5787F */ - /* The 590x chips are 10/100 only. */ - if (bge_sc && - pci_get_vendor(bge_sc->bge_dev) == BCOM_VENDORID && - (pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901 || - pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901A2 || - pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5906 || - pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5906M)) { - fast_ether = 1; - sc->mii_anegticks = MII_ANEGTICKS; - } - brgphy_reset(sc); /* Read the PHY's capabilities. */ @@ -295,27 +280,10 @@ brgphy_attach(device_t dev) /* Add the supported media types */ if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), - BRGPHY_S10); - printf("10baseT, "); - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), - BRGPHY_S10 | BRGPHY_BMCR_FDX); - printf("10baseT-FDX, "); - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), - BRGPHY_S100); - printf("100baseTX, "); - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), - BRGPHY_S100 | BRGPHY_BMCR_FDX); - printf("100baseTX-FDX, "); - if (fast_ether == 0) { - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst), - BRGPHY_S1000); - printf("1000baseT, "); - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst), - BRGPHY_S1000 | BRGPHY_BMCR_FDX); - printf("1000baseT-FDX, "); - } + mii_phy_add_media(sc); + printf("\n"); } else { + sc->mii_anegticks = MII_ANEGTICKS_GIGE; ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), BRGPHY_S1000 | BRGPHY_BMCR_FDX); printf("1000baseSX-FDX, "); @@ -337,11 +305,10 @@ brgphy_attach(device_t dev) printf("auto-neg workaround, "); bsc->serdes_flags |= BRGPHY_NOANWAIT; } + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); + printf("auto\n"); } - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); - printf("auto\n"); - #undef ADD MIIBUS_MEDIAINIT(sc->mii_dev); return (0); @@ -367,15 +334,14 @@ brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: - brgphy_mii_phy_auto(sc); + brgphy_mii_phy_auto(sc, ife->ifm_media); break; case IFM_2500_SX: case IFM_1000_SX: case IFM_1000_T: case IFM_100_TX: case IFM_10_T: - brgphy_setmedia(sc, ife->ifm_media, - mii->mii_ifp->if_flags & IFF_LINK0); + brgphy_setmedia(sc, ife->ifm_media); break; default: return (EINVAL); @@ -397,7 +363,7 @@ brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) * Check to see if we have link. If we do, we don't * need to restart the autonegotiation process. */ - val = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); + val = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (val & BMSR_LINK) { sc->mii_ticks = 0; /* Reset autoneg timer. */ break; @@ -414,7 +380,7 @@ brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) /* Retry autonegotiation */ sc->mii_ticks = 0; - brgphy_mii_phy_auto(sc); + brgphy_mii_phy_auto(sc, ife->ifm_media); break; } @@ -456,7 +422,6 @@ brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) return (0); } - /****************************************************************************/ /* Sets the PHY link speed. */ /* */ @@ -464,12 +429,10 @@ brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) /* None */ /****************************************************************************/ static void -brgphy_setmedia(struct mii_softc *sc, int media, int master) +brgphy_setmedia(struct mii_softc *sc, int media) { - struct brgphy_softc *bsc = (struct brgphy_softc *)sc; int bmcr = 0, gig; - /* Calculate the value for the BMCR register. */ switch (IFM_SUBTYPE(media)) { case IFM_2500_SX: break; @@ -486,7 +449,6 @@ brgphy_setmedia(struct mii_softc *sc, int media, int master) break; } - /* Calculate duplex settings for 1000BasetT/1000BaseX. */ if ((media & IFM_GMASK) == IFM_FDX) { bmcr |= BRGPHY_BMCR_FDX; gig = BRGPHY_1000CTL_AFD; @@ -494,53 +456,30 @@ brgphy_setmedia(struct mii_softc *sc, int media, int master) gig = BRGPHY_1000CTL_AHD; } - /* Force loopback to disconnect PHY for Ethernet medium. */ + /* Force loopback to disconnect PHY from Ethernet medium. */ brgphy_enable_loopback(sc); - /* Disable 1000BaseT advertisements. */ PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0); - /* Disable 10/100 advertisements. */ PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE); - /* Write forced link speed. */ - PHY_WRITE(sc, BRGPHY_MII_BMCR, bmcr); - /* If 10/100 only then configuration is complete. */ - if ((IFM_SUBTYPE(media) != IFM_1000_T) && (IFM_SUBTYPE(media) != IFM_1000_SX)) - goto brgphy_setmedia_exit; + if (IFM_SUBTYPE(media) != IFM_1000_T && + IFM_SUBTYPE(media) != IFM_1000_SX) { + PHY_WRITE(sc, BRGPHY_MII_BMCR, bmcr); + return; + } - /* Set duplex speed advertisement for 1000BaseT/1000BaseX. */ + if (IFM_SUBTYPE(media) == IFM_1000_T) { + gig |= BRGPHY_1000CTL_MSE; + if ((media & IFM_ETH_MASTER) != 0) + gig |= BRGPHY_1000CTL_MSC; + } PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig); - /* Restart auto-negotiation for 1000BaseT/1000BaseX. */ PHY_WRITE(sc, BRGPHY_MII_BMCR, bmcr | BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); - - /* If not 5701 PHY then configuration is complete. */ - if (bsc->mii_model != MII_MODEL_xxBROADCOM_BCM5701) - goto brgphy_setmedia_exit; - - /* - * When setting the link manually, one side must be the master and - * the other the slave. However ifmedia doesn't give us a good way - * to specify this, so we fake it by using one of the LINK flags. - * If LINK0 is set, we program the PHY to be a master, otherwise - * it's a slave. - */ - if (master) { - PHY_WRITE(sc, BRGPHY_MII_1000CTL, - gig | BRGPHY_1000CTL_MSE | BRGPHY_1000CTL_MSC); - } else { - PHY_WRITE(sc, BRGPHY_MII_1000CTL, - gig | BRGPHY_1000CTL_MSE); - } - -brgphy_setmedia_exit: - return; } /****************************************************************************/ /* Set the media status based on the PHY settings. */ -/* IFM_FLAG0 = 0 (RX flow control disabled) | 1 (enabled) */ -/* IFM_FLAG1 = 0 (TX flow control disabled) | 1 (enabled) */ /* */ /* Returns: */ /* None */ @@ -550,34 +489,34 @@ brgphy_status(struct mii_softc *sc) { struct brgphy_softc *bsc = (struct brgphy_softc *)sc; struct mii_data *mii = sc->mii_pdata; - int aux, bmcr, bmsr, anar, anlpar, xstat, val; - + int aux, bmcr, bmsr, val, xstat; + u_int flowstat; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR); bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); - anar = PHY_READ(sc, BRGPHY_MII_ANAR); - anlpar = PHY_READ(sc, BRGPHY_MII_ANLPAR); - /* Loopback is enabled. */ if (bmcr & BRGPHY_BMCR_LOOP) { - mii->mii_media_active |= IFM_LOOP; } - /* Autoneg is still in progress. */ if ((bmcr & BRGPHY_BMCR_AUTOEN) && (bmsr & BRGPHY_BMSR_ACOMP) == 0 && (bsc->serdes_flags & BRGPHY_NOANWAIT) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; - goto brgphy_status_exit; + return; } - /* Autoneg is enabled and complete, link should be up. */ if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { + /* + * NB: reading the ANAR, ANLPAR or 1000STS after the AUXSTS + * wedges at least the PHY of BCM5704 (but not others). + */ + flowstat = mii_phy_flowstatus(sc); + xstat = PHY_READ(sc, BRGPHY_MII_1000STS); aux = PHY_READ(sc, BRGPHY_MII_AUXSTS); /* If copper link is up, get the negotiated speed/duplex. */ @@ -601,8 +540,16 @@ brgphy_status(struct mii_softc *sc) default: mii->mii_media_active |= IFM_NONE; break; } + + if ((mii->mii_media_active & IFM_FDX) != 0) + mii->mii_media_active |= flowstat; + + if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T && + (xstat & BRGPHY_1000STS_MSR) != 0) + mii->mii_media_active |= IFM_ETH_MASTER; } } else { + /* Todo: Add support for flow control. */ /* If serdes link is up, get the negotiated speed/duplex. */ if (bmsr & BRGPHY_BMSR_LINK) { mii->mii_media_status |= IFM_ACTIVE; @@ -620,7 +567,6 @@ brgphy_status(struct mii_softc *sc) else mii->mii_media_active |= IFM_HDX; } - } else if (bsc->serdes_flags & BRGPHY_5708S) { PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1); @@ -642,9 +588,7 @@ brgphy_status(struct mii_softc *sc) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; - } else if (bsc->serdes_flags & BRGPHY_5709S) { - /* Select GP Status Block of the AN MMD, get autoneg results. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_GP_STATUS); xstat = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS); @@ -670,65 +614,42 @@ brgphy_status(struct mii_softc *sc) else mii->mii_media_active |= IFM_HDX; } - } - - /* Todo: Change bge to use these settings. */ - - /* Fetch flow control settings from the copper PHY. */ - if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { - /* Set FLAG0 if RX is enabled and FLAG1 if TX is enabled */ - if ((anar & BRGPHY_ANAR_PC) && (anlpar & BRGPHY_ANLPAR_PC)) { - mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1; - } else if (!(anar & BRGPHY_ANAR_PC) && (anlpar & BRGPHY_ANAR_ASP) && - (anlpar & BRGPHY_ANLPAR_PC) && (anlpar & BRGPHY_ANLPAR_ASP)) { - mii->mii_media_active |= IFM_FLAG1; - } else if ((anar & BRGPHY_ANAR_PC) && (anar & BRGPHY_ANAR_ASP) && - !(anlpar & BRGPHY_ANLPAR_PC) && (anlpar & BRGPHY_ANLPAR_ASP)) { - mii->mii_media_active |= IFM_FLAG0; - } - } - - /* Todo: Add support for fiber settings too. */ - - -brgphy_status_exit: - return; } static void -brgphy_mii_phy_auto(struct mii_softc *sc) +brgphy_mii_phy_auto(struct mii_softc *sc, int media) { struct brgphy_softc *bsc = (struct brgphy_softc *)sc; - int ktcr = 0; + int anar, ktcr = 0; brgphy_reset(sc); - /* Enable flow control in the advertisement register. */ if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { - /* Pause capability advertisement (pause capable & asymmetric) */ - PHY_WRITE(sc, BRGPHY_MII_ANAR, - BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA | - BRGPHY_ANAR_ASP | BRGPHY_ANAR_PC); + anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; + if ((media & IFM_FLOW) != 0 || + (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + anar |= BRGPHY_ANAR_PC | BRGPHY_ANAR_ASP; + PHY_WRITE(sc, BRGPHY_MII_ANAR, anar); } else { - PHY_WRITE(sc, BRGPHY_SERDES_ANAR, BRGPHY_SERDES_ANAR_FDX | - BRGPHY_SERDES_ANAR_HDX | BRGPHY_SERDES_ANAR_BOTH_PAUSE); + anar = BRGPHY_SERDES_ANAR_FDX | BRGPHY_SERDES_ANAR_HDX; + if ((media & IFM_FLOW) != 0 || + (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + anar |= BRGPHY_SERDES_ANAR_BOTH_PAUSE; + PHY_WRITE(sc, BRGPHY_SERDES_ANAR, anar); } - /* Enable speed in the 1000baseT control register */ ktcr = BRGPHY_1000CTL_AFD | BRGPHY_1000CTL_AHD; if (bsc->mii_model == MII_MODEL_xxBROADCOM_BCM5701) ktcr |= BRGPHY_1000CTL_MSE | BRGPHY_1000CTL_MSC; PHY_WRITE(sc, BRGPHY_MII_1000CTL, ktcr); ktcr = PHY_READ(sc, BRGPHY_MII_1000CTL); - /* Start autonegotiation */ - PHY_WRITE(sc, BRGPHY_MII_BMCR,BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); + PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_AUTOEN | + BRGPHY_BMCR_STARTNEG); PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); - } - /* Enable loopback to force the link down. */ static void brgphy_enable_loopback(struct mii_softc *sc) @@ -923,7 +844,6 @@ brgphy_fixup_jitter_bug(struct mii_softc *sc) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } - static void brgphy_fixup_disable_early_dac(struct mii_softc *sc) { @@ -936,7 +856,6 @@ brgphy_fixup_disable_early_dac(struct mii_softc *sc) } - static void brgphy_ethernet_wirespeed(struct mii_softc *sc) { @@ -948,7 +867,6 @@ brgphy_ethernet_wirespeed(struct mii_softc *sc) PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) | (1 << 4)); } - static void brgphy_jumbo_settings(struct mii_softc *sc, u_long mtu) { @@ -989,7 +907,7 @@ brgphy_reset(struct mii_softc *sc) struct bge_softc *bge_sc = NULL; struct bce_softc *bce_sc = NULL; struct ifnet *ifp; - int val; + int val; /* Perform a standard PHY reset. */ mii_phy_reset(sc); @@ -1029,7 +947,6 @@ brgphy_reset(struct mii_softc *sc) bce_sc = ifp->if_softc; } - /* Handle any bge (NetXtreme/NetLink) workarounds. */ if (bge_sc) { /* Fix up various bugs */ if (bge_sc->bge_phy_flags & BGE_PHY_5704_A0_BUG) @@ -1060,10 +977,7 @@ brgphy_reset(struct mii_softc *sc) /* Adjust output voltage (From Linux driver) */ if (bge_sc->bge_asicrev == BGE_ASICREV_BCM5906) PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12); - - /* Handle any bce (NetXtreme II) workarounds. */ } else if (bce_sc) { - if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5708 && (bce_sc->bce_phy_flags & BCE_PHY_SERDES_FLAG)) { @@ -1154,7 +1068,6 @@ brgphy_reset(struct mii_softc *sc) /* Restore IEEE0 block (assumed in all brgphy(4) code). */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0); - } else if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5709) { if ((BCE_CHIP_REV(bce_sc) == BCE_CHIP_REV_Ax) || (BCE_CHIP_REV(bce_sc) == BCE_CHIP_REV_Bx)) @@ -1167,6 +1080,5 @@ brgphy_reset(struct mii_softc *sc) brgphy_jumbo_settings(sc, ifp->if_mtu); brgphy_ethernet_wirespeed(sc); } - } } diff --git a/sys/dev/mii/ciphy.c b/sys/dev/mii/ciphy.c index cb94f85..3f320fb 100644 --- a/sys/dev/mii/ciphy.c +++ b/sys/dev/mii/ciphy.c @@ -165,7 +165,7 @@ ciphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) if (PHY_READ(sc, CIPHY_MII_BMCR) & CIPHY_BMCR_AUTOEN) return (0); #endif - (void) mii_phy_auto(sc); + (void)mii_phy_auto(sc); break; case IFM_1000_T: speed = CIPHY_S1000; @@ -190,30 +190,16 @@ setit: if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) break; + gig |= CIPHY_1000CTL_MSE; + if ((ife->ifm_media & IFM_ETH_MASTER) != 0) + gig |= CIPHY_1000CTL_MSC; PHY_WRITE(sc, CIPHY_MII_1000CTL, gig); PHY_WRITE(sc, CIPHY_MII_BMCR, - speed|CIPHY_BMCR_AUTOEN|CIPHY_BMCR_STARTNEG); - - /* - * When setting the link manually, one side must - * be the master and the other the slave. However - * ifmedia doesn't give us a good way to specify - * this, so we fake it by using one of the LINK - * flags. If LINK0 is set, we program the PHY to - * be a master, otherwise it's a slave. - */ - if ((mii->mii_ifp->if_flags & IFF_LINK0)) { - PHY_WRITE(sc, CIPHY_MII_1000CTL, - gig|CIPHY_1000CTL_MSE|CIPHY_1000CTL_MSC); - } else { - PHY_WRITE(sc, CIPHY_MII_1000CTL, - gig|CIPHY_1000CTL_MSE); - } + speed | CIPHY_BMCR_AUTOEN | CIPHY_BMCR_STARTNEG); break; case IFM_NONE: - PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN); + PHY_WRITE(sc, MII_BMCR, BMCR_ISO | BMCR_PDOWN); break; - case IFM_100_T4: default: return (EINVAL); } @@ -319,6 +305,10 @@ ciphy_status(struct mii_softc *sc) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; + + if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) && + (PHY_READ(sc, CIPHY_MII_1000STS) & CIPHY_1000STS_MSR) != 0) + mii->mii_media_active |= IFM_ETH_MASTER; } static void diff --git a/sys/dev/mii/e1000phy.c b/sys/dev/mii/e1000phy.c index f49f7c4..1c0a267 100644 --- a/sys/dev/mii/e1000phy.c +++ b/sys/dev/mii/e1000phy.c @@ -91,7 +91,7 @@ DRIVER_MODULE(e1000phy, miibus, e1000phy_driver, e1000phy_devclass, 0, 0); static int e1000phy_service(struct mii_softc *, struct mii_data *, int); static void e1000phy_status(struct mii_softc *); static void e1000phy_reset(struct mii_softc *); -static int e1000phy_mii_phy_auto(struct e1000phy_softc *); +static int e1000phy_mii_phy_auto(struct e1000phy_softc *, int); static const struct mii_phydesc e1000phys[] = { MII_PHY_DESC(MARVELL, E1000), @@ -146,6 +146,8 @@ e1000phy_attach(device_t dev) sc->mii_service = e1000phy_service; sc->mii_pdata = mii; + sc->mii_flags |= MIIF_NOMANPAUSE; + esc->mii_model = MII_MODEL(ma->mii_id2); ifp = sc->mii_pdata->mii_ifp; if (strcmp(ifp->if_dname, "msk") == 0 && @@ -323,7 +325,7 @@ e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { - e1000phy_mii_phy_auto(esc); + e1000phy_mii_phy_auto(esc, ife->ifm_media); break; } @@ -366,27 +368,14 @@ e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) reg &= ~E1000_CR_AUTO_NEG_ENABLE; PHY_WRITE(sc, E1000_CR, reg | E1000_CR_RESET); - /* - * When setting the link manually, one side must - * be the master and the other the slave. However - * ifmedia doesn't give us a good way to specify - * this, so we fake it by using one of the LINK - * flags. If LINK0 is set, we program the PHY to - * be a master, otherwise it's a slave. - */ - if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T || - (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_SX)) { - if ((mii->mii_ifp->if_flags & IFF_LINK0)) - PHY_WRITE(sc, E1000_1GCR, gig | - E1000_1GCR_MS_ENABLE | E1000_1GCR_MS_VALUE); - else - PHY_WRITE(sc, E1000_1GCR, gig | - E1000_1GCR_MS_ENABLE); - } else { - if ((sc->mii_extcapabilities & - (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) - PHY_WRITE(sc, E1000_1GCR, 0); - } + if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { + gig |= E1000_1GCR_MS_ENABLE; + if ((ife->ifm_media & IFM_ETH_MASTER) != 0) + gig |= E1000_1GCR_MS_VALUE; + PHY_WRITE(sc, E1000_1GCR, gig); + } else if ((sc->mii_extcapabilities & + (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) + PHY_WRITE(sc, E1000_1GCR, 0); PHY_WRITE(sc, E1000_AR, E1000_AR_SELECTOR_FIELD); PHY_WRITE(sc, E1000_CR, speed | E1000_CR_RESET); done: @@ -424,7 +413,7 @@ done: sc->mii_ticks = 0; e1000phy_reset(sc); - e1000phy_mii_phy_auto(esc); + e1000phy_mii_phy_auto(esc, ife->ifm_media); break; } @@ -440,7 +429,7 @@ static void e1000phy_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; - int bmcr, bmsr, gsr, ssr, ar, lpar; + int bmcr, bmsr, ssr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; @@ -485,38 +474,22 @@ e1000phy_status(struct mii_softc *sc) mii->mii_media_active |= IFM_1000_SX; } - if (ssr & E1000_SSR_DUPLEX) + if (ssr & E1000_SSR_DUPLEX) { mii->mii_media_active |= IFM_FDX; - else + if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) + mii->mii_media_active |= mii_phy_flowstatus(sc); + } else mii->mii_media_active |= IFM_HDX; - if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { - ar = PHY_READ(sc, E1000_AR); - lpar = PHY_READ(sc, E1000_LPAR); - /* FLAG0==rx-flow-control FLAG1==tx-flow-control */ - if ((ar & E1000_AR_PAUSE) && (lpar & E1000_LPAR_PAUSE)) { - mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1; - } else if (!(ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) && - (lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) { - mii->mii_media_active |= IFM_FLAG1; - } else if ((ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) && - !(lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) { - mii->mii_media_active |= IFM_FLAG0; - } - } - - /* FLAG2 : local PHY resolved to MASTER */ - if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) || - (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX)) { - PHY_READ(sc, E1000_1GSR); - gsr = PHY_READ(sc, E1000_1GSR); - if ((gsr & E1000_1GSR_MS_CONFIG_RES) != 0) - mii->mii_media_active |= IFM_FLAG2; + if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { + if (((PHY_READ(sc, E1000_1GSR) | PHY_READ(sc, E1000_1GSR)) & + E1000_1GSR_MS_CONFIG_RES) != 0) + mii->mii_media_active |= IFM_ETH_MASTER; } } static int -e1000phy_mii_phy_auto(struct e1000phy_softc *esc) +e1000phy_mii_phy_auto(struct e1000phy_softc *esc, int media) { struct mii_softc *sc; uint16_t reg; @@ -525,12 +498,13 @@ e1000phy_mii_phy_auto(struct e1000phy_softc *esc) if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { reg = PHY_READ(sc, E1000_AR); reg |= E1000_AR_10T | E1000_AR_10T_FD | - E1000_AR_100TX | E1000_AR_100TX_FD | - E1000_AR_PAUSE | E1000_AR_ASM_DIR; + E1000_AR_100TX | E1000_AR_100TX_FD; + if ((media & IFM_FLOW) != 0 || + (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + reg |= E1000_AR_PAUSE | E1000_AR_ASM_DIR; PHY_WRITE(sc, E1000_AR, reg | E1000_AR_SELECTOR_FIELD); } else - PHY_WRITE(sc, E1000_AR, E1000_FA_1000X_FD | E1000_FA_1000X | - E1000_FA_SYM_PAUSE | E1000_FA_ASYM_PAUSE); + PHY_WRITE(sc, E1000_AR, E1000_FA_1000X_FD | E1000_FA_1000X); if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) PHY_WRITE(sc, E1000_1GCR, E1000_1GCR_1000T_FD | E1000_1GCR_1000T); diff --git a/sys/dev/mii/gentbi.c b/sys/dev/mii/gentbi.c index ee08efe..f5d3a8b 100644 --- a/sys/dev/mii/gentbi.c +++ b/sys/dev/mii/gentbi.c @@ -267,7 +267,8 @@ gentbi_status(struct mii_softc *sc) anlpar = PHY_READ(sc, MII_ANLPAR); if ((sc->mii_extcapabilities & EXTSR_1000XFDX) != 0 && (anlpar & ANLPAR_X_FD) != 0) - mii->mii_media_active |= IFM_FDX; + mii->mii_media_active |= + IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; } else diff --git a/sys/dev/mii/ip1000phy.c b/sys/dev/mii/ip1000phy.c index b60fab6..242baf7 100644 --- a/sys/dev/mii/ip1000phy.c +++ b/sys/dev/mii/ip1000phy.c @@ -84,7 +84,7 @@ DRIVER_MODULE(ip1000phy, miibus, ip1000phy_driver, ip1000phy_devclass, 0, 0); static int ip1000phy_service(struct mii_softc *, struct mii_data *, int); static void ip1000phy_status(struct mii_softc *); static void ip1000phy_reset(struct mii_softc *); -static int ip1000phy_mii_phy_auto(struct mii_softc *); +static int ip1000phy_mii_phy_auto(struct mii_softc *, int); static const struct mii_phydesc ip1000phys[] = { MII_PHY_DESC(ICPLUS, IP1000A), @@ -120,7 +120,7 @@ ip1000phy_attach(device_t dev) sc->mii_service = ip1000phy_service; sc->mii_pdata = mii; - sc->mii_flags |= MIIF_NOISOLATE; + sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOMANPAUSE; isc->model = MII_MODEL(ma->mii_id2); isc->revision = MII_REV(ma->mii_id2); @@ -163,9 +163,8 @@ ip1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) ip1000phy_reset(sc); switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: - (void)ip1000phy_mii_phy_auto(sc); + (void)ip1000phy_mii_phy_auto(sc, ife->ifm_media); goto done; - break; case IFM_1000_T: /* @@ -199,26 +198,10 @@ ip1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) break; + gig |= IP1000PHY_1000CR_MASTER | IP1000PHY_1000CR_MANUAL; + if ((ife->ifm_media & IFM_ETH_MASTER) != 0) + gig |= IP1000PHY_1000CR_MMASTER; PHY_WRITE(sc, IP1000PHY_MII_1000CR, gig); - PHY_WRITE(sc, IP1000PHY_MII_BMCR, speed); - - /* - * When setting the link manually, one side must - * be the master and the other the slave. However - * ifmedia doesn't give us a good way to specify - * this, so we fake it by using one of the LINK - * flags. If LINK0 is set, we program the PHY to - * be a master, otherwise it's a slave. - */ - if ((mii->mii_ifp->if_flags & IFF_LINK0)) - PHY_WRITE(sc, IP1000PHY_MII_1000CR, gig | - IP1000PHY_1000CR_MASTER | - IP1000PHY_1000CR_MMASTER | - IP1000PHY_1000CR_MANUAL); - else - PHY_WRITE(sc, IP1000PHY_MII_1000CR, gig | - IP1000PHY_1000CR_MASTER | - IP1000PHY_1000CR_MANUAL); done: break; @@ -258,7 +241,7 @@ done: break; sc->mii_ticks = 0; - ip1000phy_mii_phy_auto(sc); + ip1000phy_mii_phy_auto(sc, ife->ifm_media); break; } @@ -276,7 +259,6 @@ ip1000phy_status(struct mii_softc *sc) struct ip1000phy_softc *isc; struct mii_data *mii = sc->mii_pdata; uint32_t bmsr, bmcr, stat; - uint32_t ar, lpar; isc = (struct ip1000phy_softc *)sc; @@ -345,36 +327,18 @@ ip1000phy_status(struct mii_softc *sc) mii->mii_media_active |= IFM_HDX; } - ar = PHY_READ(sc, IP1000PHY_MII_ANAR); - lpar = PHY_READ(sc, IP1000PHY_MII_ANLPAR); - - /* - * FLAG0 : Rx flow-control - * FLAG1 : Tx flow-control - */ - if ((ar & IP1000PHY_ANAR_PAUSE) && (lpar & IP1000PHY_ANLPAR_PAUSE)) - mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1; - else if (!(ar & IP1000PHY_ANAR_PAUSE) && (ar & IP1000PHY_ANAR_APAUSE) && - (lpar & IP1000PHY_ANLPAR_PAUSE) && (lpar & IP1000PHY_ANLPAR_APAUSE)) - mii->mii_media_active |= IFM_FLAG1; - else if ((ar & IP1000PHY_ANAR_PAUSE) && (ar & IP1000PHY_ANAR_APAUSE) && - !(lpar & IP1000PHY_ANLPAR_PAUSE) && - (lpar & IP1000PHY_ANLPAR_APAUSE)) { - mii->mii_media_active |= IFM_FLAG0; - } + if ((mii->mii_media_active & IFM_FDX) != 0) + mii->mii_media_active |= mii_phy_flowstatus(sc); - /* - * FLAG2 : local PHY resolved to MASTER - */ if ((mii->mii_media_active & IFM_1000_T) != 0) { stat = PHY_READ(sc, IP1000PHY_MII_1000SR); if ((stat & IP1000PHY_1000SR_MASTER) != 0) - mii->mii_media_active |= IFM_FLAG2; + mii->mii_media_active |= IFM_ETH_MASTER; } } static int -ip1000phy_mii_phy_auto(struct mii_softc *sc) +ip1000phy_mii_phy_auto(struct mii_softc *sc, int media) { struct ip1000phy_softc *isc; uint32_t reg; @@ -386,8 +350,9 @@ ip1000phy_mii_phy_auto(struct mii_softc *sc) reg |= IP1000PHY_ANAR_NP; } reg |= IP1000PHY_ANAR_10T | IP1000PHY_ANAR_10T_FDX | - IP1000PHY_ANAR_100TX | IP1000PHY_ANAR_100TX_FDX | - IP1000PHY_ANAR_PAUSE | IP1000PHY_ANAR_APAUSE; + IP1000PHY_ANAR_100TX | IP1000PHY_ANAR_100TX_FDX; + if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + reg |= IP1000PHY_ANAR_PAUSE | IP1000PHY_ANAR_APAUSE; PHY_WRITE(sc, IP1000PHY_MII_ANAR, reg | IP1000PHY_ANAR_CSMA); reg = IP1000PHY_1000CR_1000T | IP1000PHY_1000CR_1000T_FDX; diff --git a/sys/dev/mii/jmphy.c b/sys/dev/mii/jmphy.c index 0b04d80..00611c4 100644 --- a/sys/dev/mii/jmphy.c +++ b/sys/dev/mii/jmphy.c @@ -50,11 +50,11 @@ __FBSDID("$FreeBSD$"); #include "miibus_if.h" -static int jmphy_probe(device_t); -static int jmphy_attach(device_t); +static int jmphy_probe(device_t); +static int jmphy_attach(device_t); static void jmphy_reset(struct mii_softc *); static uint16_t jmphy_anar(struct ifmedia_entry *); -static int jmphy_auto(struct mii_softc *, struct ifmedia_entry *); +static int jmphy_setmedia(struct mii_softc *, struct ifmedia_entry *); struct jmphy_softc { struct mii_softc mii_sc; @@ -154,7 +154,7 @@ jmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; - if (jmphy_auto(sc, ife) != EJUSTRETURN) + if (jmphy_setmedia(sc, ife) != EJUSTRETURN) return (EINVAL); break; @@ -186,7 +186,7 @@ jmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) return (0); sc->mii_ticks = 0; - jmphy_auto(sc, ife); + (void)jmphy_setmedia(sc, ife); break; } @@ -251,16 +251,14 @@ jmphy_status(struct mii_softc *sc) } if ((ssr & JMPHY_SSR_DUPLEX) != 0) - mii->mii_media_active |= IFM_FDX; + mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; - /* XXX Flow-control. */ -#ifdef notyet + if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { if ((PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES) != 0) mii->mii_media_active |= IFM_ETH_MASTER; } -#endif } static void @@ -309,7 +307,7 @@ jmphy_anar(struct ifmedia_entry *ife) } static int -jmphy_auto(struct mii_softc *sc, struct ifmedia_entry *ife) +jmphy_setmedia(struct mii_softc *sc, struct ifmedia_entry *ife) { uint16_t anar, bmcr, gig; @@ -336,17 +334,18 @@ jmphy_auto(struct mii_softc *sc, struct ifmedia_entry *ife) bmcr |= BMCR_LOOP; anar = jmphy_anar(ife); - /* XXX Always advertise pause capability. */ - anar |= (3 << 10); + if (((IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO || + (ife->ifm_media & IFM_FDX) != 0) && + (ife->ifm_media & IFM_FLOW) != 0) || + (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + anar |= ANAR_PAUSE_TOWARDS; if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) { -#ifdef notyet - struct mii_data *mii; - - mii = sc->mii_pdata; - if ((mii->mii_media.ifm_media & IFM_ETH_MASTER) != 0) - gig |= GTCR_MAN_MS | GTCR_MAN_ADV; -#endif + if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { + gig |= GTCR_MAN_MS; + if ((ife->ifm_media & IFM_ETH_MASTER) != 0) + gig |= GTCR_ADV_MS; + } PHY_WRITE(sc, MII_100T2CR, gig); } PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA); diff --git a/sys/dev/mii/mii.h b/sys/dev/mii/mii.h index b7e0a05..1d887d2 100644 --- a/sys/dev/mii/mii.h +++ b/sys/dev/mii/mii.h @@ -128,6 +128,10 @@ #define ANAR_10_FD 0x0040 /* local device supports 10bT FD */ #define ANAR_10 0x0020 /* local device supports 10bT */ #define ANAR_CSMA 0x0001 /* protocol selector CSMA/CD */ +#define ANAR_PAUSE_NONE (0 << 10) +#define ANAR_PAUSE_SYM (1 << 10) +#define ANAR_PAUSE_ASYM (2 << 10) +#define ANAR_PAUSE_TOWARDS (3 << 10) #define ANAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */ #define ANAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */ @@ -148,6 +152,11 @@ #define ANLPAR_10_FD 0x0040 /* link partner supports 10bT FD */ #define ANLPAR_10 0x0020 /* link partner supports 10bT */ #define ANLPAR_CSMA 0x0001 /* protocol selector CSMA/CD */ +#define ANLPAR_PAUSE_MASK (3 << 10) +#define ANLPAR_PAUSE_NONE (0 << 10) +#define ANLPAR_PAUSE_SYM (1 << 10) +#define ANLPAR_PAUSE_ASYM (2 << 10) +#define ANLPAR_PAUSE_TOWARDS (3 << 10) #define ANLPAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */ #define ANLPAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */ diff --git a/sys/dev/mii/mii_physubr.c b/sys/dev/mii/mii_physubr.c index d1cc4f5..b888937 100644 --- a/sys/dev/mii/mii_physubr.c +++ b/sys/dev/mii/mii_physubr.c @@ -106,8 +106,13 @@ mii_phy_setmedia(struct mii_softc *sc) int bmcr, anar, gtcr; if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { + /* + * Force renegotiation if MIIF_DOPAUSE or MIIF_FORCEANEG. + * The former is necessary as we might switch from flow- + * control advertisment being off to on or vice versa. + */ if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0 || - (sc->mii_flags & MIIF_FORCEANEG) != 0) + (sc->mii_flags & (MIIF_DOPAUSE | MIIF_FORCEANEG)) != 0) (void)mii_phy_auto(sc); return; } @@ -124,14 +129,23 @@ mii_phy_setmedia(struct mii_softc *sc) bmcr = mii_media_table[ife->ifm_data].mm_bmcr; gtcr = mii_media_table[ife->ifm_data].mm_gtcr; - if ((mii->mii_media.ifm_media & IFM_ETH_MASTER) != 0) { - switch (IFM_SUBTYPE(ife->ifm_media)) { - case IFM_1000_T: - gtcr |= GTCR_MAN_MS | GTCR_ADV_MS; - break; + if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { + gtcr |= GTCR_MAN_MS; + if ((ife->ifm_media & IFM_ETH_MASTER) != 0) + gtcr |= GTCR_ADV_MS; + } - default: - printf("mii_phy_setmedia: MASTER on wrong media\n"); + if ((ife->ifm_media & IFM_GMASK) == (IFM_FDX | IFM_FLOW) || + (sc->mii_flags & MIIF_FORCEPAUSE) != 0) { + if ((sc->mii_flags & MIIF_IS_1000X) != 0) + anar |= ANAR_X_PAUSE_TOWARDS; + else { + anar |= ANAR_FC; + /* XXX Only 1000BASE-T has PAUSE_ASYM? */ + if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0 && + (sc->mii_extcapabilities & + (EXTSR_1000THDX | EXTSR_1000TFDX)) != 0) + anar |= ANAR_X_PAUSE_ASYM; } } @@ -147,6 +161,7 @@ mii_phy_setmedia(struct mii_softc *sc) int mii_phy_auto(struct mii_softc *sc) { + struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur; int anar, gtcr; /* @@ -160,16 +175,23 @@ mii_phy_auto(struct mii_softc *sc) if ((sc->mii_extcapabilities & EXTSR_1000XHDX) != 0) anar |= ANAR_X_HD; - if ((sc->mii_flags & MIIF_DOPAUSE) != 0) { - /* XXX Asymmetric vs. symmetric? */ - anar |= ANLPAR_X_PAUSE_TOWARDS; - } + if ((ife->ifm_media & IFM_FLOW) != 0 || + (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + anar |= ANAR_X_PAUSE_TOWARDS; PHY_WRITE(sc, MII_ANAR, anar); } else { anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; - if ((sc->mii_flags & MIIF_DOPAUSE) != 0) - anar |= ANAR_FC; + if ((ife->ifm_media & IFM_FLOW) != 0 || + (sc->mii_flags & MIIF_FORCEPAUSE) != 0) { + if ((sc->mii_capabilities & BMSR_100TXFDX) != 0) + anar |= ANAR_FC; + /* XXX Only 1000BASE-T has PAUSE_ASYM? */ + if (((sc->mii_flags & MIIF_HAVE_GTCR) != 0) && + (sc->mii_extcapabilities & + (EXTSR_1000THDX | EXTSR_1000TFDX)) != 0) + anar |= ANAR_X_PAUSE_ASYM; + } PHY_WRITE(sc, MII_ANAR, anar); if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) { gtcr = 0; @@ -291,6 +313,7 @@ mii_phy_add_media(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; const char *sep = ""; + int fdx = 0; if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 && (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) { @@ -334,6 +357,14 @@ mii_phy_add_media(struct mii_softc *sc) ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), MII_MEDIA_10_T_FDX); PRINT("10baseT-FDX"); + if ((sc->mii_flags & MIIF_DOPAUSE) != 0 && + (sc->mii_flags & MIIF_NOMANPAUSE) == 0) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, + IFM_FDX | IFM_FLOW, sc->mii_inst), + MII_MEDIA_10_T_FDX); + PRINT("10baseT-FDX-flow"); + } + fdx = 1; } if ((sc->mii_capabilities & BMSR_100TXHDX) != 0) { ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), @@ -344,6 +375,14 @@ mii_phy_add_media(struct mii_softc *sc) ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), MII_MEDIA_100_TX_FDX); PRINT("100baseTX-FDX"); + if ((sc->mii_flags & MIIF_DOPAUSE) != 0 && + (sc->mii_flags & MIIF_NOMANPAUSE) == 0) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, + IFM_FDX | IFM_FLOW, sc->mii_inst), + MII_MEDIA_100_TX_FDX); + PRINT("100baseTX-FDX-flow"); + } + fdx = 1; } if ((sc->mii_capabilities & BMSR_100T4) != 0) { ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst), @@ -369,38 +408,67 @@ mii_phy_add_media(struct mii_softc *sc) ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), MII_MEDIA_1000_X_FDX); PRINT("1000baseSX-FDX"); + if ((sc->mii_flags & MIIF_DOPAUSE) != 0 && + (sc->mii_flags & MIIF_NOMANPAUSE) == 0) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, + IFM_FDX | IFM_FLOW, sc->mii_inst), + MII_MEDIA_1000_X_FDX); + PRINT("1000baseSX-FDX-flow"); + } + fdx = 1; } /* * 1000baseT media needs to be able to manipulate - * master/slave mode. We set IFM_ETH_MASTER in - * the "don't care mask" and filter it out when - * the media is set. + * master/slave mode. * * All 1000baseT PHYs have a 1000baseT control register. */ if ((sc->mii_extcapabilities & EXTSR_1000THDX) != 0) { sc->mii_anegticks = MII_ANEGTICKS_GIGE; sc->mii_flags |= MIIF_HAVE_GTCR; - mii->mii_media.ifm_mask |= IFM_ETH_MASTER; ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst), MII_MEDIA_1000_T); PRINT("1000baseT"); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, + IFM_ETH_MASTER, sc->mii_inst), MII_MEDIA_1000_T); + PRINT("1000baseT-master"); } if ((sc->mii_extcapabilities & EXTSR_1000TFDX) != 0) { sc->mii_anegticks = MII_ANEGTICKS_GIGE; sc->mii_flags |= MIIF_HAVE_GTCR; - mii->mii_media.ifm_mask |= IFM_ETH_MASTER; ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst), MII_MEDIA_1000_T_FDX); PRINT("1000baseT-FDX"); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, + IFM_FDX | IFM_ETH_MASTER, sc->mii_inst), + MII_MEDIA_1000_T_FDX); + PRINT("1000baseT-FDX-master"); + if ((sc->mii_flags & MIIF_DOPAUSE) != 0 && + (sc->mii_flags & MIIF_NOMANPAUSE) == 0) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, + IFM_FDX | IFM_FLOW, sc->mii_inst), + MII_MEDIA_1000_T_FDX); + PRINT("1000baseT-FDX-flow"); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, + IFM_FDX | IFM_FLOW | IFM_ETH_MASTER, + sc->mii_inst), MII_MEDIA_1000_T_FDX); + PRINT("1000baseT-FDX-flow-master"); + } + fdx = 1; } } if ((sc->mii_capabilities & BMSR_ANEG) != 0) { + /* intentionally invalid index */ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), - MII_NMEDIA); /* intentionally invalid index */ + MII_NMEDIA); PRINT("auto"); + if (fdx != 0 && (sc->mii_flags & MIIF_DOPAUSE) != 0) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, IFM_FLOW, + sc->mii_inst), MII_NMEDIA); + PRINT("auto-flow"); + } } #undef ADD #undef PRINT @@ -424,7 +492,7 @@ mii_phy_match_gen(const struct mii_attach_args *ma, { for (; mpd->mpd_name != NULL; - mpd = (const struct mii_phydesc *) ((const char *) mpd + len)) { + mpd = (const struct mii_phydesc *)((const char *)mpd + len)) { if (MII_OUI(ma->mii_id1, ma->mii_id2) == mpd->mpd_oui && MII_MODEL(ma->mii_id2) == mpd->mpd_model) return (mpd); @@ -450,3 +518,55 @@ mii_phy_dev_probe(device_t dev, const struct mii_phydesc *mpd, int mrv) } return (ENXIO); } + +/* + * Return the flow control status flag from MII_ANAR & MII_ANLPAR. + */ +u_int +mii_phy_flowstatus(struct mii_softc *sc) +{ + int anar, anlpar; + + if ((sc->mii_flags & MIIF_DOPAUSE) == 0) + return (0); + + anar = PHY_READ(sc, MII_ANAR); + anlpar = PHY_READ(sc, MII_ANLPAR); + + /* + * Check for 1000BASE-X. Autonegotiation is a bit + * different on such devices. + */ + if ((sc->mii_flags & MIIF_IS_1000X) != 0) { + anar <<= 3; + anlpar <<= 3; + } + + if ((anar & ANAR_PAUSE_SYM) != 0 && (anlpar & ANLPAR_PAUSE_SYM) != 0) + return (IFM_FLOW | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE); + + if ((anar & ANAR_PAUSE_SYM) == 0) { + if ((anar & ANAR_PAUSE_ASYM) != 0 && + (anlpar & ANLPAR_PAUSE_TOWARDS) != 0) + return (IFM_FLOW | IFM_ETH_TXPAUSE); + else + return (0); + } + + if ((anar & ANAR_PAUSE_ASYM) == 0) { + if ((anlpar & ANLPAR_PAUSE_SYM) != 0) + return (IFM_FLOW | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE); + else + return (0); + } + + switch ((anlpar & ANLPAR_PAUSE_TOWARDS)) { + case ANLPAR_PAUSE_NONE: + return (0); + case ANLPAR_PAUSE_ASYM: + return (IFM_FLOW | IFM_ETH_RXPAUSE); + default: + return (IFM_FLOW | IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE); + } + /* NOTREACHED */ +} diff --git a/sys/dev/mii/miivar.h b/sys/dev/mii/miivar.h index 6783cf5..078b9a2 100644 --- a/sys/dev/mii/miivar.h +++ b/sys/dev/mii/miivar.h @@ -125,6 +125,7 @@ typedef struct mii_softc mii_softc_t; #define MIIF_INITDONE 0x00000001 /* has been initialized (mii_data) */ #define MIIF_NOISOLATE 0x00000002 /* do not isolate the PHY */ #define MIIF_NOLOOP 0x00000004 /* no loopback capability */ +#define MIIF_DOINGAUTO 0x00000008 /* doing autonegotiation (mii_softc) */ #define MIIF_AUTOTSLEEP 0x00000010 /* use tsleep(), not callout() */ #define MIIF_HAVEFIBER 0x00000020 /* from parent: has fiber interface */ #define MIIF_HAVE_GTCR 0x00000040 /* has 100base-T2/1000base-T CR */ @@ -132,6 +133,8 @@ typedef struct mii_softc mii_softc_t; #define MIIF_DOPAUSE 0x00000100 /* advertise PAUSE capability */ #define MIIF_IS_HPNA 0x00000200 /* is a HomePNA device */ #define MIIF_FORCEANEG 0x00000400 /* force auto-negotiation */ +#define MIIF_NOMANPAUSE 0x00100000 /* no manual PAUSE selection */ +#define MIIF_FORCEPAUSE 0x00200000 /* force PAUSE advertisment */ #define MIIF_MACPRIV0 0x01000000 /* private to the MAC driver */ #define MIIF_MACPRIV1 0x02000000 /* private to the MAC driver */ #define MIIF_MACPRIV2 0x04000000 /* private to the MAC driver */ @@ -236,6 +239,7 @@ void mii_phy_add_media(struct mii_softc *); int mii_phy_auto(struct mii_softc *); int mii_phy_detach(device_t dev); void mii_phy_down(struct mii_softc *); +u_int mii_phy_flowstatus(struct mii_softc *); void mii_phy_reset(struct mii_softc *); void mii_phy_setmedia(struct mii_softc *sc); void mii_phy_update(struct mii_softc *, int); diff --git a/sys/dev/mii/nsgphy.c b/sys/dev/mii/nsgphy.c index b3df8a2..7cdee42 100644 --- a/sys/dev/mii/nsgphy.c +++ b/sys/dev/mii/nsgphy.c @@ -246,7 +246,8 @@ nsgphy_status(struct mii_softc *sc) } if (physup & PHY_SUP_DUPLEX) - mii->mii_media_active |= IFM_FDX; + mii->mii_media_active |= + IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; } else diff --git a/sys/dev/mii/rgephy.c b/sys/dev/mii/rgephy.c index d1e0e51..aa4bff7 100644 --- a/sys/dev/mii/rgephy.c +++ b/sys/dev/mii/rgephy.c @@ -89,7 +89,7 @@ DRIVER_MODULE(rgephy, miibus, rgephy_driver, rgephy_devclass, 0, 0); static int rgephy_service(struct mii_softc *, struct mii_data *, int); static void rgephy_status(struct mii_softc *); -static int rgephy_mii_phy_auto(struct mii_softc *); +static int rgephy_mii_phy_auto(struct mii_softc *, int); static void rgephy_reset(struct mii_softc *); static void rgephy_loop(struct mii_softc *); static void rgephy_load_dspcode(struct mii_softc *); @@ -113,7 +113,6 @@ rgephy_attach(device_t dev) struct mii_softc *sc; struct mii_attach_args *ma; struct mii_data *mii; - const char *sep = ""; rsc = device_get_softc(dev); sc = &rsc->mii_sc; @@ -132,27 +131,21 @@ rgephy_attach(device_t dev) rsc->mii_revision = MII_REV(ma->mii_id2); #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) -#define PRINT(s) printf("%s%s", sep, s); sep = ", " #if 0 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), MII_MEDIA_100_TX); #endif - sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; - sc->mii_capabilities &= ~BMSR_ANEG; + /* RTL8169S do not report auto-sense; add manually. */ + sc->mii_capabilities = (PHY_READ(sc, MII_BMSR) | BMSR_ANEG) & + ma->mii_capmask; if (sc->mii_capabilities & BMSR_EXTSTAT) sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); - device_printf(dev, " "); mii_phy_add_media(sc); - /* RTL8169S do not report auto-sense; add manually. */ - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), MII_NMEDIA); - sep = ", "; - PRINT("auto"); printf("\n"); #undef ADD -#undef PRINT rgephy_reset(sc); MIIBUS_MEDIAINIT(sc->mii_dev); @@ -182,7 +175,8 @@ rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) rgephy_reset(sc); /* XXX hardware bug work-around */ anar = PHY_READ(sc, RGEPHY_MII_ANAR); - anar &= ~(RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX | + anar &= ~(RGEPHY_ANAR_PC | RGEPHY_ANAR_ASP | + RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX | RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10); switch (IFM_SUBTYPE(ife->ifm_media)) { @@ -194,7 +188,7 @@ rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) if (PHY_READ(sc, RGEPHY_MII_BMCR) & RGEPHY_BMCR_AUTOEN) return (0); #endif - (void) rgephy_mii_phy_auto(sc); + (void)rgephy_mii_phy_auto(sc, ife->ifm_media); break; case IFM_1000_T: speed = RGEPHY_S1000; @@ -222,32 +216,26 @@ setit: PHY_WRITE(sc, RGEPHY_MII_1000CTL, 0); PHY_WRITE(sc, RGEPHY_MII_ANAR, anar); PHY_WRITE(sc, RGEPHY_MII_BMCR, speed | - RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); + RGEPHY_BMCR_AUTOEN | + RGEPHY_BMCR_STARTNEG); break; } - /* - * When setting the link manually, one side must - * be the master and the other the slave. However - * ifmedia doesn't give us a good way to specify - * this, so we fake it by using one of the LINK - * flags. If LINK0 is set, we program the PHY to - * be a master, otherwise it's a slave. - */ - if ((mii->mii_ifp->if_flags & IFF_LINK0)) { - PHY_WRITE(sc, RGEPHY_MII_1000CTL, - gig|RGEPHY_1000CTL_MSE|RGEPHY_1000CTL_MSC); - } else { - PHY_WRITE(sc, RGEPHY_MII_1000CTL, - gig|RGEPHY_1000CTL_MSE); - } + if ((ife->ifm_media & IFM_FLOW) != 0 || + (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + anar |= RGEPHY_ANAR_PC | RGEPHY_ANAR_ASP; + + gig |= RGEPHY_1000CTL_MSE; + if ((ife->ifm_media & IFM_ETH_MASTER) != 0) + gig |= RGEPHY_1000CTL_MSC; + PHY_WRITE(sc, RGEPHY_MII_1000CTL, gig); + PHY_WRITE(sc, RGEPHY_MII_ANAR, anar); PHY_WRITE(sc, RGEPHY_MII_BMCR, speed | RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); break; case IFM_NONE: - PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN); + PHY_WRITE(sc, MII_BMCR, BMCR_ISO | BMCR_PDOWN); break; - case IFM_100_T4: default: return (EINVAL); } @@ -297,7 +285,7 @@ setit: return (0); sc->mii_ticks = 0; - rgephy_mii_phy_auto(sc); + rgephy_mii_phy_auto(sc, ife->ifm_media); break; } @@ -395,22 +383,32 @@ rgephy_status(struct mii_softc *sc) else mii->mii_media_active |= IFM_HDX; } + + if ((mii->mii_media_active & IFM_FDX) != 0) + mii->mii_media_active |= mii_phy_flowstatus(sc); + + if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) && + (PHY_READ(sc, RGEPHY_MII_1000STS) & RGEPHY_1000STS_MSR) != 0) + mii->mii_media_active |= IFM_ETH_MASTER; } static int -rgephy_mii_phy_auto(struct mii_softc *mii) +rgephy_mii_phy_auto(struct mii_softc *sc, int media) { + int anar; - rgephy_loop(mii); - rgephy_reset(mii); + rgephy_loop(sc); + rgephy_reset(sc); - PHY_WRITE(mii, RGEPHY_MII_ANAR, - BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA); + anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; + if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + anar |= RGEPHY_ANAR_PC | RGEPHY_ANAR_ASP; + PHY_WRITE(sc, RGEPHY_MII_ANAR, anar); DELAY(1000); - PHY_WRITE(mii, RGEPHY_MII_1000CTL, - RGEPHY_1000CTL_AHD|RGEPHY_1000CTL_AFD); + PHY_WRITE(sc, RGEPHY_MII_1000CTL, + RGEPHY_1000CTL_AHD | RGEPHY_1000CTL_AFD); DELAY(1000); - PHY_WRITE(mii, RGEPHY_MII_BMCR, + PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); DELAY(100); diff --git a/sys/dev/mii/smcphy.c b/sys/dev/mii/smcphy.c index f442858..a04e39f 100644 --- a/sys/dev/mii/smcphy.c +++ b/sys/dev/mii/smcphy.c @@ -54,7 +54,7 @@ static int smcphy_attach(device_t); static int smcphy_service(struct mii_softc *, struct mii_data *, int); static int smcphy_reset(struct mii_softc *); -static void smcphy_auto(struct mii_softc *); +static void smcphy_auto(struct mii_softc *, int); static device_method_t smcphy_methods[] = { /* device interface */ @@ -148,7 +148,7 @@ smcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: - smcphy_auto(sc); + smcphy_auto(sc, ife->ifm_media); break; default: @@ -187,7 +187,7 @@ smcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) if (smcphy_reset(sc) != 0) { device_printf(sc->mii_dev, "reset failed\n"); } - smcphy_auto(sc); + smcphy_auto(sc, ife->ifm_media); break; } @@ -223,13 +223,13 @@ smcphy_reset(struct mii_softc *sc) } static void -smcphy_auto(struct mii_softc *sc) +smcphy_auto(struct mii_softc *sc, int media) { uint16_t anar; anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; - if (sc->mii_flags & MIIF_DOPAUSE) + if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) anar |= ANAR_FC; PHY_WRITE(sc, MII_ANAR, anar); /* Apparently this helps. */ diff --git a/sys/dev/mii/ukphy_subr.c b/sys/dev/mii/ukphy_subr.c index 9decd36..5f2f634 100644 --- a/sys/dev/mii/ukphy_subr.c +++ b/sys/dev/mii/ukphy_subr.c @@ -117,6 +117,13 @@ ukphy_status(struct mii_softc *phy) mii->mii_media_active |= IFM_10_T|IFM_HDX; else mii->mii_media_active |= IFM_NONE; + + if ((mii->mii_media_active & IFM_1000_T) != 0 && + (gtsr & GTSR_MS_RES) != 0) + mii->mii_media_active |= IFM_ETH_MASTER; + + if ((mii->mii_media_active & IFM_FDX) != 0) + mii->mii_media_active |= mii_phy_flowstatus(phy); } else mii->mii_media_active = ife->ifm_media; } diff --git a/sys/dev/mii/xmphy.c b/sys/dev/mii/xmphy.c index 745c7b3..d662687 100644 --- a/sys/dev/mii/xmphy.c +++ b/sys/dev/mii/xmphy.c @@ -167,7 +167,7 @@ xmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) if (PHY_READ(sc, XMPHY_MII_BMCR) & XMPHY_BMCR_AUTOEN) return (0); #endif - (void) xmphy_mii_phy_auto(sc); + (void)xmphy_mii_phy_auto(sc); break; case IFM_1000_SX: mii_phy_reset(sc); @@ -179,9 +179,6 @@ xmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) PHY_WRITE(sc, XMPHY_MII_BMCR, 0); } break; - case IFM_100_T4: - case IFM_100_TX: - case IFM_10_T: default: return (EINVAL); } diff --git a/sys/dev/msk/if_msk.c b/sys/dev/msk/if_msk.c index 8eb2ffa..810ab03 100644 --- a/sys/dev/msk/if_msk.c +++ b/sys/dev/msk/if_msk.c @@ -529,11 +529,11 @@ msk_miibus_statchg(device_t dev) break; } - /* Disable Rx flow control. */ - if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FLAG0) == 0) + if ((IFM_OPTIONS(mii->mii_media_active) & + IFM_ETH_RXPAUSE) == 0) gmac |= GM_GPCR_FC_RX_DIS; - /* Disable Tx flow control. */ - if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FLAG1) == 0) + if ((IFM_OPTIONS(mii->mii_media_active) & + IFM_ETH_TXPAUSE) == 0) gmac |= GM_GPCR_FC_TX_DIS; if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) gmac |= GM_GPCR_DUP_FULL; @@ -545,7 +545,8 @@ msk_miibus_statchg(device_t dev) GMAC_READ_2(sc, sc_if->msk_port, GM_GP_CTRL); gmac = GMC_PAUSE_OFF; if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { - if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FLAG0) != 0) + if ((IFM_OPTIONS(mii->mii_media_active) & + IFM_ETH_RXPAUSE) != 0) gmac = GMC_PAUSE_ON; } CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, GMAC_CTRL), gmac); @@ -1886,6 +1887,7 @@ mskc_attach(device_t dev) } mmd->port = MSK_PORT_A; mmd->pmd = sc->msk_pmd; + mmd->mii_flags |= MIIF_DOPAUSE; if (sc->msk_pmd == 'L' || sc->msk_pmd == 'S') mmd->mii_flags |= MIIF_HAVEFIBER; if (sc->msk_pmd == 'P') diff --git a/sys/dev/nfe/if_nfe.c b/sys/dev/nfe/if_nfe.c index 347cf2b..fcc11c2 100644 --- a/sys/dev/nfe/if_nfe.c +++ b/sys/dev/nfe/if_nfe.c @@ -605,7 +605,8 @@ nfe_attach(device_t dev) /* Do MII setup */ error = mii_attach(dev, &sc->nfe_miibus, ifp, nfe_ifmedia_upd, - nfe_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); + nfe_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, + MIIF_DOPAUSE); if (error != 0) { device_printf(dev, "attaching PHYs failed\n"); goto fail; @@ -906,7 +907,8 @@ nfe_mac_config(struct nfe_softc *sc, struct mii_data *mii) if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { /* It seems all hardwares supports Rx pause frames. */ val = NFE_READ(sc, NFE_RXFILTER); - if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FLAG0) != 0) + if ((IFM_OPTIONS(mii->mii_media_active) & + IFM_ETH_RXPAUSE) != 0) val |= NFE_PFF_RX_PAUSE; else val &= ~NFE_PFF_RX_PAUSE; @@ -914,7 +916,7 @@ nfe_mac_config(struct nfe_softc *sc, struct mii_data *mii) if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { val = NFE_READ(sc, NFE_MISC1); if ((IFM_OPTIONS(mii->mii_media_active) & - IFM_FLAG1) != 0) { + IFM_ETH_TXPAUSE) != 0) { NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, NFE_TX_PAUSE_FRAME_ENABLE); val |= NFE_MISC1_TX_PAUSE; diff --git a/sys/dev/stge/if_stge.c b/sys/dev/stge/if_stge.c index 9e85771..34051b0 100644 --- a/sys/dev/stge/if_stge.c +++ b/sys/dev/stge/if_stge.c @@ -738,7 +738,7 @@ stge_attach(device_t dev) (PC_PhyDuplexPolarity | PC_PhyLnkPolarity); /* Set up MII bus. */ - flags = 0; + flags = MIIF_DOPAUSE; if (sc->sc_rev >= 0x40 && sc->sc_rev <= 0x4e) flags |= MIIF_MACPRIV0; error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, stge_mediachange, @@ -1524,9 +1524,9 @@ stge_link_task(void *arg, int pending) sc->sc_MACCtrl = 0; if (((mii->mii_media_active & IFM_GMASK) & IFM_FDX) != 0) sc->sc_MACCtrl |= MC_DuplexSelect; - if (((mii->mii_media_active & IFM_GMASK) & IFM_FLAG0) != 0) + if (((mii->mii_media_active & IFM_GMASK) & IFM_ETH_RXPAUSE) != 0) sc->sc_MACCtrl |= MC_RxFlowControlEnable; - if (((mii->mii_media_active & IFM_GMASK) & IFM_FLAG1) != 0) + if (((mii->mii_media_active & IFM_GMASK) & IFM_ETH_TXPAUSE) != 0) sc->sc_MACCtrl |= MC_TxFlowControlEnable; /* * Update STGE_MACCtrl register depending on link status. |