mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	sched_clock: Use an hrtimer instead of timer
In the next patch we're going to increase the number of bits that the generic sched_clock can handle to be greater than 32. With more than 32 bits the wraparound time can be larger than what can fit into the units that msecs_to_jiffies takes (unsigned int). Luckily, the wraparound is initially calculated in nanoseconds which we can easily use with hrtimers, so switch to using an hrtimer. Cc: Russell King <linux@arm.linux.org.uk> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> [jstultz: Fixup hrtimer intitialization order issue] Signed-off-by: John Stultz <john.stultz@linaro.org>
This commit is contained in:
		
							parent
							
								
									85c3d2dd15
								
							
						
					
					
						commit
						a08ca5d108
					
				
					 1 changed files with 21 additions and 17 deletions
				
			
		| 
						 | 
					@ -8,15 +8,17 @@
 | 
				
			||||||
#include <linux/clocksource.h>
 | 
					#include <linux/clocksource.h>
 | 
				
			||||||
#include <linux/init.h>
 | 
					#include <linux/init.h>
 | 
				
			||||||
#include <linux/jiffies.h>
 | 
					#include <linux/jiffies.h>
 | 
				
			||||||
 | 
					#include <linux/ktime.h>
 | 
				
			||||||
#include <linux/kernel.h>
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
#include <linux/moduleparam.h>
 | 
					#include <linux/moduleparam.h>
 | 
				
			||||||
#include <linux/sched.h>
 | 
					#include <linux/sched.h>
 | 
				
			||||||
#include <linux/syscore_ops.h>
 | 
					#include <linux/syscore_ops.h>
 | 
				
			||||||
#include <linux/timer.h>
 | 
					#include <linux/hrtimer.h>
 | 
				
			||||||
#include <linux/sched_clock.h>
 | 
					#include <linux/sched_clock.h>
 | 
				
			||||||
#include <linux/seqlock.h>
 | 
					#include <linux/seqlock.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct clock_data {
 | 
					struct clock_data {
 | 
				
			||||||
 | 
						ktime_t wrap_kt;
 | 
				
			||||||
	u64 epoch_ns;
 | 
						u64 epoch_ns;
 | 
				
			||||||
	u32 epoch_cyc;
 | 
						u32 epoch_cyc;
 | 
				
			||||||
	seqcount_t seq;
 | 
						seqcount_t seq;
 | 
				
			||||||
| 
						 | 
					@ -26,8 +28,7 @@ struct clock_data {
 | 
				
			||||||
	bool suspended;
 | 
						bool suspended;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void sched_clock_poll(unsigned long wrap_ticks);
 | 
					static struct hrtimer sched_clock_timer;
 | 
				
			||||||
static DEFINE_TIMER(sched_clock_timer, sched_clock_poll, 0, 0);
 | 
					 | 
				
			||||||
static int irqtime = -1;
 | 
					static int irqtime = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
core_param(irqtime, irqtime, int, 0400);
 | 
					core_param(irqtime, irqtime, int, 0400);
 | 
				
			||||||
| 
						 | 
					@ -93,15 +94,16 @@ static void notrace update_sched_clock(void)
 | 
				
			||||||
	raw_local_irq_restore(flags);
 | 
						raw_local_irq_restore(flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void sched_clock_poll(unsigned long wrap_ticks)
 | 
					static enum hrtimer_restart sched_clock_poll(struct hrtimer *hrt)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mod_timer(&sched_clock_timer, round_jiffies(jiffies + wrap_ticks));
 | 
					 | 
				
			||||||
	update_sched_clock();
 | 
						update_sched_clock();
 | 
				
			||||||
 | 
						hrtimer_forward_now(hrt, cd.wrap_kt);
 | 
				
			||||||
 | 
						return HRTIMER_RESTART;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
 | 
					void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long r, w;
 | 
						unsigned long r;
 | 
				
			||||||
	u64 res, wrap;
 | 
						u64 res, wrap;
 | 
				
			||||||
	char r_unit;
 | 
						char r_unit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -129,19 +131,13 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* calculate how many ns until we wrap */
 | 
						/* calculate how many ns until we wrap */
 | 
				
			||||||
	wrap = cyc_to_ns((1ULL << bits) - 1, cd.mult, cd.shift);
 | 
						wrap = cyc_to_ns((1ULL << bits) - 1, cd.mult, cd.shift);
 | 
				
			||||||
	do_div(wrap, NSEC_PER_MSEC);
 | 
						cd.wrap_kt = ns_to_ktime(wrap - (wrap >> 3));
 | 
				
			||||||
	w = wrap;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* calculate the ns resolution of this counter */
 | 
						/* calculate the ns resolution of this counter */
 | 
				
			||||||
	res = cyc_to_ns(1ULL, cd.mult, cd.shift);
 | 
						res = cyc_to_ns(1ULL, cd.mult, cd.shift);
 | 
				
			||||||
	pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lums\n",
 | 
						pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lluns\n",
 | 
				
			||||||
		bits, r, r_unit, res, w);
 | 
							bits, r, r_unit, res, wrap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Start the timer to keep sched_clock() properly updated and
 | 
					 | 
				
			||||||
	 * sets the initial epoch.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	sched_clock_timer.data = msecs_to_jiffies(w - (w / 10));
 | 
					 | 
				
			||||||
	update_sched_clock();
 | 
						update_sched_clock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -172,12 +168,20 @@ void __init sched_clock_postinit(void)
 | 
				
			||||||
	if (read_sched_clock == jiffy_sched_clock_read)
 | 
						if (read_sched_clock == jiffy_sched_clock_read)
 | 
				
			||||||
		setup_sched_clock(jiffy_sched_clock_read, 32, HZ);
 | 
							setup_sched_clock(jiffy_sched_clock_read, 32, HZ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sched_clock_poll(sched_clock_timer.data);
 | 
						update_sched_clock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Start the timer to keep sched_clock() properly updated and
 | 
				
			||||||
 | 
						 * sets the initial epoch.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 | 
				
			||||||
 | 
						sched_clock_timer.function = sched_clock_poll;
 | 
				
			||||||
 | 
						hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int sched_clock_suspend(void)
 | 
					static int sched_clock_suspend(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	sched_clock_poll(sched_clock_timer.data);
 | 
						sched_clock_poll(&sched_clock_timer);
 | 
				
			||||||
	cd.suspended = true;
 | 
						cd.suspended = true;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue