Index: if_re.c =================================================================== RCS file: /home/ncvs/src/sys/dev/re/if_re.c,v retrieving revision 1.28 diff -u -r1.28 if_re.c --- if_re.c 2004/07/06 02:48:29 1.28 +++ if_re.c 2004/08/25 17:44:33 @@ -203,11 +203,18 @@ static int re_tx_list_init (struct rl_softc *); static void re_rxeof (struct rl_softc *); static void re_txeof (struct rl_softc *); +#ifdef DEVICE_POLLING +static void re_poll (struct ifnet *, enum poll_cmd, int); +static void re_poll_locked (struct ifnet *, enum poll_cmd, int); +#endif static void re_intr (void *); static void re_tick (void *); +static void re_tick_locked (struct rl_softc *); static void re_start (struct ifnet *); +static void re_start_locked (struct ifnet *); static int re_ioctl (struct ifnet *, u_long, caddr_t); static void re_init (void *); +static void re_init_locked (struct rl_softc *); static void re_stop (struct rl_softc *); static void re_watchdog (struct ifnet *); static int re_suspend (device_t); @@ -452,17 +459,14 @@ u_int16_t re8139_reg = 0; sc = device_get_softc(dev); - RL_LOCK(sc); if (sc->rl_type == RL_8169) { rval = re_gmii_readreg(dev, phy, reg); - RL_UNLOCK(sc); return (rval); } /* Pretend the internal PHY is only at address 0 */ if (phy) { - RL_UNLOCK(sc); return (0); } switch (reg) { @@ -483,7 +487,6 @@ break; case MII_PHYIDR1: case MII_PHYIDR2: - RL_UNLOCK(sc); return (0); /* * Allow the rlphy driver to read the media status @@ -493,15 +496,12 @@ */ case RL_MEDIASTAT: rval = CSR_READ_1(sc, RL_MEDIASTAT); - RL_UNLOCK(sc); return (rval); default: printf("re%d: bad phy register\n", sc->rl_unit); - RL_UNLOCK(sc); return (0); } rval = CSR_READ_2(sc, re8139_reg); - RL_UNLOCK(sc); return (rval); } @@ -515,19 +515,16 @@ int rval = 0; sc = device_get_softc(dev); - RL_LOCK(sc); if (sc->rl_type == RL_8169) { rval = re_gmii_writereg(dev, phy, reg, data); - RL_UNLOCK(sc); return (rval); } /* Pretend the internal PHY is only at address 0 */ - if (phy) { - RL_UNLOCK(sc); + if (phy) return (0); - } + switch (reg) { case MII_BMCR: re8139_reg = RL_BMCR; @@ -546,16 +543,13 @@ break; case MII_PHYIDR1: case MII_PHYIDR2: - RL_UNLOCK(sc); return (0); break; default: printf("re%d: bad phy register\n", sc->rl_unit); - RL_UNLOCK(sc); return (0); } CSR_WRITE_2(sc, re8139_reg, data); - RL_UNLOCK(sc); return (0); } @@ -580,6 +574,8 @@ u_int32_t rxfilt; int mcnt = 0; + RL_LOCK_ASSERT(sc); + ifp = &sc->arpcom.ac_if; rxfilt = CSR_READ_4(sc, RL_RXCFG); @@ -625,6 +621,8 @@ { register int i; + RL_LOCK_ASSERT(sc); + CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RESET); for (i = 0; i < RL_TIMEOUT; i++) { @@ -673,11 +671,12 @@ u_int8_t src[] = { 0x00, 'w', 'o', 'r', 'l', 'd' }; /* Allocate a single mbuf */ - MGETHDR(m0, M_DONTWAIT, MT_DATA); if (m0 == NULL) return (ENOBUFS); + RL_LOCK(sc); + /* * Initialize the NIC in test mode. This sets the chip up * so that it can send and receive frames, but performs the @@ -689,10 +688,10 @@ ifp->if_flags |= IFF_PROMISC; sc->rl_testmode = 1; - re_init(sc); + re_init_locked(sc); re_stop(sc); DELAY(100000); - re_init(sc); + re_init_locked(sc); /* Put some data in the mbuf */ @@ -708,7 +707,9 @@ */ CSR_WRITE_2(sc, RL_ISR, 0xFFFF); + RL_UNLOCK(sc); IF_HANDOFF(&ifp->if_snd, m0, ifp); + RL_LOCK(sc); m0 = NULL; /* Wait for it to propagate through the chip */ @@ -787,6 +788,8 @@ if (m0 != NULL) m_freem(m0); + RL_UNLOCK(sc); + return (error); } @@ -824,15 +827,9 @@ } sc->rl_btag = rman_get_bustag(sc->rl_res); sc->rl_bhandle = rman_get_bushandle(sc->rl_res); - mtx_init(&sc->rl_mtx, - device_get_nameunit(dev), - MTX_NETWORK_LOCK, MTX_DEF); - RL_LOCK(sc); hwrev = CSR_READ_4(sc, RL_TXCFG) & RL_TXCFG_HWREV; bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); - RL_UNLOCK(sc); - mtx_destroy(&sc->rl_mtx); if (t->rl_basetype == hwrev) { device_set_desc(dev, t->rl_name); return (0); @@ -1063,7 +1060,7 @@ unit = device_get_unit(dev); mtx_init(&sc->rl_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, - MTX_DEF | MTX_RECURSE); + MTX_DEF); /* * Map control/status registers. */ @@ -1094,7 +1091,9 @@ } /* Reset the adapter. */ + RL_LOCK(sc); re_reset(sc); + RL_UNLOCK(sc); hw_rev = re_hwrevs; hwrev = CSR_READ_4(sc, RL_TXCFG) & RL_TXCFG_HWREV; @@ -1219,13 +1218,11 @@ } /* Hook interrupt last to avoid having to lock softc */ - error = bus_setup_intr(dev, sc->rl_irq, INTR_TYPE_NET, + error = bus_setup_intr(dev, sc->rl_irq, INTR_TYPE_NET | INTR_MPSAFE, re_intr, sc, &sc->rl_intrhand); - if (error) { printf("re%d: couldn't set up irq\n", unit); ether_ifdetach(ifp); - goto fail; } fail: @@ -1249,19 +1246,29 @@ struct rl_softc *sc; struct ifnet *ifp; int i; + int attached; sc = device_get_softc(dev); + ifp = &sc->arpcom.ac_if; KASSERT(mtx_initialized(&sc->rl_mtx), ("rl mutex not initialized")); + + attached = device_is_attached(dev); + /* These should only be active if attach succeeded */ + if (attached) + ether_ifdetach(ifp); + RL_LOCK(sc); - ifp = &sc->arpcom.ac_if; +#if 0 + sc->suspended = 1; +#endif /* These should only be active if attach succeeded */ - if (device_is_attached(dev)) { + if (attached) { re_stop(sc); /* * Force off the IFF_UP flag here, in case someone * still had a BPF descriptor attached to this - * interface. If they do, ether_ifattach() will cause + * interface. If they do, ether_ifdetach() will cause * the BPF code to try and clear the promisc mode * flag, which will bubble down to re_ioctl(), * which will try to call re_init() again. This will @@ -1277,6 +1284,12 @@ device_delete_child(dev, sc->rl_miibus); bus_generic_detach(dev); + /* + * The rest is resource deallocation, so we should already be + * stopped here. + */ + RL_UNLOCK(sc); + if (sc->rl_intrhand) bus_teardown_intr(dev, sc->rl_irq, sc->rl_intrhand); if (sc->rl_irq) @@ -1333,7 +1346,6 @@ if (sc->rl_parent_tag) bus_dma_tag_destroy(sc->rl_parent_tag); - RL_UNLOCK(sc); mtx_destroy(&sc->rl_mtx); return (0); @@ -1394,6 +1406,9 @@ re_tx_list_init(sc) struct rl_softc *sc; { + + RL_LOCK_ASSERT(sc); + bzero ((char *)sc->rl_ldata.rl_tx_list, RL_TX_LIST_SZ); bzero ((char *)&sc->rl_ldata.rl_tx_mbuf, (RL_TX_DESC_CNT * sizeof(struct mbuf *))); @@ -1677,32 +1692,53 @@ void *xsc; { struct rl_softc *sc; - struct mii_data *mii; sc = xsc; RL_LOCK(sc); + re_tick_locked(sc); + RL_UNLOCK(sc); +} + +static void +re_tick_locked(sc) + struct rl_softc *sc; +{ + struct mii_data *mii; + + RL_LOCK_ASSERT(sc); + mii = device_get_softc(sc->rl_miibus); mii_tick(mii); sc->rl_stat_ch = timeout(re_tick, sc, hz); - RL_UNLOCK(sc); } #ifdef DEVICE_POLLING static void -re_poll (struct ifnet *ifp, enum poll_cmd cmd, int count) +re_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) { struct rl_softc *sc = ifp->if_softc; RL_LOCK(sc); + re_poll_locked(ifp, cmd, count); + RL_UNLOCK(sc); +} + +static void +re_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) +{ + struct rl_softc *sc = ifp->if_softc; + + RL_LOCK_ASSERT(sc); + if (!(ifp->if_capenable & IFCAP_POLLING)) { ether_poll_deregister(ifp); cmd = POLL_DEREGISTER; } if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ CSR_WRITE_2(sc, RL_IMR, RL_INTRS_CPLUS); - goto done; + return; } sc->rxcycles = count; @@ -1710,14 +1746,14 @@ re_txeof(sc); if (ifp->if_snd.ifq_head != NULL) - (*ifp->if_start)(ifp); + re_start_locked(ifp); if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */ u_int16_t status; status = CSR_READ_2(sc, RL_ISR); if (status == 0xffff) - goto done; + return; if (status) CSR_WRITE_2(sc, RL_ISR, status); @@ -1727,11 +1763,9 @@ if (status & RL_ISR_SYSTEM_ERR) { re_reset(sc); - re_init(sc); + re_init_locked(sc); } } -done: - RL_UNLOCK(sc); } #endif /* DEVICE_POLLING */ @@ -1745,26 +1779,21 @@ sc = arg; - if (sc->suspended) { - return; - } - RL_LOCK(sc); + ifp = &sc->arpcom.ac_if; - if (!(ifp->if_flags & IFF_UP)) { - RL_UNLOCK(sc); - return; - } + if (sc->suspended || !(ifp->if_flags & IFF_UP)) + goto done_locked; #ifdef DEVICE_POLLING if (ifp->if_flags & IFF_POLLING) - goto done; + goto done_locked; if ((ifp->if_capenable & IFCAP_POLLING) && ether_poll_register(re_poll, ifp)) { /* ok, disable interrupts */ CSR_WRITE_2(sc, RL_IMR, 0x0000); - re_poll(ifp, 0, 1); - goto done; + re_poll_locked(ifp, 0, 1); + goto done_locked; } #endif /* DEVICE_POLLING */ @@ -1793,21 +1822,19 @@ if (status & RL_ISR_SYSTEM_ERR) { re_reset(sc); - re_init(sc); + re_init_locked(sc); } if (status & RL_ISR_LINKCHG) { untimeout(re_tick, sc, sc->rl_stat_ch); - re_tick(sc); + re_tick_locked(sc); } } if (ifp->if_snd.ifq_head != NULL) - (*ifp->if_start)(ifp); + re_start_locked(ifp); -#ifdef DEVICE_POLLING -done: -#endif +done_locked: RL_UNLOCK(sc); } @@ -1823,6 +1850,8 @@ int error; struct m_tag *mtag; + RL_LOCK_ASSERT(sc); + if (sc->rl_ldata.rl_tx_free <= 4) return (EFBIG); @@ -1918,12 +1947,23 @@ return (0); } +static void +re_start(ifp) + struct ifnet *ifp; +{ + struct rl_softc *sc; + + sc = ifp->if_softc; + RL_LOCK(sc); + re_start_locked(ifp); + RL_UNLOCK(sc); +} + /* * Main transmit routine for C+ and gigE NICs. */ - static void -re_start(ifp) +re_start_locked(ifp) struct ifnet *ifp; { struct rl_softc *sc; @@ -1931,7 +1971,8 @@ int idx; sc = ifp->if_softc; - RL_LOCK(sc); + + RL_LOCK_ASSERT(sc); idx = sc->rl_ldata.rl_tx_prodidx; @@ -1981,8 +2022,6 @@ */ CSR_WRITE_4(sc, RL_TIMERCNT, 1); - RL_UNLOCK(sc); - /* * Set a timeout in case the chip goes out to lunch. */ @@ -1994,11 +2033,22 @@ void *xsc; { struct rl_softc *sc = xsc; + + RL_LOCK(sc); + re_init_locked(sc); + RL_UNLOCK(sc); +} + +static void +re_init_locked(sc) + struct rl_softc *sc; +{ struct ifnet *ifp = &sc->arpcom.ac_if; struct mii_data *mii; u_int32_t rxcfg = 0; - RL_LOCK(sc); + RL_LOCK_ASSERT(sc); + mii = device_get_softc(sc->rl_miibus); /* @@ -2144,10 +2194,8 @@ if (sc->rl_type == RL_8169) CSR_WRITE_2(sc, RL_MAXRXPKTLEN, 16383); - if (sc->rl_testmode) { - RL_UNLOCK(sc); + if (sc->rl_testmode) return; - } mii_mediachg(mii); @@ -2157,7 +2205,6 @@ ifp->if_flags &= ~IFF_OACTIVE; sc->rl_stat_ch = timeout(re_tick, sc, hz); - RL_UNLOCK(sc); } /* @@ -2207,8 +2254,6 @@ struct mii_data *mii; int error = 0; - RL_LOCK(sc); - switch (command) { case SIOCSIFMTU: if (ifr->ifr_mtu > RL_JUMBO_MTU) @@ -2216,17 +2261,19 @@ ifp->if_mtu = ifr->ifr_mtu; break; case SIOCSIFFLAGS: - if (ifp->if_flags & IFF_UP) { - re_init(sc); - } else { - if (ifp->if_flags & IFF_RUNNING) - re_stop(sc); - } + RL_LOCK(sc); + if (ifp->if_flags & IFF_UP) + re_init_locked(sc); + else if (ifp->if_flags & IFF_RUNNING) + re_stop(sc); + RL_UNLOCK(sc); error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: + RL_LOCK(sc); re_setmulti(sc); + RL_UNLOCK(sc); error = 0; break; case SIOCGIFMEDIA: @@ -2250,8 +2297,6 @@ break; } - RL_UNLOCK(sc); - return (error); } @@ -2268,8 +2313,7 @@ re_txeof(sc); re_rxeof(sc); - - re_init(sc); + re_init_locked(sc); RL_UNLOCK(sc); } @@ -2285,7 +2329,8 @@ register int i; struct ifnet *ifp; - RL_LOCK(sc); + RL_LOCK_ASSERT(sc); + ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; @@ -2324,8 +2369,6 @@ sc->rl_ldata.rl_rx_mbuf[i] = NULL; } } - - RL_UNLOCK(sc); } /* @@ -2341,8 +2384,10 @@ sc = device_get_softc(dev); + RL_LOCK(sc); re_stop(sc); sc->suspended = 1; + RL_UNLOCK(sc); return (0); } @@ -2360,13 +2405,17 @@ struct ifnet *ifp; sc = device_get_softc(dev); + + RL_LOCK(sc); + ifp = &sc->arpcom.ac_if; /* reinitialize interface if necessary */ if (ifp->if_flags & IFF_UP) - re_init(sc); + re_init_locked(sc); sc->suspended = 0; + RL_UNLOCK(sc); return (0); } @@ -2383,5 +2432,7 @@ sc = device_get_softc(dev); + RL_LOCK(sc); re_stop(sc); + RL_UNLOCK(sc); }