Re: USB suspend/resume race

2014-05-29 Thread Martin Pieuchot
On 19/01/10(Tue) 01:07, Jean-Philippe Ouellet wrote:
 On 26/05/14(Mon) 13:46, Martin Pieuchot wrote:
  I'd appreciate if people having troubles with suspend/resume could try
  this diff an report back.
 
 Fixes it for me! :D
 Many thanks.

You're welcome.

  Previous diff was lacking the header chunk, please use this one instead.
 
 Was the corresponding commit missing the ehci.c changes from this diff
 on purpose?

Yes, it was just a debugging chunk I'm thinking about a proper change for
all the *hci drivers.



Re: USB suspend/resume race

2014-05-28 Thread Jean-Philippe Ouellet
On 26/05/14(Mon) 13:46, Martin Pieuchot wrote:
 I'd appreciate if people having troubles with suspend/resume could try
 this diff an report back.

Fixes it for me! :D
Many thanks.

 Previous diff was lacking the header chunk, please use this one instead.

Was the corresponding commit missing the ehci.c changes from this diff
on purpose?



USB suspend/resume race

2014-05-26 Thread Martin Pieuchot
It is currently possible to trigger a race between the thread doing
DVACT_QUIESCE and the USB thread exploring the buses.

This race is really easy to reproduce if you have a lot of controllers
and you try to suspend just after resuming.  In the best case, it blows
your kernel during suspend, in the worst case it blows it at resume :)

So here's a diff to avoid such race by deferring the action of detaching
the root hub to the USB thread doing exploration.

I'd appreciate if people having troubles with suspend/resume could try
this diff an report back.

Martin

Index: usb.c
===
RCS file: /home/ncvs/src/sys/dev/usb/usb.c,v
retrieving revision 1.96
diff -u -p -r1.96 usb.c
--- usb.c   11 May 2014 16:33:21 -  1.96
+++ usb.c   26 May 2014 11:19:31 -
@@ -260,11 +260,15 @@ usb_attach_roothub(struct usb_softc *sc)
 void
 usb_detach_roothub(struct usb_softc *sc)
 {
-   /* Make all devices disconnect. */
-   if (sc-sc_port.device != NULL)
-   usb_disconnect_port(sc-sc_port, (struct device *)sc);
+   /*
+* To avoid races with the usb task thread, mark the root hub
+* as disconnecting and schedule an exploration task to detach
+* it.
+*/
+   sc-sc_bus-flags |= USB_BUS_DISCONNECTING;
+   usb_needs_explore(sc-sc_bus-root_hub, 0);
 
-   usb_rem_wait_task(sc-sc_bus-root_hub, sc-sc_explore_task);
+   usb_wait_task(sc-sc_bus-root_hub, sc-sc_explore_task);
 
sc-sc_bus-root_hub = NULL;
 }
@@ -840,7 +844,18 @@ usb_explore(void *v)
usb_delay_ms(sc-sc_bus, pwrdly - waited_ms);
}
 
-   sc-sc_bus-root_hub-hub-explore(sc-sc_bus-root_hub);
+   if (sc-sc_bus-flags  USB_BUS_DISCONNECTING) {
+   /* Prevent new tasks from being scheduled. */
+   sc-sc_bus-dying = 1;
+
+   /* Make all devices disconnect. */
+   if (sc-sc_port.device != NULL)
+   usb_disconnect_port(sc-sc_port, (struct device *)sc);
+
+   sc-sc_bus-flags = ~USB_BUS_DISCONNECTING;
+   } else {
+   sc-sc_bus-root_hub-hub-explore(sc-sc_bus-root_hub);
+   }
 
