1244 lines · 33.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0+/* * This file contains the functions which manage clocksource drivers. * * Copyright (C) 2004, 2005 IBM, John Stultz (johnstul@us.ibm.com) */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/device.h>#include <linux/clocksource.h>#include <linux/init.h>#include <linux/module.h>#include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */#include <linux/tick.h>#include <linux/kthread.h> #include "tick-internal.h"#include "timekeeping_internal.h" /** * clocks_calc_mult_shift - calculate mult/shift factors for scaled math of clocks * @mult:	pointer to mult variable * @shift:	pointer to shift variable * @from:	frequency to convert from * @to:		frequency to convert to * @maxsec:	guaranteed runtime conversion range in seconds * * The function evaluates the shift/mult pair for the scaled math * operations of clocksources and clockevents. * * @to and @from are frequency values in HZ. For clock sources @to is * NSEC_PER_SEC == 1GHz and @from is the counter frequency. For clock * event @to is the counter frequency and @from is NSEC_PER_SEC. * * The @maxsec conversion range argument controls the time frame in * seconds which must be covered by the runtime conversion with the * calculated mult and shift factors. This guarantees that no 64bit * overflow happens when the input value of the conversion is * multiplied with the calculated mult factor. Larger ranges may * reduce the conversion accuracy by chosing smaller mult and shift * factors. */voidclocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 maxsec){	u64 tmp;	u32 sft, sftacc= 32; 	/*	 * Calculate the shift factor which is limiting the conversion	 * range:	 */	tmp = ((u64)maxsec * from) >> 32;	while (tmp) {		tmp >>=1;		sftacc--;	} 	/*	 * Find the conversion shift/mult pair which has the best	 * accuracy and fits the maxsec conversion range:	 */	for (sft = 32; sft > 0; sft--) {		tmp = (u64) to << sft;		tmp += from / 2;		do_div(tmp, from);		if ((tmp >> sftacc) == 0)			break;	}	*mult = tmp;	*shift = sft;}EXPORT_SYMBOL_GPL(clocks_calc_mult_shift); /*[Clocksource internal variables]--------- * curr_clocksource: *	currently selected clocksource. * suspend_clocksource: *	used to calculate the suspend time. * clocksource_list: *	linked list with the registered clocksources * clocksource_mutex: *	protects manipulations to curr_clocksource and the clocksource_list * override_name: *	Name of the user-specified clocksource. */static struct clocksource *curr_clocksource;static struct clocksource *suspend_clocksource;static LIST_HEAD(clocksource_list);static DEFINE_MUTEX(clocksource_mutex);static char override_name[CS_NAME_LEN];static int finished_booting;static u64 suspend_start; #ifdef CONFIG_CLOCKSOURCE_WATCHDOGstatic void clocksource_watchdog_work(struct work_struct *work);static void clocksource_select(void); static LIST_HEAD(watchdog_list);static struct clocksource *watchdog;static struct timer_list watchdog_timer;static DECLARE_WORK(watchdog_work, clocksource_watchdog_work);static DEFINE_SPINLOCK(watchdog_lock);static int watchdog_running;static atomic_t watchdog_reset_pending; static inline void clocksource_watchdog_lock(unsigned long *flags){	spin_lock_irqsave(&watchdog_lock, *flags);} static inline void clocksource_watchdog_unlock(unsigned long *flags){	spin_unlock_irqrestore(&watchdog_lock, *flags);} static int clocksource_watchdog_kthread(void *data);static void __clocksource_change_rating(struct clocksource *cs, int rating); /* * Interval: 0.5sec Threshold: 0.0625s */#define WATCHDOG_INTERVAL (HZ >> 1)#define WATCHDOG_THRESHOLD (NSEC_PER_SEC >> 4) static void clocksource_watchdog_work(struct work_struct *work){	/*	 * We cannot directly run clocksource_watchdog_kthread() here, because	 * clocksource_select() calls timekeeping_notify() which uses	 * stop_machine(). One cannot use stop_machine() from a workqueue() due	 * lock inversions wrt CPU hotplug.	 *	 * Also, we only ever run this work once or twice during the lifetime	 * of the kernel, so there is no point in creating a more permanent	 * kthread for this.	 *	 * If kthread_run fails the next watchdog scan over the	 * watchdog_list will find the unstable clock again.	 */	kthread_run(clocksource_watchdog_kthread, NULL, "kwatchdog");} static void __clocksource_unstable(struct clocksource *cs){	cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG);	cs->flags |= CLOCK_SOURCE_UNSTABLE; 	/*	 * If the clocksource is registered clocksource_watchdog_kthread() will	 * re-rate and re-select.	 */	if (list_empty(&cs->list)) {		cs->rating = 0;		return;	} 	if (cs->mark_unstable)		cs->mark_unstable(cs); 	/* kick clocksource_watchdog_kthread() */	if (finished_booting)		schedule_work(&watchdog_work);} /** * clocksource_mark_unstable - mark clocksource unstable via watchdog * @cs:		clocksource to be marked unstable * * This function is called by the x86 TSC code to mark clocksources as unstable; * it defers demotion and re-selection to a kthread. */void clocksource_mark_unstable(struct clocksource *cs){	unsigned long flags; 	spin_lock_irqsave(&watchdog_lock, flags);	if (!(cs->flags & CLOCK_SOURCE_UNSTABLE)) {		if (!list_empty(&cs->list) && list_empty(&cs->wd_list))			list_add(&cs->wd_list, &watchdog_list);		__clocksource_unstable(cs);	}	spin_unlock_irqrestore(&watchdog_lock, flags);} static void clocksource_watchdog(struct timer_list *unused){	struct clocksource *cs;	u64 csnow, wdnow, cslast, wdlast, delta;	int64_t wd_nsec, cs_nsec;	int next_cpu, reset_pending; 	spin_lock(&watchdog_lock);	if (!watchdog_running)		goto out; 	reset_pending = atomic_read(&watchdog_reset_pending); 	list_for_each_entry(cs, &watchdog_list, wd_list) { 		/* Clocksource already marked unstable? */		if (cs->flags & CLOCK_SOURCE_UNSTABLE) {			if (finished_booting)				schedule_work(&watchdog_work);			continue;		} 		local_irq_disable();		csnow = cs->read(cs);		wdnow = watchdog->read(watchdog);		local_irq_enable(); 		/* Clocksource initialized ? */		if (!(cs->flags & CLOCK_SOURCE_WATCHDOG) ||		    atomic_read(&watchdog_reset_pending)) {			cs->flags |= CLOCK_SOURCE_WATCHDOG;			cs->wd_last = wdnow;			cs->cs_last = csnow;			continue;		} 		delta = clocksource_delta(wdnow, cs->wd_last, watchdog->mask);		wd_nsec = clocksource_cyc2ns(delta, watchdog->mult,					     watchdog->shift); 		delta = clocksource_delta(csnow, cs->cs_last, cs->mask);		cs_nsec = clocksource_cyc2ns(delta, cs->mult, cs->shift);		wdlast = cs->wd_last; /* save these in case we print them */		cslast = cs->cs_last;		cs->cs_last = csnow;		cs->wd_last = wdnow; 		if (atomic_read(&watchdog_reset_pending))			continue; 		/* Check the deviation from the watchdog clocksource. */		if (abs(cs_nsec - wd_nsec) > WATCHDOG_THRESHOLD) {			pr_warn("timekeeping watchdog on CPU%d: Marking clocksource '%s' as unstable because the skew is too large:\n",				smp_processor_id(), cs->name);			pr_warn("                      '%s' wd_now: %llx wd_last: %llx mask: %llx\n",				watchdog->name, wdnow, wdlast, watchdog->mask);			pr_warn("                      '%s' cs_now: %llx cs_last: %llx mask: %llx\n",				cs->name, csnow, cslast, cs->mask);			__clocksource_unstable(cs);			continue;		} 		if (cs == curr_clocksource && cs->tick_stable)			cs->tick_stable(cs); 		if (!(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES) &&		    (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) &&		    (watchdog->flags & CLOCK_SOURCE_IS_CONTINUOUS)) {			/* Mark it valid for high-res. */			cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; 			/*			 * clocksource_done_booting() will sort it if			 * finished_booting is not set yet.			 */			if (!finished_booting)				continue; 			/*			 * If this is not the current clocksource let			 * the watchdog thread reselect it. Due to the			 * change to high res this clocksource might			 * be preferred now. If it is the current			 * clocksource let the tick code know about			 * that change.			 */			if (cs != curr_clocksource) {				cs->flags |= CLOCK_SOURCE_RESELECT;				schedule_work(&watchdog_work);			} else {				tick_clock_notify();			}		}	} 	/*	 * We only clear the watchdog_reset_pending, when we did a	 * full cycle through all clocksources.	 */	if (reset_pending)		atomic_dec(&watchdog_reset_pending); 	/*	 * Cycle through CPUs to check if the CPUs stay synchronized	 * to each other.	 */	next_cpu = cpumask_next(raw_smp_processor_id(), cpu_online_mask);	if (next_cpu >= nr_cpu_ids)		next_cpu = cpumask_first(cpu_online_mask); 	/*	 * Arm timer if not already pending: could race with concurrent	 * pair clocksource_stop_watchdog() clocksource_start_watchdog().	 */	if (!timer_pending(&watchdog_timer)) {		watchdog_timer.expires += WATCHDOG_INTERVAL;		add_timer_on(&watchdog_timer, next_cpu);	}out:	spin_unlock(&watchdog_lock);} static inline void clocksource_start_watchdog(void){	if (watchdog_running || !watchdog || list_empty(&watchdog_list))		return;	timer_setup(&watchdog_timer, clocksource_watchdog, 0);	watchdog_timer.expires = jiffies + WATCHDOG_INTERVAL;	add_timer_on(&watchdog_timer, cpumask_first(cpu_online_mask));	watchdog_running = 1;} static inline void clocksource_stop_watchdog(void){	if (!watchdog_running || (watchdog && !list_empty(&watchdog_list)))		return;	del_timer(&watchdog_timer);	watchdog_running = 0;} static inline void clocksource_reset_watchdog(void){	struct clocksource *cs; 	list_for_each_entry(cs, &watchdog_list, wd_list)		cs->flags &= ~CLOCK_SOURCE_WATCHDOG;} static void clocksource_resume_watchdog(void){	atomic_inc(&watchdog_reset_pending);} static void clocksource_enqueue_watchdog(struct clocksource *cs){	INIT_LIST_HEAD(&cs->wd_list); 	if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) {		/* cs is a clocksource to be watched. */		list_add(&cs->wd_list, &watchdog_list);		cs->flags &= ~CLOCK_SOURCE_WATCHDOG;	} else {		/* cs is a watchdog. */		if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS)			cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;	}} static void clocksource_select_watchdog(bool fallback){	struct clocksource *cs, *old_wd;	unsigned long flags; 	spin_lock_irqsave(&watchdog_lock, flags);	/* save current watchdog */	old_wd = watchdog;	if (fallback)		watchdog = NULL; 	list_for_each_entry(cs, &clocksource_list, list) {		/* cs is a clocksource to be watched. */		if (cs->flags & CLOCK_SOURCE_MUST_VERIFY)			continue; 		/* Skip current if we were requested for a fallback. */		if (fallback && cs == old_wd)			continue; 		/* Pick the best watchdog. */		if (!watchdog || cs->rating > watchdog->rating)			watchdog = cs;	}	/* If we failed to find a fallback restore the old one. */	if (!watchdog)		watchdog = old_wd; 	/* If we changed the watchdog we need to reset cycles. */	if (watchdog != old_wd)		clocksource_reset_watchdog(); 	/* Check if the watchdog timer needs to be started. */	clocksource_start_watchdog();	spin_unlock_irqrestore(&watchdog_lock, flags);} static void clocksource_dequeue_watchdog(struct clocksource *cs){	if (cs != watchdog) {		if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) {			/* cs is a watched clocksource. */			list_del_init(&cs->wd_list);			/* Check if the watchdog timer needs to be stopped. */			clocksource_stop_watchdog();		}	}} static int __clocksource_watchdog_kthread(void){	struct clocksource *cs, *tmp;	unsigned long flags;	int select = 0; 	spin_lock_irqsave(&watchdog_lock, flags);	list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) {		if (cs->flags & CLOCK_SOURCE_UNSTABLE) {			list_del_init(&cs->wd_list);			__clocksource_change_rating(cs, 0);			select = 1;		}		if (cs->flags & CLOCK_SOURCE_RESELECT) {			cs->flags &= ~CLOCK_SOURCE_RESELECT;			select = 1;		}	}	/* Check if the watchdog timer needs to be stopped. */	clocksource_stop_watchdog();	spin_unlock_irqrestore(&watchdog_lock, flags); 	return select;} static int clocksource_watchdog_kthread(void *data){	mutex_lock(&clocksource_mutex);	if (__clocksource_watchdog_kthread())		clocksource_select();	mutex_unlock(&clocksource_mutex);	return 0;} static bool clocksource_is_watchdog(struct clocksource *cs){	return cs == watchdog;} #else /* CONFIG_CLOCKSOURCE_WATCHDOG */ static void clocksource_enqueue_watchdog(struct clocksource *cs){	if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS)		cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;} static void clocksource_select_watchdog(bool fallback) { }static inline void clocksource_dequeue_watchdog(struct clocksource *cs) { }static inline void clocksource_resume_watchdog(void) { }static inline int __clocksource_watchdog_kthread(void) { return 0; }static bool clocksource_is_watchdog(struct clocksource *cs) { return false; }void clocksource_mark_unstable(struct clocksource *cs) { } static inline void clocksource_watchdog_lock(unsigned long *flags) { }static inline void clocksource_watchdog_unlock(unsigned long *flags) { } #endif /* CONFIG_CLOCKSOURCE_WATCHDOG */ static bool clocksource_is_suspend(struct clocksource *cs){	return cs == suspend_clocksource;} static void __clocksource_suspend_select(struct clocksource *cs){	/*	 * Skip the clocksource which will be stopped in suspend state.	 */	if (!(cs->flags & CLOCK_SOURCE_SUSPEND_NONSTOP))		return; 	/*	 * The nonstop clocksource can be selected as the suspend clocksource to	 * calculate the suspend time, so it should not supply suspend/resume	 * interfaces to suspend the nonstop clocksource when system suspends.	 */	if (cs->suspend || cs->resume) {		pr_warn("Nonstop clocksource %s should not supply suspend/resume interfaces\n",			cs->name);	} 	/* Pick the best rating. */	if (!suspend_clocksource || cs->rating > suspend_clocksource->rating)		suspend_clocksource = cs;} /** * clocksource_suspend_select - Select the best clocksource for suspend timing * @fallback:	if select a fallback clocksource */static void clocksource_suspend_select(bool fallback){	struct clocksource *cs, *old_suspend; 	old_suspend = suspend_clocksource;	if (fallback)

Lines 1–500 of 1244.