Re: Make USB WiFi drivers more robust

2023-07-25 Thread Peter Stuge
Martin Pieuchot wrote:
> > 1. The driver's ioctl function.
> > 
> > 2. The driver's USB transfer completion callbacks.
> 
> Those are called by usb_transfer_complete().  This correspond to
> xhci_xfer_done() and xhci_event_port_change().  Does those functions
> need to be called during suspend?

xhci_xfer_done() is called among other places when hardware completes
a transfer, which could happen during suspend unless endpoints were
stopped/transfers were aborted before suspend is allowed to proceed.

The USB stack (I guess xhci.c) would have to delay suspend until
active transfers complete or are aborted while failing new transfers.
I don't know if that's desirable.

A variant could be for suspend to cancel any active transfers, e.g.
using xhci_abort_xfer().

I see that xhci.c doesn't handle DVACT_SUSPEND like other ?hci.c.
It only handles DVACT_POWERDOWN. Could this be the underlying reason?


xhci_event_port_change() might be called /because of/ suspend, if
devices are shut down and the HC can report port change events while
the kernel is suspending, which xHCI spec says does not happen if the
HC is halted, which seems like a good idea while suspending - but
again I don't see xhci.c halting the HC nor doing anything else for
suspend.


@kettenis Since ehci_activate() handles DVACT_SUSPEND is it possible
to use only the EHCI driver on your machine for comparison?


//Peter



Re: Make USB WiFi drivers more robust

2023-07-24 Thread Martin Pieuchot
On 24/07/23(Mon) 12:07, Mark Kettenis wrote:
> 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:

We spend quite some time in the past years trying to get rid of the
usbd_is_dying() mechanism.  I'm quite sad to see such diff.  I've no
idea what the underlying issue is and if an alternative is possible.

The idea is that the USB stack should already take care of this, not
every driver.  Because we've seen it's hard for drivers to do that
correctly.
 
> 1. The driver's ioctl function.
> 
> 2. The driver's USB transfer completion callbacks.

Those are called by usb_transfer_complete().  This correspond to
xhci_xfer_done() and xhci_event_port_change().  Does those functions
need to be called during suspend?

It is not clear to me what your issue is.  I wish we could find a fix
inside xhci(4) or the USB stack.

Thanks,
Martin



Make USB WiFi drivers more robust

2023-07-24 Thread Mark Kettenis
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) {