if (sc-sc_bus-flags  USB_BUS_CONFIG_PENDING) {
DPRINTF((%s: %s: first explore done\n, __func__,
@@ -896,7 +911,6 @@ usb_activate(struct device *self, int ac
 
switch (act) {
case DVACT_QUIESCE:
-   sc-sc_bus-dying = 1;
if (sc-sc_bus-root_hub != NULL)
usb_detach_roothub(sc);
break;
@@ -914,10 +928,6 @@ usb_activate(struct device *self, int ac
usb_needs_explore(sc-sc_bus-root_hub, 0);
sc-sc_bus-use_polling--;
break;
-   case DVACT_DEACTIVATE:
-   rv = config_activate_children(self, act);
-   sc-sc_bus-dying = 1;
-   break;
default:
rv = config_activate_children(self, act);
break;
@@ -929,10 +939,6 @@ int
 usb_detach(struct device *self, int flags)
 {
struct usb_softc *sc = (struct usb_softc *)self;
-
-   DPRINTF((usb_detach: start\n));
-
-   sc-sc_bus-dying = 1;
 
if (sc-sc_bus-root_hub != NULL) {
usb_detach_roothub(sc);
Index: uhub.c
===
RCS file: /home/ncvs/src/sys/dev/usb/uhub.c,v
retrieving revision 1.66
diff -u -p -r1.66 uhub.c
--- uhub.c  11 Mar 2014 10:24:42 -  1.66
+++ uhub.c  26 May 2014 11:19:31 -
@@ -546,6 +546,9 @@ uhub_intr(struct usbd_xfer *xfer, void *
 {
struct uhub_softc *sc = addr;
 
+   if (usbd_is_dying(sc-sc_hub))
+   return;
+
DPRINTF(%s: intr status=%d\n, sc-sc_dev.dv_xname, status);
if (status == USBD_STALLED)
usbd_clear_endpoint_stall_async(sc-sc_ipipe);
Index: ehci.c
===
RCS file: /home/ncvs/src/sys/dev/usb/ehci.c,v
retrieving revision 1.155
diff -u -p -r1.155 ehci.c
--- ehci.c  16 May 2014 19:00:18 -  1.155
+++ ehci.c  26 May 2014 11:19:31 -
@@ -1075,6 +1075,18 @@ ehci_activate(struct device *self, int a
ehci_reset(sc);
 
sc-sc_bus.use_polling--;
+
+   if (!TAILQ_EMPTY(sc-sc_intrhead)) {
+   printf(%s: intr head not empty\n,
+   sc-sc_bus.bdev.dv_xname);
+   return (EINVAL);
+   }
+   if (sc-sc_intrxfer != NULL) {
+   printf(%s: root intr not null\n,
+   sc-sc_bus.bdev.dv_xname);
+   return (EINVAL);
+   }
+
break;
case DVACT_RESUME:
sc-sc_bus.use_polling++;



Re: USB suspend/resume race

2014-05-26 Thread Martin Pieuchot
On 26/05/14(Mon) 13:46, Martin Pieuchot wrote:
 It is currently possible to trigger a race between the thread doing
 DVACT_QUIESCE and the USB thread exploring the buses.
 
 This race is really easy to reproduce if you have a lot of controllers
 and you try to suspend just after resuming.  In the best case, it blows
 your kernel during suspend, in the worst case it blows it at resume :)
 
 So here's a diff to avoid such race by deferring the action of detaching
 the root hub to the USB thread doing exploration.
 
 I'd appreciate if people having troubles with suspend/resume could try
 this diff an report back.

Previous diff was lacking the header chunk, please use this one instead.

Martin

Index: usb.c
===
RCS file: /home/ncvs/src/sys/dev/usb/usb.c,v
retrieving revision 1.96
diff -u -p -r1.96 usb.c
--- usb.c   11 May 2014 16:33:21 -  1.96
+++ usb.c   26 May 2014 11:19:31 -
@@ -260,11 +260,15 @@ usb_attach_roothub(struct usb_softc *sc)
 void
 usb_detach_roothub(struct usb_softc *sc)
 {
-   /* Make all devices disconnect. */
-   if (sc-sc_port.device != NULL)
-   usb_disconnect_port(sc-sc_port, (struct device *)sc);
+   /*
+* To avoid races with the usb task thread, mark the root hub
+* as disconnecting and schedule an exploration task to detach
+* it.
+*/
+   sc-sc_bus-flags |= USB_BUS_DISCONNECTING;
+   usb_needs_explore(sc-sc_bus-root_hub, 0);
 
-   usb_rem_wait_task(sc-sc_bus-root_hub, sc-sc_explore_task);
+   usb_wait_task(sc-sc_bus-root_hub, sc-sc_explore_task);
 
sc-sc_bus-root_hub = NULL;
 }
@@ -840,7 +844,18 @@ usb_explore(void *v)
usb_delay_ms(sc-sc_bus, pwrdly - waited_ms);
}
 
-   sc-sc_bus-root_hub-hub-explore(sc-sc_bus-root_hub);
+   if (sc-sc_bus-flags  USB_BUS_DISCONNECTING) {
+   /* Prevent new tasks from being scheduled. */
+   sc-sc_bus-dying = 1;
+
+   /* Make all devices disconnect. */
+   if (sc-sc_port.device != NULL)
+   usb_disconnect_port(sc-sc_port, (struct device *)sc);
+
+   sc-sc_bus-flags = ~USB_BUS_DISCONNECTING;
+   } else {
+   sc-sc_bus-root_hub-hub-explore(sc-sc_bus-root_hub);
+   }
 
if (sc-sc_bus-flags  USB_BUS_CONFIG_PENDING) {
DPRINTF((%s: %s: first explore done\n, __func__,
@@ -896,7 +911,6 @@ usb_activate(struct device *self, int ac
 
switch (act) {
case DVACT_QUIESCE:
-   sc-sc_bus-dying = 1;
if (sc-sc_bus-root_hub != NULL)
usb_detach_roothub(sc);
break;
@@ -914,10 +928,6 @@ usb_activate(struct device *self, int ac
usb_needs_explore(sc-sc_bus-root_hub, 0);
sc-sc_bus-use_polling--;
break;
-   case DVACT_DEACTIVATE:
-   rv = config_activate_children(self, act);
-   sc-sc_bus-dying = 1;
-   break;
default:
rv = config_activate_children(self, act);
break;
@@ -929,10 +939,6 @@ int
 usb_detach(struct device *self, int flags)
 {
struct usb_softc *sc = (struct usb_softc *)self;
-
-   DPRINTF((usb_detach: start\n));
-
-   sc-sc_bus-dying = 1;
 
if (sc-sc_bus-root_hub != NULL) {
usb_detach_roothub(sc);
Index: uhub.c
===
RCS file: /home/ncvs/src/sys/dev/usb/uhub.c,v
retrieving revision 1.66
diff -u -p -r1.66 uhub.c
--- uhub.c  11 Mar 2014 10:24:42 -  1.66
+++ uhub.c  26 May 2014 11:19:31 -
@@ -546,6 +546,9 @@ uhub_intr(struct usbd_xfer *xfer, void *
 {
struct uhub_softc *sc = addr;
 
+   if (usbd_is_dying(sc-sc_hub))
+   return;
+
DPRINTF(%s: intr status=%d\n, sc-sc_dev.dv_xname, status);
if (status == USBD_STALLED)
usbd_clear_endpoint_stall_async(sc-sc_ipipe);
Index: ehci.c
===
RCS file: /home/ncvs/src/sys/dev/usb/ehci.c,v
retrieving revision 1.155
diff -u -p -r1.155 ehci.c
--- ehci.c  16 May 2014 19:00:18 -  1.155
+++ ehci.c  26 May 2014 11:19:31 -
@@ -1075,6 +1075,18 @@ ehci_activate(struct device *self, int a
ehci_reset(sc);
 
sc-sc_bus.use_polling--;
+
+   if (!TAILQ_EMPTY(sc-sc_intrhead)) {
+   printf(%s: intr head not empty\n,
+   sc-sc_bus.bdev.dv_xname);
+   return (EINVAL);
+   }
+   if (sc-sc_intrxfer != NULL) {
+   printf(%s: root intr not null\n,
+   sc-sc_bus.bdev.dv_xname);
+   return (EINVAL);
+   }
+
break;
case DVACT_RESUME:

Re: USB suspend/resume race

2014-05-26 Thread Mattieu Baptiste
On Mon, May 26, 2014 at 1:51 PM, Martin Pieuchot mpieuc...@nolizard.orgwrote:

 On 26/05/14(Mon) 13:46, Martin Pieuchot wrote:
  It is currently possible to trigger a race between the thread doing
  DVACT_QUIESCE and the USB thread exploring the buses.
 
  This race is really easy to reproduce if you have a lot of controllers
  and you try to suspend just after resuming.  In the best case, it blows
  your kernel during suspend, in the worst case it blows it at resume :)
 
  So here's a diff to avoid such race by deferring the action of detaching
  the root hub to the USB thread doing exploration.
 
  I'd appreciate if people having troubles with suspend/resume could try
  this diff an report back.

 Previous diff was lacking the header chunk, please use this one instead.



Hi Martin,

This seems to fix the freezes I encounter since some time when suspending
my laptop.

Thanks