linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Lauri Jakku <lja@iki.fi>
To: oneukum@suse.com, benjamin.tissoires@redhat.com
Cc: jikos@kernel.org, linux-input@vger.kernel.org,
	gregkh@linuxfoundation.org, linux-usb@vger.kernel.org,
	Lauri Jakku <lja@iki.fi>
Subject: [PATCH v5] USB: HID: random timeout failures tackle try.
Date: Tue,  4 Feb 2020 19:52:39 +0200	[thread overview]
Message-ID: <20200204175238.3817-1-lja@iki.fi> (raw)

-- v1 ------------------------------------------------------------
send, 20ms apart, control messages, if error is timeout.

There is multiple reports of random behaviour of USB HID devices.

I have mouse that acts sometimes quite randomly, I debugged with
logs others have published that there is HW timeouts that leave
device in state that it is errorneus.

To fix this I introduced retry mechanism in root of USB HID drivers.

Fix does not slow down operations at all if there is no -ETIMEDOUT
got from control message sending. If there is one, then sleep 20ms
and try again. Retry count is 20 witch translates maximium of 400ms
before giving up.

NOTE: This does not sleep anymore then before, if all is golden.

-- v2 ------------------------------------------------------------

If there is timeout, then sleep 20ms and try again. Retry count is 20
witch translates maximium of 400ms before giving up. If the 400ms
boundary is reached the HW is really bad.

JUST to be clear:
    This does not make USB HID devices to sleep anymore than
    before, if all is golden.

Why modify usb-hid-core: No need to modify driver by driver.

-- v3 ------------------------------------------------------------

Timeout given is divided by 100, but taken care that it is always
at least 10ms.

so total time in common worst-case-scenario is:

 sleep of 20ms + common timeout divided by 100 (50ms) makes
 70ms per loop, 20 loops => 1.4sec .

-- v4 ------------------------------------------------------------
No changes in code, just elaborating what is done in v[1,2,3].

-- v5 ------------------------------------------------------------
changes in code: what the build robot found:
   drivers/usb/core/message.c: In function 'usb_control_msg':
>> drivers/usb/core/message.c:173:11: error: type defaults to 'int' \
     in declaration of 'timeout_happened' [-Werror=implicit-int]
       static timeout_happened = 0;
              ^~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

Fix done: added int to declaration.


Signed-off-by: Lauri Jakku <lja@iki.fi>
---
 drivers/usb/core/message.c | 55 ++++++++++++++++++++++++++++++++++----
 1 file changed, 50 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 5adf489428aa..2e0bfe70f7c5 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -20,6 +20,7 @@
 #include <linux/usb/hcd.h>	/* for usbcore internals */
 #include <linux/usb/of.h>
 #include <asm/byteorder.h>
+#include <linux/errno.h>
 
 #include "usb.h"
 
@@ -137,7 +138,10 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
 		    __u16 size, int timeout)
 {
 	struct usb_ctrlrequest *dr;
-	int ret;
+	int ret = -ETIMEDOUT;
+
+	/* retry_cnt * 20ms, max retry time set to 400ms */
+	int retry_cnt = 20;
 
 	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
 	if (!dr)
@@ -149,11 +153,52 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
 	dr->wIndex = cpu_to_le16(index);
 	dr->wLength = cpu_to_le16(size);
 
-	ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
+	do {
+		ret = usb_internal_control_msg(dev,
+					pipe,
+					dr,
+					data,
+					size,
+					timeout);
+
+		/*
+		 * Linger a bit, prior to the next control message
+		 * or if return value is timeout, but do try few
+		 * times (max 400ms) before quitting. Adapt timeout
+		 * to be smaller when we have timeout'd first time.
+		 */
+		if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
+			msleep(200);
+		else if (ret == -ETIMEDOUT) {
+			static int timeout_happened = 0;
+
+			if ( ! timeout_happened ) {
+				timeout_happened = 1;
+
+				/* 
+				 * If timeout is given, divide it
+				 * by 100, if not, put 10ms timeout.
+				 * 
+				 * Then safeguard: if timeout is under
+				 * 10ms, make timeout to be 10ms.
+				 */
+
+				if (timeout > 0)
+					timeout /= 100;
+				else
+					timeout = 10;
+
+				if (timeout < 10)
+					timeout = 10;
+
+			}
+
+			msleep(20);
+		}
+
+		/* Loop while timeout, max loops: retry_cnt times. */
+	} while ((retry_cnt-- > 0) && (ret == -ETIMEDOUT));
 
-	/* Linger a bit, prior to the next control message. */
-	if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
-		msleep(200);
 
 	kfree(dr);
 
-- 
2.25.0


             reply	other threads:[~2020-02-04 17:54 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-04 17:52 Lauri Jakku [this message]
2020-02-04 18:07 ` [PATCH v5] USB: HID: random timeout failures tackle try Alan Stern
2020-02-04 20:14   ` Lauri Jakku
2020-02-04 18:11 ` Greg KH
2020-02-04 18:15 ` Greg KH
2020-02-04 20:05   ` Lauri Jakku
2020-02-05 10:03 ` Oliver Neukum

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200204175238.3817-1-lja@iki.fi \
    --to=lja@iki.fi \
    --cc=benjamin.tissoires@redhat.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=jikos@kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=oneukum@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).