usb: core: hub: ensure power on hcd if attempt power cycle

When do USB hot plug test in USB EHCI/OHIC interface, we
meet a problem that USB HS device can't be recognized with
the following error log:

Cannot enable. Maybe the USB cable is bad?
Cannot enable. Maybe the USB cable is bad?
attempt power cycle
Cannot enable. Maybe the USB cable is bad?
Cannot enable. Maybe the USB cable is bad?

It's hard to reproduce this issue, but the "attempt power
cycle" logic does have a problem for EHCI.

When do USB hot plug test with a USB HS device, the HS
handshake may fail at some time due to unknown reason,
and the USB controller driver will set the PORT_OWNER flag
in EHCI register to change to OHCI companion first. Then
hub_port_connect() calls the usb_hub_set_port_power() to
attempt power cycle the EHCI. However, it fail to power on
the EHCI because the EHCI driver check the PORT_OWNER flag
is true and return immediately.

This patch adds a HCD_FLAG_POWER_ON flag to ensure power on
the EHCI in this case.

Change-Id: I33f5fbaca5d9fbaa978f831db18ff7b20ea70bd8
Signed-off-by: William Wu <william.wu@rock-chips.com>
This commit is contained in:
William Wu
2019-10-22 11:13:27 +08:00
parent dfcecdd3d0
commit 42086e08cd
3 changed files with 6 additions and 1 deletions

View File

@ -5188,6 +5188,7 @@ loop:
dev_info(&port_dev->dev, "attempt power cycle\n");
usb_hub_set_port_power(hdev, hub, port1, false);
msleep(2 * hub_power_on_good_delay(hub));
set_bit(HCD_FLAG_POWER_ON, &hcd->flags);
usb_hub_set_port_power(hdev, hub, port1, true);
msleep(hub_power_on_good_delay(hub));
}

View File

@ -1174,7 +1174,7 @@ int ehci_hub_control(
goto error;
wIndex--;
temp = ehci_readl(ehci, status_reg);
if (temp & PORT_OWNER)
if ((temp & PORT_OWNER) && (!HCD_POWER_ON(hcd)))
break;
temp &= ~PORT_RWC_BITS;
@ -1217,6 +1217,7 @@ int ehci_hub_control(
if (HCS_PPC(ehci->hcs_params)) {
spin_unlock_irqrestore(&ehci->lock, flags);
ehci_port_power(ehci, wIndex, true);
clear_bit(HCD_FLAG_POWER_ON, &hcd->flags);
spin_lock_irqsave(&ehci->lock, flags);
}
break;

View File

@ -119,6 +119,7 @@ struct usb_hcd {
#define HCD_FLAG_DEAD 6 /* controller has died? */
#define HCD_FLAG_INTF_AUTHORIZED 7 /* authorize interfaces? */
#define HCD_FLAG_DEV_AUTHORIZED 8 /* authorize devices? */
#define HCD_FLAG_POWER_ON 9 /* power on */
/* The flags can be tested using these macros; they are likely to
* be slightly faster than test_bit().
@ -146,6 +147,8 @@ struct usb_hcd {
#define HCD_DEV_AUTHORIZED(hcd) \
((hcd)->flags & (1U << HCD_FLAG_DEV_AUTHORIZED))
#define HCD_POWER_ON(hcd) ((hcd)->flags & (1U << HCD_FLAG_POWER_ON))
/* Flags that get set only during HCD registration or removal. */
unsigned rh_registered:1;/* is root hub registered? */
unsigned rh_pollable:1; /* may we poll the root hub? */