summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Paul <wpaul@FreeBSD.org>2002-04-07 20:55:50 +0000
committerBill Paul <wpaul@FreeBSD.org>2002-04-07 20:55:50 +0000
commita72c060fb00fdbefd3df75aa593c99d96c200544 (patch)
treed8d07d2e39818081fc33934d98636b41b3ef3379
parenta8b1e59eb28a533a62c0ff287f0d8d8cc18ebbfc (diff)
Notes
-rw-r--r--sys/dev/mii/miidevs4
-rw-r--r--sys/dev/mii/rlphy.c114
-rw-r--r--sys/pci/if_rl.c11
3 files changed, 128 insertions, 1 deletions
diff --git a/sys/dev/mii/miidevs b/sys/dev/mii/miidevs
index 081ea1f5e394..7b808660830f 100644
--- a/sys/dev/mii/miidevs
+++ b/sys/dev/mii/miidevs
@@ -59,6 +59,7 @@ oui JATO 0x00e083 Jato Technologies
oui LEVEL1 0x00207b Level 1
oui NATSEMI 0x080017 National Semiconductor
oui QUALSEMI 0x006051 Quality Semiconductor
+oui REALTEK 0x000020 RealTek Semicondctor
oui SEEQ 0x00a07d Seeq
oui SIS 0x00e006 Silicon Integrated Systems
oui TDK 0x00c039 TDK
@@ -138,6 +139,9 @@ model NATSEMI DP83861 0x0006 DP83861 10/100/1000 media interface
/* Quality Semiconductor PHYs */
model QUALSEMI QS6612 0x0000 QS6612 10/100 media interface
+/* RealTek Semiconductor PHYs */
+model REALTEK RTL8201L 0x0020 RTL8201L 10/100 media interface
+
/* Seeq PHYs */
model xxSEEQ 80220 0x0003 Seeq 80220 10/100 media interface
model xxSEEQ 84220 0x0004 Seeq 84220 10/100 media interface
diff --git a/sys/dev/mii/rlphy.c b/sys/dev/mii/rlphy.c
index 1704b1bfc539..560465ba027b 100644
--- a/sys/dev/mii/rlphy.c
+++ b/sys/dev/mii/rlphy.c
@@ -43,10 +43,15 @@
#include <sys/bus.h>
#include <net/if.h>
+#include <net/if_arp.h>
#include <net/if_media.h>
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
+#include <dev/mii/miidevs.h>
+
+#include <machine/bus.h>
+#include <pci/if_rlreg.h>
#include "miibus_if.h"
@@ -79,6 +84,7 @@ static driver_t rlphy_driver = {
DRIVER_MODULE(rlphy, miibus, rlphy_driver, rlphy_devclass, 0, 0);
static int rlphy_service(struct mii_softc *, struct mii_data *, int);
+static void rlphy_status(struct mii_softc *);
static int rlphy_probe(dev)
device_t dev;
@@ -89,6 +95,13 @@ static int rlphy_probe(dev)
ma = device_get_ivars(dev);
parent = device_get_parent(device_get_parent(dev));
+ /* Test for RealTek 8201L PHY */
+ if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_REALTEK &&
+ MII_MODEL(ma->mii_id2) == MII_MODEL_REALTEK_RTL8201L) {
+ device_set_desc(dev, MII_STR_REALTEK_RTL8201L);
+ return(0);
+ }
+
/*
* RealTek PHY doesn't have vendor/device ID registers:
* the rl driver fakes up a return value of all zeros.
@@ -250,9 +263,108 @@ rlphy_service(sc, mii, cmd)
}
/* Update the media status. */
- ukphy_status(sc);
+ rlphy_status(sc);
/* Callback if something changed. */
mii_phy_update(sc, cmd);
return (0);
}
+
+void
+rlphy_status(phy)
+ struct mii_softc *phy;
+{
+ struct mii_data *mii = phy->mii_pdata;
+ int bmsr, bmcr, anlpar;
+ device_t parent;
+
+ 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;
+ }
+
+ if ((anlpar = PHY_READ(phy, MII_ANAR) &
+ PHY_READ(phy, MII_ANLPAR))) {
+ 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 the other side doesn't support NWAY, then the
+ * best we can do is determine if we have a 10Mbps or
+ * 100Mbps link. There's no way to know if the link
+ * is full or half duplex, so we default to half duplex
+ * and hope that the user is clever enough to manually
+ * change the media settings if we're wrong.
+ */
+
+
+ /*
+ * The RealTek PHY supports non-NWAY link speed
+ * detection, however it does not report the link
+ * detection results via the ANLPAR or BMSR registers.
+ * (What? RealTek doesn't do things the way everyone
+ * else does? I'm just shocked, shocked I tell you.)
+ * To determine the link speed, we have to do one
+ * of two things:
+ *
+ * - If this is a standalone RealTek RTL8201(L) PHY,
+ * we can determine the link speed by testing bit 0
+ * in the magic, vendor-specific register at offset
+ * 0x19.
+ *
+ * - If this is a RealTek MAC with integrated PHY, we
+ * can test the 'SPEED10' bit of the MAC's media status
+ * register.
+ */
+ parent = device_get_parent(phy->mii_dev);
+ if (strcmp(device_get_name(parent), "rl") != 0) {
+ if (PHY_READ(phy, 0x0019) & 0x01)
+ mii->mii_media_active |= IFM_100_TX;
+ else
+ mii->mii_media_active |= IFM_10_T;
+ } else {
+ 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
+ mii->mii_media_active = mii_media_from_bmcr(bmcr);
+}
diff --git a/sys/pci/if_rl.c b/sys/pci/if_rl.c
index b91257192a35..a08e56103a22 100644
--- a/sys/pci/if_rl.c
+++ b/sys/pci/if_rl.c
@@ -609,6 +609,17 @@ static int rl_miibus_readreg(dev, phy, reg)
RL_UNLOCK(sc);
return(0);
break;
+ /*
+ * Allow the rlphy driver to read the media status
+ * register. If we have a link partner which does not
+ * support NWAY, this is the register which will tell
+ * us the results of parallel detection.
+ */
+ case RL_MEDIASTAT:
+ rval = CSR_READ_1(sc, RL_MEDIASTAT);
+ RL_UNLOCK(sc);
+ return(rval);
+ break;
default:
printf("rl%d: bad phy register\n", sc->rl_unit);
RL_UNLOCK(sc);