On Thu, 18 Oct 2012, Peter Chen wrote:

> > I decided to use a different approach.  The core should know which 
> > ports are suspended without asking the HCD.  Can you test this patch in 
> > place of the other one?
> It shows below oops, you may not consider there is no device at port
> condition.

Quite right.  I consider this to be a bug in hub_for_each_child; the 
first patch below fixes that bug.

> Besides, how about using usleep_range instead of msleep? msleep is not
> precise, and should not be used at (<20ms) condition, at my platform,
> msleep 10 consumes about 19-20ms.

Good idea; the second patch below is updated to use usleep_range 
instead of msleep.  These two patches together should do what you want.

Alan Stern



First patch: Fix hub_for_each_child

Index: usb-3.6/include/linux/usb.h
===================================================================
--- usb-3.6.orig/include/linux/usb.h
+++ usb-3.6/include/linux/usb.h
@@ -588,8 +588,9 @@ extern struct usb_device *usb_hub_find_c
  */
 #define usb_hub_for_each_child(hdev, port1, child) \
        for (port1 = 1, child = usb_hub_find_child(hdev, port1); \
-               port1 <= hdev->maxchild; \
-               child = usb_hub_find_child(hdev, ++port1))
+                       port1 <= hdev->maxchild; \
+                       child = usb_hub_find_child(hdev, ++port1)) \
+               if (!child) continue; else
 
 /* USB device locking */
 #define usb_lock_device(udev)          device_lock(&(udev)->dev)



Second patch: Speed up bus resumes

Index: usb-3.6/include/linux/usb.h
===================================================================
--- usb-3.6.orig/include/linux/usb.h
+++ usb-3.6/include/linux/usb.h
@@ -482,6 +482,7 @@ struct usb3_lpm_parameters {
  * @connect_time: time device was first connected
  * @do_remote_wakeup:  remote wakeup should be enabled
  * @reset_resume: needs reset instead of resume
+ * @port_is_suspended: the upstream port is suspended (L2 or U3)
  * @wusb_dev: if this is a Wireless USB device, link to the WUSB
  *     specific data for the device.
  * @slot_id: Slot ID assigned by xHCI
@@ -560,6 +561,7 @@ struct usb_device {
 
        unsigned do_remote_wakeup:1;
        unsigned reset_resume:1;
+       unsigned port_is_suspended:1;
 #endif
        struct wusb_dev *wusb_dev;
        int slot_id;
Index: usb-3.6/drivers/usb/core/hub.c
===================================================================
--- usb-3.6.orig/drivers/usb/core/hub.c
+++ usb-3.6/drivers/usb/core/hub.c
@@ -2876,6 +2876,7 @@ int usb_port_suspend(struct usb_device *
                                (PMSG_IS_AUTO(msg) ? "auto-" : ""),
                                udev->do_remote_wakeup);
                usb_set_device_state(udev, USB_STATE_SUSPENDED);
+               udev->port_is_suspended = 1;
                msleep(10);
        }
        usb_mark_last_busy(hub->hdev);
@@ -3040,6 +3041,7 @@ int usb_port_resume(struct usb_device *u
 
  SuspendCleared:
        if (status == 0) {
+               udev->port_is_suspended = 0;
                if (hub_is_superspeed(hub->hdev)) {
                        if (portchange & USB_PORT_STAT_C_LINK_STATE)
                                clear_port_feature(hub->hdev, port1,
Index: usb-3.6/drivers/usb/core/hcd.c
===================================================================
--- usb-3.6.orig/drivers/usb/core/hcd.c
+++ usb-3.6/drivers/usb/core/hcd.c
@@ -2039,8 +2039,9 @@ int hcd_bus_resume(struct usb_device *rh
        status = hcd->driver->bus_resume(hcd);
        clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
        if (status == 0) {
-               /* TRSMRCY = 10 msec */
-               msleep(10);
+               struct usb_device *udev;
+               int port1;
+
                spin_lock_irq(&hcd_root_hub_lock);
                if (!HCD_DEAD(hcd)) {
                        usb_set_device_state(rhdev, rhdev->actconfig
@@ -2050,6 +2051,20 @@ int hcd_bus_resume(struct usb_device *rh
                        hcd->state = HC_STATE_RUNNING;
                }
                spin_unlock_irq(&hcd_root_hub_lock);
+
+               /*
+                * Check whether any of the enabled ports on the root hub are
+                * unsuspended.  If they are then a TRSMRCY delay is needed
+                * (this is what the USB-2 spec calls a "global resume").
+                * Otherwise we can skip the delay.
+                */
+               usb_hub_for_each_child(rhdev, port1, udev) {
+                       if (udev->state != USB_STATE_NOTATTACHED &&
+                                       !udev->port_is_suspended) {
+                               usleep_range(10000, 11000);     /* TRSMRCY */
+                               break;
+                       }
+               }
        } else {
                hcd->state = old_state;
                dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to