summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2004-09-30 14:58:03 +0000
committerJason Wright <jason@cvs.openbsd.org>2004-09-30 14:58:03 +0000
commit2c6a67e45c0d849f4691c2ee1d04db2dfce6dc9d (patch)
treee2e8cfd2c3d24bd45902847818ce1cf78cb4e8cf /sys
parentbcbad27ca9f84142e7c2bb04715b995d2705ca3d (diff)
rtl8139 doesn't setup ANLPAR if the other side is not NWay compatible,
to try to deduce what the link partner is the hardway. Based on FreeBSD.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/rtl81x9.c6
-rw-r--r--sys/dev/mii/rlphy.c85
2 files changed, 87 insertions, 4 deletions
diff --git a/sys/dev/ic/rtl81x9.c b/sys/dev/ic/rtl81x9.c
index 1409a41ba2c..6efc9c0cc39 100644
--- a/sys/dev/ic/rtl81x9.c
+++ b/sys/dev/ic/rtl81x9.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtl81x9.c,v 1.29 2004/09/28 07:05:50 brad Exp $ */
+/* $OpenBSD: rtl81x9.c,v 1.30 2004/09/30 14:58:02 jason Exp $ */
/*
* Copyright (c) 1997, 1998
@@ -1359,10 +1359,12 @@ rl_miibus_readreg(self, phy, reg)
case MII_ANLPAR:
rl8139_reg = RL_LPAR;
break;
+ case RL_MEDIASTAT:
+ return (CSR_READ_1(sc, RL_MEDIASTAT));
case MII_PHYIDR1:
case MII_PHYIDR2:
+ default:
return (0);
- break;
}
return (CSR_READ_2(sc, rl8139_reg));
}
diff --git a/sys/dev/mii/rlphy.c b/sys/dev/mii/rlphy.c
index 00587708100..28037f5b9c1 100644
--- a/sys/dev/mii/rlphy.c
+++ b/sys/dev/mii/rlphy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rlphy.c,v 1.12 2004/09/27 18:25:48 brad Exp $ */
+/* $OpenBSD: rlphy.c,v 1.13 2004/09/30 14:58:02 jason Exp $ */
/*
* Copyright (c) 1998, 1999 Jason L. Wright (jason@thought.net)
@@ -41,10 +41,14 @@
#include <net/if.h>
#include <net/if_media.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
#include <dev/mii/miidevs.h>
+#include <machine/bus.h>
+#include <dev/ic/rtl81x9reg.h>
int rlphymatch(struct device *, void *, void *);
void rlphyattach(struct device *, struct device *, void *);
@@ -59,10 +63,11 @@ struct cfdriver rlphy_cd = {
};
int rlphy_service(struct mii_softc *, struct mii_data *, int);
+void rlphy_status(struct mii_softc *);
void rlphy_reset(struct mii_softc *);
const struct mii_phy_funcs rlphy_funcs = {
- rlphy_service, ukphy_status, rlphy_reset,
+ rlphy_service, rlphy_status, rlphy_reset,
};
int
@@ -177,3 +182,79 @@ rlphy_reset(struct mii_softc *sc)
mii_phy_reset(sc);
PHY_WRITE(sc, MII_BMCR, bmcr);
}
+
+void
+rlphy_status(struct mii_softc *phy)
+{
+ struct mii_data *mii = phy->mii_pdata;
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ int bmsr, bmcr, anlpar;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR);
+ if (bmsr & BMSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(phy, 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;
+
+ if (bmcr & BMCR_AUTOEN) {
+ /*
+ * NWay autonegotiation takes the highest-order common
+ * bit of the ANAR and ANLPAR (i.e. best media advertised
+ * both by us and our link partner).
+ */
+ if ((bmsr & BMSR_ACOMP) == 0) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ anlpar = PHY_READ(phy, MII_ANAR) & PHY_READ(phy, MII_ANLPAR);
+
+ /*
+ * if anlpar is non-zero, NWay succeeded with an NWay
+ * link partner. Otherwise, punt.
+ */
+ if (anlpar != 0) {
+ 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;
+ else
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ if (strcmp("rl",
+ phy->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name)
+ == 0) {
+ if (PHY_READ(phy, RL_MEDIASTAT) & RL_MEDIASTAT_SPEED10)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_100_TX;
+ } else {
+ if (PHY_READ(phy, 0x0019) & 0x01)
+ mii->mii_media_active |= IFM_100_TX;
+ else
+ mii->mii_media_active |= IFM_10_T;
+ }
+
+ } else
+ mii->mii_media_active = ife->ifm_media;
+}