From e3c5a44915f4903202e20af6ca143b9751d0b38f Mon Sep 17 00:00:00 2001 From: Stephen McKay Date: Thu, 18 Apr 2002 14:40:20 +0000 Subject: [PATCH] Work around an Intel 21143 chip bug. Rev 1.56 of if_dc.c removed calls to mii_pollstat() from the dc_tick() routine. dc_tick() is called regularly to detect link up and link down status, especially when autonegotiating. The expectation was that mii_tick() (which is still called from dc_tick()) would update status information automatically in all cases where it would be sensible to do so. Unfortunately, with authentic 21143 chips this is not the case, and the driver never successfully autonegotiates. This is because (despite what it says in the 21143 manual) the chip always claims that link is not present while the autonegotiation enable bit is set. Autonegotation takes place and succeeds, but the driver tests the link bits before it switches off the autonegotiation enable bit, and success is not recognised. The simplest solution is to call dcphy_status() more often for MII_TICK calls by dropping out of the switch statement instead of exiting when we are autonegotiating and link appears to not be present. When autonegotiation succeeds, dcphy_status() will note the speed and fdx/hdx state and turn off the autonegotiation enable bit. The next call to dcphy_status() will notice that link is present, and the dc driver code will be notified. Macronix chips also use this code, but implement link detection as described in the manual, and hence don't need this patch. However, tests on a Macronix 98715AEC-C show that it does not adversely affect them. This could be done better but is the minimal effective change, and most closely mimics what was happening prior to rev 1.56 of if_dc.c. (Actually I also deleted a small amount of unnecessary code while I was in the area.) Reviewed by: wpaul --- sys/dev/dc/dcphy.c | 17 ++++++++++------- sys/dev/mii/dcphy.c | 17 ++++++++++------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/sys/dev/dc/dcphy.c b/sys/dev/dc/dcphy.c index daf38c78049d..e95786938baa 100644 --- a/sys/dev/dc/dcphy.c +++ b/sys/dev/dc/dcphy.c @@ -329,17 +329,22 @@ dcphy_service(sc, mii, cmd) if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) break; - reg = CSR_READ_4(dc_sc, DC_10BTSTAT) & - (DC_TSTAT_LS10|DC_TSTAT_LS100); - + reg = CSR_READ_4(dc_sc, DC_10BTSTAT); if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100)) break; /* * Only retry autonegotiation every 5 seconds. + * + * Otherwise, fall through to calling dcphy_status() + * since real Intel 21143 chips don't show valid link + * status until autonegotiation is switched off, and + * that only happens in dcphy_status(). Without this, + * successful autonegotation is never recognised on + * these chips. */ if (++sc->mii_ticks != 50) - return (0); + break; sc->mii_ticks = 0; /*if (DC_IS_INTEL(dc_sc))*/ @@ -373,9 +378,7 @@ dcphy_status(sc) if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return; - reg = CSR_READ_4(dc_sc, DC_10BTSTAT) & - (DC_TSTAT_LS10|DC_TSTAT_LS100); - + reg = CSR_READ_4(dc_sc, DC_10BTSTAT); if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100)) mii->mii_media_status |= IFM_ACTIVE; diff --git a/sys/dev/mii/dcphy.c b/sys/dev/mii/dcphy.c index daf38c78049d..e95786938baa 100644 --- a/sys/dev/mii/dcphy.c +++ b/sys/dev/mii/dcphy.c @@ -329,17 +329,22 @@ dcphy_service(sc, mii, cmd) if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) break; - reg = CSR_READ_4(dc_sc, DC_10BTSTAT) & - (DC_TSTAT_LS10|DC_TSTAT_LS100); - + reg = CSR_READ_4(dc_sc, DC_10BTSTAT); if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100)) break; /* * Only retry autonegotiation every 5 seconds. + * + * Otherwise, fall through to calling dcphy_status() + * since real Intel 21143 chips don't show valid link + * status until autonegotiation is switched off, and + * that only happens in dcphy_status(). Without this, + * successful autonegotation is never recognised on + * these chips. */ if (++sc->mii_ticks != 50) - return (0); + break; sc->mii_ticks = 0; /*if (DC_IS_INTEL(dc_sc))*/ @@ -373,9 +378,7 @@ dcphy_status(sc) if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return; - reg = CSR_READ_4(dc_sc, DC_10BTSTAT) & - (DC_TSTAT_LS10|DC_TSTAT_LS100); - + reg = CSR_READ_4(dc_sc, DC_10BTSTAT); if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100)) mii->mii_media_status |= IFM_ACTIVE;