On Thu, Oct 18, 2012 at 03:16:04PM -0400, Alan Stern wrote:
> 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",
>
>
Reviewed-by: Peter Chen <[email protected]>
Tested-by: Peter Chen <[email protected]>
--
Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html