xref: /openbmc/linux/kernel/time/clocksource.c (revision 6bb74df4)
1734efb46Sjohn stultz /*
2734efb46Sjohn stultz  * linux/kernel/time/clocksource.c
3734efb46Sjohn stultz  *
4734efb46Sjohn stultz  * This file contains the functions which manage clocksource drivers.
5734efb46Sjohn stultz  *
6734efb46Sjohn stultz  * Copyright (C) 2004, 2005 IBM, John Stultz (johnstul@us.ibm.com)
7734efb46Sjohn stultz  *
8734efb46Sjohn stultz  * This program is free software; you can redistribute it and/or modify
9734efb46Sjohn stultz  * it under the terms of the GNU General Public License as published by
10734efb46Sjohn stultz  * the Free Software Foundation; either version 2 of the License, or
11734efb46Sjohn stultz  * (at your option) any later version.
12734efb46Sjohn stultz  *
13734efb46Sjohn stultz  * This program is distributed in the hope that it will be useful,
14734efb46Sjohn stultz  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15734efb46Sjohn stultz  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16734efb46Sjohn stultz  * GNU General Public License for more details.
17734efb46Sjohn stultz  *
18734efb46Sjohn stultz  * You should have received a copy of the GNU General Public License
19734efb46Sjohn stultz  * along with this program; if not, write to the Free Software
20734efb46Sjohn stultz  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21734efb46Sjohn stultz  *
22734efb46Sjohn stultz  * TODO WishList:
23734efb46Sjohn stultz  *   o Allow clocksource drivers to be unregistered
24734efb46Sjohn stultz  *   o get rid of clocksource_jiffies extern
25734efb46Sjohn stultz  */
26734efb46Sjohn stultz 
27734efb46Sjohn stultz #include <linux/clocksource.h>
28734efb46Sjohn stultz #include <linux/sysdev.h>
29734efb46Sjohn stultz #include <linux/init.h>
30734efb46Sjohn stultz #include <linux/module.h>
31dc29a365SMathieu Desnoyers #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */
3279bf2bb3SThomas Gleixner #include <linux/tick.h>
33734efb46Sjohn stultz 
34734efb46Sjohn stultz /* XXX - Would like a better way for initializing curr_clocksource */
35734efb46Sjohn stultz extern struct clocksource clocksource_jiffies;
36734efb46Sjohn stultz 
37734efb46Sjohn stultz /*[Clocksource internal variables]---------
38734efb46Sjohn stultz  * curr_clocksource:
39734efb46Sjohn stultz  *	currently selected clocksource. Initialized to clocksource_jiffies.
40734efb46Sjohn stultz  * next_clocksource:
41734efb46Sjohn stultz  *	pending next selected clocksource.
42734efb46Sjohn stultz  * clocksource_list:
43734efb46Sjohn stultz  *	linked list with the registered clocksources
44734efb46Sjohn stultz  * clocksource_lock:
45734efb46Sjohn stultz  *	protects manipulations to curr_clocksource and next_clocksource
46734efb46Sjohn stultz  *	and the clocksource_list
47734efb46Sjohn stultz  * override_name:
48734efb46Sjohn stultz  *	Name of the user-specified clocksource.
49734efb46Sjohn stultz  */
50734efb46Sjohn stultz static struct clocksource *curr_clocksource = &clocksource_jiffies;
51734efb46Sjohn stultz static struct clocksource *next_clocksource;
5292c7e002SThomas Gleixner static struct clocksource *clocksource_override;
53734efb46Sjohn stultz static LIST_HEAD(clocksource_list);
54734efb46Sjohn stultz static DEFINE_SPINLOCK(clocksource_lock);
55734efb46Sjohn stultz static char override_name[32];
56734efb46Sjohn stultz static int finished_booting;
57734efb46Sjohn stultz 
586bb74df4Sjohn stultz /* clocksource_done_booting - Called near the end of core bootup
59734efb46Sjohn stultz  *
606bb74df4Sjohn stultz  * Hack to avoid lots of clocksource churn at boot time.
616bb74df4Sjohn stultz  * We use fs_initcall because we want this to start before
626bb74df4Sjohn stultz  * device_initcall but after subsys_initcall.
63734efb46Sjohn stultz  */
64ad596171Sjohn stultz static int __init clocksource_done_booting(void)
65734efb46Sjohn stultz {
66734efb46Sjohn stultz 	finished_booting = 1;
67734efb46Sjohn stultz 	return 0;
68734efb46Sjohn stultz }
696bb74df4Sjohn stultz fs_initcall(clocksource_done_booting);
70734efb46Sjohn stultz 
715d8b34fdSThomas Gleixner #ifdef CONFIG_CLOCKSOURCE_WATCHDOG
725d8b34fdSThomas Gleixner static LIST_HEAD(watchdog_list);
735d8b34fdSThomas Gleixner static struct clocksource *watchdog;
745d8b34fdSThomas Gleixner static struct timer_list watchdog_timer;
755d8b34fdSThomas Gleixner static DEFINE_SPINLOCK(watchdog_lock);
765d8b34fdSThomas Gleixner static cycle_t watchdog_last;
775d8b34fdSThomas Gleixner /*
785d8b34fdSThomas Gleixner  * Interval: 0.5sec Treshold: 0.0625s
795d8b34fdSThomas Gleixner  */
805d8b34fdSThomas Gleixner #define WATCHDOG_INTERVAL (HZ >> 1)
815d8b34fdSThomas Gleixner #define WATCHDOG_TRESHOLD (NSEC_PER_SEC >> 4)
825d8b34fdSThomas Gleixner 
835d8b34fdSThomas Gleixner static void clocksource_ratewd(struct clocksource *cs, int64_t delta)
845d8b34fdSThomas Gleixner {
855d8b34fdSThomas Gleixner 	if (delta > -WATCHDOG_TRESHOLD && delta < WATCHDOG_TRESHOLD)
865d8b34fdSThomas Gleixner 		return;
875d8b34fdSThomas Gleixner 
885d8b34fdSThomas Gleixner 	printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n",
895d8b34fdSThomas Gleixner 	       cs->name, delta);
905d8b34fdSThomas Gleixner 	cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG);
915d8b34fdSThomas Gleixner 	clocksource_change_rating(cs, 0);
925d8b34fdSThomas Gleixner 	cs->flags &= ~CLOCK_SOURCE_WATCHDOG;
935d8b34fdSThomas Gleixner 	list_del(&cs->wd_list);
945d8b34fdSThomas Gleixner }
955d8b34fdSThomas Gleixner 
965d8b34fdSThomas Gleixner static void clocksource_watchdog(unsigned long data)
975d8b34fdSThomas Gleixner {
985d8b34fdSThomas Gleixner 	struct clocksource *cs, *tmp;
995d8b34fdSThomas Gleixner 	cycle_t csnow, wdnow;
1005d8b34fdSThomas Gleixner 	int64_t wd_nsec, cs_nsec;
1015d8b34fdSThomas Gleixner 
1025d8b34fdSThomas Gleixner 	spin_lock(&watchdog_lock);
1035d8b34fdSThomas Gleixner 
1045d8b34fdSThomas Gleixner 	wdnow = watchdog->read();
1055d8b34fdSThomas Gleixner 	wd_nsec = cyc2ns(watchdog, (wdnow - watchdog_last) & watchdog->mask);
1065d8b34fdSThomas Gleixner 	watchdog_last = wdnow;
1075d8b34fdSThomas Gleixner 
1085d8b34fdSThomas Gleixner 	list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) {
1095d8b34fdSThomas Gleixner 		csnow = cs->read();
1105d8b34fdSThomas Gleixner 		/* Initialized ? */
1115d8b34fdSThomas Gleixner 		if (!(cs->flags & CLOCK_SOURCE_WATCHDOG)) {
1125d8b34fdSThomas Gleixner 			if ((cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) &&
1135d8b34fdSThomas Gleixner 			    (watchdog->flags & CLOCK_SOURCE_IS_CONTINUOUS)) {
1145d8b34fdSThomas Gleixner 				cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
11579bf2bb3SThomas Gleixner 				/*
11679bf2bb3SThomas Gleixner 				 * We just marked the clocksource as
11779bf2bb3SThomas Gleixner 				 * highres-capable, notify the rest of the
11879bf2bb3SThomas Gleixner 				 * system as well so that we transition
11979bf2bb3SThomas Gleixner 				 * into high-res mode:
12079bf2bb3SThomas Gleixner 				 */
12179bf2bb3SThomas Gleixner 				tick_clock_notify();
1225d8b34fdSThomas Gleixner 			}
1235d8b34fdSThomas Gleixner 			cs->flags |= CLOCK_SOURCE_WATCHDOG;
1245d8b34fdSThomas Gleixner 			cs->wd_last = csnow;
1255d8b34fdSThomas Gleixner 		} else {
1265d8b34fdSThomas Gleixner 			cs_nsec = cyc2ns(cs, (csnow - cs->wd_last) & cs->mask);
1275d8b34fdSThomas Gleixner 			cs->wd_last = csnow;
1285d8b34fdSThomas Gleixner 			/* Check the delta. Might remove from the list ! */
1295d8b34fdSThomas Gleixner 			clocksource_ratewd(cs, cs_nsec - wd_nsec);
1305d8b34fdSThomas Gleixner 		}
1315d8b34fdSThomas Gleixner 	}
1325d8b34fdSThomas Gleixner 
1335d8b34fdSThomas Gleixner 	if (!list_empty(&watchdog_list)) {
1345d8b34fdSThomas Gleixner 		__mod_timer(&watchdog_timer,
1355d8b34fdSThomas Gleixner 			    watchdog_timer.expires + WATCHDOG_INTERVAL);
1365d8b34fdSThomas Gleixner 	}
1375d8b34fdSThomas Gleixner 	spin_unlock(&watchdog_lock);
1385d8b34fdSThomas Gleixner }
1395d8b34fdSThomas Gleixner static void clocksource_check_watchdog(struct clocksource *cs)
1405d8b34fdSThomas Gleixner {
1415d8b34fdSThomas Gleixner 	struct clocksource *cse;
1425d8b34fdSThomas Gleixner 	unsigned long flags;
1435d8b34fdSThomas Gleixner 
1445d8b34fdSThomas Gleixner 	spin_lock_irqsave(&watchdog_lock, flags);
1455d8b34fdSThomas Gleixner 	if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) {
1465d8b34fdSThomas Gleixner 		int started = !list_empty(&watchdog_list);
1475d8b34fdSThomas Gleixner 
1485d8b34fdSThomas Gleixner 		list_add(&cs->wd_list, &watchdog_list);
1495d8b34fdSThomas Gleixner 		if (!started && watchdog) {
1505d8b34fdSThomas Gleixner 			watchdog_last = watchdog->read();
1515d8b34fdSThomas Gleixner 			watchdog_timer.expires = jiffies + WATCHDOG_INTERVAL;
1525d8b34fdSThomas Gleixner 			add_timer(&watchdog_timer);
1535d8b34fdSThomas Gleixner 		}
1545d8b34fdSThomas Gleixner 	} else if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) {
1555d8b34fdSThomas Gleixner 			cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
1565d8b34fdSThomas Gleixner 
1575d8b34fdSThomas Gleixner 		if (!watchdog || cs->rating > watchdog->rating) {
1585d8b34fdSThomas Gleixner 			if (watchdog)
1595d8b34fdSThomas Gleixner 				del_timer(&watchdog_timer);
1605d8b34fdSThomas Gleixner 			watchdog = cs;
1615d8b34fdSThomas Gleixner 			init_timer(&watchdog_timer);
1625d8b34fdSThomas Gleixner 			watchdog_timer.function = clocksource_watchdog;
1635d8b34fdSThomas Gleixner 
1645d8b34fdSThomas Gleixner 			/* Reset watchdog cycles */
1655d8b34fdSThomas Gleixner 			list_for_each_entry(cse, &watchdog_list, wd_list)
1665d8b34fdSThomas Gleixner 				cse->flags &= ~CLOCK_SOURCE_WATCHDOG;
1675d8b34fdSThomas Gleixner 			/* Start if list is not empty */
1685d8b34fdSThomas Gleixner 			if (!list_empty(&watchdog_list)) {
1695d8b34fdSThomas Gleixner 				watchdog_last = watchdog->read();
1705d8b34fdSThomas Gleixner 				watchdog_timer.expires =
1715d8b34fdSThomas Gleixner 					jiffies + WATCHDOG_INTERVAL;
1725d8b34fdSThomas Gleixner 				add_timer(&watchdog_timer);
1735d8b34fdSThomas Gleixner 			}
1745d8b34fdSThomas Gleixner 		}
1755d8b34fdSThomas Gleixner 	}
1765d8b34fdSThomas Gleixner 	spin_unlock_irqrestore(&watchdog_lock, flags);
1775d8b34fdSThomas Gleixner }
1785d8b34fdSThomas Gleixner #else
1795d8b34fdSThomas Gleixner static void clocksource_check_watchdog(struct clocksource *cs)
1805d8b34fdSThomas Gleixner {
1815d8b34fdSThomas Gleixner 	if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS)
1825d8b34fdSThomas Gleixner 		cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
1835d8b34fdSThomas Gleixner }
1845d8b34fdSThomas Gleixner #endif
1855d8b34fdSThomas Gleixner 
186734efb46Sjohn stultz /**
187a2752549Sjohn stultz  * clocksource_get_next - Returns the selected clocksource
188734efb46Sjohn stultz  *
189734efb46Sjohn stultz  */
190a2752549Sjohn stultz struct clocksource *clocksource_get_next(void)
191734efb46Sjohn stultz {
192734efb46Sjohn stultz 	unsigned long flags;
193734efb46Sjohn stultz 
194734efb46Sjohn stultz 	spin_lock_irqsave(&clocksource_lock, flags);
195734efb46Sjohn stultz 	if (next_clocksource && finished_booting) {
196734efb46Sjohn stultz 		curr_clocksource = next_clocksource;
197734efb46Sjohn stultz 		next_clocksource = NULL;
198734efb46Sjohn stultz 	}
199734efb46Sjohn stultz 	spin_unlock_irqrestore(&clocksource_lock, flags);
200734efb46Sjohn stultz 
201734efb46Sjohn stultz 	return curr_clocksource;
202734efb46Sjohn stultz }
203734efb46Sjohn stultz 
204734efb46Sjohn stultz /**
20592c7e002SThomas Gleixner  * select_clocksource - Selects the best registered clocksource.
206734efb46Sjohn stultz  *
207734efb46Sjohn stultz  * Private function. Must hold clocksource_lock when called.
208734efb46Sjohn stultz  *
20992c7e002SThomas Gleixner  * Select the clocksource with the best rating, or the clocksource,
21092c7e002SThomas Gleixner  * which is selected by userspace override.
211734efb46Sjohn stultz  */
212734efb46Sjohn stultz static struct clocksource *select_clocksource(void)
213734efb46Sjohn stultz {
2145d8b34fdSThomas Gleixner 	struct clocksource *next;
2155d8b34fdSThomas Gleixner 
21692c7e002SThomas Gleixner 	if (list_empty(&clocksource_list))
21792c7e002SThomas Gleixner 		return NULL;
218734efb46Sjohn stultz 
21992c7e002SThomas Gleixner 	if (clocksource_override)
2205d8b34fdSThomas Gleixner 		next = clocksource_override;
2215d8b34fdSThomas Gleixner 	else
2225d8b34fdSThomas Gleixner 		next = list_entry(clocksource_list.next, struct clocksource,
2235d8b34fdSThomas Gleixner 				  list);
224734efb46Sjohn stultz 
2255d8b34fdSThomas Gleixner 	if (next == curr_clocksource)
2265d8b34fdSThomas Gleixner 		return NULL;
2275d8b34fdSThomas Gleixner 
2285d8b34fdSThomas Gleixner 	return next;
229734efb46Sjohn stultz }
230734efb46Sjohn stultz 
23192c7e002SThomas Gleixner /*
23292c7e002SThomas Gleixner  * Enqueue the clocksource sorted by rating
233734efb46Sjohn stultz  */
23492c7e002SThomas Gleixner static int clocksource_enqueue(struct clocksource *c)
235734efb46Sjohn stultz {
23692c7e002SThomas Gleixner 	struct list_head *tmp, *entry = &clocksource_list;
237734efb46Sjohn stultz 
238734efb46Sjohn stultz 	list_for_each(tmp, &clocksource_list) {
23992c7e002SThomas Gleixner 		struct clocksource *cs;
240734efb46Sjohn stultz 
24192c7e002SThomas Gleixner 		cs = list_entry(tmp, struct clocksource, list);
24292c7e002SThomas Gleixner 		if (cs == c)
24392c7e002SThomas Gleixner 			return -EBUSY;
24492c7e002SThomas Gleixner 		/* Keep track of the place, where to insert */
24592c7e002SThomas Gleixner 		if (cs->rating >= c->rating)
24692c7e002SThomas Gleixner 			entry = tmp;
247734efb46Sjohn stultz 	}
24892c7e002SThomas Gleixner 	list_add(&c->list, entry);
24992c7e002SThomas Gleixner 
25092c7e002SThomas Gleixner 	if (strlen(c->name) == strlen(override_name) &&
25192c7e002SThomas Gleixner 	    !strcmp(c->name, override_name))
25292c7e002SThomas Gleixner 		clocksource_override = c;
253734efb46Sjohn stultz 
254734efb46Sjohn stultz 	return 0;
255734efb46Sjohn stultz }
256734efb46Sjohn stultz 
257734efb46Sjohn stultz /**
258a2752549Sjohn stultz  * clocksource_register - Used to install new clocksources
259734efb46Sjohn stultz  * @t:		clocksource to be registered
260734efb46Sjohn stultz  *
261734efb46Sjohn stultz  * Returns -EBUSY if registration fails, zero otherwise.
262734efb46Sjohn stultz  */
263a2752549Sjohn stultz int clocksource_register(struct clocksource *c)
264734efb46Sjohn stultz {
265734efb46Sjohn stultz 	unsigned long flags;
2665d8b34fdSThomas Gleixner 	int ret;
267734efb46Sjohn stultz 
268734efb46Sjohn stultz 	spin_lock_irqsave(&clocksource_lock, flags);
26992c7e002SThomas Gleixner 	ret = clocksource_enqueue(c);
27092c7e002SThomas Gleixner 	if (!ret)
271734efb46Sjohn stultz 		next_clocksource = select_clocksource();
272734efb46Sjohn stultz 	spin_unlock_irqrestore(&clocksource_lock, flags);
2735d8b34fdSThomas Gleixner 	if (!ret)
2745d8b34fdSThomas Gleixner 		clocksource_check_watchdog(c);
275734efb46Sjohn stultz 	return ret;
276734efb46Sjohn stultz }
277a2752549Sjohn stultz EXPORT_SYMBOL(clocksource_register);
278734efb46Sjohn stultz 
279734efb46Sjohn stultz /**
28092c7e002SThomas Gleixner  * clocksource_change_rating - Change the rating of a registered clocksource
281734efb46Sjohn stultz  *
282734efb46Sjohn stultz  */
28392c7e002SThomas Gleixner void clocksource_change_rating(struct clocksource *cs, int rating)
284734efb46Sjohn stultz {
285734efb46Sjohn stultz 	unsigned long flags;
286734efb46Sjohn stultz 
287734efb46Sjohn stultz 	spin_lock_irqsave(&clocksource_lock, flags);
28892c7e002SThomas Gleixner 	list_del(&cs->list);
2895d8b34fdSThomas Gleixner 	cs->rating = rating;
29092c7e002SThomas Gleixner 	clocksource_enqueue(cs);
291734efb46Sjohn stultz 	next_clocksource = select_clocksource();
292734efb46Sjohn stultz 	spin_unlock_irqrestore(&clocksource_lock, flags);
293734efb46Sjohn stultz }
294734efb46Sjohn stultz 
2952b013700SDaniel Walker #ifdef CONFIG_SYSFS
296734efb46Sjohn stultz /**
297734efb46Sjohn stultz  * sysfs_show_current_clocksources - sysfs interface for current clocksource
298734efb46Sjohn stultz  * @dev:	unused
299734efb46Sjohn stultz  * @buf:	char buffer to be filled with clocksource list
300734efb46Sjohn stultz  *
301734efb46Sjohn stultz  * Provides sysfs interface for listing current clocksource.
302734efb46Sjohn stultz  */
303734efb46Sjohn stultz static ssize_t
304734efb46Sjohn stultz sysfs_show_current_clocksources(struct sys_device *dev, char *buf)
305734efb46Sjohn stultz {
306734efb46Sjohn stultz 	char *curr = buf;
307734efb46Sjohn stultz 
308734efb46Sjohn stultz 	spin_lock_irq(&clocksource_lock);
309734efb46Sjohn stultz 	curr += sprintf(curr, "%s ", curr_clocksource->name);
310734efb46Sjohn stultz 	spin_unlock_irq(&clocksource_lock);
311734efb46Sjohn stultz 
312734efb46Sjohn stultz 	curr += sprintf(curr, "\n");
313734efb46Sjohn stultz 
314734efb46Sjohn stultz 	return curr - buf;
315734efb46Sjohn stultz }
316734efb46Sjohn stultz 
317734efb46Sjohn stultz /**
318734efb46Sjohn stultz  * sysfs_override_clocksource - interface for manually overriding clocksource
319734efb46Sjohn stultz  * @dev:	unused
320734efb46Sjohn stultz  * @buf:	name of override clocksource
321734efb46Sjohn stultz  * @count:	length of buffer
322734efb46Sjohn stultz  *
323734efb46Sjohn stultz  * Takes input from sysfs interface for manually overriding the default
324734efb46Sjohn stultz  * clocksource selction.
325734efb46Sjohn stultz  */
326734efb46Sjohn stultz static ssize_t sysfs_override_clocksource(struct sys_device *dev,
327734efb46Sjohn stultz 					  const char *buf, size_t count)
328734efb46Sjohn stultz {
32992c7e002SThomas Gleixner 	struct clocksource *ovr = NULL;
33092c7e002SThomas Gleixner 	struct list_head *tmp;
331734efb46Sjohn stultz 	size_t ret = count;
33292c7e002SThomas Gleixner 	int len;
33392c7e002SThomas Gleixner 
334734efb46Sjohn stultz 	/* strings from sysfs write are not 0 terminated! */
335734efb46Sjohn stultz 	if (count >= sizeof(override_name))
336734efb46Sjohn stultz 		return -EINVAL;
337734efb46Sjohn stultz 
338734efb46Sjohn stultz 	/* strip of \n: */
339734efb46Sjohn stultz 	if (buf[count-1] == '\n')
340734efb46Sjohn stultz 		count--;
341734efb46Sjohn stultz 
342734efb46Sjohn stultz 	spin_lock_irq(&clocksource_lock);
343734efb46Sjohn stultz 
34492c7e002SThomas Gleixner 	if (count > 0)
345734efb46Sjohn stultz 		memcpy(override_name, buf, count);
346734efb46Sjohn stultz 	override_name[count] = 0;
347734efb46Sjohn stultz 
34892c7e002SThomas Gleixner 	len = strlen(override_name);
34992c7e002SThomas Gleixner 	if (len) {
35092c7e002SThomas Gleixner 		ovr = clocksource_override;
351734efb46Sjohn stultz 		/* try to select it: */
35292c7e002SThomas Gleixner 		list_for_each(tmp, &clocksource_list) {
35392c7e002SThomas Gleixner 			struct clocksource *cs;
35492c7e002SThomas Gleixner 
35592c7e002SThomas Gleixner 			cs = list_entry(tmp, struct clocksource, list);
35692c7e002SThomas Gleixner 			if (strlen(cs->name) == len &&
35792c7e002SThomas Gleixner 			    !strcmp(cs->name, override_name))
35892c7e002SThomas Gleixner 				ovr = cs;
35992c7e002SThomas Gleixner 		}
36092c7e002SThomas Gleixner 	}
36192c7e002SThomas Gleixner 
36292c7e002SThomas Gleixner 	/* Reselect, when the override name has changed */
36392c7e002SThomas Gleixner 	if (ovr != clocksource_override) {
36492c7e002SThomas Gleixner 		clocksource_override = ovr;
365734efb46Sjohn stultz 		next_clocksource = select_clocksource();
36692c7e002SThomas Gleixner 	}
367734efb46Sjohn stultz 
368734efb46Sjohn stultz 	spin_unlock_irq(&clocksource_lock);
369734efb46Sjohn stultz 
370734efb46Sjohn stultz 	return ret;
371734efb46Sjohn stultz }
372734efb46Sjohn stultz 
373734efb46Sjohn stultz /**
374734efb46Sjohn stultz  * sysfs_show_available_clocksources - sysfs interface for listing clocksource
375734efb46Sjohn stultz  * @dev:	unused
376734efb46Sjohn stultz  * @buf:	char buffer to be filled with clocksource list
377734efb46Sjohn stultz  *
378734efb46Sjohn stultz  * Provides sysfs interface for listing registered clocksources
379734efb46Sjohn stultz  */
380734efb46Sjohn stultz static ssize_t
381734efb46Sjohn stultz sysfs_show_available_clocksources(struct sys_device *dev, char *buf)
382734efb46Sjohn stultz {
383734efb46Sjohn stultz 	struct list_head *tmp;
384734efb46Sjohn stultz 	char *curr = buf;
385734efb46Sjohn stultz 
386734efb46Sjohn stultz 	spin_lock_irq(&clocksource_lock);
387734efb46Sjohn stultz 	list_for_each(tmp, &clocksource_list) {
388734efb46Sjohn stultz 		struct clocksource *src;
389734efb46Sjohn stultz 
390734efb46Sjohn stultz 		src = list_entry(tmp, struct clocksource, list);
391734efb46Sjohn stultz 		curr += sprintf(curr, "%s ", src->name);
392734efb46Sjohn stultz 	}
393734efb46Sjohn stultz 	spin_unlock_irq(&clocksource_lock);
394734efb46Sjohn stultz 
395734efb46Sjohn stultz 	curr += sprintf(curr, "\n");
396734efb46Sjohn stultz 
397734efb46Sjohn stultz 	return curr - buf;
398734efb46Sjohn stultz }
399734efb46Sjohn stultz 
400734efb46Sjohn stultz /*
401734efb46Sjohn stultz  * Sysfs setup bits:
402734efb46Sjohn stultz  */
403734efb46Sjohn stultz static SYSDEV_ATTR(current_clocksource, 0600, sysfs_show_current_clocksources,
404734efb46Sjohn stultz 		   sysfs_override_clocksource);
405734efb46Sjohn stultz 
406734efb46Sjohn stultz static SYSDEV_ATTR(available_clocksource, 0600,
407734efb46Sjohn stultz 		   sysfs_show_available_clocksources, NULL);
408734efb46Sjohn stultz 
409734efb46Sjohn stultz static struct sysdev_class clocksource_sysclass = {
410734efb46Sjohn stultz 	set_kset_name("clocksource"),
411734efb46Sjohn stultz };
412734efb46Sjohn stultz 
413734efb46Sjohn stultz static struct sys_device device_clocksource = {
414734efb46Sjohn stultz 	.id	= 0,
415734efb46Sjohn stultz 	.cls	= &clocksource_sysclass,
416734efb46Sjohn stultz };
417734efb46Sjohn stultz 
418ad596171Sjohn stultz static int __init init_clocksource_sysfs(void)
419734efb46Sjohn stultz {
420734efb46Sjohn stultz 	int error = sysdev_class_register(&clocksource_sysclass);
421734efb46Sjohn stultz 
422734efb46Sjohn stultz 	if (!error)
423734efb46Sjohn stultz 		error = sysdev_register(&device_clocksource);
424734efb46Sjohn stultz 	if (!error)
425734efb46Sjohn stultz 		error = sysdev_create_file(
426734efb46Sjohn stultz 				&device_clocksource,
427734efb46Sjohn stultz 				&attr_current_clocksource);
428734efb46Sjohn stultz 	if (!error)
429734efb46Sjohn stultz 		error = sysdev_create_file(
430734efb46Sjohn stultz 				&device_clocksource,
431734efb46Sjohn stultz 				&attr_available_clocksource);
432734efb46Sjohn stultz 	return error;
433734efb46Sjohn stultz }
434734efb46Sjohn stultz 
435734efb46Sjohn stultz device_initcall(init_clocksource_sysfs);
4362b013700SDaniel Walker #endif /* CONFIG_SYSFS */
437734efb46Sjohn stultz 
438734efb46Sjohn stultz /**
439734efb46Sjohn stultz  * boot_override_clocksource - boot clock override
440734efb46Sjohn stultz  * @str:	override name
441734efb46Sjohn stultz  *
442734efb46Sjohn stultz  * Takes a clocksource= boot argument and uses it
443734efb46Sjohn stultz  * as the clocksource override name.
444734efb46Sjohn stultz  */
445734efb46Sjohn stultz static int __init boot_override_clocksource(char* str)
446734efb46Sjohn stultz {
447734efb46Sjohn stultz 	unsigned long flags;
448734efb46Sjohn stultz 	spin_lock_irqsave(&clocksource_lock, flags);
449734efb46Sjohn stultz 	if (str)
450734efb46Sjohn stultz 		strlcpy(override_name, str, sizeof(override_name));
451734efb46Sjohn stultz 	spin_unlock_irqrestore(&clocksource_lock, flags);
452734efb46Sjohn stultz 	return 1;
453734efb46Sjohn stultz }
454734efb46Sjohn stultz 
455734efb46Sjohn stultz __setup("clocksource=", boot_override_clocksource);
456734efb46Sjohn stultz 
457734efb46Sjohn stultz /**
458734efb46Sjohn stultz  * boot_override_clock - Compatibility layer for deprecated boot option
459734efb46Sjohn stultz  * @str:	override name
460734efb46Sjohn stultz  *
461734efb46Sjohn stultz  * DEPRECATED! Takes a clock= boot argument and uses it
462734efb46Sjohn stultz  * as the clocksource override name
463734efb46Sjohn stultz  */
464734efb46Sjohn stultz static int __init boot_override_clock(char* str)
465734efb46Sjohn stultz {
4665d0cf410Sjohn stultz 	if (!strcmp(str, "pmtmr")) {
4675d0cf410Sjohn stultz 		printk("Warning: clock=pmtmr is deprecated. "
4685d0cf410Sjohn stultz 			"Use clocksource=acpi_pm.\n");
4695d0cf410Sjohn stultz 		return boot_override_clocksource("acpi_pm");
4705d0cf410Sjohn stultz 	}
4715d0cf410Sjohn stultz 	printk("Warning! clock= boot option is deprecated. "
4725d0cf410Sjohn stultz 		"Use clocksource=xyz\n");
473734efb46Sjohn stultz 	return boot_override_clocksource(str);
474734efb46Sjohn stultz }
475734efb46Sjohn stultz 
476734efb46Sjohn stultz __setup("clock=", boot_override_clock);
477