blob: 2f6a3d6e43bc05f3b1f7ff2bcad205eb11eedbcb [file] [log] [blame]
john stultz734efb42006-06-26 00:25:05 -07001/*
2 * linux/kernel/time/clocksource.c
3 *
4 * This file contains the functions which manage clocksource drivers.
5 *
6 * Copyright (C) 2004, 2005 IBM, John Stultz (johnstul@us.ibm.com)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * TODO WishList:
23 * o Allow clocksource drivers to be unregistered
24 * o get rid of clocksource_jiffies extern
25 */
26
27#include <linux/clocksource.h>
28#include <linux/sysdev.h>
29#include <linux/init.h>
30#include <linux/module.h>
Mathieu Desnoyersdc29a362007-02-10 01:43:43 -080031#include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */
john stultz734efb42006-06-26 00:25:05 -070032
33/* XXX - Would like a better way for initializing curr_clocksource */
34extern struct clocksource clocksource_jiffies;
35
36/*[Clocksource internal variables]---------
37 * curr_clocksource:
38 * currently selected clocksource. Initialized to clocksource_jiffies.
39 * next_clocksource:
40 * pending next selected clocksource.
41 * clocksource_list:
42 * linked list with the registered clocksources
43 * clocksource_lock:
44 * protects manipulations to curr_clocksource and next_clocksource
45 * and the clocksource_list
46 * override_name:
47 * Name of the user-specified clocksource.
48 */
49static struct clocksource *curr_clocksource = &clocksource_jiffies;
50static struct clocksource *next_clocksource;
Thomas Gleixner92c7e002007-02-16 01:27:33 -080051static struct clocksource *clocksource_override;
john stultz734efb42006-06-26 00:25:05 -070052static LIST_HEAD(clocksource_list);
53static DEFINE_SPINLOCK(clocksource_lock);
54static char override_name[32];
55static int finished_booting;
56
57/* clocksource_done_booting - Called near the end of bootup
58 *
59 * Hack to avoid lots of clocksource churn at boot time
60 */
john stultzad596172006-06-26 00:25:06 -070061static int __init clocksource_done_booting(void)
john stultz734efb42006-06-26 00:25:05 -070062{
63 finished_booting = 1;
64 return 0;
65}
66
67late_initcall(clocksource_done_booting);
68
69/**
john stultza2752542006-06-26 00:25:14 -070070 * clocksource_get_next - Returns the selected clocksource
john stultz734efb42006-06-26 00:25:05 -070071 *
72 */
john stultza2752542006-06-26 00:25:14 -070073struct clocksource *clocksource_get_next(void)
john stultz734efb42006-06-26 00:25:05 -070074{
75 unsigned long flags;
76
77 spin_lock_irqsave(&clocksource_lock, flags);
78 if (next_clocksource && finished_booting) {
79 curr_clocksource = next_clocksource;
80 next_clocksource = NULL;
81 }
82 spin_unlock_irqrestore(&clocksource_lock, flags);
83
84 return curr_clocksource;
85}
86
87/**
Thomas Gleixner92c7e002007-02-16 01:27:33 -080088 * select_clocksource - Selects the best registered clocksource.
john stultz734efb42006-06-26 00:25:05 -070089 *
90 * Private function. Must hold clocksource_lock when called.
91 *
Thomas Gleixner92c7e002007-02-16 01:27:33 -080092 * Select the clocksource with the best rating, or the clocksource,
93 * which is selected by userspace override.
john stultz734efb42006-06-26 00:25:05 -070094 */
95static struct clocksource *select_clocksource(void)
96{
Thomas Gleixner92c7e002007-02-16 01:27:33 -080097 if (list_empty(&clocksource_list))
98 return NULL;
john stultz734efb42006-06-26 00:25:05 -070099
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800100 if (clocksource_override)
101 return clocksource_override;
john stultz734efb42006-06-26 00:25:05 -0700102
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800103 return list_entry(clocksource_list.next, struct clocksource, list);
john stultz734efb42006-06-26 00:25:05 -0700104}
105
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800106/*
107 * Enqueue the clocksource sorted by rating
john stultz734efb42006-06-26 00:25:05 -0700108 */
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800109static int clocksource_enqueue(struct clocksource *c)
john stultz734efb42006-06-26 00:25:05 -0700110{
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800111 struct list_head *tmp, *entry = &clocksource_list;
john stultz734efb42006-06-26 00:25:05 -0700112
113 list_for_each(tmp, &clocksource_list) {
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800114 struct clocksource *cs;
john stultz734efb42006-06-26 00:25:05 -0700115
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800116 cs = list_entry(tmp, struct clocksource, list);
117 if (cs == c)
118 return -EBUSY;
119 /* Keep track of the place, where to insert */
120 if (cs->rating >= c->rating)
121 entry = tmp;
john stultz734efb42006-06-26 00:25:05 -0700122 }
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800123 list_add(&c->list, entry);
124
125 if (strlen(c->name) == strlen(override_name) &&
126 !strcmp(c->name, override_name))
127 clocksource_override = c;
john stultz734efb42006-06-26 00:25:05 -0700128
129 return 0;
130}
131
132/**
john stultza2752542006-06-26 00:25:14 -0700133 * clocksource_register - Used to install new clocksources
john stultz734efb42006-06-26 00:25:05 -0700134 * @t: clocksource to be registered
135 *
136 * Returns -EBUSY if registration fails, zero otherwise.
137 */
john stultza2752542006-06-26 00:25:14 -0700138int clocksource_register(struct clocksource *c)
john stultz734efb42006-06-26 00:25:05 -0700139{
john stultz734efb42006-06-26 00:25:05 -0700140 unsigned long flags;
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800141 int ret = 0;
john stultz734efb42006-06-26 00:25:05 -0700142
143 spin_lock_irqsave(&clocksource_lock, flags);
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800144 ret = clocksource_enqueue(c);
145 if (!ret)
john stultz734efb42006-06-26 00:25:05 -0700146 next_clocksource = select_clocksource();
john stultz734efb42006-06-26 00:25:05 -0700147 spin_unlock_irqrestore(&clocksource_lock, flags);
148 return ret;
149}
john stultza2752542006-06-26 00:25:14 -0700150EXPORT_SYMBOL(clocksource_register);
john stultz734efb42006-06-26 00:25:05 -0700151
152/**
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800153 * clocksource_change_rating - Change the rating of a registered clocksource
john stultz734efb42006-06-26 00:25:05 -0700154 *
john stultz734efb42006-06-26 00:25:05 -0700155 */
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800156void clocksource_change_rating(struct clocksource *cs, int rating)
john stultz734efb42006-06-26 00:25:05 -0700157{
158 unsigned long flags;
159
160 spin_lock_irqsave(&clocksource_lock, flags);
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800161 list_del(&cs->list);
162 clocksource_enqueue(cs);
john stultz734efb42006-06-26 00:25:05 -0700163 next_clocksource = select_clocksource();
164 spin_unlock_irqrestore(&clocksource_lock, flags);
165}
166
Daniel Walker2b013702006-12-10 02:21:30 -0800167#ifdef CONFIG_SYSFS
john stultz734efb42006-06-26 00:25:05 -0700168/**
169 * sysfs_show_current_clocksources - sysfs interface for current clocksource
170 * @dev: unused
171 * @buf: char buffer to be filled with clocksource list
172 *
173 * Provides sysfs interface for listing current clocksource.
174 */
175static ssize_t
176sysfs_show_current_clocksources(struct sys_device *dev, char *buf)
177{
178 char *curr = buf;
179
180 spin_lock_irq(&clocksource_lock);
181 curr += sprintf(curr, "%s ", curr_clocksource->name);
182 spin_unlock_irq(&clocksource_lock);
183
184 curr += sprintf(curr, "\n");
185
186 return curr - buf;
187}
188
189/**
190 * sysfs_override_clocksource - interface for manually overriding clocksource
191 * @dev: unused
192 * @buf: name of override clocksource
193 * @count: length of buffer
194 *
195 * Takes input from sysfs interface for manually overriding the default
196 * clocksource selction.
197 */
198static ssize_t sysfs_override_clocksource(struct sys_device *dev,
199 const char *buf, size_t count)
200{
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800201 struct clocksource *ovr = NULL;
202 struct list_head *tmp;
john stultz734efb42006-06-26 00:25:05 -0700203 size_t ret = count;
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800204 int len;
205
john stultz734efb42006-06-26 00:25:05 -0700206 /* strings from sysfs write are not 0 terminated! */
207 if (count >= sizeof(override_name))
208 return -EINVAL;
209
210 /* strip of \n: */
211 if (buf[count-1] == '\n')
212 count--;
john stultz734efb42006-06-26 00:25:05 -0700213
214 spin_lock_irq(&clocksource_lock);
215
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800216 if (count > 0)
217 memcpy(override_name, buf, count);
john stultz734efb42006-06-26 00:25:05 -0700218 override_name[count] = 0;
219
Thomas Gleixner92c7e002007-02-16 01:27:33 -0800220 len = strlen(override_name);
221 if (len) {
222 ovr = clocksource_override;
223 /* try to select it: */
224 list_for_each(tmp, &clocksource_list) {
225 struct clocksource *cs;
226
227 cs = list_entry(tmp, struct clocksource, list);
228 if (strlen(cs->name) == len &&
229 !strcmp(cs->name, override_name))
230 ovr = cs;
231 }
232 }
233
234 /* Reselect, when the override name has changed */
235 if (ovr != clocksource_override) {
236 clocksource_override = ovr;
237 next_clocksource = select_clocksource();
238 }
john stultz734efb42006-06-26 00:25:05 -0700239
240 spin_unlock_irq(&clocksource_lock);
241
242 return ret;
243}
244
245/**
246 * sysfs_show_available_clocksources - sysfs interface for listing clocksource
247 * @dev: unused
248 * @buf: char buffer to be filled with clocksource list
249 *
250 * Provides sysfs interface for listing registered clocksources
251 */
252static ssize_t
253sysfs_show_available_clocksources(struct sys_device *dev, char *buf)
254{
255 struct list_head *tmp;
256 char *curr = buf;
257
258 spin_lock_irq(&clocksource_lock);
259 list_for_each(tmp, &clocksource_list) {
260 struct clocksource *src;
261
262 src = list_entry(tmp, struct clocksource, list);
263 curr += sprintf(curr, "%s ", src->name);
264 }
265 spin_unlock_irq(&clocksource_lock);
266
267 curr += sprintf(curr, "\n");
268
269 return curr - buf;
270}
271
272/*
273 * Sysfs setup bits:
274 */
275static SYSDEV_ATTR(current_clocksource, 0600, sysfs_show_current_clocksources,
Daniel Walkerf5f1a242006-12-10 02:21:33 -0800276 sysfs_override_clocksource);
john stultz734efb42006-06-26 00:25:05 -0700277
278static SYSDEV_ATTR(available_clocksource, 0600,
Daniel Walkerf5f1a242006-12-10 02:21:33 -0800279 sysfs_show_available_clocksources, NULL);
john stultz734efb42006-06-26 00:25:05 -0700280
281static struct sysdev_class clocksource_sysclass = {
282 set_kset_name("clocksource"),
283};
284
285static struct sys_device device_clocksource = {
286 .id = 0,
287 .cls = &clocksource_sysclass,
288};
289
john stultzad596172006-06-26 00:25:06 -0700290static int __init init_clocksource_sysfs(void)
john stultz734efb42006-06-26 00:25:05 -0700291{
292 int error = sysdev_class_register(&clocksource_sysclass);
293
294 if (!error)
295 error = sysdev_register(&device_clocksource);
296 if (!error)
297 error = sysdev_create_file(
298 &device_clocksource,
299 &attr_current_clocksource);
300 if (!error)
301 error = sysdev_create_file(
302 &device_clocksource,
303 &attr_available_clocksource);
304 return error;
305}
306
307device_initcall(init_clocksource_sysfs);
Daniel Walker2b013702006-12-10 02:21:30 -0800308#endif /* CONFIG_SYSFS */
john stultz734efb42006-06-26 00:25:05 -0700309
310/**
311 * boot_override_clocksource - boot clock override
312 * @str: override name
313 *
314 * Takes a clocksource= boot argument and uses it
315 * as the clocksource override name.
316 */
317static int __init boot_override_clocksource(char* str)
318{
319 unsigned long flags;
320 spin_lock_irqsave(&clocksource_lock, flags);
321 if (str)
322 strlcpy(override_name, str, sizeof(override_name));
323 spin_unlock_irqrestore(&clocksource_lock, flags);
324 return 1;
325}
326
327__setup("clocksource=", boot_override_clocksource);
328
329/**
330 * boot_override_clock - Compatibility layer for deprecated boot option
331 * @str: override name
332 *
333 * DEPRECATED! Takes a clock= boot argument and uses it
334 * as the clocksource override name
335 */
336static int __init boot_override_clock(char* str)
337{
john stultz5d0cf412006-06-26 00:25:12 -0700338 if (!strcmp(str, "pmtmr")) {
339 printk("Warning: clock=pmtmr is deprecated. "
340 "Use clocksource=acpi_pm.\n");
341 return boot_override_clocksource("acpi_pm");
342 }
343 printk("Warning! clock= boot option is deprecated. "
344 "Use clocksource=xyz\n");
john stultz734efb42006-06-26 00:25:05 -0700345 return boot_override_clocksource(str);
346}
347
348__setup("clock=", boot_override_clock);