summaryrefslogtreecommitdiff
path: root/sys/dev/mii/mii_physubr.c
diff options
context:
space:
mode:
authorNathan Binkert <nate@cvs.openbsd.org>2000-08-26 20:04:19 +0000
committerNathan Binkert <nate@cvs.openbsd.org>2000-08-26 20:04:19 +0000
commit841e005741a8dcb32a106f13731c7dd1e832d2b7 (patch)
tree61d0acb17595089ed91f7518d6314428615d1b9e /sys/dev/mii/mii_physubr.c
parentbd43edc61a95550b14f127a9a6b2902a6208f11b (diff)
sync mii code with netbsd
adds detach functionality for phys some code cleanup Nobody really had time to test all of this out, but theo said commit anyway
Diffstat (limited to 'sys/dev/mii/mii_physubr.c')
-rw-r--r--sys/dev/mii/mii_physubr.c255
1 files changed, 216 insertions, 39 deletions
diff --git a/sys/dev/mii/mii_physubr.c b/sys/dev/mii/mii_physubr.c
index fdd73799975..00cf21dc32e 100644
--- a/sys/dev/mii/mii_physubr.c
+++ b/sys/dev/mii/mii_physubr.c
@@ -1,8 +1,8 @@
-/* $OpenBSD: mii_physubr.c,v 1.4 2000/06/30 01:02:33 art Exp $ */
-/* $NetBSD: mii_physubr.c,v 1.2.6.1 1999/04/23 15:40:26 perry Exp $ */
+/* $OpenBSD: mii_physubr.c,v 1.5 2000/08/26 20:04:17 nate Exp $ */
+/* $NetBSD: mii_physubr.c,v 1.16 2000/03/15 20:34:43 thorpej Exp $ */
/*-
- * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -51,6 +51,7 @@
#include <net/if.h>
#include <net/if_media.h>
+#include <net/route.h>
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
@@ -64,7 +65,7 @@ const struct mii_media mii_media_table[] = {
{ BMCR_FDX, ANAR_CSMA|ANAR_10_FD }, /* 10baseT-FDX */
{ BMCR_S100, ANAR_CSMA|ANAR_T4 }, /* 100baseT4 */
{ BMCR_S100, ANAR_CSMA|ANAR_TX }, /* 100baseTX */
- { BMCR_S100|BMCR_FDX, ANAR_CSMA|ANAR_TX_FD }, /* 100baseTX-FDX */
+ { BMCR_S100|BMCR_FDX, ANAR_CSMA|ANAR_TX_FD }, /* 100baseTX-FDX */
};
void mii_phy_auto_timeout __P((void *));
@@ -73,10 +74,16 @@ void
mii_phy_setmedia(sc)
struct mii_softc *sc;
{
- struct mii_data*mii = sc->mii_pdata;
+ struct mii_data *mii = sc->mii_pdata;
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int bmcr, anar;
+ if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
+ if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0)
+ (void) mii_phy_auto(sc, 1);
+ return;
+ }
+
/*
* Table index is stored in the media entry.
*/
@@ -97,28 +104,24 @@ mii_phy_setmedia(sc)
}
int
-mii_phy_auto(mii, waitfor)
- struct mii_softc *mii;
+mii_phy_auto(sc, waitfor)
+ 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) {
+ PHY_WRITE(sc, MII_ANAR,
+ BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA);
+ 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
}
/*
@@ -134,10 +137,10 @@ 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;
- timeout_set(&mii->mii_phy_timo, mii_phy_auto_timeout, mii);
- timeout_add(&mii->mii_phy_timo, hz / 2);
+ if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
+ sc->mii_flags |= MIIF_DOINGAUTO;
+ timeout_set(&sc->mii_phy_timo, mii_phy_auto_timeout, sc);
+ timeout_add(&sc->mii_phy_timo, hz / 2);
}
return (EJUSTRETURN);
}
@@ -146,41 +149,94 @@ void
mii_phy_auto_timeout(arg)
void *arg;
{
- struct mii_softc *mii = arg;
+ struct mii_softc *sc = arg;
int s, bmsr;
+ if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
+ return;
+
s = splnet();
- mii->mii_flags &= ~MIIF_DOINGAUTO;
- bmsr = PHY_READ(mii, MII_BMSR);
+ 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;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int reg;
+
+ /* Just bail now if the interface is down. */
+ if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
+ return (EJUSTRETURN);
+
+ /*
+ * If we're not doing autonegotiation, we don't need to do
+ * any extra work here. However, we need to check the link
+ * status so we can generate an announcement if the status
+ * changes.
+ */
+ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
+ return (0);
+
+ /* 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) {
+ /*
+ * See above.
+ */
+ return (0);
+ }
+
+ /*
+ * Only retry autonegotiation every 5 seconds.
+ */
+ if (++sc->mii_ticks != 5)
+ return (EJUSTRETURN);
+
+ sc->mii_ticks = 0;
+ mii_phy_reset(sc);
+
+ if (mii_phy_auto(sc, 0) == EJUSTRETURN)
+ return (EJUSTRETURN);
+
+ /*
+ * Might need to generate a status message if autonegotiation
+ * failed.
+ */
+ return (0);
+}
+
void
-mii_phy_reset(mii)
- struct mii_softc *mii;
+mii_phy_reset(sc)
+ 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
mii_phy_down(sc)
struct mii_softc *sc;
@@ -191,18 +247,86 @@ mii_phy_down(sc)
}
}
+
+void
+mii_phy_status(sc)
+ struct mii_softc *sc;
+{
+
+ (*sc->mii_status)(sc);
+}
+
+void
+mii_phy_update(sc, cmd)
+ struct mii_softc *sc;
+ int cmd;
+{
+ struct mii_data *mii = sc->mii_pdata;
+
+ if (sc->mii_media_active != mii->mii_media_active ||
+ sc->mii_media_status != mii->mii_media_status ||
+ cmd == MII_MEDIACHG) {
+ (*mii->mii_statchg)(sc->mii_dev.dv_parent);
+ mii_phy_statusmsg(sc);
+ sc->mii_media_active = mii->mii_media_active;
+ sc->mii_media_status = mii->mii_media_status;
+ }
+}
+
+void
+mii_phy_statusmsg(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+ struct ifnet *ifp = mii->mii_ifp;
+ int s, baudrate, link_state, announce = 0;
+
+ if (mii->mii_media_status & IFM_AVALID) {
+ if (mii->mii_media_status & IFM_ACTIVE)
+ link_state = LINK_STATE_UP;
+ else
+ link_state = LINK_STATE_DOWN;
+ } else
+ link_state = LINK_STATE_UNKNOWN;
+
+ baudrate = ifmedia_baudrate(mii->mii_media_active);
+
+ if (link_state != ifp->if_link_state) {
+ ifp->if_link_state = link_state;
+ /*
+ * XXX Right here we'd like to notify protocols
+ * XXX that the link status has changed, so that
+ * XXX e.g. Duplicate Address Detection can restart.
+ */
+ announce = 1;
+ }
+
+ if (baudrate != ifp->if_baudrate) {
+ ifp->if_baudrate = baudrate;
+ announce = 1;
+ }
+
+ if (announce) {
+ s = splimp(); /* XXX Should be splnet() */
+ rt_ifmsg(ifp);
+ splx(s);
+ }
+}
+
/*
* 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_add_media(sc)
+mii_phy_add_media(sc)
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),
@@ -216,23 +340,28 @@ mii_add_media(sc)
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_LOOP,
sc->mii_inst), MII_MEDIA_10_T);
#endif
+ PRINT("10baseT");
}
-
- if (sc->mii_capabilities & BMSR_10TFDX)
+ 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);
#if 0
if ((sc->mii_flags & MIIF_NOLOOP) == 0)
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, IFM_LOOP,
- sc->mii_inst), MII_MEDIA_100_T4);
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP,
+ sc->mii_inst), MII_MEDIA_100_TX);
#endif
+ PRINT("100baseTX");
}
- if (sc->mii_capabilities & BMSR_100TXFDX)
+ 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);
@@ -241,9 +370,57 @@ mii_add_media(sc)
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, IFM_LOOP,
sc->mii_inst), MII_MEDIA_100_T4);
#endif
+ PRINT("100baseT4");
}
- if (sc->mii_capabilities & BMSR_ANEG)
+ 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
+}
+
+void
+mii_phy_delete_media(sc)
+ struct mii_softc *sc;
+{
+ struct mii_data *mii = sc->mii_pdata;
+
+ ifmedia_delete_instance(&mii->mii_media, sc->mii_inst);
+}
+
+int
+mii_phy_activate(self, act)
+ struct device *self;
+ enum devact act;
+{
+ int rv = 0;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ rv = EOPNOTSUPP;
+ break;
+
+ case DVACT_DEACTIVATE:
+ /* Nothing special to do. */
+ break;
+ }
+
+ return (rv);
+}
+
+int
+mii_phy_detach(self, flags)
+ struct device *self;
+ int flags;
+{
+ struct mii_softc *sc = (void *) self;
+
+ if (sc->mii_flags & MIIF_DOINGAUTO)
+ untimeout(mii_phy_auto_timeout, sc);
+
+ mii_phy_delete_media(sc);
+
+ return (0);
}