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
This commit is contained in:
parent
57bd39c6d6
commit
efd4fc3fb3
26
UPDATING
26
UPDATING
@ -22,6 +22,32 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 9.x IS SLOW:
|
||||
machines to maximize performance. (To disable malloc debugging, run
|
||||
ln -s aj /etc/malloc.conf.)
|
||||
|
||||
20101114:
|
||||
Generic IEEE 802.3 annex 31B full duplex flow control support has been
|
||||
added to mii(4) and bge(4), bce(4), msk(4), nfe(4) and stge(4) along
|
||||
with brgphy(4), e1000phy(4) as well as ip1000phy() have been converted
|
||||
to take advantage of it instead of using custom implementations. This
|
||||
means that these drivers now no longer unconditionally advertise
|
||||
support for flow control but only do so if flow control is a selected
|
||||
media option. This was implemented in the generic support that way in
|
||||
order to allow flow control to be switched on and off via ifconfig(8)
|
||||
with the PHY specific default to typically off in order to protect
|
||||
from unwanted effects. Consequently, if you used flow control with
|
||||
one of the above mentioned drivers you now need to explicitly enable
|
||||
it, for example via:
|
||||
ifconfig bge0 media auto mediaopt flowcontrol
|
||||
|
||||
Along with the above mentioned changes generic support for setting
|
||||
1000baseT master mode also has been added and brgphy(4), ciphy(4),
|
||||
e1000phy(4) as well as ip1000phy(4) have been converted to take
|
||||
advantage of it. This means that these drivers now no longer take the
|
||||
link0 parameter for selecting master mode but the master media option
|
||||
has to be used instead, for example like in the following:
|
||||
ifconfig bge0 media 1000baseT mediaopt full-duplex,master
|
||||
|
||||
Selection of master mode now is also available with all other PHY
|
||||
drivers supporting 1000baseT.
|
||||
|
||||
20101111:
|
||||
The TCP stack has received a significant update to add support for
|
||||
modularised congestion control and generally improve the clarity of
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
||||
/* Set duplex speed advertisement for 1000BaseT/1000BaseX. */
|
||||
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);
|
||||
if (IFM_SUBTYPE(media) != IFM_1000_T &&
|
||||
IFM_SUBTYPE(media) != IFM_1000_SX) {
|
||||
PHY_WRITE(sc, BRGPHY_MII_BMCR, bmcr);
|
||||
return;
|
||||
}
|
||||
|
||||
brgphy_setmedia_exit:
|
||||
return;
|
||||
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);
|
||||
PHY_WRITE(sc, BRGPHY_MII_BMCR,
|
||||
bmcr | BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ ciphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
|
||||
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
|
||||
|
@ -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 @@ e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
|
||||
|
||||
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);
|
||||
|
@ -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 @@ ip1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
|
||||
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);
|
||||
if ((mii->mii_media_active & IFM_FDX) != 0)
|
||||
mii->mii_media_active |= mii_phy_flowstatus(sc);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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')
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -155,6 +155,8 @@ uint64_t ifmedia_baudrate(int);
|
||||
/* note 31 is the max! */
|
||||
|
||||
#define IFM_ETH_MASTER 0x00000100 /* master mode (1000baseT) */
|
||||
#define IFM_ETH_RXPAUSE 0x00000200 /* receive PAUSE frames */
|
||||
#define IFM_ETH_TXPAUSE 0x00000400 /* transmit PAUSE frames */
|
||||
|
||||
/*
|
||||
* Token ring
|
||||
@ -262,6 +264,7 @@ uint64_t ifmedia_baudrate(int);
|
||||
*/
|
||||
#define IFM_FDX 0x00100000 /* Force full duplex */
|
||||
#define IFM_HDX 0x00200000 /* Force half duplex */
|
||||
#define IFM_FLOW 0x00400000 /* enable hardware flow control */
|
||||
#define IFM_FLAG0 0x01000000 /* Driver defined flag */
|
||||
#define IFM_FLAG1 0x02000000 /* Driver defined flag */
|
||||
#define IFM_FLAG2 0x04000000 /* Driver defined flag */
|
||||
@ -279,6 +282,9 @@ uint64_t ifmedia_baudrate(int);
|
||||
#define IFM_MSHIFT 16 /* Mode shift */
|
||||
#define IFM_GMASK 0x0ff00000 /* Global options */
|
||||
|
||||
/* Ethernet flow control mask */
|
||||
#define IFM_ETH_FMASK (IFM_FLOW | IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE)
|
||||
|
||||
/*
|
||||
* Status bits
|
||||
*/
|
||||
@ -388,6 +394,9 @@ struct ifmedia_description {
|
||||
}
|
||||
|
||||
#define IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS { \
|
||||
{ IFM_ETH_MASTER, "master" }, \
|
||||
{ IFM_ETH_RXPAUSE, "rxpause" }, \
|
||||
{ IFM_ETH_TXPAUSE, "txpause" }, \
|
||||
{ 0, NULL }, \
|
||||
}
|
||||
|
||||
@ -583,6 +592,7 @@ struct ifmedia_description {
|
||||
#define IFM_SHARED_OPTION_DESCRIPTIONS { \
|
||||
{ IFM_FDX, "full-duplex" }, \
|
||||
{ IFM_HDX, "half-duplex" }, \
|
||||
{ IFM_FLOW, "flowcontrol" }, \
|
||||
{ IFM_FLAG0, "flag0" }, \
|
||||
{ IFM_FLAG1, "flag1" }, \
|
||||
{ IFM_FLAG2, "flag2" }, \
|
||||
|
Loading…
Reference in New Issue
Block a user