summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2010-11-14 13:26:10 +0000
committermarius <marius@FreeBSD.org>2010-11-14 13:26:10 +0000
commit278d761d736b370c6ad85e2ff6593c0f73d10c6f (patch)
tree0a614cfaa905b5ed3990c39e22746b87533fa46d /sys/dev
parent521fec1e8ecddcd8437e230ff52cc8f28994a2c0 (diff)
downloadFreeBSD-src-278d761d736b370c6ad85e2ff6593c0f73d10c6f.zip
FreeBSD-src-278d761d736b370c6ad85e2ff6593c0f73d10c6f.tar.gz
o Flesh out the generic IEEE 802.3 annex 31B full duplex flow control
support in mii(4): - Merge generic flow control advertisement (which can be enabled by passing by MIIF_DOPAUSE to mii_attach(9)) and parsing support from NetBSD into mii_physubr.c and ukphy_subr.c. Unlike as in NetBSD, IFM_FLOW isn't implemented as a global option via the "don't care mask" but instead as a media specific option this. This has the following advantages: o allows flow control advertisement with autonegotiation to be turned on and off via ifconfig(8) with the default typically being off (though MIIF_FORCEPAUSE has been added causing flow control to be always advertised, allowing to easily MFC this changes for drivers that previously used home-grown support for flow control that behaved that way without breaking POLA) o allows to deal with PHY drivers where flow control advertisement with manual selection doesn't work or at least isn't implemented, like it's the case with brgphy(4), e1000phy(4) and ip1000phy(4), by setting MIIF_NOMANPAUSE o the available combinations of media options are readily available from the `ifconfig -m` output - Add IFM_FLOW to IFM_SHARED_OPTION_DESCRIPTIONS and IFM_ETH_RXPAUSE and IFM_ETH_TXPAUSE to IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS so these are understood by ifconfig(8). o Make the master/slave support in mii(4) actually usable: - Change IFM_ETH_MASTER from being implemented as a global option via the "don't care mask" to a media specific one as it actually is only applicable to IFM_1000_T to date. - Let mii_phy_setmedia() set GTCR_MAN_MS in IFM_1000_T slave mode to actually configure manually selected slave mode (like we also do in the PHY specific implementations). - Add IFM_ETH_MASTER to IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS so it is understood by ifconfig(8). o Switch bge(4), bce(4), msk(4), nfe(4) and stge(4) along with brgphy(4), e1000phy(4) and ip1000phy(4) to use the generic flow control support instead of home-grown solutions via IFM_FLAGs. This includes changing these PHY drivers and smcphy(4) to no longer unconditionally advertise support for flow control but only if the selected media has IFM_FLOW set (or MIIF_FORCEPAUSE is set) and implemented for these media variants, i.e. typically only for copper. o Switch brgphy(4), ciphy(4), e1000phy(4) and ip1000phy(4) to report and set IFM_1000_T master mode via IFM_ETH_MASTER instead of via IFF_LINK0 and some IFM_FLAGn. o Switch brgphy(4) to add at least the the supported copper media based on the contents of the BMSR via mii_phy_add_media() instead of hardcoding them. The latter approach seems to have developed historically, besides causing unnecessary code duplication it was also undesirable because brgphy_mii_phy_auto() already based the capability advertisement on the contents of the BMSR though. o Let brgphy(4) set IFM_1000_T master mode on all supported PHY and not just BCM5701. Apparently this was a misinterpretation of a workaround in the Linux tg3 driver; BCM5701 seem to require RGPHY_1000CTL_MSE and BRGPHY_1000CTL_MSC to be set when configuring autonegotiation but this doesn't mean we can't set these as well on other PHYs for manual media selection. o Let ukphy_status() report IFM_1000_T master mode via IFM_ETH_MASTER so IFM_1000_T master mode support now is generally available with all PHY drivers. o Don't let e1000phy(4) set master/slave bits for IFM_1000_SX as it's not applicable there. Reviewed by: yongari (plus additional testing) Obtained from: NetBSD (partially), OpenBSD (partially) MFC after: 2 weeks
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/bce/if_bce.c7
-rw-r--r--sys/dev/bge/if_bge.c10
-rw-r--r--sys/dev/mii/brgphy.c193
-rw-r--r--sys/dev/mii/ciphy.c30
-rw-r--r--sys/dev/mii/e1000phy.c82
-rw-r--r--sys/dev/mii/ip1000phy.c63
-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/smcphy.c10
-rw-r--r--sys/dev/mii/ukphy_subr.c7
-rw-r--r--sys/dev/msk/if_msk.c12
-rw-r--r--sys/dev/nfe/if_nfe.c8
-rw-r--r--sys/dev/stge/if_stge.c6
14 files changed, 300 insertions, 303 deletions
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..9b5be11 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);
@@ -3102,9 +3104,9 @@ bge_attach(device_t dev)
again:
bge_asf_driver_up(sc);
- error = (mii_attach(dev, &sc->bge_miibus, ifp,
+ error = mii_attach(dev, &sc->bge_miibus, ifp,
bge_ifmedia_upd, bge_ifmedia_sts, BMSR_DEFCAPMASK,
- phy_addr, MII_OFFSET_ANY, 0));
+ 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/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);
}
-
}
}
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/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/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/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/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.
OpenPOWER on IntegriCloud