diff options
Diffstat (limited to 'kernel/hrtimer.c')
| -rw-r--r-- | kernel/hrtimer.c | 53 | 
1 files changed, 37 insertions, 16 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index ae34bf51682..6db7a5ed52b 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -657,6 +657,14 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,  	return 0;  } +static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base) +{ +	ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset; +	ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset; + +	return ktime_get_update_offsets(offs_real, offs_boot); +} +  /*   * Retrigger next event is called after clock was set   * @@ -665,22 +673,12 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,  static void retrigger_next_event(void *arg)  {  	struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases); -	struct timespec realtime_offset, xtim, wtm, sleep;  	if (!hrtimer_hres_active())  		return; -	/* Optimized out for !HIGH_RES */ -	get_xtime_and_monotonic_and_sleep_offset(&xtim, &wtm, &sleep); -	set_normalized_timespec(&realtime_offset, -wtm.tv_sec, -wtm.tv_nsec); - -	/* Adjust CLOCK_REALTIME offset */  	raw_spin_lock(&base->lock); -	base->clock_base[HRTIMER_BASE_REALTIME].offset = -		timespec_to_ktime(realtime_offset); -	base->clock_base[HRTIMER_BASE_BOOTTIME].offset = -		timespec_to_ktime(sleep); - +	hrtimer_update_base(base);  	hrtimer_force_reprogram(base, 0);  	raw_spin_unlock(&base->lock);  } @@ -710,13 +708,25 @@ static int hrtimer_switch_to_hres(void)  		base->clock_base[i].resolution = KTIME_HIGH_RES;  	tick_setup_sched_timer(); -  	/* "Retrigger" the interrupt to get things going */  	retrigger_next_event(NULL);  	local_irq_restore(flags);  	return 1;  } +/* + * Called from timekeeping code to reprogramm the hrtimer interrupt + * device. If called from the timer interrupt context we defer it to + * softirq context. + */ +void clock_was_set_delayed(void) +{ +	struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); + +	cpu_base->clock_was_set = 1; +	__raise_softirq_irqoff(HRTIMER_SOFTIRQ); +} +  #else  static inline int hrtimer_hres_active(void) { return 0; } @@ -1250,11 +1260,10 @@ void hrtimer_interrupt(struct clock_event_device *dev)  	cpu_base->nr_events++;  	dev->next_event.tv64 = KTIME_MAX; -	entry_time = now = ktime_get(); +	raw_spin_lock(&cpu_base->lock); +	entry_time = now = hrtimer_update_base(cpu_base);  retry:  	expires_next.tv64 = KTIME_MAX; - -	raw_spin_lock(&cpu_base->lock);  	/*  	 * We set expires_next to KTIME_MAX here with cpu_base->lock  	 * held to prevent that a timer is enqueued in our queue via @@ -1330,8 +1339,12 @@ retry:  	 * We need to prevent that we loop forever in the hrtimer  	 * interrupt routine. We give it 3 attempts to avoid  	 * overreacting on some spurious event. +	 * +	 * Acquire base lock for updating the offsets and retrieving +	 * the current time.  	 */ -	now = ktime_get(); +	raw_spin_lock(&cpu_base->lock); +	now = hrtimer_update_base(cpu_base);  	cpu_base->nr_retries++;  	if (++retries < 3)  		goto retry; @@ -1343,6 +1356,7 @@ retry:  	 */  	cpu_base->nr_hangs++;  	cpu_base->hang_detected = 1; +	raw_spin_unlock(&cpu_base->lock);  	delta = ktime_sub(now, entry_time);  	if (delta.tv64 > cpu_base->max_hang_time.tv64)  		cpu_base->max_hang_time = delta; @@ -1395,6 +1409,13 @@ void hrtimer_peek_ahead_timers(void)  static void run_hrtimer_softirq(struct softirq_action *h)  { +	struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); + +	if (cpu_base->clock_was_set) { +		cpu_base->clock_was_set = 0; +		clock_was_set(); +	} +  	hrtimer_peek_ahead_timers();  }  |