diff mbox series

[v3,1/2] USB: Verify the port status when timeout happens during port suspend

Message ID 20210513041446.3082-2-chris.chiu@canonical.com (mailing list archive)
State Superseded
Headers show
Series USB: propose a generic fix for PORT_SUSPEND set feature timeout | expand

Commit Message

Chris Chiu May 13, 2021, 4:14 a.m. UTC
From: Chris Chiu <chris.chiu@canonical.com>

On the Realtek high-speed Hub(0bda:5487), the port which has wakeup
enabled_descendants will sometimes timeout when setting PORT_SUSPEND
feature. After checking the PORT_SUSPEND bit in wPortStatus, it is
already set. However, the hub will fail to activate because the
PORT_SUSPEND feature of that port is not cleared during resume. All
connected devices are lost after resume.

Check the port status to verify whether it's really suspended when
timeout happpens. If yes, mark it as suspended so the device can
be resumed correctly.

Signed-off-by: Chris Chiu <chris.chiu@canonical.com>
---

Changelog:
  v3:
    - create a new goto target for the timeout case instead of
      reset_resume
    - Revise the commit title/message because reset_resume is not
      required.
  v2:
    - create a new variable to keep the result of hub_port_status
      when suspend timeout.

 drivers/usb/core/hub.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

Comments

Alan Stern May 13, 2021, 2:35 p.m. UTC | #1
On Thu, May 13, 2021 at 12:14:45PM +0800, chris.chiu@canonical.com wrote:
> From: Chris Chiu <chris.chiu@canonical.com>
> 
> On the Realtek high-speed Hub(0bda:5487), the port which has wakeup
> enabled_descendants will sometimes timeout when setting PORT_SUSPEND
> feature. After checking the PORT_SUSPEND bit in wPortStatus, it is
> already set. However, the hub will fail to activate because the
> PORT_SUSPEND feature of that port is not cleared during resume. All
> connected devices are lost after resume.

The last two sentences of this paragraph are now inaccurate.  Please fix 
them up to match the current patch version.

> Check the port status to verify whether it's really suspended when
> timeout happpens. If yes, mark it as suspended so the device can
> be resumed correctly.
> 
> Signed-off-by: Chris Chiu <chris.chiu@canonical.com>
> ---
> 
> Changelog:
>   v3:
>     - create a new goto target for the timeout case instead of
>       reset_resume
>     - Revise the commit title/message because reset_resume is not
>       required.
>   v2:
>     - create a new variable to keep the result of hub_port_status
>       when suspend timeout.
> 
>  drivers/usb/core/hub.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index b2bc4b7c4289..c5d64175eaa9 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
> @@ -3385,6 +3385,21 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
>  		status = 0;
>  	}
>  	if (status) {
> +		if (status == -ETIMEDOUT) {
> +			u16 portstatus, portchange;
> +

Extra blank line.

> +			int ret = hub_port_status(hub, port1, &portstatus,
> +					&portchange);
> +
> +			dev_dbg(&port_dev->dev,
> +				"suspend timeout, status %04x\n", portstatus);

The portstatus value shouldn't be printed if ret < 0, because it won't 
be initialized.  If you want, initialize portstatus to 0 in the 
declaration.

Also, there should be a comment here explaining why this code is needed.  
It should say pretty the same thing as the patch description, but more 
briefly (two sentences should be sufficient).

Alan Stern

> +
> +			if (ret == 0 && port_is_suspended(hub, portstatus)) {
> +				status = 0;
> +				goto suspend_done;
> +			}
> +		}
> +
>  		dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status);
>  
>  		/* Try to enable USB3 LTM again */
> @@ -3401,6 +3416,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
>  		if (!PMSG_IS_AUTO(msg))
>  			status = 0;
>  	} else {
> + suspend_done:
>  		dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n",
>  				(PMSG_IS_AUTO(msg) ? "auto-" : ""),
>  				udev->do_remote_wakeup);
> -- 
> 2.20.1
>
diff mbox series

Patch

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b2bc4b7c4289..c5d64175eaa9 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3385,6 +3385,21 @@  int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 		status = 0;
 	}
 	if (status) {
+		if (status == -ETIMEDOUT) {
+			u16 portstatus, portchange;
+
+			int ret = hub_port_status(hub, port1, &portstatus,
+					&portchange);
+
+			dev_dbg(&port_dev->dev,
+				"suspend timeout, status %04x\n", portstatus);
+
+			if (ret == 0 && port_is_suspended(hub, portstatus)) {
+				status = 0;
+				goto suspend_done;
+			}
+		}
+
 		dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status);
 
 		/* Try to enable USB3 LTM again */
@@ -3401,6 +3416,7 @@  int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 		if (!PMSG_IS_AUTO(msg))
 			status = 0;
 	} else {
+ suspend_done:
 		dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n",
 				(PMSG_IS_AUTO(msg) ? "auto-" : ""),
 				udev->do_remote_wakeup);