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++;

Reply via email to