mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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: 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>
This commit is contained in:
parent
920e7522e3
commit
a7f3813e58
1 changed files with 20 additions and 15 deletions
|
@ -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 {
|
||||||
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(
|
||||||
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)
|
||||||
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,
|
||||||
* 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)
|
||||||
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)
|
||||||
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 @@ return_urb:
|
||||||
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)
|
||||||
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);
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
Loading…
Add table
Reference in a new issue