diff --git a/sys/dev/usb/if_aue.c b/sys/dev/usb/if_aue.c index 89e2c5f55447..bd9226a3ba67 100644 --- a/sys/dev/usb/if_aue.c +++ b/sys/dev/usb/if_aue.c @@ -240,7 +240,7 @@ CFATTACH_DECL_NEW(aue, sizeof(struct aue_softc), aue_match, aue_attach, static void aue_reset_pegasus_II(struct aue_softc *); static void aue_uno_stop(struct ifnet *, int); -static int aue_uno_ioctl(struct ifnet *, u_long, void *); +static void aue_uno_mcast(struct ifnet *); static int aue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); static int aue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); static void aue_uno_mii_statchg(struct ifnet *); @@ -252,7 +252,7 @@ static void aue_uno_intr(struct usbnet *, usbd_status); static const struct usbnet_ops aue_ops = { .uno_stop = aue_uno_stop, - .uno_ioctl = aue_uno_ioctl, + .uno_mcast = aue_uno_mcast, .uno_read_reg = aue_uno_mii_read_reg, .uno_write_reg = aue_uno_mii_write_reg, .uno_statchg = aue_uno_mii_statchg, @@ -483,6 +483,8 @@ aue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ); for (i = 0; i < AUE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return ENXIO; if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) break; } @@ -524,6 +526,8 @@ aue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE); for (i = 0; i < AUE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return ENXIO; if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) break; } @@ -607,10 +611,10 @@ aue_crc(void *addrv) } static void -aue_setiff_locked(struct usbnet *un) +aue_uno_mcast(struct ifnet *ifp) { + struct usbnet * const un = ifp->if_softc; struct aue_softc * const sc = usbnet_softc(un); - struct ifnet * const ifp = usbnet_ifp(un); struct ethercom * ec = usbnet_ec(un); struct ether_multi *enm; struct ether_multistep step; @@ -623,21 +627,20 @@ aue_setiff_locked(struct usbnet *un) usbnet_isowned_core(un); if (ifp->if_flags & IFF_PROMISC) { + ETHER_LOCK(ec); allmulti: - ifp->if_flags |= IFF_ALLMULTI; + ec->ec_flags |= ETHER_F_ALLMULTI; + ETHER_UNLOCK(ec); AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); return; } - AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); - /* now program new ones */ ETHER_LOCK(ec); ETHER_FIRST_MULTI(step, ec, enm); while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { - ETHER_UNLOCK(ec); goto allmulti; } @@ -645,13 +648,14 @@ allmulti: hashtbl[h >> 3] |= 1 << (h & 0x7); ETHER_NEXT_MULTI(step, enm); } + ec->ec_flags &= ~ETHER_F_ALLMULTI; ETHER_UNLOCK(ec); + AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); + /* write the hashtable */ for (i = 0; i < 8; i++) aue_csr_write_1(sc, AUE_MAR0 + i, hashtbl[i]); - - ifp->if_flags &= ~IFF_ALLMULTI; } static void @@ -680,6 +684,8 @@ aue_reset(struct aue_softc *sc) AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC); for (i = 0; i < AUE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC)) break; } @@ -948,7 +954,7 @@ aue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) } static int -aue_init_locked(struct ifnet *ifp) +aue_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; struct aue_softc *sc = usbnet_softc(un); @@ -982,7 +988,7 @@ aue_init_locked(struct ifnet *ifp) rv = usbnet_init_rx_tx(un); /* Load the multicast filter. */ - aue_setiff_locked(un); + aue_uno_mcast(ifp); /* Enable RX and TX */ aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB); @@ -994,42 +1000,6 @@ aue_init_locked(struct ifnet *ifp) return rv; } -static int -aue_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - int rv; - - usbnet_lock_core(un); - usbnet_busy(un); - rv = aue_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return rv; -} - -static int -aue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - - AUEHIST_FUNC(); - AUEHIST_CALLARGSN(5, "aue%jd: enter cmd %#jx data %#jx", - device_unit(((struct usbnet *)(ifp->if_softc))->un_dev), - cmd, (uintptr_t)data, 0); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - aue_uno_init(ifp); - break; - default: - break; - } - - return 0; -} - static void aue_uno_stop(struct ifnet *ifp, int disable) { diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c index eba67386e770..cb42c4ce17a3 100644 --- a/sys/dev/usb/if_axe.c +++ b/sys/dev/usb/if_axe.c @@ -259,7 +259,7 @@ CFATTACH_DECL_NEW(axe, sizeof(struct axe_softc), axe_match, axe_attach, usbnet_detach, usbnet_activate); static void axe_uno_stop(struct ifnet *, int); -static int axe_uno_ioctl(struct ifnet *, u_long, void *); +static void axe_uno_mcast(struct ifnet *); static int axe_uno_init(struct ifnet *); static int axe_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); static int axe_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); @@ -276,7 +276,7 @@ static void axe_ax88772b_init(struct axe_softc *); static const struct usbnet_ops axe_ops = { .uno_stop = axe_uno_stop, - .uno_ioctl = axe_uno_ioctl, + .uno_mcast = axe_uno_mcast, .uno_read_reg = axe_uno_mii_read_reg, .uno_write_reg = axe_uno_mii_write_reg, .uno_statchg = axe_uno_mii_statchg, @@ -426,11 +426,11 @@ axe_uno_mii_statchg(struct ifnet *ifp) } static void -axe_rcvfilt_locked(struct usbnet *un) +axe_uno_mcast(struct ifnet *ifp) { AXEHIST_FUNC(); AXEHIST_CALLED(); + struct usbnet * const un = ifp->if_softc; struct axe_softc * const sc = usbnet_softc(un); - struct ifnet * const ifp = usbnet_ifp(un); struct ethercom *ec = usbnet_ec(un); struct ether_multi *enm; struct ether_multistep step; @@ -930,10 +930,8 @@ axe_attach(device_t parent, device_t self, void *aux) /* We need the PHYID for init dance in some cases */ usbnet_lock_core(un); - usbnet_busy(un); if (axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, &sc->axe_phyaddrs)) { aprint_error_dev(self, "failed to read phyaddrs\n"); - usbnet_unbusy(un); usbnet_unlock_core(un); return; } @@ -964,13 +962,11 @@ axe_attach(device_t parent, device_t self, void *aux) } else { if (axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->axe_ipgs)) { aprint_error_dev(self, "failed to read ipg\n"); - usbnet_unbusy(un); usbnet_unlock_core(un); return; } } - usbnet_unbusy(un); usbnet_unlock_core(un); if (!AXE_IS_172(un)) @@ -1140,8 +1136,6 @@ axe_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) size_t hdr_len = 0, tlr_len = 0; int length, boundary; - usbnet_isowned_tx(un); - if (!AXE_IS_172(un)) { /* * Copy the mbuf data into a contiguous buffer, leaving two @@ -1216,7 +1210,7 @@ axe_csum_cfg(struct axe_softc *sc) } static int -axe_init_locked(struct ifnet *ifp) +axe_uno_init(struct ifnet *ifp) { AXEHIST_FUNC(); AXEHIST_CALLED(); struct usbnet * const un = ifp->if_softc; @@ -1307,48 +1301,11 @@ axe_init_locked(struct ifnet *ifp) axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); /* Accept multicast frame or run promisc. mode */ - axe_rcvfilt_locked(un); + axe_uno_mcast(ifp); return usbnet_init_rx_tx(un); } -static int -axe_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - int ret = axe_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return ret; -} - -static int -axe_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - axe_rcvfilt_locked(un); - break; - default: - break; - } - - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return 0; -} - static void axe_uno_stop(struct ifnet *ifp, int disable) { diff --git a/sys/dev/usb/if_axen.c b/sys/dev/usb/if_axen.c index bf91d56b356d..55ffb9335e3b 100644 --- a/sys/dev/usb/if_axen.c +++ b/sys/dev/usb/if_axen.c @@ -80,6 +80,7 @@ static void axen_ax88179_init(struct usbnet *); static void axen_uno_stop(struct ifnet *, int); static int axen_uno_ioctl(struct ifnet *, u_long, void *); +static void axen_uno_mcast(struct ifnet *); static int axen_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); static int axen_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); static void axen_uno_mii_statchg(struct ifnet *); @@ -92,6 +93,7 @@ static int axen_uno_init(struct ifnet *); static const struct usbnet_ops axen_ops = { .uno_stop = axen_uno_stop, .uno_ioctl = axen_uno_ioctl, + .uno_mcast = axen_uno_mcast, .uno_read_reg = axen_uno_mii_read_reg, .uno_write_reg = axen_uno_mii_write_reg, .uno_statchg = axen_uno_mii_statchg, @@ -223,9 +225,9 @@ axen_uno_mii_statchg(struct ifnet *ifp) } static void -axen_setiff_locked(struct usbnet *un) +axen_uno_mcast(struct ifnet *ifp) { - struct ifnet * const ifp = usbnet_ifp(un); + struct usbnet * const un = ifp->if_softc; struct ethercom *ec = usbnet_ec(un); struct ether_multi *enm; struct ether_multistep step; @@ -366,7 +368,6 @@ axen_ax88179_init(struct usbnet *un) uint8_t val; usbnet_lock_core(un); - usbnet_busy(un); /* XXX: ? */ axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_UNK_05, &val); @@ -450,7 +451,6 @@ axen_ax88179_init(struct usbnet *un) default: aprint_error_dev(un->un_dev, "unknown uplink bus:0x%02x\n", val); - usbnet_unbusy(un); usbnet_unlock_core(un); return; } @@ -510,7 +510,6 @@ axen_ax88179_init(struct usbnet *un) usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x1F, 0x0000); #endif - usbnet_unbusy(un); usbnet_unlock_core(un); } @@ -556,15 +555,8 @@ axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) struct usbnet * const un = ifp->if_softc; usbnet_lock_core(un); - usbnet_busy(un); switch (cmd) { - case SIOCSIFFLAGS: - case SIOCSETHERCAP: - case SIOCADDMULTI: - case SIOCDELMULTI: - axen_setiff_locked(un); - break; case SIOCSIFCAP: axen_setoe_locked(un); break; @@ -572,7 +564,6 @@ axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) break; } - usbnet_unbusy(un); usbnet_unlock_core(un); return 0; @@ -676,14 +667,11 @@ axen_attach(device_t parent, device_t self, void *aux) /* Get station address. */ usbnet_lock_core(un); - usbnet_busy(un); if (axen_get_eaddr(un, &un->un_eaddr)) { - usbnet_unbusy(un); usbnet_unlock_core(un); printf("EEPROM checksum error\n"); return; } - usbnet_unbusy(un); usbnet_unlock_core(un); axen_ax88179_init(un); @@ -894,7 +882,7 @@ axen_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) } static int -axen_init_locked(struct ifnet *ifp) +axen_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; uint16_t rxmode; @@ -920,7 +908,7 @@ axen_init_locked(struct ifnet *ifp) axen_setoe_locked(un); /* Program promiscuous mode and multicast filters. */ - axen_setiff_locked(un); + axen_uno_mcast(ifp); /* Enable receiver, set RX mode */ axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval); @@ -932,20 +920,6 @@ axen_init_locked(struct ifnet *ifp) return usbnet_init_rx_tx(un); } -static int -axen_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - int ret = axen_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return ret; -} - static void axen_uno_stop(struct ifnet *ifp, int disable) { diff --git a/sys/dev/usb/if_cdce.c b/sys/dev/usb/if_cdce.c index 3edf73d856ca..c7ee6bef2792 100644 --- a/sys/dev/usb/if_cdce.c +++ b/sys/dev/usb/if_cdce.c @@ -261,7 +261,6 @@ cdce_uno_init(struct ifnet *ifp) struct usbnet *un = ifp->if_softc; int rv; - usbnet_lock_core(un); if (usbnet_isdying(un)) rv = EIO; else { @@ -269,7 +268,6 @@ cdce_uno_init(struct ifnet *ifp) rv = usbnet_init_rx_tx(un); usbnet_set_link(un, rv == 0); } - usbnet_unlock_core(un); return rv; } @@ -279,8 +277,6 @@ cdce_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len) { struct ifnet *ifp = usbnet_ifp(un); - usbnet_isowned_rx(un); - /* Strip off CRC added by Zaurus, if present */ if (un->un_flags & CDCE_ZAURUS && total_len > 4) total_len -= 4; diff --git a/sys/dev/usb/if_cue.c b/sys/dev/usb/if_cue.c index e730297a939d..a3902bc54679 100644 --- a/sys/dev/usb/if_cue.c +++ b/sys/dev/usb/if_cue.c @@ -141,14 +141,14 @@ CFATTACH_DECL_NEW(cue, sizeof(struct cue_softc), cue_match, cue_attach, static unsigned cue_uno_tx_prepare(struct usbnet *, struct mbuf *, struct usbnet_chain *); static void cue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); -static int cue_uno_ioctl(struct ifnet *, u_long, void *); +static void cue_uno_mcast(struct ifnet *); static void cue_uno_stop(struct ifnet *, int); static int cue_uno_init(struct ifnet *); static void cue_uno_tick(struct usbnet *); static const struct usbnet_ops cue_ops = { .uno_stop = cue_uno_stop, - .uno_ioctl = cue_uno_ioctl, + .uno_mcast = cue_uno_mcast, .uno_tx_prepare = cue_uno_tx_prepare, .uno_rx_loop = cue_uno_rx_loop, .uno_init = cue_uno_init, @@ -357,11 +357,11 @@ cue_crc(const char *addr) } static void -cue_setiff_locked(struct usbnet *un) +cue_uno_mcast(struct ifnet *ifp) { + struct usbnet *un = ifp->if_softc; struct cue_softc *sc = usbnet_softc(un); struct ethercom *ec = usbnet_ec(un); - struct ifnet *ifp = usbnet_ifp(un); struct ether_multi *enm; struct ether_multistep step; uint32_t h, i; @@ -370,8 +370,10 @@ cue_setiff_locked(struct usbnet *un) device_xname(un->un_dev), ifp->if_flags)); if (ifp->if_flags & IFF_PROMISC) { + ETHER_LOCK(ec); allmulti: - ifp->if_flags |= IFF_ALLMULTI; + ec->ec_flags |= ETHER_F_ALLMULTI; + ETHER_UNLOCK(ec); for (i = 0; i < CUE_MCAST_TABLE_LEN; i++) sc->cue_mctab[i] = 0xFF; cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, @@ -389,7 +391,6 @@ allmulti: while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { - ETHER_UNLOCK(ec); goto allmulti; } @@ -397,10 +398,9 @@ allmulti: sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); ETHER_NEXT_MULTI(step, enm); } + ec->ec_flags &= ~ETHER_F_ALLMULTI; ETHER_UNLOCK(ec); - ifp->if_flags &= ~IFF_ALLMULTI; - /* * Also include the broadcast address in the filter * so we can receive broadcast frames. @@ -613,7 +613,7 @@ cue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) } static int -cue_init_locked(struct ifnet *ifp) +cue_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; int i, ctl; @@ -622,7 +622,7 @@ cue_init_locked(struct ifnet *ifp) DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); if (usbnet_isdying(un)) - return -1; + return ENXIO; /* Cancel pending I/O */ usbnet_stop(un, ifp, 1); @@ -648,7 +648,7 @@ cue_init_locked(struct ifnet *ifp) cue_csr_write_1(un, CUE_ETHCTL, ctl); /* Load the multicast filter. */ - cue_setiff_locked(un); + cue_uno_mcast(ifp); /* * Set the number of RX and TX buffers that we want @@ -667,44 +667,6 @@ cue_init_locked(struct ifnet *ifp) return usbnet_init_rx_tx(un); } -static int -cue_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - int rv; - - usbnet_lock_core(un); - usbnet_busy(un); - rv = cue_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return rv; -} - -static int -cue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - cue_setiff_locked(un); - break; - default: - break; - } - - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return 0; -} - /* Stop and reset the adapter. */ static void cue_uno_stop(struct ifnet *ifp, int disable) diff --git a/sys/dev/usb/if_kue.c b/sys/dev/usb/if_kue.c index 172bc93fa301..15f32d81409f 100644 --- a/sys/dev/usb/if_kue.c +++ b/sys/dev/usb/if_kue.c @@ -174,11 +174,11 @@ CFATTACH_DECL_NEW(kue, sizeof(struct kue_softc), kue_match, kue_attach, static void kue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); static unsigned kue_uno_tx_prepare(struct usbnet *, struct mbuf *, struct usbnet_chain *); -static int kue_uno_ioctl(struct ifnet *, u_long, void *); +static void kue_uno_mcast(struct ifnet *); static int kue_uno_init(struct ifnet *); static const struct usbnet_ops kue_ops = { - .uno_ioctl = kue_uno_ioctl, + .uno_mcast = kue_uno_mcast, .uno_tx_prepare = kue_uno_tx_prepare, .uno_rx_loop = kue_uno_rx_loop, .uno_init = kue_uno_init, @@ -318,11 +318,11 @@ kue_load_fw(struct usbnet *un) } static void -kue_setiff_locked(struct usbnet *un) +kue_uno_mcast(struct ifnet *ifp) { + struct usbnet * un = ifp->if_softc; struct ethercom * ec = usbnet_ec(un); struct kue_softc * sc = usbnet_softc(un); - struct ifnet * const ifp = usbnet_ifp(un); struct ether_multi *enm; struct ether_multistep step; int i; @@ -336,8 +336,10 @@ kue_setiff_locked(struct usbnet *un) sc->kue_rxfilt &= ~KUE_RXFILT_PROMISC; if (ifp->if_flags & IFF_PROMISC) { + ETHER_LOCK(ec); allmulti: - ifp->if_flags |= IFF_ALLMULTI; + ec->ec_flags |= ETHER_F_ALLMULTI; + ETHER_UNLOCK(ec); sc->kue_rxfilt |= KUE_RXFILT_ALLMULTI|KUE_RXFILT_PROMISC; sc->kue_rxfilt &= ~KUE_RXFILT_MULTICAST; kue_setword(un, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt); @@ -353,7 +355,6 @@ allmulti: if (i == KUE_MCFILTCNT(sc) || memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { - ETHER_UNLOCK(ec); goto allmulti; } @@ -361,10 +362,9 @@ allmulti: ETHER_NEXT_MULTI(step, enm); i++; } + ec->ec_flags &= ~ETHER_F_ALLMULTI; ETHER_UNLOCK(ec); - ifp->if_flags &= ~IFF_ALLMULTI; - sc->kue_rxfilt |= KUE_RXFILT_MULTICAST; kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SET_MCAST_FILTERS, i, sc->kue_mcfilters, i * ETHER_ADDR_LEN); @@ -591,7 +591,7 @@ kue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) } static int -kue_init_locked(struct ifnet *ifp) +kue_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; struct kue_softc *sc = usbnet_softc(un); @@ -622,49 +622,11 @@ kue_init_locked(struct ifnet *ifp) kue_setword(un, KUE_CMD_SET_URB_SIZE, 64); /* Load the multicast filter. */ - kue_setiff_locked(un); + kue_uno_mcast(ifp); return usbnet_init_rx_tx(un); } -static int -kue_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - int rv; - - usbnet_lock_core(un); - usbnet_busy(un); - rv = kue_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return rv; -} - -static int -kue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - kue_setiff_locked(un); - break; - default: - break; - } - - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return 0; -} - #ifdef _MODULE #include "ioconf.c" #endif diff --git a/sys/dev/usb/if_mos.c b/sys/dev/usb/if_mos.c index 347104b7b0df..afe02a06ed22 100644 --- a/sys/dev/usb/if_mos.c +++ b/sys/dev/usb/if_mos.c @@ -145,7 +145,7 @@ CFATTACH_DECL_NEW(mos, sizeof(struct usbnet), static void mos_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); static unsigned mos_uno_tx_prepare(struct usbnet *, struct mbuf *, struct usbnet_chain *); -static int mos_uno_ioctl(struct ifnet *, u_long, void *); +static void mos_uno_mcast(struct ifnet *); static int mos_uno_init(struct ifnet *); static void mos_chip_init(struct usbnet *); static void mos_uno_stop(struct ifnet *ifp, int disable); @@ -164,7 +164,7 @@ static int mos_write_mcast(struct usbnet *, uint8_t *); static const struct usbnet_ops mos_ops = { .uno_stop = mos_uno_stop, - .uno_ioctl = mos_uno_ioctl, + .uno_mcast = mos_uno_mcast, .uno_read_reg = mos_uno_mii_read_reg, .uno_write_reg = mos_uno_mii_write_reg, .uno_statchg = mos_uno_mii_statchg, @@ -364,6 +364,8 @@ mos_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) MOS_PHYSTS_PENDING); for (i = 0; i < MOS_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return ENXIO; if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY) break; } @@ -396,6 +398,8 @@ mos_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) MOS_PHYSTS_PENDING); for (i = 0; i < MOS_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return ENXIO; if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY) break; } @@ -454,9 +458,9 @@ mos_uno_mii_statchg(struct ifnet *ifp) } static void -mos_rcvfilt_locked(struct usbnet *un) +mos_uno_mcast(struct ifnet *ifp) { - struct ifnet *ifp = usbnet_ifp(un); + struct usbnet *un = ifp->if_softc; struct ethercom *ec = usbnet_ec(un); struct ether_multi *enm; struct ether_multistep step; @@ -719,7 +723,7 @@ mos_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) } static int -mos_init_locked(struct ifnet *ifp) +mos_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; u_int8_t rxmode; @@ -744,7 +748,7 @@ mos_init_locked(struct ifnet *ifp) mos_reg_write_1(un, MOS_IPG1, ipgs[1]); /* Accept multicast frame or run promisc. mode */ - mos_rcvfilt_locked(un); + mos_uno_mcast(ifp); /* Enable receiver and transmitter, bridge controls speed/duplex mode */ rxmode = mos_reg_read_1(un, MOS_CTL); @@ -755,43 +759,6 @@ mos_init_locked(struct ifnet *ifp) return usbnet_init_rx_tx(un); } -static int -mos_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - int ret = mos_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return ret; -} - -static int -mos_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - mos_rcvfilt_locked(un); - break; - default: - break; - } - - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return 0; -} - void mos_uno_stop(struct ifnet *ifp, int disable) { diff --git a/sys/dev/usb/if_mue.c b/sys/dev/usb/if_mue.c index 559b9eff2569..c63911009771 100644 --- a/sys/dev/usb/if_mue.c +++ b/sys/dev/usb/if_mue.c @@ -92,7 +92,7 @@ static int mue_chip_init(struct usbnet *); static void mue_set_macaddr(struct usbnet *); static int mue_get_macaddr(struct usbnet *, prop_dictionary_t); static int mue_prepare_tso(struct usbnet *, struct mbuf *); -static void mue_setiff_locked(struct usbnet *); +static void mue_uno_mcast(struct ifnet *); static void mue_sethwcsum_locked(struct usbnet *); static void mue_setmtu_locked(struct usbnet *); static void mue_reset(struct usbnet *); @@ -111,6 +111,7 @@ static int mue_uno_init(struct ifnet *); static const struct usbnet_ops mue_ops = { .uno_stop = mue_uno_stop, .uno_ioctl = mue_uno_ioctl, + .uno_mcast = mue_uno_mcast, .uno_read_reg = mue_uno_mii_read_reg, .uno_write_reg = mue_uno_mii_write_reg, .uno_statchg = mue_uno_mii_statchg, @@ -200,6 +201,8 @@ mue_wait_for_bits(struct usbnet *un, uint32_t reg, int ntries; for (ntries = 0; ntries < 1000; ntries++) { + if (usbnet_isdying(un)) + return 1; val = mue_csr_read(un, reg); if ((val & set) || !(val & clear)) return 0; @@ -993,10 +996,10 @@ mue_prepare_tso(struct usbnet *un, struct mbuf *m) } static void -mue_setiff_locked(struct usbnet *un) +mue_uno_mcast(struct ifnet *ifp) { + struct usbnet *un = ifp->if_softc; struct ethercom *ec = usbnet_ec(un); - struct ifnet * const ifp = usbnet_ifp(un); const uint8_t *enaddr = CLLADDR(ifp->if_sadl); struct ether_multi *enm; struct ether_multistep step; @@ -1020,10 +1023,11 @@ mue_setiff_locked(struct usbnet *un) /* Always accept broadcast frames. */ rxfilt |= MUE_RFE_CTL_BROADCAST; + ETHER_LOCK(ec); if (ifp->if_flags & IFF_PROMISC) { rxfilt |= MUE_RFE_CTL_UNICAST; allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; - ifp->if_flags |= IFF_ALLMULTI; + ec->ec_flags |= ETHER_F_ALLMULTI; if (ifp->if_flags & IFF_PROMISC) DPRINTF(un, "promisc\n"); else @@ -1033,7 +1037,6 @@ allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; pfiltbl[0][0] = MUE_ENADDR_HI(enaddr) | MUE_ADDR_FILTX_VALID; pfiltbl[0][1] = MUE_ENADDR_LO(enaddr); i = 1; - ETHER_LOCK(ec); ETHER_FIRST_MULTI(step, ec, enm); while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, @@ -1041,7 +1044,6 @@ allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; memset(pfiltbl, 0, sizeof(pfiltbl)); memset(hashtbl, 0, sizeof(hashtbl)); rxfilt &= ~MUE_RFE_CTL_MULTICAST_HASH; - ETHER_UNLOCK(ec); goto allmulti; } if (i < MUE_NUM_ADDR_FILTX) { @@ -1059,14 +1061,14 @@ allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; i++; ETHER_NEXT_MULTI(step, enm); } - ETHER_UNLOCK(ec); + ec->ec_flags &= ~ETHER_F_ALLMULTI; rxfilt |= MUE_RFE_CTL_PERFECT; - ifp->if_flags &= ~IFF_ALLMULTI; if (rxfilt & MUE_RFE_CTL_MULTICAST_HASH) DPRINTF(un, "perfect filter and hash tables\n"); else DPRINTF(un, "perfect filter\n"); } + ETHER_UNLOCK(ec); for (i = 0; i < MUE_NUM_ADDR_FILTX; i++) { hireg = (un->un_flags & LAN7500) ? @@ -1219,7 +1221,7 @@ mue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) } static int -mue_init_locked(struct ifnet *ifp) +mue_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; @@ -1238,7 +1240,7 @@ mue_init_locked(struct ifnet *ifp) mue_set_macaddr(un); /* Load the multicast filter. */ - mue_setiff_locked(un); + mue_uno_mcast(ifp); /* TCP/UDP checksum offload engines. */ mue_sethwcsum_locked(un); @@ -1249,36 +1251,14 @@ mue_init_locked(struct ifnet *ifp) return usbnet_init_rx_tx(un); } -static int -mue_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - int rv; - - usbnet_lock_core(un); - usbnet_busy(un); - rv = mue_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return rv; -} - static int mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) { struct usbnet * const un = ifp->if_softc; usbnet_lock_core(un); - usbnet_busy(un); switch (cmd) { - case SIOCSIFFLAGS: - case SIOCSETHERCAP: - case SIOCADDMULTI: - case SIOCDELMULTI: - mue_setiff_locked(un); - break; case SIOCSIFCAP: mue_sethwcsum_locked(un); break; @@ -1289,7 +1269,6 @@ mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) break; } - usbnet_unbusy(un); usbnet_unlock_core(un); return 0; diff --git a/sys/dev/usb/if_smsc.c b/sys/dev/usb/if_smsc.c index 6cf37e507d1c..751d0c982eb7 100644 --- a/sys/dev/usb/if_smsc.c +++ b/sys/dev/usb/if_smsc.c @@ -174,7 +174,6 @@ static int smsc_chip_init(struct usbnet *); static int smsc_setmacaddress(struct usbnet *, const uint8_t *); static int smsc_uno_init(struct ifnet *); -static int smsc_init_locked(struct ifnet *); static void smsc_uno_stop(struct ifnet *, int); static void smsc_reset(struct smsc_softc *); @@ -187,6 +186,7 @@ static int smsc_uno_miibus_readreg(struct usbnet *, int, int, uint16_t *); static int smsc_uno_miibus_writereg(struct usbnet *, int, int, uint16_t); static int smsc_uno_ioctl(struct ifnet *, u_long, void *); +static void smsc_uno_mcast(struct ifnet *); static unsigned smsc_uno_tx_prepare(struct usbnet *, struct mbuf *, struct usbnet_chain *); static void smsc_uno_rx_loop(struct usbnet *, struct usbnet_chain *, @@ -195,6 +195,7 @@ static void smsc_uno_rx_loop(struct usbnet *, struct usbnet_chain *, static const struct usbnet_ops smsc_ops = { .uno_stop = smsc_uno_stop, .uno_ioctl = smsc_uno_ioctl, + .uno_mcast = smsc_uno_mcast, .uno_read_reg = smsc_uno_miibus_readreg, .uno_write_reg = smsc_uno_miibus_writereg, .uno_statchg = smsc_uno_miibus_statchg, @@ -264,6 +265,8 @@ smsc_wait_for_bits(struct usbnet *un, uint32_t reg, uint32_t bits) int err, i; for (i = 0; i < 100; i++) { + if (usbnet_isdying(un)) + return ENXIO; if ((err = smsc_readreg(un, reg, &val)) != 0) return err; if (!(val & bits)) @@ -408,11 +411,11 @@ smsc_hash(uint8_t addr[ETHER_ADDR_LEN]) } static void -smsc_setiff_locked(struct usbnet *un) +smsc_uno_mcast(struct ifnet *ifp) { USMSCHIST_FUNC(); USMSCHIST_CALLED(); + struct usbnet * const un = ifp->if_softc; struct smsc_softc * const sc = usbnet_softc(un); - struct ifnet * const ifp = usbnet_ifp(un); struct ethercom *ec = usbnet_ec(un); struct ether_multi *enm; struct ether_multistep step; @@ -424,8 +427,11 @@ smsc_setiff_locked(struct usbnet *un) if (usbnet_isdying(un)) return; - if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { + if (ifp->if_flags & IFF_PROMISC) { + ETHER_LOCK(ec); allmulti: + ec->ec_flags |= ETHER_F_ALLMULTI; + ETHER_UNLOCK(ec); DPRINTF("receive all multicast enabled", 0, 0, 0, 0); sc->sc_mac_csr |= SMSC_MAC_CSR_MCPAS; sc->sc_mac_csr &= ~SMSC_MAC_CSR_HPFILT; @@ -440,7 +446,6 @@ allmulti: ETHER_FIRST_MULTI(step, ec, enm); while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { - ETHER_UNLOCK(ec); goto allmulti; } @@ -448,6 +453,7 @@ allmulti: hashtbl[hash >> 5] |= 1 << (hash & 0x1F); ETHER_NEXT_MULTI(step, enm); } + ec->ec_flags &= ~ETHER_F_ALLMULTI; ETHER_UNLOCK(ec); /* Debug */ @@ -460,7 +466,6 @@ allmulti: /* Write the hash table and mac control registers */ //XXX should we be doing this? - ifp->if_flags &= ~IFF_ALLMULTI; smsc_writereg(un, SMSC_HASHH, hashtbl[1]); smsc_writereg(un, SMSC_HASHL, hashtbl[0]); smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); @@ -549,20 +554,6 @@ smsc_reset(struct smsc_softc *sc) static int smsc_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - int ret = smsc_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return ret; -} - -static int -smsc_init_locked(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; struct smsc_softc * const sc = usbnet_softc(un); @@ -579,7 +570,7 @@ smsc_init_locked(struct ifnet *ifp) smsc_reset(sc); /* Load the multicast filter. */ - smsc_setiff_locked(un); + smsc_uno_mcast(ifp); /* TCP/UDP checksum offload engines. */ smsc_setoe_locked(un); @@ -754,15 +745,8 @@ smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) struct usbnet * const un = ifp->if_softc; usbnet_lock_core(un); - usbnet_busy(un); switch (cmd) { - case SIOCSIFFLAGS: - case SIOCSETHERCAP: - case SIOCADDMULTI: - case SIOCDELMULTI: - smsc_setiff_locked(un); - break; case SIOCSIFCAP: smsc_setoe_locked(un); break; @@ -770,7 +754,6 @@ smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) break; } - usbnet_unbusy(un); usbnet_unlock_core(un); return 0; @@ -882,7 +865,6 @@ smsc_attach(device_t parent, device_t self, void *aux) un->un_phyno = 1; usbnet_lock_core(un); - usbnet_busy(un); /* * Attempt to get the mac address, if an EEPROM is not attached this * will just return FF:FF:FF:FF:FF:FF, so in such cases we invent a MAC @@ -910,7 +892,6 @@ smsc_attach(device_t parent, device_t self, void *aux) un->un_eaddr[0] = (uint8_t)((mac_l) & 0xff); } } - usbnet_unbusy(un); usbnet_unlock_core(un); usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, diff --git a/sys/dev/usb/if_udav.c b/sys/dev/usb/if_udav.c index a38a83a53df0..32978d4d2dd5 100644 --- a/sys/dev/usb/if_udav.c +++ b/sys/dev/usb/if_udav.c @@ -69,12 +69,11 @@ static unsigned udav_uno_tx_prepare(struct usbnet *, struct mbuf *, struct usbnet_chain *); static void udav_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); static void udav_uno_stop(struct ifnet *, int); -static int udav_uno_ioctl(struct ifnet *, u_long, void *); +static void udav_uno_mcast(struct ifnet *); static int udav_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); static int udav_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); static void udav_uno_mii_statchg(struct ifnet *); static int udav_uno_init(struct ifnet *); -static void udav_setiff_locked(struct usbnet *); static void udav_reset(struct usbnet *); static int udav_csr_read(struct usbnet *, int, void *, int); @@ -132,7 +131,7 @@ static const struct udav_type { static const struct usbnet_ops udav_ops = { .uno_stop = udav_uno_stop, - .uno_ioctl = udav_uno_ioctl, + .uno_mcast = udav_uno_mcast, .uno_read_reg = udav_uno_mii_read_reg, .uno_write_reg = udav_uno_mii_write_reg, .uno_statchg = udav_uno_mii_statchg, @@ -240,14 +239,12 @@ udav_attach(device_t parent, device_t self, void *aux) usbnet_attach(un, "udavdet"); usbnet_lock_core(un); - usbnet_busy(un); // /* reset the adapter */ // udav_reset(un); /* Get Ethernet Address */ err = udav_csr_read(un, UDAV_PAR, un->un_eaddr, ETHER_ADDR_LEN); - usbnet_unbusy(un); usbnet_unlock_core(un); if (err) { aprint_error_dev(self, "read MAC address failed\n"); @@ -478,10 +475,7 @@ udav_uno_init(struct ifnet *ifp) DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); - usbnet_lock_core(un); - if (usbnet_isdying(un)) { - usbnet_unlock_core(un); return EIO; } @@ -489,8 +483,6 @@ udav_uno_init(struct ifnet *ifp) if (ifp->if_flags & IFF_RUNNING) usbnet_stop(un, ifp, 1); - usbnet_busy(un); - memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); udav_csr_write(un, UDAV_PAR, eaddr, ETHER_ADDR_LEN); @@ -508,7 +500,7 @@ udav_uno_init(struct ifnet *ifp) UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); /* Load the multicast filter */ - udav_setiff_locked(un); + udav_uno_mcast(ifp); /* Enable RX */ UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_RXEN); @@ -521,8 +513,6 @@ udav_uno_init(struct ifnet *ifp) rc = 0; if (rc != 0) { - usbnet_unbusy(un); - usbnet_unlock_core(un); return rc; } @@ -531,9 +521,6 @@ udav_uno_init(struct ifnet *ifp) else rc = usbnet_init_rx_tx(un); - usbnet_unbusy(un); - usbnet_unlock_core(un); - return rc; } @@ -573,6 +560,8 @@ udav_chip_init(struct usbnet *un) UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_RST); for (int i = 0; i < UDAV_TX_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; if (!(udav_csr_read1(un, UDAV_NCR) & UDAV_NCR_RST)) break; delay(10); /* XXX */ @@ -586,10 +575,10 @@ udav_chip_init(struct usbnet *un) (ether_crc32_le((addr), ETHER_ADDR_LEN) & ((1 << UDAV_BITS) - 1)) static void -udav_setiff_locked(struct usbnet *un) +udav_uno_mcast(struct ifnet *ifp) { + struct usbnet * const un = ifp->if_softc; struct ethercom *ec = usbnet_ec(un); - struct ifnet * const ifp = usbnet_ifp(un); struct ether_multi *enm; struct ether_multistep step; uint8_t hashes[8]; @@ -609,11 +598,16 @@ udav_setiff_locked(struct usbnet *un) } if (ifp->if_flags & IFF_PROMISC) { + ETHER_LOCK(ec); + ec->ec_flags |= ETHER_F_ALLMULTI; + ETHER_UNLOCK(ec); UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); return; - } else if (ifp->if_flags & IFF_ALLMULTI) { + } else if (ifp->if_flags & IFF_ALLMULTI) { /* XXX ??? Can't happen? */ + ETHER_LOCK(ec); allmulti: - ifp->if_flags |= IFF_ALLMULTI; + ec->ec_flags |= ETHER_F_ALLMULTI; + ETHER_UNLOCK(ec); UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); return; @@ -630,7 +624,6 @@ allmulti: while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { - ETHER_UNLOCK(ec); goto allmulti; } @@ -638,10 +631,10 @@ allmulti: hashes[h>>3] |= 1 << (h & 0x7); ETHER_NEXT_MULTI(step, enm); } + ec->ec_flags &= ~ETHER_F_ALLMULTI; ETHER_UNLOCK(ec); /* disable all multicast */ - ifp->if_flags &= ~IFF_ALLMULTI; UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL); /* write hash value to the register */ @@ -721,29 +714,6 @@ udav_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) usbnet_enqueue(un, buf, pkt_len, 0, 0, 0); } -static int -udav_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - udav_setiff_locked(un); - break; - default: - break; - } - - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return 0; -} - /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ static void udav_uno_stop(struct ifnet *ifp, int disable) diff --git a/sys/dev/usb/if_upl.c b/sys/dev/usb/if_upl.c index fb99702f160e..cf4ba9de209f 100644 --- a/sys/dev/usb/if_upl.c +++ b/sys/dev/usb/if_upl.c @@ -257,12 +257,10 @@ upl_uno_init(struct ifnet *ifp) struct usbnet * const un = ifp->if_softc; int rv; - usbnet_lock_core(un); if (usbnet_isdying(un)) rv = EIO; else rv = usbnet_init_rx_tx(un); - usbnet_unlock_core(un); return rv; } diff --git a/sys/dev/usb/if_ure.c b/sys/dev/usb/if_ure.c index ea5b3023dd31..8d6da56a603a 100644 --- a/sys/dev/usb/if_ure.c +++ b/sys/dev/usb/if_ure.c @@ -86,7 +86,7 @@ static void ure_disable_teredo(struct usbnet *); static void ure_init_fifo(struct usbnet *); static void ure_uno_stop(struct ifnet *, int); -static int ure_uno_ioctl(struct ifnet *, u_long, void *); +static void ure_uno_mcast(struct ifnet *); static int ure_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); static int ure_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); static void ure_uno_miibus_statchg(struct ifnet *); @@ -104,7 +104,7 @@ CFATTACH_DECL_NEW(ure, sizeof(struct usbnet), ure_match, ure_attach, static const struct usbnet_ops ure_ops = { .uno_stop = ure_uno_stop, - .uno_ioctl = ure_uno_ioctl, + .uno_mcast = ure_uno_mcast, .uno_read_reg = ure_uno_mii_read_reg, .uno_write_reg = ure_uno_mii_write_reg, .uno_statchg = ure_uno_miibus_statchg, @@ -331,10 +331,10 @@ ure_uno_miibus_statchg(struct ifnet *ifp) } static void -ure_rcvfilt_locked(struct usbnet *un) +ure_uno_mcast(struct ifnet *ifp) { + struct usbnet *un = ifp->if_softc; struct ethercom *ec = usbnet_ec(un); - struct ifnet *ifp = usbnet_ifp(un); struct ether_multi *enm; struct ether_multistep step; uint32_t mchash[2] = { 0, 0 }; @@ -396,6 +396,8 @@ ure_reset(struct usbnet *un) ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST); for (i = 0; i < URE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; if (!(ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) & URE_CR_RST)) break; @@ -406,7 +408,7 @@ ure_reset(struct usbnet *un) } static int -ure_init_locked(struct ifnet *ifp) +ure_uno_init(struct ifnet *ifp) { struct usbnet * const un = ifp->if_softc; uint8_t eaddr[8]; @@ -446,25 +448,11 @@ ure_init_locked(struct ifnet *ifp) ~URE_RXDY_GATED_EN); /* Accept multicast frame or run promisc. mode. */ - ure_rcvfilt_locked(un); + ure_uno_mcast(ifp); return usbnet_init_rx_tx(un); } -static int -ure_uno_init(struct ifnet *ifp) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - int ret = ure_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return ret; -} - static void ure_uno_stop(struct ifnet *ifp, int disable __unused) { @@ -543,6 +531,8 @@ ure_rtl8153_init(struct usbnet *un) URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); for (i = 0; i < URE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; if (ure_read_2(un, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) & URE_AUTOLOAD_DONE) break; @@ -552,6 +542,8 @@ ure_rtl8153_init(struct usbnet *un) URE_PRINTF(un, "timeout waiting for chip autoload\n"); for (i = 0; i < URE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; val = ure_ocp_reg_read(un, URE_OCP_PHY_STATUS) & URE_PHY_STAT_MASK; if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN) @@ -750,6 +742,8 @@ ure_init_fifo(struct usbnet *un) ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) & ~URE_MCU_BORW_EN); for (i = 0; i < URE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & URE_LINK_LIST_READY) break; @@ -761,6 +755,8 @@ ure_init_fifo(struct usbnet *un) ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) | URE_RE_INIT_LL); for (i = 0; i < URE_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & URE_LINK_LIST_READY) break; @@ -794,29 +790,6 @@ ure_init_fifo(struct usbnet *un) URE_TXFIFO_THR_NORMAL); } -static int -ure_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - ure_rcvfilt_locked(un); - break; - default: - break; - } - - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return 0; -} - static int ure_match(device_t parent, cfdata_t match, void *aux) { diff --git a/sys/dev/usb/if_url.c b/sys/dev/usb/if_url.c index 764b9c654682..9dbf854db9cb 100644 --- a/sys/dev/usb/if_url.c +++ b/sys/dev/usb/if_url.c @@ -77,11 +77,10 @@ static unsigned url_uno_tx_prepare(struct usbnet *, struct mbuf *, static void url_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); static int url_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); static int url_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); -static int url_uno_ioctl(struct ifnet *, u_long, void *); static void url_uno_stop(struct ifnet *, int); static void url_uno_mii_statchg(struct ifnet *); static int url_uno_init(struct ifnet *); -static void url_rcvfilt_locked(struct usbnet *); +static void url_uno_mcast(struct ifnet *); static void url_reset(struct usbnet *); static int url_csr_read_1(struct usbnet *, int); @@ -93,7 +92,7 @@ static int url_mem(struct usbnet *, int, int, void *, int); static const struct usbnet_ops url_ops = { .uno_stop = url_uno_stop, - .uno_ioctl = url_uno_ioctl, + .uno_mcast = url_uno_mcast, .uno_read_reg = url_uno_mii_read_reg, .uno_write_reg = url_uno_mii_write_reg, .uno_statchg = url_uno_mii_statchg, @@ -244,7 +243,6 @@ url_attach(device_t parent, device_t self, void *aux) usbnet_attach(un, "urldet"); usbnet_lock_core(un); - usbnet_busy(un); /* reset the adapter */ url_reset(un); @@ -252,22 +250,15 @@ url_attach(device_t parent, device_t self, void *aux) /* Get Ethernet Address */ err = url_mem(un, URL_CMD_READMEM, URL_IDR0, (void *)un->un_eaddr, ETHER_ADDR_LEN); - usbnet_unbusy(un); usbnet_unlock_core(un); if (err) { aprint_error_dev(self, "read MAC address failed\n"); - goto bad; + return; } /* initialize interface information */ usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, 0, &unm); - - return; - - bad: - usbnet_set_dying(un, true); - return; } /* read/write memory */ @@ -401,7 +392,7 @@ url_init_locked(struct ifnet *ifp) URL_SETBIT2(un, URL_RCR, URL_RCR_TAIL | URL_RCR_AD | URL_RCR_AB); /* Accept multicast frame or run promisc. mode */ - url_rcvfilt_locked(un); + url_uno_mcast(ifp); /* Enable RX and TX */ URL_SETBIT(un, URL_CR, URL_CR_TE | URL_CR_RE); @@ -412,13 +403,7 @@ url_init_locked(struct ifnet *ifp) static int url_uno_init(struct ifnet *ifp) { - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); int ret = url_init_locked(ifp); - usbnet_unbusy(un); - usbnet_unlock_core(un); return ret; } @@ -436,6 +421,8 @@ url_reset(struct usbnet *un) URL_SETBIT(un, URL_CR, URL_CR_SOFT_RST); for (i = 0; i < URL_TX_TIMEOUT; i++) { + if (usbnet_isdying(un)) + return; if (!(url_csr_read_1(un, URL_CR) & URL_CR_SOFT_RST)) break; delay(10); /* XXX */ @@ -445,9 +432,9 @@ url_reset(struct usbnet *un) } static void -url_rcvfilt_locked(struct usbnet *un) +url_uno_mcast(struct ifnet *ifp) { - struct ifnet * const ifp = usbnet_ifp(un); + struct usbnet * const un = ifp->if_softc; struct ethercom *ec = usbnet_ec(un); struct ether_multi *enm; struct ether_multistep step; @@ -565,29 +552,6 @@ static void url_intr(void) } #endif -static int -url_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) -{ - struct usbnet * const un = ifp->if_softc; - - usbnet_lock_core(un); - usbnet_busy(un); - - switch (cmd) { - case SIOCADDMULTI: - case SIOCDELMULTI: - url_rcvfilt_locked(un); - break; - default: - break; - } - - usbnet_unbusy(un); - usbnet_unlock_core(un); - - return 0; -} - /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ static void url_uno_stop(struct ifnet *ifp, int disable) diff --git a/sys/dev/usb/if_urndis.c b/sys/dev/usb/if_urndis.c index 381207450d72..ff4da0414739 100644 --- a/sys/dev/usb/if_urndis.c +++ b/sys/dev/usb/if_urndis.c @@ -883,8 +883,15 @@ static int urndis_uno_init(struct ifnet *ifp) { struct usbnet *un = ifp->if_softc; + int error; - return urndis_init_un(ifp, un); + KASSERT(IFNET_LOCKED(ifp)); + + usbnet_unlock_core(un); + error = urndis_init_un(ifp, un); + usbnet_lock_core(un); + + return error; } static int diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c index 1712d2f687f0..31562ec087a7 100644 --- a/sys/dev/usb/usbnet.c +++ b/sys/dev/usb/usbnet.c @@ -56,7 +56,6 @@ struct usbnet_private { * and the MII / media data. * - unp_rxlock protects the rx path and its data * - unp_txlock protects the tx path and its data - * - unp_detachcv handles detach vs open references * * the lock ordering is: * ifnet lock -> unp_core_lock -> unp_rxlock -> unp_txlock @@ -66,22 +65,22 @@ struct usbnet_private { kmutex_t unp_core_lock; kmutex_t unp_rxlock; kmutex_t unp_txlock; - kcondvar_t unp_detachcv; struct usbnet_cdata unp_cdata; struct ethercom unp_ec; struct mii_data unp_mii; + struct usb_task unp_mcasttask; struct usb_task unp_ticktask; struct callout unp_stat_ch; struct usbd_pipe *unp_ep[USBNET_ENDPT_MAX]; - bool unp_dying; + volatile bool unp_dying; bool unp_stopping; bool unp_attached; + bool unp_ifp_attached; bool unp_link; - int unp_refcnt; int unp_timer; unsigned short unp_if_flags; unsigned unp_number; @@ -97,6 +96,9 @@ struct usbnet_private { volatile unsigned usbnet_number; +static void usbnet_isowned_rx(struct usbnet *); +static void usbnet_isowned_tx(struct usbnet *); + static int usbnet_modcmd(modcmd_t, void *); #ifdef USB_DEBUG @@ -149,6 +151,8 @@ fail: static void uno_stop(struct usbnet *un, struct ifnet *ifp, int disable) { + KASSERTMSG(!un->un_pri->unp_ifp_attached || IFNET_LOCKED(ifp), + "%s", ifp->if_xname); usbnet_isowned_core(un); if (un->un_ops->uno_stop) (*un->un_ops->uno_stop)(ifp, disable); @@ -157,11 +161,11 @@ uno_stop(struct usbnet *un, struct ifnet *ifp, int disable) static int uno_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data) { - /* - * There are cases where IFNET_LOCK will not be held when we - * are called (e.g. add/delete multicast address), so we can't - * assert it. - */ + + KASSERTMSG(cmd != SIOCADDMULTI, "%s", ifp->if_xname); + KASSERTMSG(cmd != SIOCDELMULTI, "%s", ifp->if_xname); + KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); + if (un->un_ops->uno_ioctl) return (*un->un_ops->uno_ioctl)(ifp, cmd, data); return 0; @@ -170,14 +174,22 @@ uno_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data) static int uno_override_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data) { - /* See above. */ + + switch (cmd) { + case SIOCADDMULTI: + case SIOCDELMULTI: + break; + default: + KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); + } + return (*un->un_ops->uno_override_ioctl)(ifp, cmd, data); } static int uno_init(struct usbnet *un, struct ifnet *ifp) { - KASSERT(IFNET_LOCKED(ifp)); + KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); return (*un->un_ops->uno_init)(ifp); } @@ -333,7 +345,6 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) struct usbnet_chain * const c = priv; struct usbnet * const un = c->unc_un; struct usbnet_private * const unp = un->un_pri; - struct ifnet * const ifp = usbnet_ifp(un); uint32_t total_len; USBNETHIST_CALLARGSN(5, "%jd: enter: status %#jx xfer %#jx", @@ -341,9 +352,9 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) mutex_enter(&unp->unp_rxlock); - if (unp->unp_dying || unp->unp_stopping || + if (usbnet_isdying(un) || unp->unp_stopping || status == USBD_INVAL || status == USBD_NOT_STARTED || - status == USBD_CANCELLED || !(ifp->if_flags & IFF_RUNNING)) + status == USBD_CANCELLED) goto out; if (status != USBD_NORMAL_COMPLETION) { @@ -368,7 +379,7 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) usbnet_isowned_rx(un); done: - if (unp->unp_dying || unp->unp_stopping) + if (usbnet_isdying(un) || unp->unp_stopping) goto out; mutex_exit(&unp->unp_rxlock); @@ -397,7 +408,7 @@ usbnet_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) unp->unp_number, status, (uintptr_t)xfer, 0); mutex_enter(&unp->unp_txlock); - if (unp->unp_stopping || unp->unp_dying) { + if (unp->unp_stopping || usbnet_isdying(un)) { mutex_exit(&unp->unp_txlock); return; } @@ -440,14 +451,13 @@ usbnet_pipe_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) struct usbnet * const un = priv; struct usbnet_private * const unp = un->un_pri; struct usbnet_intr * const uni = un->un_intr; - struct ifnet * const ifp = usbnet_ifp(un); - if (uni == NULL || unp->unp_dying || unp->unp_stopping || + if (uni == NULL || usbnet_isdying(un) || unp->unp_stopping || status == USBD_INVAL || status == USBD_NOT_STARTED || - status == USBD_CANCELLED || !(ifp->if_flags & IFF_RUNNING)) { + status == USBD_CANCELLED) { USBNETHIST_CALLARGS("%jd: uni %#jx d/s %#jx status %#jx", unp->unp_number, (uintptr_t)uni, - (unp->unp_dying << 8) | unp->unp_stopping, status); + (usbnet_isdying(un) << 8) | unp->unp_stopping, status); return; } @@ -818,14 +828,15 @@ usbnet_init_rx_tx(struct usbnet * const un) usbd_status err; int error = 0; + KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), + "%s", ifp->if_xname); + usbnet_isowned_core(un); - if (unp->unp_dying) { + if (usbnet_isdying(un)) { return EIO; } - usbnet_busy(un); - /* Open RX and TX pipes. */ err = usbnet_ep_open_pipes(un); if (err) { @@ -849,16 +860,15 @@ usbnet_init_rx_tx(struct usbnet * const un) goto out; } - /* Start up the receive pipe(s). */ - usbnet_rx_start_pipes(un); - /* Indicate we are up and running. */ -#if 0 - /* XXX if_mcast_op() can call this without ifnet locked */ - KASSERT(ifp->if_softc == NULL || IFNET_LOCKED(ifp)); -#endif + /* XXX urndis calls usbnet_init_rx_tx before usbnet_attach_ifp. */ + KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), + "%s", ifp->if_xname); ifp->if_flags |= IFF_RUNNING; + /* Start up the receive pipe(s). */ + usbnet_rx_start_pipes(un); + callout_schedule(&unp->unp_stat_ch, hz); out: @@ -867,34 +877,12 @@ out: usbnet_tx_list_fini(un); usbnet_ep_close_pipes(un); } - usbnet_unbusy(un); usbnet_isowned_core(un); return error; } -void -usbnet_busy(struct usbnet *un) -{ - struct usbnet_private * const unp = un->un_pri; - - usbnet_isowned_core(un); - - unp->unp_refcnt++; -} - -void -usbnet_unbusy(struct usbnet *un) -{ - struct usbnet_private * const unp = un->un_pri; - - usbnet_isowned_core(un); - - if (--unp->unp_refcnt < 0) - cv_broadcast(&unp->unp_detachcv); -} - /* MII management. */ int @@ -902,23 +890,19 @@ usbnet_mii_readreg(device_t dev, int phy, int reg, uint16_t *val) { USBNETHIST_FUNC(); struct usbnet * const un = device_private(dev); - struct usbnet_private * const unp = un->un_pri; int err; /* MII layer ensures core_lock is held. */ usbnet_isowned_core(un); - if (unp->unp_dying) { + if (usbnet_isdying(un)) { return EIO; } - usbnet_busy(un); err = uno_read_reg(un, phy, reg, val); - usbnet_unbusy(un); - if (err) { USBNETHIST_CALLARGS("%jd: read PHY failed: %jd", - unp->unp_number, err, 0, 0); + un->un_pri->unp_number, err, 0, 0); return err; } @@ -930,23 +914,19 @@ usbnet_mii_writereg(device_t dev, int phy, int reg, uint16_t val) { USBNETHIST_FUNC(); struct usbnet * const un = device_private(dev); - struct usbnet_private * const unp = un->un_pri; int err; /* MII layer ensures core_lock is held. */ usbnet_isowned_core(un); - if (unp->unp_dying) { + if (usbnet_isdying(un)) { return EIO; } - usbnet_busy(un); err = uno_write_reg(un, phy, reg, val); - usbnet_unbusy(un); - if (err) { USBNETHIST_CALLARGS("%jd: write PHY failed: %jd", - unp->unp_number, err, 0, 0); + un->un_pri->unp_number, err, 0, 0); return err; } @@ -962,9 +942,7 @@ usbnet_mii_statchg(struct ifnet *ifp) /* MII layer ensures core_lock is held. */ usbnet_isowned_core(un); - usbnet_busy(un); uno_mii_statchg(un, ifp); - usbnet_unbusy(un); } static int @@ -978,7 +956,10 @@ usbnet_media_upd(struct ifnet *ifp) /* ifmedia layer ensures core_lock is held. */ usbnet_isowned_core(un); - if (unp->unp_dying) + /* ifmedia changes only with IFNET_LOCK held. */ + KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); + + if (usbnet_isdying(un)) return EIO; unp->unp_link = false; @@ -1004,7 +985,7 @@ usbnet_ifflags_cb(struct ethercom *ec) struct usbnet_private * const unp = un->un_pri; int rv = 0; - mutex_enter(&unp->unp_core_lock); + KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); const u_short changed = ifp->if_flags ^ unp->unp_if_flags; if ((changed & ~(IFF_CANTCHANGE | IFF_DEBUG)) == 0) { @@ -1015,8 +996,6 @@ usbnet_ifflags_cb(struct ethercom *ec) rv = ENETRESET; } - mutex_exit(&unp->unp_core_lock); - return rv; } @@ -1035,12 +1014,61 @@ usbnet_if_ioctl(struct ifnet *ifp, u_long cmd, void *data) return uno_override_ioctl(un, ifp, cmd, data); error = ether_ioctl(ifp, cmd, data); - if (error == ENETRESET) - error = uno_ioctl(un, ifp, cmd, data); + if (error == ENETRESET) { + switch (cmd) { + case SIOCADDMULTI: + case SIOCDELMULTI: + usb_add_task(un->un_udev, &unp->unp_mcasttask, + USB_TASKQ_DRIVER); + error = 0; + break; + default: + error = uno_ioctl(un, ifp, cmd, data); + } + } return error; } +static void +usbnet_mcast_task(void *arg) +{ + USBNETHIST_FUNC(); + struct usbnet * const un = arg; + struct ifnet * const ifp = usbnet_ifp(un); + + USBNETHIST_CALLARGSN(10, "%jd: enter", + un->un_pri->unp_number, 0, 0, 0); + + /* + * If we're detaching, we must check usbnet_isdying _before_ + * touching IFNET_LOCK -- the ifnet may have been detached by + * the time this task runs. This is racy -- unp_dying may be + * set immediately after we test it -- but nevertheless safe, + * because usbnet_detach waits for the task to complete before + * issuing if_detach, and necessary, so that we don't touch + * IFNET_LOCK after if_detach. See usbnet_detach for details. + */ + if (usbnet_isdying(un)) + return; + + /* + * If the hardware is running, ask the driver to reprogram the + * multicast filter. If the hardware is not running, the + * driver is responsible for programming the multicast filter + * as part of its uno_init routine to bring the hardware up. + */ + IFNET_LOCK(ifp); + if (ifp->if_flags & IFF_RUNNING) { + if (un->un_ops->uno_mcast) { + mutex_enter(&un->un_pri->unp_core_lock); + (*un->un_ops->uno_mcast)(ifp); + mutex_exit(&un->un_pri->unp_core_lock); + } + } + IFNET_UNLOCK(ifp); +} + /* * Generic stop network function: * - mark as stopping @@ -1061,32 +1089,44 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable) USBNETHIST_FUNC(); USBNETHIST_CALLED(); + KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), + "%s", ifp->if_xname); usbnet_isowned_core(un); - usbnet_busy(un); - + /* + * Prevent new activity (rescheduling ticks, xfers, &c.) and + * clear the watchdog timer. + */ mutex_enter(&unp->unp_rxlock); mutex_enter(&unp->unp_txlock); unp->unp_stopping = true; + unp->unp_timer = 0; mutex_exit(&unp->unp_txlock); mutex_exit(&unp->unp_rxlock); - uno_stop(un, ifp, disable); - /* - * XXXSMP Would like to - * KASSERT(IFNET_LOCKED(ifp)) - * here but the locking order is: - * ifnet -> core_lock -> rxlock -> txlock - * and core_lock is already held. + * Stop the timer first, then the task -- if the timer was + * already firing, we stop the task or wait for it complete + * only after if last fired. Setting unp_stopping prevents the + * timer task from being scheduled again. */ - ifp->if_flags &= ~IFF_RUNNING; - unp->unp_timer = 0; - callout_halt(&unp->unp_stat_ch, &unp->unp_core_lock); usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER, &unp->unp_core_lock); + /* + * Now that the software is quiescent, ask the driver to stop + * the hardware. The driver's uno_stop routine now has + * exclusive access to any registers that might previously have + * been used by to ifmedia, mii, or ioctl callbacks. + * + * Don't bother if the device is being detached, though -- if + * it's been unplugged then there's no point in trying to touch + * the registers. + */ + if (!usbnet_isdying(un)) + uno_stop(un, ifp, disable); + /* Stop transfers. */ usbnet_ep_stop_pipes(un); @@ -1097,7 +1137,10 @@ usbnet_stop(struct usbnet *un, struct ifnet *ifp, int disable) /* Close pipes. */ usbnet_ep_close_pipes(un); - usbnet_unbusy(un); + /* Everything is quesced now. */ + KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), + "%s", ifp->if_xname); + ifp->if_flags &= ~IFF_RUNNING; } static void @@ -1106,6 +1149,8 @@ usbnet_if_stop(struct ifnet *ifp, int disable) struct usbnet * const un = ifp->if_softc; struct usbnet_private * const unp = un->un_pri; + KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); + mutex_enter(&unp->unp_core_lock); usbnet_stop(un, ifp, disable); mutex_exit(&unp->unp_core_lock); @@ -1126,10 +1171,8 @@ usbnet_tick(void *arg) USBNETHIST_CALLARGSN(10, "%jd: enter", unp->unp_number, 0, 0, 0); - if (unp != NULL && !unp->unp_stopping && !unp->unp_dying) { - /* Perform periodic stuff in process context */ - usb_add_task(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER); - } + /* Perform periodic stuff in process context */ + usb_add_task(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER); } static void @@ -1164,27 +1207,15 @@ usbnet_tick_task(void *arg) USBNETHIST_FUNC(); struct usbnet * const un = arg; struct usbnet_private * const unp = un->un_pri; - - if (unp == NULL) - return; - - USBNETHIST_CALLARGSN(8, "%jd: enter", unp->unp_number, 0, 0, 0); - - mutex_enter(&unp->unp_core_lock); - if (unp->unp_stopping || unp->unp_dying) { - mutex_exit(&unp->unp_core_lock); - return; - } - struct ifnet * const ifp = usbnet_ifp(un); struct mii_data * const mii = usbnet_mii(un); - KASSERT(ifp != NULL); /* embedded member */ - - usbnet_busy(un); - mutex_exit(&unp->unp_core_lock); + USBNETHIST_CALLARGSN(8, "%jd: enter", unp->unp_number, 0, 0, 0); - if (unp->unp_timer != 0 && --unp->unp_timer == 0) + mutex_enter(&unp->unp_txlock); + const bool timeout = unp->unp_timer != 0 && --unp->unp_timer == 0; + mutex_exit(&unp->unp_txlock); + if (timeout) usbnet_watchdog(ifp); DPRINTFN(8, "mii %#jx ifp %#jx", (uintptr_t)mii, (uintptr_t)ifp, 0, 0); @@ -1200,8 +1231,7 @@ usbnet_tick_task(void *arg) uno_tick(un); mutex_enter(&unp->unp_core_lock); - usbnet_unbusy(un); - if (!unp->unp_stopping && !unp->unp_dying) + if (!unp->unp_stopping && !usbnet_isdying(un)) callout_schedule(&unp->unp_stat_ch, hz); mutex_exit(&unp->unp_core_lock); } @@ -1211,8 +1241,22 @@ usbnet_if_init(struct ifnet *ifp) { USBNETHIST_FUNC(); USBNETHIST_CALLED(); struct usbnet * const un = ifp->if_softc; + int error; + + KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); + + /* + * Prevent anyone from bringing the interface back up once + * we're detaching. + */ + if (usbnet_isdying(un)) + return EIO; + + mutex_enter(&un->un_pri->unp_core_lock); + error = uno_init(un, ifp); + mutex_exit(&un->un_pri->unp_core_lock); - return uno_init(un, ifp); + return error; } @@ -1224,12 +1268,6 @@ usbnet_set_link(struct usbnet *un, bool link) un->un_pri->unp_link = link; } -void -usbnet_set_dying(struct usbnet *un, bool link) -{ - un->un_pri->unp_dying = link; -} - struct ifnet * usbnet_ifp(struct usbnet *un) { @@ -1269,7 +1307,7 @@ usbnet_havelink(struct usbnet *un) bool usbnet_isdying(struct usbnet *un) { - return un->un_pri == NULL || un->un_pri->unp_dying; + return atomic_load_relaxed(&un->un_pri->unp_dying); } @@ -1287,46 +1325,22 @@ usbnet_unlock_core(struct usbnet *un) mutex_exit(&un->un_pri->unp_core_lock); } -kmutex_t * +kmutex_t* usbnet_mutex_core(struct usbnet *un) { return &un->un_pri->unp_core_lock; } -void -usbnet_lock_rx(struct usbnet *un) -{ - mutex_enter(&un->un_pri->unp_rxlock); -} - -void -usbnet_unlock_rx(struct usbnet *un) -{ - mutex_exit(&un->un_pri->unp_rxlock); -} - -kmutex_t * -usbnet_mutex_rx(struct usbnet *un) -{ - return &un->un_pri->unp_rxlock; -} - -void -usbnet_lock_tx(struct usbnet *un) -{ - mutex_enter(&un->un_pri->unp_txlock); -} - -void -usbnet_unlock_tx(struct usbnet *un) +static void +usbnet_isowned_rx(struct usbnet *un) { - mutex_exit(&un->un_pri->unp_txlock); + KASSERT(mutex_owned(&un->un_pri->unp_rxlock)); } -kmutex_t * -usbnet_mutex_tx(struct usbnet *un) +static void +usbnet_isowned_tx(struct usbnet *un) { - return &un->un_pri->unp_txlock; + KASSERT(mutex_owned(&un->un_pri->unp_txlock)); } /* Autoconf management. */ @@ -1373,14 +1387,16 @@ usbnet_attach(struct usbnet *un, un->un_pri = kmem_zalloc(sizeof(*un->un_pri), KM_SLEEP); struct usbnet_private * const unp = un->un_pri; - usb_init_task(&unp->unp_ticktask, usbnet_tick_task, un, USB_TASKQ_MPSAFE); + usb_init_task(&unp->unp_mcasttask, usbnet_mcast_task, un, + USB_TASKQ_MPSAFE); + usb_init_task(&unp->unp_ticktask, usbnet_tick_task, un, + USB_TASKQ_MPSAFE); callout_init(&unp->unp_stat_ch, CALLOUT_MPSAFE); callout_setfunc(&unp->unp_stat_ch, usbnet_tick, un); mutex_init(&unp->unp_txlock, MUTEX_DEFAULT, IPL_SOFTUSB); mutex_init(&unp->unp_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB); mutex_init(&unp->unp_core_lock, MUTEX_DEFAULT, IPL_NONE); - cv_init(&unp->unp_detachcv, detname); rnd_attach_source(&unp->unp_rndsrc, device_xname(un->un_dev), RND_TYPE_NET, RND_FLAG_DEFAULT); @@ -1435,7 +1451,9 @@ usbnet_attach_ifp(struct usbnet *un, struct ifnet * const ifp = usbnet_ifp(un); KASSERT(unp->unp_attached); + KASSERT(!unp->unp_ifp_attached); + ifp->if_softc = un; strlcpy(ifp->if_xname, device_xname(un->un_dev), IFNAMSIZ); ifp->if_flags = if_flags; ifp->if_extflags = IFEF_MPSAFE | if_extflags; @@ -1454,6 +1472,7 @@ usbnet_attach_ifp(struct usbnet *un, if (ifp->_if_input == NULL) ifp->if_percpuq = if_percpuq_create(ifp); if_register(ifp); + unp->unp_ifp_attached = true; /* * If ethernet address is all zero, skip ether_ifattach() and @@ -1471,7 +1490,6 @@ usbnet_attach_ifp(struct usbnet *un, /* Now ready, and attached. */ IFQ_SET_READY(&ifp->if_snd); - ifp->if_softc = un; usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, un->un_udev, un->un_dev); @@ -1493,39 +1511,42 @@ usbnet_detach(device_t self, int flags) struct ifnet * const ifp = usbnet_ifp(un); struct mii_data * const mii = usbnet_mii(un); - mutex_enter(&unp->unp_core_lock); - unp->unp_dying = true; - mutex_exit(&unp->unp_core_lock); + /* + * Prevent new activity. After we stop the interface, it + * cannot be brought back up. + */ + atomic_store_relaxed(&unp->unp_dying, true); - if (ifp->if_flags & IFF_RUNNING) { + /* + * If we're still running on the network, stop and wait for all + * asynchronous activity to finish. + * + * If usbnet_attach_ifp never ran, IFNET_LOCK won't work, but + * no activity is possible, so just skip this part. + */ + if (unp->unp_ifp_attached) { IFNET_LOCK(ifp); - usbnet_if_stop(ifp, 1); + if (ifp->if_flags & IFF_RUNNING) { + usbnet_if_stop(ifp, 1); + } IFNET_UNLOCK(ifp); } - callout_halt(&unp->unp_stat_ch, NULL); - usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER, - NULL); - - mutex_enter(&unp->unp_core_lock); - unp->unp_refcnt--; - while (unp->unp_refcnt >= 0) { - /* Wait for processes to go away */ - cv_wait(&unp->unp_detachcv, &unp->unp_core_lock); - } - mutex_exit(&unp->unp_core_lock); - - usbnet_rx_list_free(un); - usbnet_tx_list_free(un); + /* + * The callout and tick task can't be scheduled anew at this + * point, and usbnet_if_stop has waited for them to complete. + */ + KASSERT(!callout_pending(&unp->unp_stat_ch)); + KASSERT(!usb_task_pending(un->un_udev, &unp->unp_ticktask)); - callout_destroy(&unp->unp_stat_ch); - rnd_detach_source(&unp->unp_rndsrc); + usb_rem_task_wait(un->un_udev, &unp->unp_mcasttask, USB_TASKQ_DRIVER, + NULL); if (mii) { mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY); ifmedia_fini(&mii->mii_media); } - if (ifp->if_softc) { + if (unp->unp_ifp_attached) { if (!usbnet_empty_eaddr(un)) ether_ifdetach(ifp); else @@ -1534,14 +1555,61 @@ usbnet_detach(device_t self, int flags) } usbnet_ec(un)->ec_mii = NULL; - cv_destroy(&unp->unp_detachcv); + /* + * We have already waited for the multicast task to complete. + * Unfortunately, until if_detach, nothing has prevented it + * from running again -- another thread might issue if_mcast_op + * between the time of our first usb_rem_task_wait and the time + * we actually get around to if_detach. + * + * Fortunately, the first usb_rem_task_wait ensures that if the + * task is scheduled again, it will witness our setting of + * unp_dying to true[*]. So after that point, if the task is + * scheduled again, it will decline to touch IFNET_LOCK and do + * nothing. But we still need to wait for it to complete. + * + * It would be nice if we could write + * + * if_pleasestopissuingmcastopsthanks(ifp); + * usb_rem_task_wait(..., &unp->unp_mcasttask, ...); + * if_detach(ifp); + * + * and then we would need only one usb_rem_task_wait. + * + * Unfortunately, there is no such operation available in + * sys/net at the moment, and it would require a bit of + * coordination with if_mcast_op and doifioctl probably under a + * new lock. So we'll use this kludge until that mechanism is + * invented. + * + * [*] This is not exactly a documented property of the API, + * but it is implied by the single lock in the task queue + * serializing changes to the task state. + */ + usb_rem_task_wait(un->un_udev, &unp->unp_mcasttask, USB_TASKQ_DRIVER, + NULL); + + usbnet_rx_list_free(un); + usbnet_tx_list_free(un); + + rnd_detach_source(&unp->unp_rndsrc); + mutex_destroy(&unp->unp_core_lock); mutex_destroy(&unp->unp_rxlock); mutex_destroy(&unp->unp_txlock); + callout_destroy(&unp->unp_stat_ch); + pmf_device_deregister(un->un_dev); - usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, un->un_udev, un->un_dev); + /* + * Notify userland that we're going away, if we arrived in the + * first place. + */ + if (unp->unp_ifp_attached) { + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, un->un_udev, + un->un_dev); + } kmem_free(unp, sizeof(*unp)); un->un_pri = NULL; @@ -1561,9 +1629,7 @@ usbnet_activate(device_t self, devact_t act) case DVACT_DEACTIVATE: if_deactivate(ifp); - mutex_enter(&unp->unp_core_lock); - unp->unp_dying = true; - mutex_exit(&unp->unp_core_lock); + atomic_store_relaxed(&unp->unp_dying, true); mutex_enter(&unp->unp_rxlock); mutex_enter(&unp->unp_txlock); diff --git a/sys/dev/usb/usbnet.h b/sys/dev/usb/usbnet.h index 15e9dfc7b351..9ce537d7b849 100644 --- a/sys/dev/usb/usbnet.h +++ b/sys/dev/usb/usbnet.h @@ -131,6 +131,8 @@ enum usbnet_ep { typedef void (*usbnet_stop_cb)(struct ifnet *, int); /* Interface ioctl callback. */ typedef int (*usbnet_ioctl_cb)(struct ifnet *, u_long, void *); +/* Reprogram multicast filters callback. */ +typedef void (*usbnet_mcast_cb)(struct ifnet *); /* Initialise device callback. */ typedef int (*usbnet_init_cb)(struct ifnet *); @@ -170,16 +172,17 @@ typedef void (*usbnet_intr_cb)(struct usbnet *, usbd_status); * Note that when CORE_LOCK is held, IFNET_LOCK may or may not also * be held. * - * Note that the IFNET_LOCK **may not be held** for some ioctl - * operations (add/delete multicast addresses, for example). - * - * Busy reference counts are maintained across calls to: uno_stop, - * uno_read_reg, uno_write_reg, uno_statchg, and uno_tick. + * Note that the IFNET_LOCK **may not be held** for some the ioctl + * commands SIOCADDMULTI/SIOCDELMULTI. These commands are only passed + * explicitly to uno_override_ioctl; for all other devices, they are + * handled inside usbnet by scheduling a task to asynchronously call + * uno_mcast with IFNET_LOCK held. */ struct usbnet_ops { usbnet_stop_cb uno_stop; /* C */ - usbnet_ioctl_cb uno_ioctl; /* I (maybe) */ - usbnet_ioctl_cb uno_override_ioctl; /* I (maybe) */ + usbnet_ioctl_cb uno_ioctl; /* I */ + usbnet_ioctl_cb uno_override_ioctl; /* I (except mcast) */ + usbnet_mcast_cb uno_mcast; /* I */ usbnet_init_cb uno_init; /* I */ usbnet_mii_read_reg_cb uno_read_reg; /* C */ usbnet_mii_write_reg_cb uno_write_reg; /* C */ @@ -284,7 +287,6 @@ struct usbnet { /* Various accessors. */ void usbnet_set_link(struct usbnet *, bool); -void usbnet_set_dying(struct usbnet *, bool); struct ifnet *usbnet_ifp(struct usbnet *); struct ethercom *usbnet_ec(struct usbnet *); @@ -309,27 +311,6 @@ usbnet_isowned_core(struct usbnet *un) KASSERT(mutex_owned(usbnet_mutex_core(un))); } -void usbnet_busy(struct usbnet *); -void usbnet_unbusy(struct usbnet *); - -void usbnet_lock_rx(struct usbnet *); -void usbnet_unlock_rx(struct usbnet *); -kmutex_t *usbnet_mutex_rx(struct usbnet *); -static __inline__ void -usbnet_isowned_rx(struct usbnet *un) -{ - KASSERT(mutex_owned(usbnet_mutex_rx(un))); -} - -void usbnet_lock_tx(struct usbnet *); -void usbnet_unlock_tx(struct usbnet *); -kmutex_t *usbnet_mutex_tx(struct usbnet *); -static __inline__ void -usbnet_isowned_tx(struct usbnet *un) -{ - KASSERT(mutex_owned(usbnet_mutex_tx(un))); -} - /* * Endpoint / rx/tx chain management: *