Index: if_re.c =================================================================== RCS file: /home/ncvs/src/sys/dev/re/if_re.c,v retrieving revision 1.72 diff -u -r1.72 if_re.c --- if_re.c 3 Aug 2006 00:15:19 -0000 1.72 +++ if_re.c 24 Aug 2006 04:58:35 -0000 @@ -266,6 +266,7 @@ static int re_miibus_readreg (device_t, int, int); static int re_miibus_writereg (device_t, int, int, int); static void re_miibus_statchg (device_t); +static void re_link_task (void *, int); static void re_setmulti (struct rl_softc *); static void re_reset (struct rl_softc *); @@ -499,15 +500,17 @@ sc = device_get_softc(dev); + RL_MII_LOCK(sc); if (sc->rl_type == RL_8169) { rval = re_gmii_readreg(dev, phy, reg); + RL_MII_UNLOCK(sc); return (rval); } /* Pretend the internal PHY is only at address 0 */ - if (phy) { - return (0); - } + if (phy) + goto done; + switch (reg) { case MII_BMCR: re8139_reg = RL_BMCR; @@ -526,7 +529,8 @@ break; case MII_PHYIDR1: case MII_PHYIDR2: - return (0); + goto done; + break; /* * Allow the rlphy driver to read the media status * register. If we have a link partner which does not @@ -535,12 +539,19 @@ */ case RL_MEDIASTAT: rval = CSR_READ_1(sc, RL_MEDIASTAT); - return (rval); + goto done; + break; default: if_printf(sc->rl_ifp, "bad phy register\n"); - return (0); + goto done; } rval = CSR_READ_2(sc, re8139_reg); + if (sc->rl_type == RL_8139CPLUS && re8139_reg == RL_BMCR) { + /* 8139C+ has different bit layout */ + rval &= ~(BMCR_LOOP | BMCR_ISO); + } + RL_MII_UNLOCK(sc); +done: return (rval); } @@ -555,18 +566,24 @@ sc = device_get_softc(dev); + RL_MII_LOCK(sc); if (sc->rl_type == RL_8169) { rval = re_gmii_writereg(dev, phy, reg, data); + RL_MII_UNLOCK(sc); return (rval); } /* Pretend the internal PHY is only at address 0 */ if (phy) - return (0); + goto done; switch (reg) { case MII_BMCR: re8139_reg = RL_BMCR; + if (sc->rl_type == RL_8139CPLUS) { + /* 8139C+ has different bit layout */ + data &= ~(BMCR_LOOP | BMCR_ISO); + } break; case MII_BMSR: re8139_reg = RL_BMSR; @@ -582,13 +599,16 @@ break; case MII_PHYIDR1: case MII_PHYIDR2: - return (0); + goto done; break; default: if_printf(sc->rl_ifp, "bad phy register\n"); - return (0); + goto done; } CSR_WRITE_2(sc, re8139_reg, data); +done: + RL_MII_UNLOCK(sc); + return (0); } @@ -596,7 +616,47 @@ re_miibus_statchg(dev) device_t dev; { + struct rl_softc *sc; + sc = device_get_softc(dev); + + RL_MII_LOCK(sc); + taskqueue_enqueue(taskqueue_swi, &sc->rl_link_task); + RL_MII_UNLOCK(sc); +} + +static void +re_link_task(arg, pending) + void *arg; + int pending; +{ + struct rl_softc *sc; + struct mii_data *mii; + struct ifnet *ifp; + + sc = (struct rl_softc *)arg; + + RL_LOCK(sc); + + mii = device_get_softc(sc->rl_miibus); + ifp = sc->rl_ifp; + if (ifp == NULL) { + RL_UNLOCK(sc); + return; + } + + if (mii->mii_media_status & IFM_ACTIVE) { + if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { + sc->rl_link = 1; + if (ifp->if_drv_flags & IFF_DRV_RUNNING && + !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + taskqueue_enqueue_fast(taskqueue_fast, + &sc->rl_txtask); + } + } else + sc->rl_link = 0; + + RL_UNLOCK(sc); } /* @@ -1135,7 +1195,9 @@ mtx_init(&sc->rl_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); + mtx_init(&sc->rl_mii_mtx, "rl_mii_mutex", NULL, MTX_DEF); callout_init_mtx(&sc->rl_stat_callout, &sc->rl_mtx, 0); + TASK_INIT(&sc->rl_link_task, 0, re_link_task, sc); /* * Map control/status registers. @@ -1334,6 +1396,7 @@ re_stop(sc); RL_UNLOCK(sc); callout_drain(&sc->rl_stat_callout); + taskqueue_drain(taskqueue_swi, &sc->rl_link_task); /* * Force off the IFF_UP flag here, in case someone * still had a BPF descriptor attached to this @@ -1836,19 +1899,6 @@ mii = device_get_softc(sc->rl_miibus); mii_tick(mii); - if (sc->rl_link) { - if (!(mii->mii_media_status & IFM_ACTIVE)) - sc->rl_link = 0; - } else { - if (mii->mii_media_status & IFM_ACTIVE && - IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { - sc->rl_link = 1; - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - taskqueue_enqueue_fast(taskqueue_fast, - &sc->rl_txtask); - } - } - callout_reset(&sc->rl_stat_callout, hz, re_tick, sc); } @@ -1966,11 +2016,6 @@ re_init_locked(sc); } - if (status & RL_ISR_LINKCHG) { - callout_stop(&sc->rl_stat_callout); - re_tick(sc); - } - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) taskqueue_enqueue_fast(taskqueue_fast, &sc->rl_txtask); @@ -2401,16 +2446,15 @@ if (sc->rl_testmode) return; + sc->rl_link = 0; + mii_mediachg(mii); - CSR_WRITE_1(sc, RL_CFG1, RL_CFG1_DRVLOAD|RL_CFG1_FULLDUPLEX); + CSR_WRITE_1(sc, RL_CFG1, CSR_READ_1(sc, RL_CFG1) | RL_CFG1_DRVLOAD); ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - - sc->rl_link = 0; - callout_reset(&sc->rl_stat_callout, hz, re_tick, sc); } @@ -2426,9 +2470,7 @@ sc = ifp->if_softc; mii = device_get_softc(sc->rl_miibus); - RL_LOCK(sc); mii_mediachg(mii); - RL_UNLOCK(sc); return (0); } @@ -2447,9 +2489,7 @@ sc = ifp->if_softc; mii = device_get_softc(sc->rl_miibus); - RL_LOCK(sc); mii_pollstat(mii); - RL_UNLOCK(sc); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; } @@ -2552,10 +2592,17 @@ sc = ifp->if_softc; RL_LOCK(sc); + re_txeof(sc); + if (sc->rl_ldata.rl_tx_free == RL_TX_DESC_CNT) { + if_printf(ifp, "watchdog timeout (missed Tx interrupt) " + "-- recovering\n"); + RL_UNLOCK(sc); + return; + } + if_printf(ifp, "watchdog timeout\n"); ifp->if_oerrors++; - re_txeof(sc); re_rxeof(sc); re_init_locked(sc); Index: ../../pci/if_rlreg.h =================================================================== RCS file: /home/ncvs/src/sys/pci/if_rlreg.h,v retrieving revision 1.60 diff -u -r1.60 if_rlreg.h --- ../../pci/if_rlreg.h 1 Aug 2006 17:18:25 -0000 1.60 +++ ../../pci/if_rlreg.h 24 Aug 2006 04:58:35 -0000 @@ -733,7 +733,9 @@ struct task rl_txtask; struct task rl_inttask; + struct task rl_link_task; + struct mtx rl_mii_mtx; struct mtx rl_intlock; int rl_txstart; int rl_link; @@ -743,6 +745,10 @@ #define RL_UNLOCK(_sc) mtx_unlock(&(_sc)->rl_mtx) #define RL_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rl_mtx, MA_OWNED) +#define RL_MII_LOCK(_sc) mtx_lock(&(_sc)->rl_mii_mtx) +#define RL_MII_UNLOCK(_sc) mtx_unlock(&(_sc)->rl_mii_mtx) +#define RL_MII_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rl_mii_mtx, MA_OWNED) + /* * register space access macros */