diff options
| author | Bill Paul <wpaul@FreeBSD.org> | 2002-04-07 20:55:50 +0000 |
|---|---|---|
| committer | Bill Paul <wpaul@FreeBSD.org> | 2002-04-07 20:55:50 +0000 |
| commit | a72c060fb00fdbefd3df75aa593c99d96c200544 (patch) | |
| tree | d8d07d2e39818081fc33934d98636b41b3ef3379 | |
| parent | a8b1e59eb28a533a62c0ff287f0d8d8cc18ebbfc (diff) | |
Notes
| -rw-r--r-- | sys/dev/mii/miidevs | 4 | ||||
| -rw-r--r-- | sys/dev/mii/rlphy.c | 114 | ||||
| -rw-r--r-- | sys/pci/if_rl.c | 11 |
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); |
