Commit a7f3813e authored by Marcello Sylvester Bauer's avatar Marcello Sylvester Bauer Committed by Greg Kroah-Hartman

usb: gadget: dummy_hcd: Switch to hrtimer transfer scheduler

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: default avatarMarcello Sylvester Bauer <marcello.bauer@9elements.com>
Signed-off-by: default avatarMarcello Sylvester Bauer <sylv@sylv.io>
Reviewed-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Link: https://lore.kernel.org/r/57a1c2180ff74661600e010c234d1dbaba1d0d46.1712843963.git.sylv@sylv.ioSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 920e7522
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/timer.h> #include <linux/hrtimer.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -240,7 +240,7 @@ enum dummy_rh_state { ...@@ -240,7 +240,7 @@ enum dummy_rh_state {
struct dummy_hcd { struct dummy_hcd {
struct dummy *dum; struct dummy *dum;
enum dummy_rh_state rh_state; enum dummy_rh_state rh_state;
struct timer_list timer; struct hrtimer timer;
u32 port_status; u32 port_status;
u32 old_status; u32 old_status;
unsigned long re_timeout; unsigned long re_timeout;
...@@ -1301,8 +1301,8 @@ static int dummy_urb_enqueue( ...@@ -1301,8 +1301,8 @@ static int dummy_urb_enqueue(
urb->error_count = 1; /* mark as a new urb */ urb->error_count = 1; /* mark as a new urb */
/* kick the scheduler, it'll do the rest */ /* kick the scheduler, it'll do the rest */
if (!timer_pending(&dum_hcd->timer)) if (!hrtimer_active(&dum_hcd->timer))
mod_timer(&dum_hcd->timer, jiffies + 1); hrtimer_start(&dum_hcd->timer, ms_to_ktime(1), HRTIMER_MODE_REL);
done: done:
spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
...@@ -1323,7 +1323,7 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) ...@@ -1323,7 +1323,7 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
rc = usb_hcd_check_unlink_urb(hcd, urb, status); rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING && if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
!list_empty(&dum_hcd->urbp_list)) !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); spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
return rc; return rc;
...@@ -1777,7 +1777,7 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb, ...@@ -1777,7 +1777,7 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
* drivers except that the callbacks are invoked from soft interrupt * drivers except that the callbacks are invoked from soft interrupt
* context. * 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_hcd *dum_hcd = from_timer(dum_hcd, t, timer);
struct dummy *dum = dum_hcd->dum; struct dummy *dum = dum_hcd->dum;
...@@ -1808,8 +1808,6 @@ static void dummy_timer(struct timer_list *t) ...@@ -1808,8 +1808,6 @@ static void dummy_timer(struct timer_list *t)
break; break;
} }
/* FIXME if HZ != 1000 this will probably misbehave ... */
/* look at each urb queued by the host side driver */ /* look at each urb queued by the host side driver */
spin_lock_irqsave(&dum->lock, flags); spin_lock_irqsave(&dum->lock, flags);
...@@ -1817,7 +1815,7 @@ static void dummy_timer(struct timer_list *t) ...@@ -1817,7 +1815,7 @@ static void dummy_timer(struct timer_list *t)
dev_err(dummy_dev(dum_hcd), dev_err(dummy_dev(dum_hcd),
"timer fired with no URBs pending?\n"); "timer fired with no URBs pending?\n");
spin_unlock_irqrestore(&dum->lock, flags); spin_unlock_irqrestore(&dum->lock, flags);
return; return HRTIMER_NORESTART;
} }
dum_hcd->next_frame_urbp = NULL; dum_hcd->next_frame_urbp = NULL;
...@@ -1995,10 +1993,12 @@ static void dummy_timer(struct timer_list *t) ...@@ -1995,10 +1993,12 @@ static void dummy_timer(struct timer_list *t)
dum_hcd->udev = NULL; dum_hcd->udev = NULL;
} else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) { } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
/* want a 1 msec delay here */ /* 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); spin_unlock_irqrestore(&dum->lock, flags);
return HRTIMER_NORESTART;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -2387,7 +2387,7 @@ static int dummy_bus_resume(struct usb_hcd *hcd) ...@@ -2387,7 +2387,7 @@ static int dummy_bus_resume(struct usb_hcd *hcd)
dum_hcd->rh_state = DUMMY_RH_RUNNING; dum_hcd->rh_state = DUMMY_RH_RUNNING;
set_link_state(dum_hcd); set_link_state(dum_hcd);
if (!list_empty(&dum_hcd->urbp_list)) 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; hcd->state = HC_STATE_RUNNING;
} }
spin_unlock_irq(&dum_hcd->dum->lock); spin_unlock_irq(&dum_hcd->dum->lock);
...@@ -2465,7 +2465,8 @@ static DEVICE_ATTR_RO(urbs); ...@@ -2465,7 +2465,8 @@ static DEVICE_ATTR_RO(urbs);
static int dummy_start_ss(struct dummy_hcd *dum_hcd) 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->rh_state = DUMMY_RH_RUNNING;
dum_hcd->stream_en_ep = 0; dum_hcd->stream_en_ep = 0;
INIT_LIST_HEAD(&dum_hcd->urbp_list); INIT_LIST_HEAD(&dum_hcd->urbp_list);
...@@ -2494,7 +2495,8 @@ static int dummy_start(struct usb_hcd *hcd) ...@@ -2494,7 +2495,8 @@ static int dummy_start(struct usb_hcd *hcd)
return dummy_start_ss(dum_hcd); return dummy_start_ss(dum_hcd);
spin_lock_init(&dum_hcd->dum->lock); 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; dum_hcd->rh_state = DUMMY_RH_RUNNING;
INIT_LIST_HEAD(&dum_hcd->urbp_list); INIT_LIST_HEAD(&dum_hcd->urbp_list);
...@@ -2513,8 +2515,11 @@ static int dummy_start(struct usb_hcd *hcd) ...@@ -2513,8 +2515,11 @@ static int dummy_start(struct usb_hcd *hcd)
static void dummy_stop(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); struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
hrtimer_cancel(&dum_hcd->timer);
device_remove_file(dummy_dev(dum_hcd), &dev_attr_urbs);
dev_info(dummy_dev(dum_hcd), "stopped\n");
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment