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 - 1.65
+++ dev/usb/if_athn_usb.c 24 Jul 2023 09:55:08 -
@@ -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 = >sc_sc;
struct ifnet *ifp = >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.c21 Apr 2022 21:03:03 - 1.134
+++ dev/usb/if_atu.c24 Jul 2023 09:55:09 -
@@ -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.c8 Mar 2023 04:43:08 - 1.8
+++ dev/usb/if_mtw.c24 Jul 2023 09:55:09 -
@@ -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 - 1.72
+++ dev/usb/if_otus.c 24 Jul 2023 09:55:09 -
@@ -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_ic;
struct ifnet *ifp = >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.c21 Apr 2022 21:03:03 - 1.149
+++ dev/usb/if_ral.c24 Jul 2023 09:55:09 -
@@ -648,6 +648,9 @@ ural_txeof(struct usbd_xfer *xfer, void
struct ifnet *ifp = >ic_if;
int s;
+ if (usbd_is_dying(sc->sc_udev))
+ return;
+
if (status != USBD_NORMAL_COMPLETION) {