diff options
| author | John-Mark Gurney <jmg@FreeBSD.org> | 2004-09-03 16:41:41 +0000 |
|---|---|---|
| committer | John-Mark Gurney <jmg@FreeBSD.org> | 2004-09-03 16:41:41 +0000 |
| commit | 97b9d4baf5eaa4b7020f4d140a5932ed6158892c (patch) | |
| tree | 9e197e7f8f70ec2512a017fd946325e39ea7a25b | |
| parent | 1e454c2527bd559d90e5ce3508ada54a010c48d4 (diff) | |
Notes
| -rw-r--r-- | sys/dev/re/if_re.c | 219 |
1 files changed, 135 insertions, 84 deletions
diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c index bff901f98829..edc4c35cdbaf 100644 --- a/sys/dev/re/if_re.c +++ b/sys/dev/re/if_re.c @@ -205,11 +205,18 @@ static int re_rx_list_init (struct rl_softc *); 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); @@ -454,17 +461,14 @@ re_miibus_readreg(dev, phy, reg) 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) { @@ -485,7 +489,6 @@ re_miibus_readreg(dev, phy, reg) break; case MII_PHYIDR1: case MII_PHYIDR2: - RL_UNLOCK(sc); return (0); /* * Allow the rlphy driver to read the media status @@ -495,15 +498,12 @@ re_miibus_readreg(dev, phy, reg) */ 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); } @@ -517,19 +517,16 @@ re_miibus_writereg(dev, phy, reg, data) 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; @@ -548,16 +545,13 @@ re_miibus_writereg(dev, phy, reg, data) 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); } @@ -582,6 +576,8 @@ re_setmulti(sc) u_int32_t rxfilt; int mcnt = 0; + RL_LOCK_ASSERT(sc); + ifp = &sc->arpcom.ac_if; rxfilt = CSR_READ_4(sc, RL_RXCFG); @@ -627,6 +623,8 @@ re_reset(sc) { register int i; + RL_LOCK_ASSERT(sc); + CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RESET); for (i = 0; i < RL_TIMEOUT; i++) { @@ -675,11 +673,12 @@ re_diag(sc) 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 @@ -691,10 +690,10 @@ re_diag(sc) 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 */ @@ -710,7 +709,9 @@ re_diag(sc) */ 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 */ @@ -789,6 +790,8 @@ done: if (m0 != NULL) m_freem(m0); + RL_UNLOCK(sc); + return (error); } @@ -826,15 +829,9 @@ re_probe(dev) } 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); @@ -1065,7 +1062,7 @@ re_attach(dev) 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. */ @@ -1096,7 +1093,9 @@ re_attach(dev) } /* 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; @@ -1221,13 +1220,11 @@ re_attach(dev) } /* 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: @@ -1251,19 +1248,29 @@ re_detach(dev) 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 @@ -1279,6 +1286,12 @@ re_detach(dev) 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) @@ -1335,7 +1348,6 @@ re_detach(dev) if (sc->rl_parent_tag) bus_dma_tag_destroy(sc->rl_parent_tag); - RL_UNLOCK(sc); mtx_destroy(&sc->rl_mtx); return (0); @@ -1396,6 +1408,9 @@ static int 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 *))); @@ -1679,32 +1694,53 @@ re_tick(xsc) 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; @@ -1712,14 +1748,14 @@ re_poll (struct ifnet *ifp, enum poll_cmd cmd, int count) 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); @@ -1729,11 +1765,9 @@ re_poll (struct ifnet *ifp, enum poll_cmd cmd, int count) if (status & RL_ISR_SYSTEM_ERR) { re_reset(sc); - re_init(sc); + re_init_locked(sc); } } -done: - RL_UNLOCK(sc); } #endif /* DEVICE_POLLING */ @@ -1747,26 +1781,21 @@ re_intr(arg) 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 */ @@ -1795,21 +1824,19 @@ re_intr(arg) 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); } @@ -1825,6 +1852,8 @@ re_encap(sc, m_head, idx) int error; struct m_tag *mtag; + RL_LOCK_ASSERT(sc); + if (sc->rl_ldata.rl_tx_free <= 4) return (EFBIG); @@ -1920,12 +1949,23 @@ re_encap(sc, m_head, idx) 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; @@ -1933,7 +1973,8 @@ re_start(ifp) int idx; sc = ifp->if_softc; - RL_LOCK(sc); + + RL_LOCK_ASSERT(sc); idx = sc->rl_ldata.rl_tx_prodidx; @@ -1983,8 +2024,6 @@ re_start(ifp) */ CSR_WRITE_4(sc, RL_TIMERCNT, 1); - RL_UNLOCK(sc); - /* * Set a timeout in case the chip goes out to lunch. */ @@ -1996,11 +2035,22 @@ re_init(xsc) 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); /* @@ -2146,10 +2196,8 @@ re_init(xsc) 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); @@ -2159,7 +2207,6 @@ re_init(xsc) ifp->if_flags &= ~IFF_OACTIVE; sc->rl_stat_ch = timeout(re_tick, sc, hz); - RL_UNLOCK(sc); } /* @@ -2209,8 +2256,6 @@ re_ioctl(ifp, command, data) struct mii_data *mii; int error = 0; - RL_LOCK(sc); - switch (command) { case SIOCSIFMTU: if (ifr->ifr_mtu > RL_JUMBO_MTU) @@ -2218,17 +2263,19 @@ re_ioctl(ifp, command, data) 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: @@ -2252,8 +2299,6 @@ re_ioctl(ifp, command, data) break; } - RL_UNLOCK(sc); - return (error); } @@ -2270,8 +2315,7 @@ re_watchdog(ifp) re_txeof(sc); re_rxeof(sc); - - re_init(sc); + re_init_locked(sc); RL_UNLOCK(sc); } @@ -2287,7 +2331,8 @@ re_stop(sc) register int i; struct ifnet *ifp; - RL_LOCK(sc); + RL_LOCK_ASSERT(sc); + ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; @@ -2326,8 +2371,6 @@ re_stop(sc) sc->rl_ldata.rl_rx_mbuf[i] = NULL; } } - - RL_UNLOCK(sc); } /* @@ -2343,8 +2386,10 @@ re_suspend(dev) sc = device_get_softc(dev); + RL_LOCK(sc); re_stop(sc); sc->suspended = 1; + RL_UNLOCK(sc); return (0); } @@ -2362,13 +2407,17 @@ re_resume(dev) 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); } @@ -2385,5 +2434,7 @@ re_shutdown(dev) sc = device_get_softc(dev); + RL_LOCK(sc); re_stop(sc); + RL_UNLOCK(sc); } |
