diff options
-rw-r--r-- | sys/dev/mii/brgphy.c | 375 |
1 files changed, 296 insertions, 79 deletions
diff --git a/sys/dev/mii/brgphy.c b/sys/dev/mii/brgphy.c index cd5be3501c2..b6279316099 100644 --- a/sys/dev/mii/brgphy.c +++ b/sys/dev/mii/brgphy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: brgphy.c,v 1.80 2008/06/11 23:53:49 brad Exp $ */ +/* $OpenBSD: brgphy.c,v 1.81 2008/06/13 22:23:08 brad Exp $ */ /* * Copyright (c) 2000 @@ -63,6 +63,7 @@ #include <dev/mii/brgphyreg.h> #include <dev/pci/if_bgereg.h> +#include <dev/pci/if_bnxreg.h> int brgphy_probe(struct device *, void *, void *); void brgphy_attach(struct device *, struct device *, void *); @@ -77,7 +78,9 @@ struct cfdriver brgphy_cd = { }; int brgphy_service(struct mii_softc *, struct mii_data *, int); -void brgphy_status(struct mii_softc *); +void brgphy_copper_status(struct mii_softc *); +void brgphy_fiber_status(struct mii_softc *); +void brgphy_5708s_status(struct mii_softc *); int brgphy_mii_phy_auto(struct mii_softc *); void brgphy_loop(struct mii_softc *); void brgphy_reset(struct mii_softc *); @@ -92,8 +95,16 @@ void brgphy_crc_bug(struct mii_softc *); void brgphy_jumbo_settings(struct mii_softc *); void brgphy_eth_wirespeed(struct mii_softc *); -const struct mii_phy_funcs brgphy_funcs = { - brgphy_service, brgphy_status, brgphy_reset, +const struct mii_phy_funcs brgphy_copper_funcs = { + brgphy_service, brgphy_copper_status, brgphy_reset, +}; + +const struct mii_phy_funcs brgphy_fiber_funcs = { + brgphy_service, brgphy_fiber_status, brgphy_reset, +}; + +const struct mii_phy_funcs brgphy_5708s_funcs = { + brgphy_service, brgphy_5708s_status, brgphy_reset, }; static const struct mii_phydesc brgphys[] = { @@ -135,6 +146,8 @@ static const struct mii_phydesc brgphys[] = { MII_STR_xxBROADCOM_BCM5706 }, { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5708C, MII_STR_xxBROADCOM_BCM5708C }, + { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5708S, + MII_STR_xxBROADCOM2_BCM5708S }, { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5906, MII_STR_BROADCOM2_BCM5906 }, @@ -157,39 +170,65 @@ void brgphy_attach(struct device *parent, struct device *self, void *aux) { struct mii_softc *sc = (struct mii_softc *)self; + struct bnx_softc *bnx_sc = NULL; struct mii_attach_args *ma = aux; struct mii_data *mii = ma->mii_data; const struct mii_phydesc *mpd; + char *devname; + + devname = sc->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name; mpd = mii_phy_match(ma, brgphys); printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); sc->mii_inst = mii->mii_instance; sc->mii_phy = ma->mii_phyno; - sc->mii_funcs = &brgphy_funcs; sc->mii_model = MII_MODEL(ma->mii_id2); sc->mii_rev = MII_REV(ma->mii_id2); sc->mii_pdata = mii; sc->mii_flags = ma->mii_flags; + if (sc->mii_flags & MIIF_HAVEFIBER) { + if (MII_OUI(ma->mii_id1, ma->mii_id2) == + MII_OUI_xxBROADCOM && + (sc->mii_model == MII_MODEL_xxBROADCOM_BCM5706 || + sc->mii_model == MII_MODEL_xxBROADCOM_BCM5714 || + sc->mii_model == MII_MODEL_xxBROADCOM_BCM5780)) + sc->mii_funcs = &brgphy_fiber_funcs; + else if (MII_OUI(ma->mii_id1, ma->mii_id2) == + MII_OUI_xxBROADCOM2 && sc->mii_model == + MII_MODEL_xxBROADCOM2_BCM5708S) + sc->mii_funcs = &brgphy_5708s_funcs; + } else + sc->mii_funcs = &brgphy_copper_funcs; sc->mii_anegticks = MII_ANEGTICKS; - sc->mii_flags |= MIIF_NOISOLATE; + sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; + + if (strcmp(devname, "bnx") == 0) + bnx_sc = sc->mii_pdata->mii_ifp->if_softc; PHY_RESET(sc); sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; if (sc->mii_capabilities & BMSR_EXTSTAT) sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); - if ((sc->mii_capabilities & BMSR_MEDIAMASK) || - (sc->mii_extcapabilities & EXTSR_MEDIAMASK)) - mii_phy_add_media(sc); + + mii_phy_add_media(sc); + + if (sc->mii_flags & MIIF_HAVEFIBER && bnx_sc && + (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG)) { + sc->mii_anegticks = MII_ANEGTICKS_GIGE; + ifmedia_add(&mii->mii_media, + IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, IFM_FDX, + sc->mii_inst), 0, NULL); + } } int brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg, speed, gig; + int reg, speed = 0, gig; if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0) return (ENXIO); @@ -226,6 +265,9 @@ brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) case IFM_AUTO: (void) brgphy_mii_phy_auto(sc); break; + case IFM_2500_SX: + speed = BRGPHY_5708S_BMCR_2500; + goto setit; case IFM_1000_T: speed = BRGPHY_S1000; goto setit; @@ -247,7 +289,9 @@ setit: PHY_WRITE(sc, BRGPHY_MII_BMCR, speed); PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE); - if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) + if ((IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) && + (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_SX) && + (IFM_SUBTYPE(ife->ifm_media) != IFM_2500_SX)) break; PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig); @@ -290,8 +334,8 @@ setit: * need to restart the autonegotiation process. Read * the BMSR twice in case it's latched. */ - reg = PHY_READ(sc, BRGPHY_MII_AUXSTS); - if (reg & BRGPHY_AUXSTS_LINK) + reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); + if (reg & BMSR_LINK) break; /* @@ -336,19 +380,16 @@ setit: } void -brgphy_status(struct mii_softc *sc) +brgphy_copper_status(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int bmsr, bmcr, gsr; + int bmcr, bmsr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; - bmsr = PHY_READ(sc, BRGPHY_MII_BMSR); - if (PHY_READ(sc, BRGPHY_MII_AUXSTS) & BRGPHY_AUXSTS_LINK) - mii->mii_media_status |= IFM_ACTIVE; - + bmsr = PHY_READ(sc, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR); bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); if (bmcr & BRGPHY_BMCR_LOOP) @@ -360,6 +401,12 @@ brgphy_status(struct mii_softc *sc) mii->mii_media_active |= IFM_NONE; return; } + } + + if (bmsr & BRGPHY_BMSR_LINK) { + int gsr; + + mii->mii_media_status |= IFM_ACTIVE; switch (PHY_READ(sc, BRGPHY_MII_AUXSTS) & BRGPHY_AUXSTS_AN_RES) { @@ -386,7 +433,7 @@ brgphy_status(struct mii_softc *sc) break; default: mii->mii_media_active |= IFM_NONE; - break; + return; } if (mii->mii_media_active & IFM_FDX) @@ -396,34 +443,146 @@ brgphy_status(struct mii_softc *sc) if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) && gsr & BRGPHY_1000STS_MSR) mii->mii_media_active |= IFM_ETH_MASTER; + } else + mii->mii_media_active = ife->ifm_media; +} - return; +void +brgphy_fiber_status(struct mii_softc *sc) +{ + struct mii_data *mii = sc->mii_pdata; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int bmcr, bmsr; + + 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); + + if (bmcr & BRGPHY_BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BRGPHY_BMCR_AUTOEN) { + if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } } - mii->mii_media_active = ife->ifm_media; + if (bmsr & BRGPHY_BMSR_LINK) { + mii->mii_media_status |= IFM_ACTIVE; + mii->mii_media_active |= IFM_1000_SX; + + /* + * If autoneg enabled, read negotiated + * duplex settings + */ + if (bmcr & BRGPHY_BMCR_AUTOEN) { + int val; + + val = PHY_READ(sc, BRGPHY_SERDES_ANAR) & + PHY_READ(sc, BRGPHY_SERDES_ANLPAR); + + if (val & BRGPHY_SERDES_ANAR_FDX) + mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; + + if (mii->mii_media_active & IFM_FDX) + mii->mii_media_active |= + mii_phy_flowstatus(sc); + } + mii->mii_media_active |= IFM_FDX; + } else + mii->mii_media_active = ife->ifm_media; } +void +brgphy_5708s_status(struct mii_softc *sc) +{ + struct mii_data *mii = sc->mii_pdata; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int bmcr, bmsr; + + 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); + + if (bmcr & BRGPHY_BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BRGPHY_BMCR_AUTOEN) { + if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + } + + if (bmsr & BRGPHY_BMSR_LINK) { + int xstat; + + mii->mii_media_status |= IFM_ACTIVE; + + PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, + BRGPHY_5708S_DIG_PG0); + + xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1); + + /* Todo: Create #defines for hard coded values */ + switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) { + case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10: + mii->mii_media_active |= IFM_10_FL; + break; + case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100: + mii->mii_media_active |= IFM_100_FX; + break; + case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G: + mii->mii_media_active |= IFM_1000_SX; + break; + case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G: + mii->mii_media_active |= IFM_2500_SX; + break; + } + + if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX) + mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; + } else + mii->mii_media_active = ife->ifm_media; +} int brgphy_mii_phy_auto(struct mii_softc *sc) { int anar, ktcr = 0; - brgphy_loop(sc); PHY_RESET(sc); + + if (sc->mii_flags & MIIF_HAVEFIBER) { + anar = BRGPHY_SERDES_ANAR_FDX | BRGPHY_SERDES_ANAR_HDX; + if (sc->mii_flags & MIIF_DOPAUSE) + anar |= BRGPHY_SERDES_ANAR_BOTH_PAUSE; + PHY_WRITE(sc, BRGPHY_SERDES_ANAR, anar); + } else { + anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; + if (sc->mii_flags & MIIF_DOPAUSE) + anar |= BRGPHY_ANAR_ASP | BRGPHY_ANAR_PC; + PHY_WRITE(sc, BRGPHY_MII_ANAR, anar); + } + /* Enable speed in the 1000baseT control register */ - ktcr = BRGPHY_1000CTL_AFD|BRGPHY_1000CTL_AHD; + ktcr = BRGPHY_1000CTL_AFD | BRGPHY_1000CTL_AHD; if (sc->mii_model == MII_MODEL_xxBROADCOM_BCM5701) - ktcr |= BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC; + ktcr |= BRGPHY_1000CTL_MSE | BRGPHY_1000CTL_MSC; PHY_WRITE(sc, BRGPHY_MII_1000CTL, ktcr); ktcr = PHY_READ(sc, BRGPHY_MII_1000CTL); - DELAY(1000); - anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; - if (sc->mii_flags & MIIF_DOPAUSE) - anar |= BRGPHY_ANAR_PC | BRGPHY_ANAR_ASP; - PHY_WRITE(sc, BRGPHY_MII_ANAR, anar); - DELAY(1000); /* Start autonegotiation */ PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); @@ -452,6 +611,7 @@ void brgphy_reset(struct mii_softc *sc) { struct bge_softc *bge_sc = NULL; + struct bnx_softc *bnx_sc = NULL; char *devname; devname = sc->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name; @@ -479,60 +639,117 @@ brgphy_reset(struct mii_softc *sc) /* Handle any bge (NetXtreme/NetLink) workarounds. */ if (strcmp(devname, "bge") == 0) { - bge_sc = sc->mii_pdata->mii_ifp->if_softc; - - if (bge_sc->bge_flags & BGE_PHY_ADC_BUG) - brgphy_adc_bug(sc); - if (bge_sc->bge_flags & BGE_PHY_5704_A0_BUG) - brgphy_5704_a0_bug(sc); - if (bge_sc->bge_flags & BGE_PHY_BER_BUG) - brgphy_ber_bug(sc); - else if (bge_sc->bge_flags & BGE_PHY_JITTER_BUG) { - PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00); - PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a); - - if (bge_sc->bge_flags & BGE_PHY_ADJUST_TRIM) { - PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, - 0x110b); - PHY_WRITE(sc, BRGPHY_TEST1, - BRGPHY_TEST1_TRIM_EN | 0x4); - } else { - PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, - 0x010b); + if (!(sc->mii_flags & MIIF_HAVEFIBER)) { + bge_sc = sc->mii_pdata->mii_ifp->if_softc; + + if (bge_sc->bge_flags & BGE_PHY_ADC_BUG) + brgphy_adc_bug(sc); + if (bge_sc->bge_flags & BGE_PHY_5704_A0_BUG) + brgphy_5704_a0_bug(sc); + if (bge_sc->bge_flags & BGE_PHY_BER_BUG) + brgphy_ber_bug(sc); + else if (bge_sc->bge_flags & BGE_PHY_JITTER_BUG) { + PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00); + PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, + 0x000a); + + if (bge_sc->bge_flags & BGE_PHY_ADJUST_TRIM) { + PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, + 0x110b); + PHY_WRITE(sc, BRGPHY_TEST1, + BRGPHY_TEST1_TRIM_EN | 0x4); + } else { + PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, + 0x010b); + } + + PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400); + } + if (bge_sc->bge_flags & BGE_PHY_CRC_BUG) + brgphy_crc_bug(sc); + + /* Set Jumbo frame settings in the PHY. */ + if (bge_sc->bge_flags & BGE_JUMBO_CAP) + brgphy_jumbo_settings(sc); + + /* Adjust output voltage */ + if (sc->mii_model == MII_MODEL_BROADCOM2_BCM5906) + PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12); + + /* Enable Ethernet@Wirespeed */ + if (!(bge_sc->bge_flags & BGE_NO_ETH_WIRE_SPEED)) + brgphy_eth_wirespeed(sc); + + /* Enable Link LED on Dell boxes */ + if (bge_sc->bge_flags & BGE_NO_3LED) { + PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, + PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) + & ~BRGPHY_PHY_EXTCTL_3_LED); } - - PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400); - } - if (bge_sc->bge_flags & BGE_PHY_CRC_BUG) - brgphy_crc_bug(sc); - - /* Set Jumbo frame settings in the PHY. */ - if (bge_sc->bge_flags & BGE_JUMBO_CAP) - brgphy_jumbo_settings(sc); - - /* Adjust output voltage */ - if (sc->mii_model == MII_MODEL_BROADCOM2_BCM5906) - PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12); - - /* Enable Ethernet@Wirespeed */ - if (!(bge_sc->bge_flags & BGE_NO_ETH_WIRE_SPEED)) - brgphy_eth_wirespeed(sc); - - /* Enable Link LED on Dell boxes */ - if (bge_sc->bge_flags & BGE_NO_3LED) { - PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, - PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) - & ~BRGPHY_PHY_EXTCTL_3_LED); } /* Handle any bnx (NetXtreme II) workarounds. */ } else if (strcmp(devname, "bnx") == 0) { - brgphy_ber_bug(sc); + bnx_sc = sc->mii_pdata->mii_ifp->if_softc; + + if (sc->mii_model == MII_MODEL_xxBROADCOM2_BCM5708S) { + /* Store autoneg capabilities/results in digital block (Page 0) */ + PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2); + PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0, + BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE); + PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); + + /* Enable fiber mode and autodetection */ + PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1, + PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) | + BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN | + BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE); + + /* Enable parallel detection */ + PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2, + PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) | + BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN); + + /* Advertise 2.5G support through next page during autoneg */ + if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) + PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1, + PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) | + BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); + + /* Increase TX signal amplitude */ + if ((BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_A0) || + (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B0) || + (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B1)) { + PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, + BRGPHY_5708S_TX_MISC_PG5); + PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1, + PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) & + ~BRGPHY_5708S_PG5_TXACTL1_VCM); + PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, + BRGPHY_5708S_DIG_PG0); + } + + /* Backplanes use special driver/pre-driver/pre-emphasis values. */ + if ((bnx_sc->bnx_shared_hw_cfg & BNX_SHARED_HW_CFG_PHY_BACKPLANE) && + (bnx_sc->bnx_port_hw_cfg & BNX_PORT_HW_CFG_CFG_TXCTL3_MASK)) { + PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, + BRGPHY_5708S_TX_MISC_PG5); + PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3, + bnx_sc->bnx_port_hw_cfg & + BNX_PORT_HW_CFG_CFG_TXCTL3_MASK); + PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, + BRGPHY_5708S_DIG_PG0); + } + } else { + if (!(sc->mii_flags & MIIF_HAVEFIBER)) { + brgphy_ber_bug(sc); - /* Set Jumbo frame settings in the PHY. */ - brgphy_jumbo_settings(sc); + /* Set Jumbo frame settings in the PHY. */ + brgphy_jumbo_settings(sc); - /* Enable Ethernet@Wirespeed */ - brgphy_eth_wirespeed(sc); + /* Enable Ethernet@Wirespeed */ + brgphy_eth_wirespeed(sc); + } + } } } |