mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-01 00:58:39 +02: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 @@ 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) | ||||||
| 		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…
	
		Reference in a new issue
	
	 Marcello Sylvester Bauer
						Marcello Sylvester Bauer