summaryrefslogtreecommitdiffstats
path: root/sys/dev/mii/brgphy.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/mii/brgphy.c')
-rw-r--r--sys/dev/mii/brgphy.c193
1 files changed, 58 insertions, 135 deletions
diff --git a/sys/dev/mii/brgphy.c b/sys/dev/mii/brgphy.c
index 62fcd8f..c0b1428 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);
@@ -279,8 +276,7 @@ brgphy_attach(device_t dev)
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;
+ ma->mii_capmask &= ~BMSR_EXTSTAT;
}
brgphy_reset(sc);
@@ -295,27 +291,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 +316,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 +345,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 +374,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 +391,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 +433,6 @@ brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
return (0);
}
-
/****************************************************************************/
/* Sets the PHY link speed. */
/* */
@@ -464,12 +440,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 +460,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 +467,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 +500,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 +551,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 +578,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 +599,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 +625,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 +855,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 +867,6 @@ brgphy_fixup_disable_early_dac(struct mii_softc *sc)
}
-
static void
brgphy_ethernet_wirespeed(struct mii_softc *sc)
{
@@ -948,7 +878,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 +918,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 +958,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 +988,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 +1079,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 +1091,5 @@ brgphy_reset(struct mii_softc *sc)
brgphy_jumbo_settings(sc, ifp->if_mtu);
brgphy_ethernet_wirespeed(sc);
}
-
}
}
OpenPOWER on IntegriCloud