--- //depot/vendor/freebsd/src/sys/pci/if_dc.c 2005/08/10 20:35:18 +++ //depot/user/jhb/acpipci/pci/if_dc.c 2005/08/11 21:22:08 @@ -235,8 +235,10 @@ static void dc_tx_underrun(struct dc_softc *); static void dc_intr(void *); static void dc_start(struct ifnet *); +static void dc_start_locked(struct ifnet *); static int dc_ioctl(struct ifnet *, u_long, caddr_t); static void dc_init(void *); +static void dc_init_locked(struct dc_softc *); static void dc_stop(struct dc_softc *); static void dc_watchdog(struct ifnet *); static void dc_shutdown(device_t); @@ -343,8 +345,6 @@ #define SIO_SET(x) DC_SETBIT(sc, DC_SIO, (x)) #define SIO_CLR(x) DC_CLRBIT(sc, DC_SIO, (x)) -#define IS_MPSAFE 0 - static void dc_delay(struct dc_softc *sc) { @@ -670,7 +670,8 @@ { int i, ack; - DC_LOCK(sc); + if (sc->dc_ifp->if_input != NULL) + DC_LOCK_ASSERT(sc); /* * Set up frame for RX. @@ -724,8 +725,6 @@ dc_mii_writebit(sc, 0); dc_mii_writebit(sc, 0); - DC_UNLOCK(sc); - if (ack) return (1); return (0); @@ -738,7 +737,8 @@ dc_mii_writereg(struct dc_softc *sc, struct dc_mii_frame *frame) { - DC_LOCK(sc); + if (sc->dc_ifp->if_input != NULL) + DC_LOCK_ASSERT(sc); /* * Set up frame for TX. */ @@ -763,8 +763,6 @@ dc_mii_writebit(sc, 0); dc_mii_writebit(sc, 0); - DC_UNLOCK(sc); - return (0); } @@ -776,6 +774,8 @@ int i, rval, phy_reg = 0; sc = device_get_softc(dev); + if (sc->dc_ifp->if_input != NULL) + DC_LOCK_ASSERT(sc); bzero(&frame, sizeof(frame)); /* @@ -898,6 +898,8 @@ int i, phy_reg = 0; sc = device_get_softc(dev); + if (sc->dc_ifp->if_input != NULL) + DC_LOCK_ASSERT(sc); bzero(&frame, sizeof(frame)); if (DC_IS_ADMTEK(sc) && phy != DC_ADMTEK_PHYADDR) @@ -973,6 +975,8 @@ struct ifmedia *ifm; sc = device_get_softc(dev); + if (sc->dc_ifp->if_input != NULL) + DC_LOCK_ASSERT(sc); if (DC_IS_ADMTEK(sc)) return; @@ -1007,6 +1011,8 @@ rev = pci_read_config(dev, DC_PCI_CFRV, 4) & 0xFF; sc = device_get_softc(dev); + if (sc->dc_ifp->if_input != NULL) + DC_LOCK_ASSERT(sc); mii = device_get_softc(sc->dc_miibus); ifm = &mii->mii_media; @@ -1844,7 +1850,7 @@ sc = device_get_softc(dev); mtx_init(&sc->dc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, - MTX_DEF | MTX_RECURSE); + MTX_DEF); /* * Map control/status registers. @@ -2194,8 +2200,6 @@ /* XXX: bleah, MTU gets overwritten in ether_ifattach() */ ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - if (!IS_MPSAFE) - ifp->if_flags |= IFF_NEEDSGIANT; ifp->if_ioctl = dc_ioctl; ifp->if_start = dc_start; ifp->if_watchdog = dc_watchdog; @@ -2276,7 +2280,7 @@ #endif ifp->if_capenable = ifp->if_capabilities; - callout_init(&sc->dc_stat_ch, IS_MPSAFE ? CALLOUT_MPSAFE : 0); + callout_init_mtx(&sc->dc_stat_ch, &sc->dc_mtx, 0); #ifdef SRM_MEDIA sc->dc_srm_media = 0; @@ -2310,8 +2314,7 @@ ether_ifattach(ifp, eaddr); /* Hook interrupt last to avoid having to lock softc */ - error = bus_setup_intr(dev, sc->dc_irq, INTR_TYPE_NET | - (IS_MPSAFE ? INTR_MPSAFE : 0), + error = bus_setup_intr(dev, sc->dc_irq, INTR_TYPE_NET | INTR_MPSAFE, dc_intr, sc, &sc->dc_intrhand); if (error) { @@ -2344,13 +2347,15 @@ sc = device_get_softc(dev); KASSERT(mtx_initialized(&sc->dc_mtx), ("dc mutex not initialized")); - DC_LOCK(sc); ifp = sc->dc_ifp; /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { + DC_LOCK(sc); dc_stop(sc); + DC_UNLOCK(sc); + callout_drain(&sc->dc_stat_ch); ether_ifdetach(ifp); if_free(ifp); } @@ -2390,7 +2395,6 @@ } free(sc->dc_srom, M_DEVBUF); - DC_UNLOCK(sc); mtx_destroy(&sc->dc_mtx); return (0); @@ -2751,7 +2755,7 @@ DC_INC(i, DC_RX_LIST_CNT); continue; } else { - dc_init(sc); + dc_init_locked(sc); return; } } @@ -2879,7 +2883,7 @@ if (txstat & DC_TXSTAT_LATECOLL) ifp->if_collisions++; if (!(txstat & DC_TXSTAT_UNDERRUN)) { - dc_init(sc); + dc_init_locked(sc); return; } } @@ -2918,7 +2922,7 @@ u_int32_t r; sc = xsc; - DC_LOCK(sc); + DC_LOCK_ASSERT(sc); ifp = sc->dc_ifp; mii = device_get_softc(sc->dc_miibus); @@ -2972,15 +2976,13 @@ IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { sc->dc_link++; if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - dc_start(ifp); + dc_start_locked(ifp); } if (sc->dc_flags & DC_21143_NWAY && !sc->dc_link) callout_reset(&sc->dc_stat_ch, hz/10, dc_tick, sc); else callout_reset(&sc->dc_stat_ch, hz, dc_tick, sc); - - DC_UNLOCK(sc); } /* @@ -2994,7 +2996,7 @@ int i; if (DC_IS_DAVICOM(sc)) - dc_init(sc); + dc_init_locked(sc); if (DC_IS_INTEL(sc)) { /* @@ -3013,7 +3015,7 @@ if (i == DC_TIMEOUT) { if_printf(sc->dc_ifp, "failed to force tx to idle state\n"); - dc_init(sc); + dc_init_locked(sc); } } @@ -3055,7 +3057,7 @@ dc_txeof(sc); if (!IFQ_IS_EMPTY(&ifp->if_snd) && !(ifp->if_drv_flags & IFF_DRV_OACTIVE)) - dc_start(ifp); + dc_start_locked(ifp); if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */ u_int32_t status; @@ -3088,7 +3090,7 @@ if (status & DC_ISR_BUS_ERR) { if_printf(ifp, "dc_poll: bus error\n"); dc_reset(sc); - dc_init(sc); + dc_init_locked(sc); } } DC_UNLOCK(sc); @@ -3175,7 +3177,7 @@ if (status & DC_ISR_BUS_ERR) { dc_reset(sc); - dc_init(sc); + dc_init_locked(sc); } } @@ -3183,7 +3185,7 @@ CSR_WRITE_4(sc, DC_IMR, DC_INTRS); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - dc_start(ifp); + dc_start_locked(ifp); #ifdef DEVICE_POLLING done: @@ -3312,23 +3314,30 @@ dc_start(struct ifnet *ifp) { struct dc_softc *sc; + + sc = ifp->if_softc; + DC_LOCK(sc); + dc_start_locked(ifp); + DC_UNLOCK(sc); +} + +static void +dc_start_locked(struct ifnet *ifp) +{ + struct dc_softc *sc; struct mbuf *m_head = NULL, *m; unsigned int queued = 0; int idx; sc = ifp->if_softc; - DC_LOCK(sc); + DC_LOCK_ASSERT(sc); - if (!sc->dc_link && ifp->if_snd.ifq_len < 10) { - DC_UNLOCK(sc); + if (!sc->dc_link && ifp->if_snd.ifq_len < 10) return; - } - if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { - DC_UNLOCK(sc); + if (ifp->if_drv_flags & IFF_DRV_OACTIVE) return; - } idx = sc->dc_cdata.dc_tx_first = sc->dc_cdata.dc_tx_prod; @@ -3380,18 +3389,35 @@ */ ifp->if_timer = 5; } - - DC_UNLOCK(sc); } static void dc_init(void *xsc) { struct dc_softc *sc = xsc; + + DC_LOCK(sc); + dc_init_locked(sc); +#ifdef SRM_MEDIA + if(sc->dc_srm_media) { + struct ifreq ifr; + + ifr.ifr_media = sc->dc_srm_media; + sc->dc_srm_media = 0; + DC_UNLOCK(sc); + ifmedia_ioctl(sc->dc_ifp, &ifr, &mii->mii_media, SIOCSIFMEDIA); + } else +#endif + DC_UNLOCK(sc); +} + +static void +dc_init_locked(struct dc_softc *sc) +{ struct ifnet *ifp = sc->dc_ifp; struct mii_data *mii; - DC_LOCK(sc); + DC_LOCK_ASSERT(sc); mii = device_get_softc(sc->dc_miibus); @@ -3487,7 +3513,6 @@ if_printf(ifp, "initialization failed: no memory for rx buffers\n"); dc_stop(sc); - DC_UNLOCK(sc); return; } @@ -3559,17 +3584,6 @@ else callout_reset(&sc->dc_stat_ch, hz, dc_tick, sc); } - -#ifdef SRM_MEDIA - if(sc->dc_srm_media) { - struct ifreq ifr; - - ifr.ifr_media = sc->dc_srm_media; - ifmedia_ioctl(ifp, &ifr, &mii->mii_media, SIOCSIFMEDIA); - sc->dc_srm_media = 0; - } -#endif - DC_UNLOCK(sc); } /* @@ -3584,6 +3598,7 @@ sc = ifp->if_softc; mii = device_get_softc(sc->dc_miibus); + DC_LOCK(sc); mii_mediachg(mii); ifm = &mii->mii_media; @@ -3592,6 +3607,7 @@ dc_setcfg(sc, ifm->ifm_media); else sc->dc_link = 0; + DC_UNLOCK(sc); return (0); } @@ -3608,6 +3624,7 @@ sc = ifp->if_softc; mii = device_get_softc(sc->dc_miibus); + DC_LOCK(sc); mii_pollstat(mii); ifm = &mii->mii_media; if (DC_IS_DAVICOM(sc)) { @@ -3619,6 +3636,7 @@ } ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; + DC_UNLOCK(sc); } static int @@ -3629,10 +3647,9 @@ struct mii_data *mii; int error = 0; - DC_LOCK(sc); - switch (command) { case SIOCSIFFLAGS: + DC_LOCK(sc); if (ifp->if_flags & IFF_UP) { int need_setfilt = (ifp->if_flags ^ sc->dc_if_flags) & (IFF_PROMISC | IFF_ALLMULTI); @@ -3642,18 +3659,21 @@ dc_setfilt(sc); } else { sc->dc_txthresh = 0; - dc_init(sc); + dc_init_locked(sc); } } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) dc_stop(sc); } sc->dc_if_flags = ifp->if_flags; + DC_UNLOCK(sc); error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: + DC_LOCK(sc); dc_setfilt(sc); + DC_UNLOCK(sc); error = 0; break; case SIOCGIFMEDIA: @@ -3661,21 +3681,24 @@ mii = device_get_softc(sc->dc_miibus); error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); #ifdef SRM_MEDIA + DC_LOCK(sc); if (sc->dc_srm_media) sc->dc_srm_media = 0; + DC_UNLOCK(sc); #endif break; case SIOCSIFCAP: + /* XXX: What is the right locking here? */ + DC_LOCK(sc); ifp->if_capenable &= ~IFCAP_POLLING; ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING; + DC_UNLOCK(sc); break; default: error = ether_ioctl(ifp, command, data); break; } - DC_UNLOCK(sc); - return (error); } @@ -3693,10 +3716,10 @@ dc_stop(sc); dc_reset(sc); - dc_init(sc); + dc_init_locked(sc); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - dc_start(ifp); + dc_start_locked(ifp); DC_UNLOCK(sc); } @@ -3714,7 +3737,7 @@ int i; u_int32_t ctl; - DC_LOCK(sc); + DC_LOCK_ASSERT(sc); ifp = sc->dc_ifp; ifp->if_timer = 0; @@ -3762,8 +3785,6 @@ } } bzero(&ld->dc_tx_list, sizeof(ld->dc_tx_list)); - - DC_UNLOCK(sc); } /* @@ -3775,15 +3796,13 @@ dc_suspend(device_t dev) { struct dc_softc *sc; - int s; - - s = splimp(); sc = device_get_softc(dev); + DC_LOCK(sc); dc_stop(sc); sc->suspended = 1; + DC_UNLOCK(sc); - splx(s); return (0); } @@ -3797,20 +3816,18 @@ { struct dc_softc *sc; struct ifnet *ifp; - int s; - s = splimp(); - sc = device_get_softc(dev); ifp = sc->dc_ifp; /* reinitialize interface if necessary */ + DC_LOCK(sc); if (ifp->if_flags & IFF_UP) - dc_init(sc); + dc_init_locked(sc); sc->suspended = 0; + DC_UNLOCK(sc); - splx(s); return (0); } @@ -3825,5 +3842,7 @@ sc = device_get_softc(dev); + DC_LOCK(sc); dc_stop(sc); + DC_UNLOCK(sc); }