summaryrefslogtreecommitdiffstats
path: root/sys/dev/mii
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/mii')
-rw-r--r--sys/dev/mii/atphy.c36
-rw-r--r--sys/dev/mii/brgphy.c202
-rw-r--r--sys/dev/mii/ciphy.c30
-rw-r--r--sys/dev/mii/e1000phy.c82
-rw-r--r--sys/dev/mii/gentbi.c3
-rw-r--r--sys/dev/mii/ip1000phy.c63
-rw-r--r--sys/dev/mii/jmphy.c37
-rw-r--r--sys/dev/mii/mii.h9
-rw-r--r--sys/dev/mii/mii_physubr.c162
-rw-r--r--sys/dev/mii/miivar.h4
-rw-r--r--sys/dev/mii/nsgphy.c3
-rw-r--r--sys/dev/mii/rgephy.c78
-rw-r--r--sys/dev/mii/smcphy.c10
-rw-r--r--sys/dev/mii/ukphy_subr.c7
-rw-r--r--sys/dev/mii/xmphy.c5
15 files changed, 358 insertions, 373 deletions
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);
}
OpenPOWER on IntegriCloud