]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.1
authorSasha Levin <sashal@kernel.org>
Sun, 3 Nov 2024 20:24:39 +0000 (15:24 -0500)
committerSasha Levin <sashal@kernel.org>
Sun, 3 Nov 2024 20:24:39 +0000 (15:24 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-6.1/series
queue-6.1/usb-gadget-dummy-hcd-fix-task-hung-problem.patch [new file with mode: 0644]
queue-6.1/usb-gadget-dummy_hcd-execute-hrtimer-callback-in-sof.patch [new file with mode: 0644]
queue-6.1/usb-gadget-dummy_hcd-set-transfer-interval-to-1-micr.patch [new file with mode: 0644]
queue-6.1/usb-gadget-dummy_hcd-switch-to-hrtimer-transfer-sche.patch [new file with mode: 0644]

index e2f46290bb956ccf5e2345d9f68ea2bc23d08fbe..716f64e708ef3c9c6973383ae8a6809da507cc7d 100644 (file)
@@ -63,3 +63,7 @@ cifs-fix-creating-native-symlinks-pointing-to-curren.patch
 net-amd-mvme147-fix-probe-banner-message.patch
 nfs-remove-revoked-delegation-from-server-s-delegati.patch
 misc-sgi-gru-don-t-disable-preemption-in-gru-driver.patch
+usb-gadget-dummy_hcd-switch-to-hrtimer-transfer-sche.patch
+usb-gadget-dummy_hcd-set-transfer-interval-to-1-micr.patch
+usb-gadget-dummy_hcd-execute-hrtimer-callback-in-sof.patch
+usb-gadget-dummy-hcd-fix-task-hung-problem.patch
diff --git a/queue-6.1/usb-gadget-dummy-hcd-fix-task-hung-problem.patch b/queue-6.1/usb-gadget-dummy-hcd-fix-task-hung-problem.patch
new file mode 100644 (file)
index 0000000..abab33f
--- /dev/null
@@ -0,0 +1,124 @@
+From 85f088c658432975d8da3a9e795e4232918db101 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 16 Oct 2024 11:44:45 -0400
+Subject: USB: gadget: dummy-hcd: Fix "task hung" problem
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+[ Upstream commit 5189df7b8088268012882c220d6aca4e64981348 ]
+
+The syzbot fuzzer has been encountering "task hung" problems ever
+since the dummy-hcd driver was changed to use hrtimers instead of
+regular timers.  It turns out that the problems are caused by a subtle
+difference between the timer_pending() and hrtimer_active() APIs.
+
+The changeover blindly replaced the first by the second.  However,
+timer_pending() returns True when the timer is queued but not when its
+callback is running, whereas hrtimer_active() returns True when the
+hrtimer is queued _or_ its callback is running.  This difference
+occasionally caused dummy_urb_enqueue() to think that the callback
+routine had not yet started when in fact it was almost finished.  As a
+result the hrtimer was not restarted, which made it impossible for the
+driver to dequeue later the URB that was just enqueued.  This caused
+usb_kill_urb() to hang, and things got worse from there.
+
+Since hrtimers have no API for telling when they are queued and the
+callback isn't running, the driver must keep track of this for itself.
+That's what this patch does, adding a new "timer_pending" flag and
+setting or clearing it at the appropriate times.
+
+Reported-by: syzbot+f342ea16c9d06d80b585@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/linux-usb/6709234e.050a0220.3e960.0011.GAE@google.com/
+Tested-by: syzbot+f342ea16c9d06d80b585@syzkaller.appspotmail.com
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Fixes: a7f3813e589f ("usb: gadget: dummy_hcd: Switch to hrtimer transfer scheduler")
+Cc: Marcello Sylvester Bauer <sylv@sylv.io>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/2dab644e-ef87-4de8-ac9a-26f100b2c609@rowland.harvard.edu
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/gadget/udc/dummy_hcd.c | 20 +++++++++++++++-----
+ 1 file changed, 15 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
+index 019e8f3007c94..6e18e8e76e8b9 100644
+--- a/drivers/usb/gadget/udc/dummy_hcd.c
++++ b/drivers/usb/gadget/udc/dummy_hcd.c
+@@ -254,6 +254,7 @@ struct dummy_hcd {
+       u32                             stream_en_ep;
+       u8                              num_stream[30 / 2];
++      unsigned                        timer_pending:1;
+       unsigned                        active:1;
+       unsigned                        old_active:1;
+       unsigned                        resuming:1;
+@@ -1304,9 +1305,11 @@ static int dummy_urb_enqueue(
+               urb->error_count = 1;           /* mark as a new urb */
+       /* kick the scheduler, it'll do the rest */
+-      if (!hrtimer_active(&dum_hcd->timer))
++      if (!dum_hcd->timer_pending) {
++              dum_hcd->timer_pending = 1;
+               hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
+                               HRTIMER_MODE_REL_SOFT);
++      }
+  done:
+       spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
+@@ -1325,9 +1328,10 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+       spin_lock_irqsave(&dum_hcd->dum->lock, flags);
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+-      if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
+-                      !list_empty(&dum_hcd->urbp_list))
++      if (rc == 0 && !dum_hcd->timer_pending) {
++              dum_hcd->timer_pending = 1;
+               hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL_SOFT);
++      }
+       spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
+       return rc;
+@@ -1814,6 +1818,7 @@ static enum hrtimer_restart dummy_timer(struct hrtimer *t)
+       /* look at each urb queued by the host side driver */
+       spin_lock_irqsave(&dum->lock, flags);
++      dum_hcd->timer_pending = 0;
+       if (!dum_hcd->udev) {
+               dev_err(dummy_dev(dum_hcd),
+@@ -1995,8 +2000,10 @@ static enum hrtimer_restart dummy_timer(struct hrtimer *t)
+       if (list_empty(&dum_hcd->urbp_list)) {
+               usb_put_dev(dum_hcd->udev);
+               dum_hcd->udev = NULL;
+-      } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
++      } else if (!dum_hcd->timer_pending &&
++                      dum_hcd->rh_state == DUMMY_RH_RUNNING) {
+               /* want a 1 msec delay here */
++              dum_hcd->timer_pending = 1;
+               hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
+                               HRTIMER_MODE_REL_SOFT);
+       }
+@@ -2391,8 +2398,10 @@ static int dummy_bus_resume(struct usb_hcd *hcd)
+       } else {
+               dum_hcd->rh_state = DUMMY_RH_RUNNING;
+               set_link_state(dum_hcd);
+-              if (!list_empty(&dum_hcd->urbp_list))
++              if (!list_empty(&dum_hcd->urbp_list)) {
++                      dum_hcd->timer_pending = 1;
+                       hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL_SOFT);
++              }
+               hcd->state = HC_STATE_RUNNING;
+       }
+       spin_unlock_irq(&dum_hcd->dum->lock);
+@@ -2523,6 +2532,7 @@ static void dummy_stop(struct usb_hcd *hcd)
+       struct dummy_hcd        *dum_hcd = hcd_to_dummy_hcd(hcd);
+       hrtimer_cancel(&dum_hcd->timer);
++      dum_hcd->timer_pending = 0;
+       device_remove_file(dummy_dev(dum_hcd), &dev_attr_urbs);
+       dev_info(dummy_dev(dum_hcd), "stopped\n");
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.1/usb-gadget-dummy_hcd-execute-hrtimer-callback-in-sof.patch b/queue-6.1/usb-gadget-dummy_hcd-execute-hrtimer-callback-in-sof.patch
new file mode 100644 (file)
index 0000000..90c7b50
--- /dev/null
@@ -0,0 +1,118 @@
+From ea6a80c9cfa890428434f75cdbc8f729c8f34b76 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 Sep 2024 03:30:51 +0200
+Subject: usb: gadget: dummy_hcd: execute hrtimer callback in softirq context
+
+From: Andrey Konovalov <andreyknvl@gmail.com>
+
+[ Upstream commit 9313d139aa25e572d860f6f673b73a20f32d7f93 ]
+
+Commit a7f3813e589f ("usb: gadget: dummy_hcd: Switch to hrtimer transfer
+scheduler") switched dummy_hcd to use hrtimer and made the timer's
+callback be executed in the hardirq context.
+
+With that change, __usb_hcd_giveback_urb now gets executed in the hardirq
+context, which causes problems for KCOV and KMSAN.
+
+One problem is that KCOV now is unable to collect coverage from
+the USB code that gets executed from the dummy_hcd's timer callback,
+as KCOV cannot collect coverage in the hardirq context.
+
+Another problem is that the dummy_hcd hrtimer might get triggered in the
+middle of a softirq with KCOV remote coverage collection enabled, and that
+causes a WARNING in KCOV, as reported by syzbot. (I sent a separate patch
+to shut down this WARNING, but that doesn't fix the other two issues.)
+
+Finally, KMSAN appears to ignore tracking memory copying operations
+that happen in the hardirq context, which causes false positive
+kernel-infoleaks, as reported by syzbot.
+
+Change the hrtimer in dummy_hcd to execute the callback in the softirq
+context.
+
+Reported-by: syzbot+2388cdaeb6b10f0c13ac@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=2388cdaeb6b10f0c13ac
+Reported-by: syzbot+17ca2339e34a1d863aad@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=17ca2339e34a1d863aad
+Reported-by: syzbot+c793a7eca38803212c61@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=c793a7eca38803212c61
+Reported-by: syzbot+1e6e0b916b211bee1bd6@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=1e6e0b916b211bee1bd6
+Reported-by: kernel test robot <oliver.sang@intel.com>
+Closes: https://lore.kernel.org/oe-lkp/202406141323.413a90d2-lkp@intel.com
+Fixes: a7f3813e589f ("usb: gadget: dummy_hcd: Switch to hrtimer transfer scheduler")
+Cc: stable@vger.kernel.org
+Acked-by: Marcello Sylvester Bauer <sylv@sylv.io>
+Signed-off-by: Andrey Konovalov <andreyknvl@gmail.com>
+Reported-by: syzbot+edd9fe0d3a65b14588d5@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=edd9fe0d3a65b14588d5
+Link: https://lore.kernel.org/r/20240904013051.4409-1-andrey.konovalov@linux.dev
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/gadget/udc/dummy_hcd.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
+index 32a03de215d37..019e8f3007c94 100644
+--- a/drivers/usb/gadget/udc/dummy_hcd.c
++++ b/drivers/usb/gadget/udc/dummy_hcd.c
+@@ -1305,7 +1305,8 @@ static int dummy_urb_enqueue(
+       /* kick the scheduler, it'll do the rest */
+       if (!hrtimer_active(&dum_hcd->timer))
+-              hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS), HRTIMER_MODE_REL);
++              hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
++                              HRTIMER_MODE_REL_SOFT);
+  done:
+       spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
+@@ -1326,7 +1327,7 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
+                       !list_empty(&dum_hcd->urbp_list))
+-              hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL);
++              hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL_SOFT);
+       spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
+       return rc;
+@@ -1996,7 +1997,8 @@ static enum hrtimer_restart dummy_timer(struct hrtimer *t)
+               dum_hcd->udev = NULL;
+       } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
+               /* want a 1 msec delay here */
+-              hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS), HRTIMER_MODE_REL);
++              hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
++                              HRTIMER_MODE_REL_SOFT);
+       }
+       spin_unlock_irqrestore(&dum->lock, flags);
+@@ -2390,7 +2392,7 @@ static int dummy_bus_resume(struct usb_hcd *hcd)
+               dum_hcd->rh_state = DUMMY_RH_RUNNING;
+               set_link_state(dum_hcd);
+               if (!list_empty(&dum_hcd->urbp_list))
+-                      hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL);
++                      hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL_SOFT);
+               hcd->state = HC_STATE_RUNNING;
+       }
+       spin_unlock_irq(&dum_hcd->dum->lock);
+@@ -2468,7 +2470,7 @@ static DEVICE_ATTR_RO(urbs);
+ static int dummy_start_ss(struct dummy_hcd *dum_hcd)
+ {
+-      hrtimer_init(&dum_hcd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
++      hrtimer_init(&dum_hcd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+       dum_hcd->timer.function = dummy_timer;
+       dum_hcd->rh_state = DUMMY_RH_RUNNING;
+       dum_hcd->stream_en_ep = 0;
+@@ -2498,7 +2500,7 @@ static int dummy_start(struct usb_hcd *hcd)
+               return dummy_start_ss(dum_hcd);
+       spin_lock_init(&dum_hcd->dum->lock);
+-      hrtimer_init(&dum_hcd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
++      hrtimer_init(&dum_hcd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+       dum_hcd->timer.function = dummy_timer;
+       dum_hcd->rh_state = DUMMY_RH_RUNNING;
+-- 
+2.43.0
+
diff --git a/queue-6.1/usb-gadget-dummy_hcd-set-transfer-interval-to-1-micr.patch b/queue-6.1/usb-gadget-dummy_hcd-set-transfer-interval-to-1-micr.patch
new file mode 100644 (file)
index 0000000..1df5f0a
--- /dev/null
@@ -0,0 +1,60 @@
+From 9d514adef89e7deb2adf6b0fd4b5c8f05b9101c4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 11 Apr 2024 17:22:11 +0200
+Subject: usb: gadget: dummy_hcd: Set transfer interval to 1 microframe
+
+From: Marcello Sylvester Bauer <sylv@sylv.io>
+
+[ Upstream commit 0a723ed3baa941ca4f51d87bab00661f41142835 ]
+
+Currently, the transfer polling interval is set to 1ms, which is the
+frame rate of full-speed and low-speed USB. The USB 2.0 specification
+introduces microframes (125 microseconds) to improve the timing
+precision of data transfers.
+
+Reducing the transfer interval to 1 microframe increases data throughput
+for high-speed and super-speed USB communication
+
+Signed-off-by: Marcello Sylvester Bauer <marcello.bauer@9elements.com>
+Signed-off-by: Marcello Sylvester Bauer <sylv@sylv.io>
+Link: https://lore.kernel.org/r/6295dbb84ca76884551df9eb157cce569377a22c.1712843963.git.sylv@sylv.io
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/gadget/udc/dummy_hcd.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
+index 4f9c6e86456fe..32a03de215d37 100644
+--- a/drivers/usb/gadget/udc/dummy_hcd.c
++++ b/drivers/usb/gadget/udc/dummy_hcd.c
+@@ -50,6 +50,8 @@
+ #define POWER_BUDGET  500     /* in mA; use 8 for low-power port testing */
+ #define POWER_BUDGET_3        900     /* in mA */
++#define DUMMY_TIMER_INT_NSECS 125000 /* 1 microframe */
++
+ static const char     driver_name[] = "dummy_hcd";
+ static const char     driver_desc[] = "USB Host+Gadget Emulator";
+@@ -1303,7 +1305,7 @@ static int dummy_urb_enqueue(
+       /* kick the scheduler, it'll do the rest */
+       if (!hrtimer_active(&dum_hcd->timer))
+-              hrtimer_start(&dum_hcd->timer, ms_to_ktime(1), HRTIMER_MODE_REL);
++              hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS), HRTIMER_MODE_REL);
+  done:
+       spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
+@@ -1994,7 +1996,7 @@ static enum hrtimer_restart dummy_timer(struct hrtimer *t)
+               dum_hcd->udev = NULL;
+       } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
+               /* want a 1 msec delay here */
+-              hrtimer_start(&dum_hcd->timer, ms_to_ktime(1), HRTIMER_MODE_REL);
++              hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS), HRTIMER_MODE_REL);
+       }
+       spin_unlock_irqrestore(&dum->lock, flags);
+-- 
+2.43.0
+
diff --git a/queue-6.1/usb-gadget-dummy_hcd-switch-to-hrtimer-transfer-sche.patch b/queue-6.1/usb-gadget-dummy_hcd-switch-to-hrtimer-transfer-sche.patch
new file mode 100644 (file)
index 0000000..4394781
--- /dev/null
@@ -0,0 +1,153 @@
+From 25489ee7043a92e4d8a17b04ce1f86f22ea047b2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 11 Apr 2024 16:51:28 +0200
+Subject: usb: gadget: dummy_hcd: Switch to hrtimer transfer scheduler
+
+From: Marcello Sylvester Bauer <sylv@sylv.io>
+
+[ Upstream commit a7f3813e589fd8e2834720829a47b5eb914a9afe ]
+
+The dummy_hcd transfer scheduler assumes that the internal kernel timer
+frequency is set to 1000Hz to give a polling interval of 1ms. Reducing
+the timer frequency will result in an anti-proportional reduction in
+transfer performance. Switch to a hrtimer to decouple this association.
+
+Signed-off-by: Marcello Sylvester Bauer <marcello.bauer@9elements.com>
+Signed-off-by: Marcello Sylvester Bauer <sylv@sylv.io>
+Reviewed-by: Alan Stern <stern@rowland.harvard.edu>
+Link: https://lore.kernel.org/r/57a1c2180ff74661600e010c234d1dbaba1d0d46.1712843963.git.sylv@sylv.io
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/gadget/udc/dummy_hcd.c | 35 +++++++++++++++++-------------
+ 1 file changed, 20 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
+index 899ac9f9c2796..4f9c6e86456fe 100644
+--- a/drivers/usb/gadget/udc/dummy_hcd.c
++++ b/drivers/usb/gadget/udc/dummy_hcd.c
+@@ -30,7 +30,7 @@
+ #include <linux/slab.h>
+ #include <linux/errno.h>
+ #include <linux/init.h>
+-#include <linux/timer.h>
++#include <linux/hrtimer.h>
+ #include <linux/list.h>
+ #include <linux/interrupt.h>
+ #include <linux/platform_device.h>
+@@ -240,7 +240,7 @@ enum dummy_rh_state {
+ struct dummy_hcd {
+       struct dummy                    *dum;
+       enum dummy_rh_state             rh_state;
+-      struct timer_list               timer;
++      struct hrtimer                  timer;
+       u32                             port_status;
+       u32                             old_status;
+       unsigned long                   re_timeout;
+@@ -1302,8 +1302,8 @@ static int dummy_urb_enqueue(
+               urb->error_count = 1;           /* mark as a new urb */
+       /* kick the scheduler, it'll do the rest */
+-      if (!timer_pending(&dum_hcd->timer))
+-              mod_timer(&dum_hcd->timer, jiffies + 1);
++      if (!hrtimer_active(&dum_hcd->timer))
++              hrtimer_start(&dum_hcd->timer, ms_to_ktime(1), HRTIMER_MODE_REL);
+  done:
+       spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
+@@ -1324,7 +1324,7 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
+                       !list_empty(&dum_hcd->urbp_list))
+-              mod_timer(&dum_hcd->timer, jiffies);
++              hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL);
+       spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
+       return rc;
+@@ -1778,7 +1778,7 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
+  * drivers except that the callbacks are invoked from soft interrupt
+  * context.
+  */
+-static void dummy_timer(struct timer_list *t)
++static enum hrtimer_restart dummy_timer(struct hrtimer *t)
+ {
+       struct dummy_hcd        *dum_hcd = from_timer(dum_hcd, t, timer);
+       struct dummy            *dum = dum_hcd->dum;
+@@ -1809,8 +1809,6 @@ static void dummy_timer(struct timer_list *t)
+               break;
+       }
+-      /* FIXME if HZ != 1000 this will probably misbehave ... */
+-
+       /* look at each urb queued by the host side driver */
+       spin_lock_irqsave(&dum->lock, flags);
+@@ -1818,7 +1816,7 @@ static void dummy_timer(struct timer_list *t)
+               dev_err(dummy_dev(dum_hcd),
+                               "timer fired with no URBs pending?\n");
+               spin_unlock_irqrestore(&dum->lock, flags);
+-              return;
++              return HRTIMER_NORESTART;
+       }
+       dum_hcd->next_frame_urbp = NULL;
+@@ -1996,10 +1994,12 @@ static void dummy_timer(struct timer_list *t)
+               dum_hcd->udev = NULL;
+       } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
+               /* want a 1 msec delay here */
+-              mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
++              hrtimer_start(&dum_hcd->timer, ms_to_ktime(1), HRTIMER_MODE_REL);
+       }
+       spin_unlock_irqrestore(&dum->lock, flags);
++
++      return HRTIMER_NORESTART;
+ }
+ /*-------------------------------------------------------------------------*/
+@@ -2388,7 +2388,7 @@ static int dummy_bus_resume(struct usb_hcd *hcd)
+               dum_hcd->rh_state = DUMMY_RH_RUNNING;
+               set_link_state(dum_hcd);
+               if (!list_empty(&dum_hcd->urbp_list))
+-                      mod_timer(&dum_hcd->timer, jiffies);
++                      hrtimer_start(&dum_hcd->timer, ns_to_ktime(0), HRTIMER_MODE_REL);
+               hcd->state = HC_STATE_RUNNING;
+       }
+       spin_unlock_irq(&dum_hcd->dum->lock);
+@@ -2466,7 +2466,8 @@ static DEVICE_ATTR_RO(urbs);
+ static int dummy_start_ss(struct dummy_hcd *dum_hcd)
+ {
+-      timer_setup(&dum_hcd->timer, dummy_timer, 0);
++      hrtimer_init(&dum_hcd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
++      dum_hcd->timer.function = dummy_timer;
+       dum_hcd->rh_state = DUMMY_RH_RUNNING;
+       dum_hcd->stream_en_ep = 0;
+       INIT_LIST_HEAD(&dum_hcd->urbp_list);
+@@ -2495,7 +2496,8 @@ static int dummy_start(struct usb_hcd *hcd)
+               return dummy_start_ss(dum_hcd);
+       spin_lock_init(&dum_hcd->dum->lock);
+-      timer_setup(&dum_hcd->timer, dummy_timer, 0);
++      hrtimer_init(&dum_hcd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
++      dum_hcd->timer.function = dummy_timer;
+       dum_hcd->rh_state = DUMMY_RH_RUNNING;
+       INIT_LIST_HEAD(&dum_hcd->urbp_list);
+@@ -2514,8 +2516,11 @@ static int dummy_start(struct usb_hcd *hcd)
+ static void dummy_stop(struct usb_hcd *hcd)
+ {
+-      device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
+-      dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
++      struct dummy_hcd        *dum_hcd = hcd_to_dummy_hcd(hcd);
++
++      hrtimer_cancel(&dum_hcd->timer);
++      device_remove_file(dummy_dev(dum_hcd), &dev_attr_urbs);
++      dev_info(dummy_dev(dum_hcd), "stopped\n");
+ }
+ /*-------------------------------------------------------------------------*/
+-- 
+2.43.0
+