@@ -817,9 +817,9 @@ static void hub_tt_work(struct work_struct *work)
*
* Return: 0 if successful. A negative error code otherwise.
*/
-int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
- int port1, bool set)
+int usb_hub_set_port_power(struct usb_hub *hub, int port1, bool set)
{
+ struct usb_device *hdev = hub->hdev;
int ret;
if (set)
@@ -2739,6 +2739,26 @@ static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1,
|| link_state == USB_SS_PORT_LS_COMP_MOD;
}
+static void hub_port_power_cycle(struct usb_hub *hub, int port1)
+{
+ int ret;
+
+ ret = usb_hub_set_port_power(hub, port1, false);
+ if (ret) {
+ dev_info(&udev->dev, "failed to disable port power\n");
+ return;
+ }
+
+ msleep(2 * hub_power_on_good_delay(hub));
+ ret = usb_hub_set_port_power(hub, port1, true);
+ if (ret) {
+ dev_info(&udev->dev, "failed to enable port power\n");
+ return;
+ }
+
+ msleep(hub_power_on_good_delay(hub));
+}
+
static int hub_port_wait_reset(struct usb_hub *hub, int port1,
struct usb_device *udev, unsigned int delay, bool warm)
{
@@ -5131,10 +5151,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
/* When halfway through our retry count, power-cycle the port */
if (i == (SET_CONFIG_TRIES / 2) - 1) {
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));
- usb_hub_set_port_power(hdev, hub, port1, true);
- msleep(hub_power_on_good_delay(hub));
+ hub_port_power_cycle(hub, port1);
}
}
if (hub->hdev->parent ||
@@ -113,8 +113,7 @@ extern int usb_hub_create_port_device(struct usb_hub *hub,
int port1);
extern void usb_hub_remove_port_device(struct usb_hub *hub,
int port1);
-extern int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
- int port1, bool set);
+extern int usb_hub_set_port_power(struct usb_hub *hub, int port1, bool set);
extern struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev);
extern int hub_port_debounce(struct usb_hub *hub, int port1,
bool must_be_connected);
@@ -214,7 +214,7 @@ static int usb_port_runtime_resume(struct device *dev)
pm_runtime_get_sync(&peer->dev);
usb_autopm_get_interface(intf);
- retval = usb_hub_set_port_power(hdev, hub, port1, true);
+ retval = usb_hub_set_port_power(hub, port1, true);
msleep(hub_power_on_good_delay(hub));
if (udev && !retval) {
/*
@@ -267,7 +267,7 @@ static int usb_port_runtime_suspend(struct device *dev)
return -EBUSY;
usb_autopm_get_interface(intf);
- retval = usb_hub_set_port_power(hdev, hub, port1, false);
+ retval = usb_hub_set_port_power(hub, port1, false);
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
if (!port_dev->is_superspeed)
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
Add a new function, hub_port_power_cycle() to power cycle port's power. It'll be used by a following patch. In addition to that, check the return value of usb_hub_set_port_power(), so we don't need to wait if the set power operation fails. Furthermore, remove parameter *hdev from usb_hub_set_port_power(), since we can get *hdev from *hub directly. Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com> --- drivers/usb/core/hub.c | 29 +++++++++++++++++++++++------ drivers/usb/core/hub.h | 3 +-- drivers/usb/core/port.c | 4 ++-- 3 files changed, 26 insertions(+), 10 deletions(-)