HID: usbhid: do not sleep when opening device

Message ID 20200529195951.GA3767@dtor-ws
State New
Headers show
Series
  • HID: usbhid: do not sleep when opening device
Related show

Commit Message

Dmitry Torokhov May 29, 2020, 7:59 p.m.
usbhid tries to give the device 50 milliseconds to drain its queues
when opening the device, but does it naively by simply sleeping in open
handler, which slows down device probing (and thus may affect overall
boot time).

However we do not need to sleep as we can instead mark a point of time
in the future when we should start processing the events.

Reported-by: Nicolas Boichat <drinkcat@chromium.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/hid/usbhid/hid-core.c | 27 +++++++++++++++------------
 drivers/hid/usbhid/usbhid.h   |  1 +
 2 files changed, 16 insertions(+), 12 deletions(-)

Patch

diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index c7bc9db5b192..e69992e945b2 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -95,6 +95,19 @@  static int hid_start_in(struct hid_device *hid)
 				set_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
 		} else {
 			clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
+
+			if (test_and_clear_bit(HID_RESUME_RUNNING,
+					       &usbhid->iofl)) {
+				/*
+				 * In case events are generated while nobody was
+				 * listening, some are released when the device
+				 * is re-opened. Wait 50 msec for the queue to
+				 * empty before allowing events to go through
+				 * hid.
+				 */
+				usbhid->input_start_time = jiffies +
+							   msecs_to_jiffies(50);
+			}
 		}
 	}
 	spin_unlock_irqrestore(&usbhid->lock, flags);
@@ -280,7 +293,8 @@  static void hid_irq_in(struct urb *urb)
 		if (!test_bit(HID_OPENED, &usbhid->iofl))
 			break;
 		usbhid_mark_busy(usbhid);
-		if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
+		if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl) &&
+		    time_after(jiffies, usbhid->input_start_time)) {
 			hid_input_report(urb->context, HID_INPUT_REPORT,
 					 urb->transfer_buffer,
 					 urb->actual_length, 1);
@@ -714,17 +728,6 @@  static int usbhid_open(struct hid_device *hid)
 	}
 
 	usb_autopm_put_interface(usbhid->intf);
-
-	/*
-	 * In case events are generated while nobody was listening,
-	 * some are released when the device is re-opened.
-	 * Wait 50 msec for the queue to empty before allowing events
-	 * to go through hid.
-	 */
-	if (res == 0)
-		msleep(50);
-
-	clear_bit(HID_RESUME_RUNNING, &usbhid->iofl);
 	return res;
 }
 
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 8620408bd7af..805949671b96 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -82,6 +82,7 @@  struct usbhid_device {
 
 	spinlock_t lock;						/* fifo spinlock */
 	unsigned long iofl;                                             /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
+	unsigned long input_start_time;					/* When to start handling input, in jiffies */
 	struct timer_list io_retry;                                     /* Retry timer */
 	unsigned long stop_retry;                                       /* Time to give up, in jiffies */
 	unsigned int retry_delay;                                       /* Delay length in ms */