aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjohn stultz <johnstul@us.ibm.com>2006-06-26 03:25:05 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 12:58:20 -0400
commit734efb467b31e56c2f9430590a9aa867ecf3eea1 (patch)
tree30bf6b52d1e67128e656fb9a01cd7e6e13b7755e
parentade1a29e168ba08b699a418ff5e762315fa33f70 (diff)
[PATCH] Time: Clocksource Infrastructure
This introduces the clocksource management infrastructure. A clocksource is a driver-like architecture generic abstraction of a free-running counter. This code defines the clocksource structure, and provides management code for registering, selecting, accessing and scaling clocksources. Additionally, this includes the trivial jiffies clocksource, a lowest common denominator clocksource, provided mainly for use as an example. [hirofumi@mail.parknet.co.jp: Don't enable IRQ too early] Signed-off-by: John Stultz <johnstul@us.ibm.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Paul Mundt <lethal@linux-sh.org> Signed-off-by: John Stultz <johnstul@us.ibm.com> Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--Documentation/kernel-parameters.txt14
-rw-r--r--include/linux/clocksource.h181
-rw-r--r--kernel/time/Makefile1
-rw-r--r--kernel/time/clocksource.c344
-rw-r--r--kernel/time/jiffies.c73
5 files changed, 609 insertions, 4 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index bca6f389da66..968631678d4a 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -61,6 +61,7 @@ parameter is applicable:
61 MTD MTD support is enabled. 61 MTD MTD support is enabled.
62 NET Appropriate network support is enabled. 62 NET Appropriate network support is enabled.
63 NUMA NUMA support is enabled. 63 NUMA NUMA support is enabled.
64 GENERIC_TIME The generic timeofday code is enabled.
64 NFS Appropriate NFS support is enabled. 65 NFS Appropriate NFS support is enabled.
65 OSS OSS sound support is enabled. 66 OSS OSS sound support is enabled.
66 PARIDE The ParIDE subsystem is enabled. 67 PARIDE The ParIDE subsystem is enabled.
@@ -341,10 +342,11 @@ running once the system is up.
341 Value can be changed at runtime via 342 Value can be changed at runtime via
342 /selinux/checkreqprot. 343 /selinux/checkreqprot.
343 344
344 clock= [BUGS=IA-32,HW] gettimeofday timesource override. 345 clock= [BUGS=IA-32, HW] gettimeofday clocksource override.
345 Forces specified timesource (if avaliable) to be used 346 [Deprecated]
346 when calculating gettimeofday(). If specicified 347 Forces specified clocksource (if avaliable) to be used
347 timesource is not avalible, it defaults to PIT. 348 when calculating gettimeofday(). If specified
349 clocksource is not avalible, it defaults to PIT.
348 Format: { pit | tsc | cyclone | pmtmr } 350 Format: { pit | tsc | cyclone | pmtmr }
349 351
350 disable_8254_timer 352 disable_8254_timer
@@ -1617,6 +1619,10 @@ running once the system is up.
1617 1619
1618 time Show timing data prefixed to each printk message line 1620 time Show timing data prefixed to each printk message line
1619 1621
1622 clocksource= [GENERIC_TIME] Override the default clocksource
1623 Override the default clocksource and use the clocksource
1624 with the name specified.
1625
1620 tipar.timeout= [HW,PPT] 1626 tipar.timeout= [HW,PPT]
1621 Set communications timeout in tenths of a second 1627 Set communications timeout in tenths of a second
1622 (default 15). 1628 (default 15).
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
new file mode 100644
index 000000000000..c4187cda0ee4
--- /dev/null
+++ b/include/linux/clocksource.h
@@ -0,0 +1,181 @@
1/* linux/include/linux/clocksource.h
2 *
3 * This file contains the structure definitions for clocksources.
4 *
5 * If you are not a clocksource, or timekeeping code, you should
6 * not be including this file!
7 */
8#ifndef _LINUX_CLOCKSOURCE_H
9#define _LINUX_CLOCKSOURCE_H
10
11#include <linux/types.h>
12#include <linux/timex.h>
13#include <linux/time.h>
14#include <linux/list.h>
15#include <asm/div64.h>
16#include <asm/io.h>
17
18/* clocksource cycle base type */
19typedef u64 cycle_t;
20
21/**
22 * struct clocksource - hardware abstraction for a free running counter
23 * Provides mostly state-free accessors to the underlying hardware.
24 *
25 * @name: ptr to clocksource name
26 * @list: list head for registration
27 * @rating: rating value for selection (higher is better)
28 * To avoid rating inflation the following
29 * list should give you a guide as to how
30 * to assign your clocksource a rating
31 * 1-99: Unfit for real use
32 * Only available for bootup and testing purposes.
33 * 100-199: Base level usability.
34 * Functional for real use, but not desired.
35 * 200-299: Good.
36 * A correct and usable clocksource.
37 * 300-399: Desired.
38 * A reasonably fast and accurate clocksource.
39 * 400-499: Perfect
40 * The ideal clocksource. A must-use where
41 * available.
42 * @read: returns a cycle value
43 * @mask: bitmask for two's complement
44 * subtraction of non 64 bit counters
45 * @mult: cycle to nanosecond multiplier
46 * @shift: cycle to nanosecond divisor (power of two)
47 * @update_callback: called when safe to alter clocksource values
48 * @is_continuous: defines if clocksource is free-running.
49 * @interval_cycles: Used internally by timekeeping core, please ignore.
50 * @interval_snsecs: Used internally by timekeeping core, please ignore.
51 */
52struct clocksource {
53 char *name;
54 struct list_head list;
55 int rating;
56 cycle_t (*read)(void);
57 cycle_t mask;
58 u32 mult;
59 u32 shift;
60 int (*update_callback)(void);
61 int is_continuous;
62
63 /* timekeeping specific data, ignore */
64 cycle_t interval_cycles;
65 u64 interval_snsecs;
66};
67
68
69/**
70 * clocksource_khz2mult - calculates mult from khz and shift
71 * @khz: Clocksource frequency in KHz
72 * @shift_constant: Clocksource shift factor
73 *
74 * Helper functions that converts a khz counter frequency to a timsource
75 * multiplier, given the clocksource shift value
76 */
77static inline u32 clocksource_khz2mult(u32 khz, u32 shift_constant)
78{
79 /* khz = cyc/(Million ns)
80 * mult/2^shift = ns/cyc
81 * mult = ns/cyc * 2^shift
82 * mult = 1Million/khz * 2^shift
83 * mult = 1000000 * 2^shift / khz
84 * mult = (1000000<<shift) / khz
85 */
86 u64 tmp = ((u64)1000000) << shift_constant;
87
88 tmp += khz/2; /* round for do_div */
89 do_div(tmp, khz);
90
91 return (u32)tmp;
92}
93
94/**
95 * clocksource_hz2mult - calculates mult from hz and shift
96 * @hz: Clocksource frequency in Hz
97 * @shift_constant: Clocksource shift factor
98 *
99 * Helper functions that converts a hz counter
100 * frequency to a timsource multiplier, given the
101 * clocksource shift value
102 */
103static inline u32 clocksource_hz2mult(u32 hz, u32 shift_constant)
104{
105 /* hz = cyc/(Billion ns)
106 * mult/2^shift = ns/cyc
107 * mult = ns/cyc * 2^shift
108 * mult = 1Billion/hz * 2^shift
109 * mult = 1000000000 * 2^shift / hz
110 * mult = (1000000000<<shift) / hz
111 */
112 u64 tmp = ((u64)1000000000) << shift_constant;
113
114 tmp += hz/2; /* round for do_div */
115 do_div(tmp, hz);
116
117 return (u32)tmp;
118}
119
120/**
121 * read_clocksource: - Access the clocksource's current cycle value
122 * @cs: pointer to clocksource being read
123 *
124 * Uses the clocksource to return the current cycle_t value
125 */
126static inline cycle_t read_clocksource(struct clocksource *cs)
127{
128 return cs->read();
129}
130
131/**
132 * cyc2ns - converts clocksource cycles to nanoseconds
133 * @cs: Pointer to clocksource
134 * @cycles: Cycles
135 *
136 * Uses the clocksource and ntp ajdustment to convert cycle_ts to nanoseconds.
137 *
138 * XXX - This could use some mult_lxl_ll() asm optimization
139 */
140static inline s64 cyc2ns(struct clocksource *cs, cycle_t cycles)
141{
142 u64 ret = (u64)cycles;
143 ret = (ret * cs->mult) >> cs->shift;
144 return ret;
145}
146
147/**
148 * calculate_clocksource_interval - Calculates a clocksource interval struct
149 *
150 * @c: Pointer to clocksource.
151 * @length_nsec: Desired interval length in nanoseconds.
152 *
153 * Calculates a fixed cycle/nsec interval for a given clocksource/adjustment
154 * pair and interval request.
155 *
156 * Unless you're the timekeeping code, you should not be using this!
157 */
158static inline void calculate_clocksource_interval(struct clocksource *c,
159 unsigned long length_nsec)
160{
161 u64 tmp;
162
163 /* XXX - All of this could use a whole lot of optimization */
164 tmp = length_nsec;
165 tmp <<= c->shift;
166 tmp += c->mult/2;
167 do_div(tmp, c->mult);
168
169 c->interval_cycles = (cycle_t)tmp;
170 if(c->interval_cycles == 0)
171 c->interval_cycles = 1;
172
173 c->interval_snsecs = (u64)c->interval_cycles * c->mult;
174}
175
176/* used to install a new clocksource */
177int register_clocksource(struct clocksource*);
178void reselect_clocksource(void);
179struct clocksource* get_next_clocksource(void);
180
181#endif /* _LINUX_CLOCKSOURCE_H */
diff --git a/kernel/time/Makefile b/kernel/time/Makefile
new file mode 100644
index 000000000000..e1dfd8e86cce
--- /dev/null
+++ b/kernel/time/Makefile
@@ -0,0 +1 @@
obj-y += clocksource.o jiffies.o
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
new file mode 100644
index 000000000000..95dd2200a109
--- /dev/null
+++ b/kernel/time/clocksource.c
@@ -0,0 +1,344 @@
1/*
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>
31
32/* XXX - Would like a better way for initializing curr_clocksource */
33extern struct clocksource clocksource_jiffies;
34
35/*[Clocksource internal variables]---------
36 * curr_clocksource:
37 * currently selected clocksource. Initialized to clocksource_jiffies.
38 * next_clocksource:
39 * pending next selected clocksource.
40 * clocksource_list:
41 * linked list with the registered clocksources
42 * clocksource_lock:
43 * protects manipulations to curr_clocksource and next_clocksource
44 * and the clocksource_list
45 * override_name:
46 * Name of the user-specified clocksource.
47 */
48static struct clocksource *curr_clocksource = &clocksource_jiffies;
49static struct clocksource *next_clocksource;
50static LIST_HEAD(clocksource_list);
51static DEFINE_SPINLOCK(clocksource_lock);
52static char override_name[32];
53static int finished_booting;
54
55/* clocksource_done_booting - Called near the end of bootup
56 *
57 * Hack to avoid lots of clocksource churn at boot time
58 */
59static int clocksource_done_booting(void)
60{
61 finished_booting = 1;
62 return 0;
63}
64
65late_initcall(clocksource_done_booting);
66
67/**
68 * get_next_clocksource - Returns the selected clocksource
69 *
70 */
71struct clocksource *get_next_clocksource(void)
72{
73 unsigned long flags;
74
75 spin_lock_irqsave(&clocksource_lock, flags);
76 if (next_clocksource && finished_booting) {
77 curr_clocksource = next_clocksource;
78 next_clocksource = NULL;
79 }
80 spin_unlock_irqrestore(&clocksource_lock, flags);
81
82 return curr_clocksource;
83}
84
85/**
86 * select_clocksource - Finds the best registered clocksource.
87 *
88 * Private function. Must hold clocksource_lock when called.
89 *
90 * Looks through the list of registered clocksources, returning
91 * the one with the highest rating value. If there is a clocksource
92 * name that matches the override string, it returns that clocksource.
93 */
94static struct clocksource *select_clocksource(void)
95{
96 struct clocksource *best = NULL;
97 struct list_head *tmp;
98
99 list_for_each(tmp, &clocksource_list) {
100 struct clocksource *src;
101
102 src = list_entry(tmp, struct clocksource, list);
103 if (!best)
104 best = src;
105
106 /* check for override: */
107 if (strlen(src->name) == strlen(override_name) &&
108 !strcmp(src->name, override_name)) {
109 best = src;
110 break;
111 }
112 /* pick the highest rating: */
113 if (src->rating > best->rating)
114 best = src;
115 }
116
117 return best;
118}
119
120/**
121 * is_registered_source - Checks if clocksource is registered
122 * @c: pointer to a clocksource
123 *
124 * Private helper function. Must hold clocksource_lock when called.
125 *
126 * Returns one if the clocksource is already registered, zero otherwise.
127 */
128static int is_registered_source(struct clocksource *c)
129{
130 int len = strlen(c->name);
131 struct list_head *tmp;
132
133 list_for_each(tmp, &clocksource_list) {
134 struct clocksource *src;
135
136 src = list_entry(tmp, struct clocksource, list);
137 if (strlen(src->name) == len && !strcmp(src->name, c->name))
138 return 1;
139 }
140
141 return 0;
142}
143
144/**
145 * register_clocksource - Used to install new clocksources
146 * @t: clocksource to be registered
147 *
148 * Returns -EBUSY if registration fails, zero otherwise.
149 */
150int register_clocksource(struct clocksource *c)
151{
152 int ret = 0;
153 unsigned long flags;
154
155 spin_lock_irqsave(&clocksource_lock, flags);
156 /* check if clocksource is already registered */
157 if (is_registered_source(c)) {
158 printk("register_clocksource: Cannot register %s. "
159 "Already registered!", c->name);
160 ret = -EBUSY;
161 } else {
162 /* register it */
163 list_add(&c->list, &clocksource_list);
164 /* scan the registered clocksources, and pick the best one */
165 next_clocksource = select_clocksource();
166 }
167 spin_unlock_irqrestore(&clocksource_lock, flags);
168 return ret;
169}
170
171EXPORT_SYMBOL(register_clocksource);
172
173/**
174 * reselect_clocksource - Rescan list for next clocksource
175 *
176 * A quick helper function to be used if a clocksource changes its
177 * rating. Forces the clocksource list to be re-scaned for the best
178 * clocksource.
179 */
180void reselect_clocksource(void)
181{
182 unsigned long flags;
183
184 spin_lock_irqsave(&clocksource_lock, flags);
185 next_clocksource = select_clocksource();
186 spin_unlock_irqrestore(&clocksource_lock, flags);
187}
188
189/**
190 * sysfs_show_current_clocksources - sysfs interface for current clocksource
191 * @dev: unused
192 * @buf: char buffer to be filled with clocksource list
193 *
194 * Provides sysfs interface for listing current clocksource.
195 */
196static ssize_t
197sysfs_show_current_clocksources(struct sys_device *dev, char *buf)
198{
199 char *curr = buf;
200
201 spin_lock_irq(&clocksource_lock);
202 curr += sprintf(curr, "%s ", curr_clocksource->name);
203 spin_unlock_irq(&clocksource_lock);
204
205 curr += sprintf(curr, "\n");
206
207 return curr - buf;
208}
209
210/**
211 * sysfs_override_clocksource - interface for manually overriding clocksource
212 * @dev: unused
213 * @buf: name of override clocksource
214 * @count: length of buffer
215 *
216 * Takes input from sysfs interface for manually overriding the default
217 * clocksource selction.
218 */
219static ssize_t sysfs_override_clocksource(struct sys_device *dev,
220 const char *buf, size_t count)
221{
222 size_t ret = count;
223 /* strings from sysfs write are not 0 terminated! */
224 if (count >= sizeof(override_name))
225 return -EINVAL;
226
227 /* strip of \n: */
228 if (buf[count-1] == '\n')
229 count--;
230 if (count < 1)
231 return -EINVAL;
232
233 spin_lock_irq(&clocksource_lock);
234
235 /* copy the name given: */
236 memcpy(override_name, buf, count);
237 override_name[count] = 0;
238
239 /* try to select it: */
240 next_clocksource = select_clocksource();
241
242 spin_unlock_irq(&clocksource_lock);
243
244 return ret;
245}
246
247/**
248 * sysfs_show_available_clocksources - sysfs interface for listing clocksource
249 * @dev: unused
250 * @buf: char buffer to be filled with clocksource list
251 *
252 * Provides sysfs interface for listing registered clocksources
253 */
254static ssize_t
255sysfs_show_available_clocksources(struct sys_device *dev, char *buf)
256{
257 struct list_head *tmp;
258 char *curr = buf;
259
260 spin_lock_irq(&clocksource_lock);
261 list_for_each(tmp, &clocksource_list) {
262 struct clocksource *src;
263
264 src = list_entry(tmp, struct clocksource, list);
265 curr += sprintf(curr, "%s ", src->name);
266 }
267 spin_unlock_irq(&clocksource_lock);
268
269 curr += sprintf(curr, "\n");
270
271 return curr - buf;
272}
273
274/*
275 * Sysfs setup bits:
276 */
277static SYSDEV_ATTR(current_clocksource, 0600, sysfs_show_current_clocksources,
278 sysfs_override_clocksource);
279
280static SYSDEV_ATTR(available_clocksource, 0600,
281 sysfs_show_available_clocksources, NULL);
282
283static struct sysdev_class clocksource_sysclass = {
284 set_kset_name("clocksource"),
285};
286
287static struct sys_device device_clocksource = {
288 .id = 0,
289 .cls = &clocksource_sysclass,
290};
291
292static int init_clocksource_sysfs(void)
293{
294 int error = sysdev_class_register(&clocksource_sysclass);
295
296 if (!error)
297 error = sysdev_register(&device_clocksource);
298 if (!error)
299 error = sysdev_create_file(
300 &device_clocksource,
301 &attr_current_clocksource);
302 if (!error)
303 error = sysdev_create_file(
304 &device_clocksource,
305 &attr_available_clocksource);
306 return error;
307}
308
309device_initcall(init_clocksource_sysfs);
310
311/**
312 * boot_override_clocksource - boot clock override
313 * @str: override name
314 *
315 * Takes a clocksource= boot argument and uses it
316 * as the clocksource override name.
317 */
318static int __init boot_override_clocksource(char* str)
319{
320 unsigned long flags;
321 spin_lock_irqsave(&clocksource_lock, flags);
322 if (str)
323 strlcpy(override_name, str, sizeof(override_name));
324 spin_unlock_irqrestore(&clocksource_lock, flags);
325 return 1;
326}
327
328__setup("clocksource=", boot_override_clocksource);
329
330/**
331 * boot_override_clock - Compatibility layer for deprecated boot option
332 * @str: override name
333 *
334 * DEPRECATED! Takes a clock= boot argument and uses it
335 * as the clocksource override name
336 */
337static int __init boot_override_clock(char* str)
338{
339 printk("Warning! clock= boot option is deprecated.\n");
340
341 return boot_override_clocksource(str);
342}
343
344__setup("clock=", boot_override_clock);
diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c
new file mode 100644
index 000000000000..1fe8376e717b
--- /dev/null
+++ b/kernel/time/jiffies.c
@@ -0,0 +1,73 @@
1/***********************************************************************
2* linux/kernel/time/jiffies.c
3*
4* This file contains the jiffies based clocksource.
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************************************************************************/
23#include <linux/clocksource.h>
24#include <linux/jiffies.h>
25#include <linux/init.h>
26
27/* The Jiffies based clocksource is the lowest common
28 * denominator clock source which should function on
29 * all systems. It has the same coarse resolution as
30 * the timer interrupt frequency HZ and it suffers
31 * inaccuracies caused by missed or lost timer
32 * interrupts and the inability for the timer
33 * interrupt hardware to accuratly tick at the
34 * requested HZ value. It is also not reccomended
35 * for "tick-less" systems.
36 */
37#define NSEC_PER_JIFFY ((u32)((((u64)NSEC_PER_SEC)<<8)/ACTHZ))
38
39/* Since jiffies uses a simple NSEC_PER_JIFFY multiplier
40 * conversion, the .shift value could be zero. However
41 * this would make NTP adjustments impossible as they are
42 * in units of 1/2^.shift. Thus we use JIFFIES_SHIFT to
43 * shift both the nominator and denominator the same
44 * amount, and give ntp adjustments in units of 1/2^8
45 *
46 * The value 8 is somewhat carefully chosen, as anything
47 * larger can result in overflows. NSEC_PER_JIFFY grows as
48 * HZ shrinks, so values greater then 8 overflow 32bits when
49 * HZ=100.
50 */
51#define JIFFIES_SHIFT 8
52
53static cycle_t jiffies_read(void)
54{
55 return (cycle_t) jiffies;
56}
57
58struct clocksource clocksource_jiffies = {
59 .name = "jiffies",
60 .rating = 0, /* lowest rating*/
61 .read = jiffies_read,
62 .mask = 0xffffffff, /*32bits*/
63 .mult = NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */
64 .shift = JIFFIES_SHIFT,
65 .is_continuous = 0, /* tick based, not free running */
66};
67
68static int __init init_jiffies_clocksource(void)
69{
70 return register_clocksource(&clocksource_jiffies);
71}
72
73module_init(init_jiffies_clocksource);