summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/mii/inphy.c27
-rw-r--r--sys/dev/mii/mii.h2
-rw-r--r--sys/dev/mii/mii_physubr.c244
-rw-r--r--sys/dev/mii/miivar.h1
-rw-r--r--sys/dev/mii/nsgphy.c255
-rw-r--r--sys/dev/mii/nsgphyreg.h4
-rw-r--r--sys/dev/nge/if_nge.c4
7 files changed, 247 insertions, 290 deletions
diff --git a/sys/dev/mii/inphy.c b/sys/dev/mii/inphy.c
index 58e070f..6ad444a 100644
--- a/sys/dev/mii/inphy.c
+++ b/sys/dev/mii/inphy.c
@@ -144,7 +144,7 @@ inphy_attach(device_t dev)
sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
device_printf(dev, " ");
- mii_add_media(sc);
+ mii_phy_add_media(sc);
printf("\n");
MIIBUS_MEDIAINIT(sc->mii_dev);
@@ -192,27 +192,7 @@ inphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
break;
- switch (IFM_SUBTYPE(ife->ifm_media)) {
- case IFM_AUTO:
- /*
- * If we're already in auto mode, just return.
- */
- if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
- return (0);
- (void) mii_phy_auto(sc, 0);
- break;
- case IFM_100_T4:
- /*
- * XXX Not supported as a manual setting right now.
- */
- return (EINVAL);
- default:
- /*
- * BMCR data is stored in the ifmedia entry.
- */
- PHY_WRITE(sc, MII_ANAR, mii_anar(ife->ifm_media));
- PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
- }
+ mii_phy_setmedia(sc);
break;
case MII_TICK:
@@ -235,6 +215,7 @@ static void
inphy_status(struct mii_softc *sc)
{
struct mii_data *mii = sc->mii_pdata;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int bmsr, bmcr, scr;
mii->mii_media_status = IFM_AVALID;
@@ -268,5 +249,5 @@ inphy_status(struct mii_softc *sc)
if (scr & SCR_FDX)
mii->mii_media_active |= IFM_FDX;
} else
- mii->mii_media_active |= mii_media_from_bmcr(bmcr);
+ mii->mii_media_active = ife->ifm_media;
}
diff --git a/sys/dev/mii/mii.h b/sys/dev/mii/mii.h
index d37fb5f..963c226 100644
--- a/sys/dev/mii/mii.h
+++ b/sys/dev/mii/mii.h
@@ -92,7 +92,7 @@
* info available in register 15, but 802.3 section 22.2.4.3 also
* states that that all 1000 Mb/s capable PHYs will set this bit to 1.
*/
-#if 1
+#if 0
#define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX|BMSR_10TFDX| \
BMSR_10THDX|BMSR_ANEG)
diff --git a/sys/dev/mii/mii_physubr.c b/sys/dev/mii/mii_physubr.c
index 2bc17b0..c2b7a11 100644
--- a/sys/dev/mii/mii_physubr.c
+++ b/sys/dev/mii/mii_physubr.c
@@ -1,7 +1,7 @@
/* $NetBSD: mii_physubr.c,v 1.5 1999/08/03 19:41:49 drochner Exp $ */
/*-
- * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -127,10 +127,9 @@ mii_phy_setmedia(struct mii_softc *sc)
* Table index is stored in the media entry.
*/
-#ifdef DIAGNOSTIC
- if (ife->ifm_data < 0 || ife->ifm_data >= MII_NMEDIA)
- panic("mii_phy_setmedia");
-#endif
+ KASSERT(ife->ifm_data >=0 && ife->ifm_data < MII_NMEDIA,
+ ("invalid ife->ifm_data (0x%x) in mii_phy_setmedia",
+ ife->ifm_data));
anar = mii_media_table[ife->ifm_data].mm_anar;
bmcr = mii_media_table[ife->ifm_data].mm_bmcr;
@@ -157,29 +156,57 @@ mii_phy_setmedia(struct mii_softc *sc)
}
int
-mii_phy_auto(mii, waitfor)
- struct mii_softc *mii;
- int waitfor;
+mii_phy_auto(struct mii_softc *sc, int waitfor)
{
int bmsr, i;
- if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
- PHY_WRITE(mii, MII_ANAR,
- BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA);
- PHY_WRITE(mii, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
+ if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
+ /*
+ * Check for 1000BASE-X. Autonegotiation is a bit
+ * different on such devices.
+ */
+ if (sc->mii_flags & MIIF_IS_1000X) {
+ uint16_t anar = 0;
+
+ if (sc->mii_extcapabilities & EXTSR_1000XFDX)
+ anar |= ANAR_X_FD;
+ if (sc->mii_extcapabilities & EXTSR_1000XHDX)
+ anar |= ANAR_X_HD;
+
+ if (sc->mii_flags & MIIF_DOPAUSE) {
+ /* XXX Asymmetric vs. symmetric? */
+ anar |= ANLPAR_X_PAUSE_TOWARDS;
+ }
+
+ PHY_WRITE(sc, MII_ANAR, anar);
+ } else {
+ uint16_t anar;
+
+ anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) |
+ ANAR_CSMA;
+ if (sc->mii_flags & MIIF_DOPAUSE)
+ anar |= ANAR_FC;
+ PHY_WRITE(sc, MII_ANAR, anar);
+ if (sc->mii_flags & MIIF_HAVE_GTCR) {
+ uint16_t gtcr = 0;
+
+ if (sc->mii_extcapabilities & EXTSR_1000TFDX)
+ gtcr |= GTCR_ADV_1000TFDX;
+ if (sc->mii_extcapabilities & EXTSR_1000THDX)
+ gtcr |= GTCR_ADV_1000THDX;
+
+ PHY_WRITE(sc, MII_100T2CR, gtcr);
+ }
+ }
+ PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
}
if (waitfor) {
/* Wait 500ms for it to complete. */
for (i = 0; i < 500; i++) {
- if ((bmsr = PHY_READ(mii, MII_BMSR)) & BMSR_ACOMP)
+ if ((bmsr = PHY_READ(sc, MII_BMSR)) & BMSR_ACOMP)
return (0);
DELAY(1000);
-#if 0
- if ((bmsr & BMSR_ACOMP) == 0)
- printf("%s: autonegotiation failed to complete\n",
- mii->mii_dev.dv_xname);
-#endif
}
/*
@@ -195,9 +222,9 @@ mii_phy_auto(mii, waitfor)
* the tick handler driving autonegotiation. Don't want 500ms
* delays all the time while the system is running!
*/
- if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
- mii->mii_flags |= MIIF_DOINGAUTO;
- mii->mii_auto_ch = timeout(mii_phy_auto_timeout, mii, hz >> 1);
+ if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
+ sc->mii_flags |= MIIF_DOINGAUTO;
+ sc->mii_auto_ch = timeout(mii_phy_auto_timeout, sc, hz >> 1);
}
return (EJUSTRETURN);
}
@@ -213,37 +240,33 @@ mii_phy_auto_stop(sc)
}
void
-mii_phy_auto_timeout(arg)
- void *arg;
+mii_phy_auto_timeout(void *arg)
{
- struct mii_softc *mii = arg;
+ struct mii_softc *sc = arg;
int s, bmsr;
- s = splnet();
- mii->mii_flags &= ~MIIF_DOINGAUTO;
- bmsr = PHY_READ(mii, MII_BMSR);
#if 0
- if ((bmsr & BMSR_ACOMP) == 0)
- printf("%s: autonegotiation failed to complete\n",
- sc->sc_dev.dv_xname);
+ if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
+ return;
#endif
+ s = splnet();
+ sc->mii_flags &= ~MIIF_DOINGAUTO;
+ bmsr = PHY_READ(sc, MII_BMSR);
+
/* Update the media status. */
- (void) (*mii->mii_service)(mii, mii->mii_pdata, MII_POLLSTAT);
+ (void) (*sc->mii_service)(sc, sc->mii_pdata, MII_POLLSTAT);
splx(s);
}
int
-mii_phy_tick(sc)
- struct mii_softc *sc;
+mii_phy_tick(struct mii_softc *sc)
{
struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
struct ifnet *ifp = sc->mii_pdata->mii_ifp;
int reg;
- /*
- * Is the interface even up?
- */
+ /* Just bail now if the interface is down. */
if ((ifp->if_flags & IFF_UP) == 0)
return (EJUSTRETURN);
@@ -256,18 +279,21 @@ mii_phy_tick(sc)
if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
return (0);
- /*
- * check for link.
- * Read the status register twice; BMSR_LINK is latch-low.
- */
+ /* Read the status register twice; BMSR_LINK is latch-low. */
reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
- if (reg & BMSR_LINK)
+ if (reg & BMSR_LINK) {
+ /*
+ * See above.
+ */
return (0);
+ }
/*
- * Only retry autonegotiation every 5 seconds.
+ * Only retry autonegotiation every N seconds.
*/
- if (++sc->mii_ticks != 5)
+ if (sc->mii_anegticks == 0)
+ sc->mii_anegticks = 5;
+ if (++sc->mii_ticks != sc->mii_anegticks)
return (EJUSTRETURN);
sc->mii_ticks = 0;
@@ -283,27 +309,26 @@ mii_phy_tick(sc)
}
void
-mii_phy_reset(mii)
- struct mii_softc *mii;
+mii_phy_reset(struct mii_softc *sc)
{
int reg, i;
- if (mii->mii_flags & MIIF_NOISOLATE)
+ if (sc->mii_flags & MIIF_NOISOLATE)
reg = BMCR_RESET;
else
reg = BMCR_RESET | BMCR_ISO;
- PHY_WRITE(mii, MII_BMCR, reg);
+ PHY_WRITE(sc, MII_BMCR, reg);
/* Wait 100ms for it to complete. */
for (i = 0; i < 100; i++) {
- reg = PHY_READ(mii, MII_BMCR);
+ reg = PHY_READ(sc, MII_BMCR);
if ((reg & BMCR_RESET) == 0)
break;
DELAY(1000);
}
- if (mii->mii_inst != 0 && ((mii->mii_flags & MIIF_NOISOLATE) == 0))
- PHY_WRITE(mii, MII_BMCR, reg | BMCR_ISO);
+ if (sc->mii_inst != 0 && ((sc->mii_flags & MIIF_NOISOLATE) == 0))
+ PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
}
void
@@ -436,3 +461,122 @@ mii_add_media(struct mii_softc *sc)
#undef ADD
#undef PRINT
}
+
+/*
+ * Initialize generic PHY media based on BMSR, called when a PHY is
+ * attached. We expect to be set up to print a comma-separated list
+ * of media names. Does not print a newline.
+ */
+void
+mii_phy_add_media(struct mii_softc *sc)
+{
+ struct mii_data *mii = sc->mii_pdata;
+ const char *sep = "";
+
+#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
+#define PRINT(s) printf("%s%s", sep, s); sep = ", "
+
+ if ((sc->mii_flags & MIIF_NOISOLATE) == 0)
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
+ MII_MEDIA_NONE);
+
+ /*
+ * There are different interpretations for the bits in
+ * HomePNA PHYs. And there is really only one media type
+ * that is supported.
+ */
+ if (sc->mii_flags & MIIF_IS_HPNA) {
+ if (sc->mii_capabilities & BMSR_10THDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0,
+ sc->mii_inst),
+ MII_MEDIA_10_T);
+ PRINT("HomePNA1");
+ }
+ return;
+ }
+
+ if (sc->mii_capabilities & BMSR_10THDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
+ MII_MEDIA_10_T);
+ PRINT("10baseT");
+ }
+ if (sc->mii_capabilities & BMSR_10TFDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
+ MII_MEDIA_10_T_FDX);
+ PRINT("10baseT-FDX");
+ }
+ if (sc->mii_capabilities & BMSR_100TXHDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
+ MII_MEDIA_100_TX);
+ PRINT("100baseTX");
+ }
+ if (sc->mii_capabilities & BMSR_100TXFDX) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
+ MII_MEDIA_100_TX_FDX);
+ PRINT("100baseTX-FDX");
+ }
+ if (sc->mii_capabilities & BMSR_100T4) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
+ MII_MEDIA_100_T4);
+ PRINT("100baseT4");
+ }
+
+ if (sc->mii_extcapabilities & EXTSR_MEDIAMASK) {
+ /*
+ * XXX Right now only handle 1000SX and 1000TX. Need
+ * XXX to handle 1000LX and 1000CX some how.
+ *
+ * Note since it can take 5 seconds to auto-negotiate
+ * a gigabit link, we make anegticks 10 seconds for
+ * all the gigabit media types.
+ */
+ if (sc->mii_extcapabilities & EXTSR_1000XHDX) {
+ sc->mii_anegticks = 10;
+ sc->mii_flags |= MIIF_IS_1000X;
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,
+ sc->mii_inst), MII_MEDIA_1000_X);
+ PRINT("1000baseSX");
+ }
+ if (sc->mii_extcapabilities & EXTSR_1000XFDX) {
+ sc->mii_anegticks = 10;
+ sc->mii_flags |= MIIF_IS_1000X;
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
+ sc->mii_inst), MII_MEDIA_1000_X_FDX);
+ PRINT("1000baseSX-FDX");
+ }
+
+ /*
+ * 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.
+ *
+ * All 1000baseT PHYs have a 1000baseT control register.
+ */
+ if (sc->mii_extcapabilities & EXTSR_1000THDX) {
+ sc->mii_anegticks = 10;
+ 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");
+ }
+ if (sc->mii_extcapabilities & EXTSR_1000TFDX) {
+ sc->mii_anegticks = 10;
+ 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");
+ }
+ }
+
+ if (sc->mii_capabilities & BMSR_ANEG) {
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
+ MII_NMEDIA); /* intentionally invalid index */
+ PRINT("auto");
+ }
+#undef ADD
+#undef PRINT
+}
+
diff --git a/sys/dev/mii/miivar.h b/sys/dev/mii/miivar.h
index 69668b0..bc214d9 100644
--- a/sys/dev/mii/miivar.h
+++ b/sys/dev/mii/miivar.h
@@ -197,6 +197,7 @@ void mii_tick(struct mii_data *);
void mii_pollstat(struct mii_data *);
int mii_phy_probe(device_t, device_t *, ifm_change_cb_t, ifm_stat_cb_t);
void mii_add_media(struct mii_softc *);
+void mii_phy_add_media(struct mii_softc *);
int mii_media_from_bmcr(int);
diff --git a/sys/dev/mii/nsgphy.c b/sys/dev/mii/nsgphy.c
index adae9fb..0ee59ea 100644
--- a/sys/dev/mii/nsgphy.c
+++ b/sys/dev/mii/nsgphy.c
@@ -2,6 +2,12 @@
* Copyright (c) 2001 Wind River Systems
* Copyright (c) 2001
* Bill Paul <wpaul@bsdi.com>. All rights reserved.
+ * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -97,7 +103,6 @@ DRIVER_MODULE(nsgphy, miibus, nsgphy_driver, nsgphy_devclass, 0, 0);
static int nsgphy_service(struct mii_softc *, struct mii_data *,int);
static void nsgphy_status(struct mii_softc *);
-static int nsgphy_mii_phy_auto(struct mii_softc *, int);
extern void mii_phy_auto_timeout(void *);
static int
@@ -127,7 +132,6 @@ nsgphy_attach(device_t dev)
struct mii_softc *sc;
struct mii_attach_args *ma;
struct mii_data *mii;
- const char *sep = "";
sc = device_get_softc(dev);
ma = device_get_ivars(dev);
@@ -139,48 +143,17 @@ nsgphy_attach(device_t dev)
sc->mii_phy = ma->mii_phyno;
sc->mii_service = nsgphy_service;
sc->mii_pdata = mii;
+ sc->mii_anegticks = 5;
- sc->mii_flags |= MIIF_NOISOLATE;
mii->mii_instance++;
-#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
-#define PRINT(s) printf("%s%s", sep, s); sep = ", "
-
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
- BMCR_ISO);
-#if 0
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
- BMCR_LOOP|BMCR_S100);
-#endif
-
- mii_phy_reset(sc);
-
- device_printf(dev, " ");
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst),
- BMCR_S1000|BMCR_FDX);
- PRINT("1000baseTX-FDX");
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst),
- BMCR_S1000);
- PRINT("1000baseTX");
sc->mii_capabilities = (PHY_READ(sc, MII_BMSR) |
(BMSR_10TFDX|BMSR_10THDX)) & ma->mii_capmask;
if (sc->mii_capabilities & BMSR_EXTSTAT)
sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
- BMCR_S100|BMCR_FDX);
- PRINT("100baseTX-FDX");
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), BMCR_S100);
- PRINT("100baseTX");
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
- BMCR_S10|BMCR_FDX);
- PRINT("10baseT-FDX");
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), BMCR_S10);
- PRINT("10baseT");
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
- PRINT("auto");
+
+ mii_phy_add_media(sc);
printf("\n");
-#undef ADD
-#undef PRINT
MIIBUS_MEDIAINIT(sc->mii_dev);
return(0);
@@ -234,59 +207,7 @@ nsgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
break;
-
- switch (IFM_SUBTYPE(ife->ifm_media)) {
- case IFM_AUTO:
-#ifdef foo
- /*
- * If we're already in auto mode, just return.
- */
- if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
- return (0);
-#endif
- (void) nsgphy_mii_phy_auto(sc, 0);
- break;
- case IFM_1000_T:
- if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
- PHY_WRITE(sc, MII_BMCR,
- BMCR_FDX|BMCR_SPEED1);
- } else {
- PHY_WRITE(sc, MII_BMCR,
- BMCR_SPEED1);
- }
- PHY_WRITE(sc, MII_ANAR, ANAR_CSMA);
-
- /*
- * 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, MII_100T2CR,
- GTCR_MAN_MS|GTCR_ADV_MS);
- } else {
- PHY_WRITE(sc, MII_100T2CR, GTCR_MAN_MS);
- }
- break;
- case IFM_100_T4:
- /*
- * XXX Not supported as a manual setting right now.
- */
- return (EINVAL);
- case IFM_NONE:
- PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN);
- break;
- default:
- /*
- * BMCR data is stored in the ifmedia entry.
- */
- PHY_WRITE(sc, MII_ANAR, mii_anar(ife->ifm_media));
- PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
- break;
- }
+ mii_phy_setmedia(sc);
break;
case MII_TICK:
@@ -296,39 +217,8 @@ nsgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
if (IFM_INST(ife->ifm_media) != sc->mii_inst)
return (0);
- /*
- * Is the interface even up?
- */
- if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ if (mii_phy_tick(sc) == EJUSTRETURN)
return (0);
-
- /*
- * Only used for autonegotiation.
- */
- if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
- break;
-
- /*
- * Check to see if we have link.
- */
- reg = PHY_READ(sc, NSGPHY_MII_PHYSUP);
- if (reg & NSGPHY_PHYSUP_LNKSTS)
- break;
-
- /*
- * Only retry autonegotiation every 5 seconds.
- * Actually, for gigE PHYs, we should wait longer, since
- * 5 seconds is the mimimum time the documentation
- * says to wait for a 1000mbps link to be established.
- */
- if (++sc->mii_ticks != 10)
- return (0);
-
- sc->mii_ticks = 0;
-
- mii_phy_reset(sc);
- if (nsgphy_mii_phy_auto(sc, 0) == EJUSTRETURN)
- return(0);
break;
}
@@ -344,19 +234,25 @@ static void
nsgphy_status(struct mii_softc *sc)
{
struct mii_data *mii = sc->mii_pdata;
- int bmsr, bmcr, physup, anlpar, gstat;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int bmsr, bmcr, physup, gtsr;
mii->mii_media_status = IFM_AVALID;
mii->mii_media_active = IFM_ETHER;
- bmsr = PHY_READ(sc, MII_BMSR);
+ bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
physup = PHY_READ(sc, NSGPHY_MII_PHYSUP);
- if (physup & NSGPHY_PHYSUP_LNKSTS)
+ if (physup & PHY_SUP_LINK)
mii->mii_media_status |= IFM_ACTIVE;
bmcr = PHY_READ(sc, MII_BMCR);
+ if (bmcr & BMCR_ISO) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
if (bmcr & BMCR_LOOP)
mii->mii_media_active |= IFM_LOOP;
@@ -371,100 +267,29 @@ nsgphy_status(struct mii_softc *sc)
mii->mii_media_active |= IFM_NONE;
return;
}
- anlpar = PHY_READ(sc, MII_ANLPAR);
- gstat = PHY_READ(sc, MII_100T2SR);
- if (gstat & GTSR_LP_1000TFDX)
- mii->mii_media_active |= IFM_1000_T|IFM_FDX;
- else if (gstat & GTSR_LP_1000THDX)
- mii->mii_media_active |= IFM_1000_T|IFM_HDX;
- else if (anlpar & ANLPAR_T4)
- mii->mii_media_active |= IFM_100_T4;
- else if (anlpar & ANLPAR_TX_FD)
- mii->mii_media_active |= IFM_100_TX|IFM_FDX;
- else if (anlpar & ANLPAR_TX)
- mii->mii_media_active |= IFM_100_TX;
- else if (anlpar & ANLPAR_10_FD)
- mii->mii_media_active |= IFM_10_T|IFM_FDX;
- else if (anlpar & ANLPAR_10)
- mii->mii_media_active |= IFM_10_T|IFM_HDX;
- else
- mii->mii_media_active |= IFM_NONE;
- return;
- }
-
- switch(bmcr & (BMCR_SPEED1|BMCR_SPEED0)) {
- case BMCR_S1000:
- mii->mii_media_active |= IFM_1000_T;
- break;
- case BMCR_S100:
- mii->mii_media_active |= IFM_100_TX;
- break;
- case BMCR_S10:
- mii->mii_media_active |= IFM_10_T;
- break;
- default:
- break;
- }
-
- if (bmcr & BMCR_FDX)
- mii->mii_media_active |= IFM_FDX;
- else
- mii->mii_media_active |= IFM_HDX;
- return;
-}
+ switch (physup & (PHY_SUP_SPEED1|PHY_SUP_SPEED0)) {
+ case PHY_SUP_SPEED1:
+ mii->mii_media_active |= IFM_1000_T;
+ gtsr = PHY_READ(sc, MII_100T2SR);
+ if (gtsr & GTSR_MS_RES)
+ mii->mii_media_active |= IFM_ETH_MASTER;
+ break;
+ case PHY_SUP_SPEED0:
+ mii->mii_media_active |= IFM_100_TX;
+ break;
-static int
-nsgphy_mii_phy_auto(struct mii_softc *mii, int waitfor)
-{
- int bmsr, ktcr = 0, i;
-
- if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
- mii_phy_reset(mii);
- PHY_WRITE(mii, MII_BMCR, 0);
- DELAY(1000);
- ktcr = PHY_READ(mii, MII_100T2CR);
- PHY_WRITE(mii, MII_100T2CR, ktcr |
- (GTCR_ADV_1000TFDX|GTCR_ADV_1000THDX));
- ktcr = PHY_READ(mii, MII_100T2CR);
- DELAY(1000);
- PHY_WRITE(mii, MII_ANAR,
- BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA);
- DELAY(1000);
- PHY_WRITE(mii, MII_BMCR,
- BMCR_AUTOEN | BMCR_STARTNEG);
- }
+ case 0:
+ mii->mii_media_active |= IFM_10_T;
+ break;
- if (waitfor) {
- /* Wait 500ms for it to complete. */
- for (i = 0; i < 500; i++) {
- if ((bmsr = PHY_READ(mii, MII_BMSR)) & BMSR_ACOMP)
- return (0);
- DELAY(1000);
-#if 0
- if ((bmsr & BMSR_ACOMP) == 0)
- printf("%s: autonegotiation failed to complete\n",
- mii->mii_dev.dv_xname);
-#endif
+ default:
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
}
-
- /*
- * Don't need to worry about clearing MIIF_DOINGAUTO.
- * If that's set, a timeout is pending, and it will
- * clear the flag.
- */
- return (EIO);
- }
-
- /*
- * Just let it finish asynchronously. This is for the benefit of
- * the tick handler driving autonegotiation. Don't want 500ms
- * delays all the time while the system is running!
- */
- if ((mii->mii_flags & MIIF_DOINGAUTO) == 0) {
- mii->mii_flags |= MIIF_DOINGAUTO;
- mii->mii_auto_ch = timeout(mii_phy_auto_timeout, mii, hz >> 1);
- }
- return (EJUSTRETURN);
+ if (physup & PHY_SUP_DUPLEX)
+ mii->mii_media_active |= IFM_FDX;
+ } else
+ mii->mii_media_active = ife->ifm_media;
}
diff --git a/sys/dev/mii/nsgphyreg.h b/sys/dev/mii/nsgphyreg.h
index 0c6ef4b..c7680f1 100644
--- a/sys/dev/mii/nsgphyreg.h
+++ b/sys/dev/mii/nsgphyreg.h
@@ -54,10 +54,14 @@
#define NSGPHY_STRAPOPT_SPDSEL (NSGPHY_STRAPOPT_SPEED1|NSGPHY_STRAPOPT_SPEED0)
#define NSGPHY_MII_PHYSUP 0x11 /* PHY support/current status */
+#define PHY_SUP_SPEED1 0x0010 /* speed bit 1 */
+#define PHY_SUP_SPEED0 0x0008 /* speed bit 1 */
#define NSGPHY_PHYSUP_SPEED1 0x0010 /* speed status */
#define NSGPHY_PHYSUP_SPEED0 0x0008 /* speed status */
#define NSGPHY_PHYSUP_SPDSTS (NSGPHY_PHYSUP_SPEED1|NSGPHY_PHYSUP_SPEED0)
#define NSGPHY_PHYSUP_LNKSTS 0x0004 /* link status */
+#define PHY_SUP_LINK 0x0004 /* link status */
+#define PHY_SUP_DUPLEX 0x0002 /* 1 == full-duplex */
#define NSGPHY_PHYSUP_DUPSTS 0x0002 /* duplex status 1 == full */
#define NSGPHY_PHYSUP_10BT 0x0001 /* 10baseT resolved */
diff --git a/sys/dev/nge/if_nge.c b/sys/dev/nge/if_nge.c
index 53bd1f0..2b5f169 100644
--- a/sys/dev/nge/if_nge.c
+++ b/sys/dev/nge/if_nge.c
@@ -1980,10 +1980,12 @@ static void nge_stop(sc)
ifp->if_flags |= IFF_UP;
ifm = mii->mii_media.ifm_cur;
mtmp = ifm->ifm_media;
- ifm->ifm_media = IFM_ETHER|IFM_NONE;
+#if 0
+ ifm->ifm_media = IFM_ETHER|IFM_AUTO;
mii_mediachg(mii);
ifm->ifm_media = mtmp;
ifp->if_flags = itmp;
+#endif
sc->nge_link = 0;
OpenPOWER on IntegriCloud