Hi All, I recently committed a change to the xhci(4) driver that fixed an issue with suspending a machine while it has USB devices plugged in. Unfortunately this diff had some unintended side effects. After looking at the way the USB stack works, I've come to the conclusion that it is best to try and fix the drivers to self-protect against events coming in while the device is being detached. Some drivers already do this, some drivers only do this partially. The diff below makes sure that all of the USB WiFi drivers do this in a consistent way by checking that we're in the processes of detaching the devices at the following points:
1. The driver's ioctl function. 2. The driver's USB transfer completion callbacks. I may have missed some other points that need protection. So it would be great if users of USB WiFi devices could test this diff and try to suspend or hibernate their machine with the WiFi interface active. My plan is to only commit the xhci.c bit after checking the other USB drivers for potential problems. ok? Index: dev/usb/if_athn_usb.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_athn_usb.c,v retrieving revision 1.65 diff -u -p -r1.65 if_athn_usb.c --- dev/usb/if_athn_usb.c 10 Jul 2022 21:13:41 -0000 1.65 +++ dev/usb/if_athn_usb.c 24 Jul 2023 09:55:08 -0000 @@ -2131,6 +2131,9 @@ athn_usb_rxeof(struct usbd_xfer *xfer, v uint16_t pktlen; int off, len; + if (usbd_is_dying(usc->sc_udev)) + return; + if (__predict_false(status != USBD_NORMAL_COMPLETION)) { DPRINTF(("RX status=%d\n", status)); if (status == USBD_STALLED) @@ -2240,6 +2243,9 @@ athn_usb_txeof(struct usbd_xfer *xfer, v struct athn_softc *sc = &usc->sc_sc; struct ifnet *ifp = &sc->sc_ic.ic_if; int s; + + if (usbd_is_dying(usc->sc_udev)) + return; s = splnet(); /* Put this Tx buffer back to our free list. */ Index: dev/usb/if_atu.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_atu.c,v retrieving revision 1.134 diff -u -p -r1.134 if_atu.c --- dev/usb/if_atu.c 21 Apr 2022 21:03:03 -0000 1.134 +++ dev/usb/if_atu.c 24 Jul 2023 09:55:09 -0000 @@ -1774,6 +1774,9 @@ atu_txeof(struct usbd_xfer *xfer, void * c->atu_mbuf = NULL; } + if (usbd_is_dying(sc->atu_udev)) + return; + if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; @@ -2109,6 +2112,9 @@ atu_ioctl(struct ifnet *ifp, u_long comm { struct atu_softc *sc = ifp->if_softc; int err = 0, s; + + if (usbd_is_dying(sc->atu_udev)) + return ENXIO; s = splnet(); switch (command) { Index: dev/usb/if_mtw.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_mtw.c,v retrieving revision 1.8 diff -u -p -r1.8 if_mtw.c --- dev/usb/if_mtw.c 8 Mar 2023 04:43:08 -0000 1.8 +++ dev/usb/if_mtw.c 24 Jul 2023 09:55:09 -0000 @@ -2140,6 +2140,9 @@ mtw_rxeof(struct usbd_xfer *xfer, void * uint32_t dmalen; int xferlen; + if (usbd_is_dying(sc->sc_udev)) + return; + if (__predict_false(status != USBD_NORMAL_COMPLETION)) { DPRINTF(("RX status=%d\n", status)); if (status == USBD_STALLED) Index: dev/usb/if_otus.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_otus.c,v retrieving revision 1.72 diff -u -p -r1.72 if_otus.c --- dev/usb/if_otus.c 8 Mar 2023 04:43:08 -0000 1.72 +++ dev/usb/if_otus.c 24 Jul 2023 09:55:09 -0000 @@ -995,6 +995,9 @@ otus_cmd_rxeof(struct otus_softc *sc, ui struct ar_cmd_hdr *hdr; int s; + if (usbd_is_dying(sc->sc_udev)) + return; + if (__predict_false(len < sizeof (*hdr))) { DPRINTF(("cmd too small %d\n", len)); return; @@ -1256,6 +1259,9 @@ otus_txeof(struct usbd_xfer *xfer, void struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = &ic->ic_if; int s; + + if (usbd_is_dying(sc->sc_udev)) + return; s = splnet(); sc->tx_queued--; Index: dev/usb/if_ral.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_ral.c,v retrieving revision 1.149 diff -u -p -r1.149 if_ral.c --- dev/usb/if_ral.c 21 Apr 2022 21:03:03 -0000 1.149 +++ dev/usb/if_ral.c 24 Jul 2023 09:55:09 -0000 @@ -648,6 +648,9 @@ ural_txeof(struct usbd_xfer *xfer, void struct ifnet *ifp = &ic->ic_if; int s; + if (usbd_is_dying(sc->sc_udev)) + return; + if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; @@ -691,6 +694,9 @@ ural_rxeof(struct usbd_xfer *xfer, void struct ieee80211_node *ni; struct mbuf *mnew, *m; int s, len; + + if (usbd_is_dying(sc->sc_udev)) + return; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) Index: dev/usb/if_rsu.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_rsu.c,v retrieving revision 1.52 diff -u -p -r1.52 if_rsu.c --- dev/usb/if_rsu.c 8 Mar 2023 04:43:08 -0000 1.52 +++ dev/usb/if_rsu.c 24 Jul 2023 09:55:09 -0000 @@ -1440,6 +1440,9 @@ rsu_rxeof(struct usbd_xfer *xfer, void * struct ifnet *ifp = &sc->sc_ic.ic_if; int len; + if (usbd_is_dying(sc->sc_udev)) + return; + if (__predict_false(status != USBD_NORMAL_COMPLETION)) { DPRINTF(("RX status=%d\n", status)); if (status == USBD_STALLED) @@ -1482,6 +1485,9 @@ rsu_txeof(struct usbd_xfer *xfer, void * struct rsu_softc *sc = data->sc; struct ifnet *ifp = &sc->sc_ic.ic_if; int s; + + if (usbd_is_dying(sc->sc_udev)) + return; s = splnet(); /* Put this Tx buffer back to our free list. */ Index: dev/usb/if_rum.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_rum.c,v retrieving revision 1.127 diff -u -p -r1.127 if_rum.c --- dev/usb/if_rum.c 21 Apr 2022 21:03:03 -0000 1.127 +++ dev/usb/if_rum.c 24 Jul 2023 09:55:09 -0000 @@ -718,6 +718,9 @@ rum_txeof(struct usbd_xfer *xfer, void * struct ifnet *ifp = &ic->ic_if; int s; + if (usbd_is_dying(sc->sc_udev)) + return; + if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; @@ -761,6 +764,9 @@ rum_rxeof(struct usbd_xfer *xfer, void * struct ieee80211_node *ni; struct mbuf *mnew, *m; int s, len; + + if (usbd_is_dying(sc->sc_udev)) + return; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) Index: dev/usb/if_run.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_run.c,v retrieving revision 1.138 diff -u -p -r1.138 if_run.c --- dev/usb/if_run.c 8 Mar 2023 04:43:08 -0000 1.138 +++ dev/usb/if_run.c 24 Jul 2023 09:55:09 -0000 @@ -2327,6 +2327,9 @@ run_rxeof(struct usbd_xfer *xfer, void * int xferlen; uint16_t rxwisize; + if (usbd_is_dying(sc->sc_udev)) + return; + rxwisize = sizeof(struct rt2860_rxwi); if (sc->mac_ver == 0x5592) rxwisize += sizeof(uint64_t); @@ -2383,6 +2386,9 @@ run_txeof(struct usbd_xfer *xfer, void * struct run_tx_ring *txq = &sc->txq[data->qid]; struct ifnet *ifp = &sc->sc_ic.ic_if; int s; + + if (usbd_is_dying(sc->sc_udev)) + return; s = splnet(); txq->queued--; Index: dev/usb/if_uath.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_uath.c,v retrieving revision 1.88 diff -u -p -r1.88 if_uath.c --- dev/usb/if_uath.c 21 Apr 2022 21:03:03 -0000 1.88 +++ dev/usb/if_uath.c 24 Jul 2023 09:55:09 -0000 @@ -1092,6 +1092,9 @@ uath_cmd_rxeof(struct usbd_xfer *xfer, v struct uath_softc *sc = cmd->sc; struct uath_cmd_hdr *hdr; + if (usbd_is_dying(sc->sc_udev)) + return; + if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_STALLED) usbd_clear_endpoint_stall_async(sc->cmd_rx_pipe); @@ -1162,6 +1165,9 @@ uath_data_rxeof(struct usbd_xfer *xfer, uint32_t hdr; int s, len; + if (usbd_is_dying(sc->sc_udev)) + return; + if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; @@ -1313,6 +1319,9 @@ uath_data_txeof(struct usbd_xfer *xfer, struct ifnet *ifp = &ic->ic_if; int s; + if (usbd_is_dying(sc->sc_udev)) + return; + if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; @@ -1531,7 +1540,11 @@ uath_watchdog(struct ifnet *ifp) int uath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { + struct uath_softc *sc = ifp->if_softc; int s, error = 0; + + if (usbd_is_dying(sc->sc_udev)) + return ENXIO; s = splnet(); Index: dev/usb/if_upgt.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_upgt.c,v retrieving revision 1.89 diff -u -p -r1.89 if_upgt.c --- dev/usb/if_upgt.c 21 Apr 2022 21:03:03 -0000 1.89 +++ dev/usb/if_upgt.c 24 Jul 2023 09:55:09 -0000 @@ -1126,6 +1126,9 @@ upgt_ioctl(struct ifnet *ifp, u_long cmd int s, error = 0; uint8_t chan; + if (usbd_is_dying(sc->sc_udev)) + return (ENXIO); + s = splnet(); switch (cmd) { @@ -1624,6 +1627,9 @@ upgt_rx_cb(struct usbd_xfer *xfer, void uint16_t h2_type; DPRINTF(3, "%s: %s\n", sc->sc_dev.dv_xname, __func__); + + if (usbd_is_dying(sc->sc_udev)) + return; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) Index: dev/usb/if_urtw.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_urtw.c,v retrieving revision 1.72 diff -u -p -r1.72 if_urtw.c --- dev/usb/if_urtw.c 21 Apr 2022 21:03:03 -0000 1.72 +++ dev/usb/if_urtw.c 24 Jul 2023 09:55:09 -0000 @@ -2495,6 +2495,9 @@ urtw_txeof_low(struct usbd_xfer *xfer, v struct ifnet *ifp = &ic->ic_if; int s; + if (usbd_is_dying(sc->sc_udev)) + return; + if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; @@ -2533,6 +2536,9 @@ urtw_txeof_normal(struct usbd_xfer *xfer struct ifnet *ifp = &ic->ic_if; int s; + if (usbd_is_dying(sc->sc_udev)) + return; + if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; @@ -3045,6 +3051,9 @@ urtw_rxeof(struct usbd_xfer *xfer, void struct mbuf *m, *mnew; uint8_t *desc, quality, rate; int actlen, flen, len, nf, rssi, s; + + if (usbd_is_dying(sc->sc_udev)) + return; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) Index: dev/usb/if_urtwn.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_urtwn.c,v retrieving revision 1.108 diff -u -p -r1.108 if_urtwn.c --- dev/usb/if_urtwn.c 12 Jun 2023 11:27:30 -0000 1.108 +++ dev/usb/if_urtwn.c 24 Jul 2023 09:55:09 -0000 @@ -1315,6 +1315,9 @@ urtwn_rxeof(struct usbd_xfer *xfer, void uint8_t *buf; int len, totlen, pktlen, infosz, npkts, error, align; + if (usbd_is_dying(sc->sc_udev)) + return; + if (__predict_false(status != USBD_NORMAL_COMPLETION)) { DPRINTF(("RX status=%d\n", status)); if (status == USBD_STALLED) @@ -1428,6 +1431,9 @@ urtwn_txeof(struct usbd_xfer *xfer, void struct urtwn_softc *sc = data->sc; struct ifnet *ifp = &sc->sc_sc.sc_ic.ic_if; int s; + + if (usbd_is_dying(sc->sc_udev)) + return; s = splnet(); /* Put this Tx buffer back to our free list. */ Index: dev/usb/if_zyd.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_zyd.c,v retrieving revision 1.128 diff -u -p -r1.128 if_zyd.c --- dev/usb/if_zyd.c 21 Apr 2022 21:03:03 -0000 1.128 +++ dev/usb/if_zyd.c 24 Jul 2023 09:55:09 -0000 @@ -2000,6 +2000,9 @@ zyd_rxeof(struct usbd_xfer *xfer, void * const struct zyd_rx_desc *desc; int len; + if (usbd_is_dying(sc->sc_udev)) + return; + if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; @@ -2059,6 +2062,9 @@ zyd_txeof(struct usbd_xfer *xfer, void * struct ifnet *ifp = &ic->ic_if; int s; + if (usbd_is_dying(sc->sc_udev)) + return; + if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; @@ -2301,6 +2307,9 @@ zyd_ioctl(struct ifnet *ifp, u_long cmd, struct ieee80211com *ic = &sc->sc_ic; struct ifreq *ifr; int s, error = 0; + + if (usbd_is_dying(sc->sc_udev)) + return ENXIO; s = splnet(); Index: dev/usb/xhci.c =================================================================== RCS file: /cvs/src/sys/dev/usb/xhci.c,v retrieving revision 1.130 diff -u -p -r1.130 xhci.c --- dev/usb/xhci.c 20 Jul 2023 09:43:00 -0000 1.130 +++ dev/usb/xhci.c 24 Jul 2023 09:55:09 -0000 @@ -656,7 +656,7 @@ xhci_softintr(void *v) { struct xhci_softc *sc = v; - if (sc->sc_bus.dying) + if (sc->sc_dead) return; sc->sc_bus.intr_context++;