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@xxxxxxxxxxxxx> --- v2: - No change. drivers/usb/core/hub.c | 30 ++++++++++++++++++++++++------ drivers/usb/core/hub.h | 3 +-- drivers/usb/core/port.c | 4 ++-- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1709895387b9..6b6cd76ac5e6 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -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,27 @@ 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) +{ + struct usb_port *port_dev = hub->ports[port1 - 1]; + int ret; + + ret = usb_hub_set_port_power(hub, port1, false); + if (ret) { + dev_info(&port_dev->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(&port_dev->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) { @@ -5216,10 +5237,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 || diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index a9e24e4b8df1..325a55637a6f 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -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); diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index bbbb35fa639f..0fc6f24c6da1 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -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); -- 2.17.1