aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorMarc Zyngier <Marc.Zyngier@arm.com>2011-12-15 06:19:23 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-12-18 18:00:26 -0500
commit2f0778afac79bd8d226225556858a636931eeabc (patch)
treee00cea674f3d6cc8c5584aa5b75239f11f6d229d /arch/arm
parent3bdc3484e8f2b1b219ad0397d81ce4601fbaf76d (diff)
ARM: 7205/2: sched_clock: allow sched_clock to be selected at runtime
sched_clock() is yet another blocker on the road to the single image. This patch implements an idea by Russell King: http://www.spinics.net/lists/linux-omap/msg49561.html Instead of asking the platform to implement both sched_clock() itself and the rollover callback, simply register a read() function, and let the ARM code care about sched_clock() itself, the conversion to ns and the rollover. sched_clock() uses this read() function as an indirection to the platform code. If the platform doesn't provide a read(), the code falls back to the jiffy counter (just like the default sched_clock). This allow some simplifications and possibly some footprint gain when multiple platforms are compiled in. Among the drawbacks, the removal of the *_fixed_sched_clock optimization which could negatively impact some platforms (sa1100, tegra, versatile and omap). Tested on 11MPCore, OMAP4 and Tegra. Cc: Imre Kaloz <kaloz@openwrt.org> Cc: Eric Miao <eric.y.miao@gmail.com> Cc: Colin Cross <ccross@android.com> Cc: Erik Gilling <konkers@android.com> Cc: Olof Johansson <olof@lixom.net> Cc: Sascha Hauer <kernel@pengutronix.de> Cc: Alessandro Rubini <rubini@unipv.it> Cc: STEricsson <STEricsson_nomadik_linux@list.st.com> Cc: Lennert Buytenhek <kernel@wantstofly.org> Cc: Ben Dooks <ben-linux@fluff.org> Tested-by: Jamie Iles <jamie@jamieiles.com> Tested-by: Tony Lindgren <tony@atomide.com> Tested-by: Kyungmin Park <kyungmin.park@samsung.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Acked-by: Nicolas Pitre <nico@linaro.org> Acked-by: Krzysztof Halasa <khc@pm.waw.pl> Acked-by: Kukjin Kim <kgene.kim@samsung.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/include/asm/sched_clock.h108
-rw-r--r--arch/arm/kernel/sched_clock.c118
-rw-r--r--arch/arm/mach-ixp4xx/common.c16
-rw-r--r--arch/arm/mach-mmp/time.c16
-rw-r--r--arch/arm/mach-omap1/time.c58
-rw-r--r--arch/arm/mach-omap2/timer.c20
-rw-r--r--arch/arm/mach-picoxcell/time.c17
-rw-r--r--arch/arm/mach-pxa/time.c15
-rw-r--r--arch/arm/mach-sa1100/time.c28
-rw-r--r--arch/arm/mach-tegra/timer.c24
-rw-r--r--arch/arm/mach-u300/timer.c15
-rw-r--r--arch/arm/plat-iop/time.c16
-rw-r--r--arch/arm/plat-mxc/time.c15
-rw-r--r--arch/arm/plat-nomadik/timer.c20
-rw-r--r--arch/arm/plat-omap/counter_32k.c40
-rw-r--r--arch/arm/plat-omap/include/plat/common.h1
-rw-r--r--arch/arm/plat-orion/time.c21
-rw-r--r--arch/arm/plat-s5p/s5p-time.c19
-rw-r--r--arch/arm/plat-versatile/sched-clock.c29
19 files changed, 161 insertions, 435 deletions
diff --git a/arch/arm/include/asm/sched_clock.h b/arch/arm/include/asm/sched_clock.h
index c8e6ddf3e860..e3f757263438 100644
--- a/arch/arm/include/asm/sched_clock.h
+++ b/arch/arm/include/asm/sched_clock.h
@@ -8,113 +8,7 @@
8#ifndef ASM_SCHED_CLOCK 8#ifndef ASM_SCHED_CLOCK
9#define ASM_SCHED_CLOCK 9#define ASM_SCHED_CLOCK
10 10
11#include <linux/kernel.h>
12#include <linux/types.h>
13
14struct clock_data {
15 u64 epoch_ns;
16 u32 epoch_cyc;
17 u32 epoch_cyc_copy;
18 u32 mult;
19 u32 shift;
20};
21
22#define DEFINE_CLOCK_DATA(name) struct clock_data name
23
24static inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift)
25{
26 return (cyc * mult) >> shift;
27}
28
29/*
30 * Atomically update the sched_clock epoch. Your update callback will
31 * be called from a timer before the counter wraps - read the current
32 * counter value, and call this function to safely move the epochs
33 * forward. Only use this from the update callback.
34 */
35static inline void update_sched_clock(struct clock_data *cd, u32 cyc, u32 mask)
36{
37 unsigned long flags;
38 u64 ns = cd->epoch_ns +
39 cyc_to_ns((cyc - cd->epoch_cyc) & mask, cd->mult, cd->shift);
40
41 /*
42 * Write epoch_cyc and epoch_ns in a way that the update is
43 * detectable in cyc_to_fixed_sched_clock().
44 */
45 raw_local_irq_save(flags);
46 cd->epoch_cyc = cyc;
47 smp_wmb();
48 cd->epoch_ns = ns;
49 smp_wmb();
50 cd->epoch_cyc_copy = cyc;
51 raw_local_irq_restore(flags);
52}
53
54/*
55 * If your clock rate is known at compile time, using this will allow
56 * you to optimize the mult/shift loads away. This is paired with
57 * init_fixed_sched_clock() to ensure that your mult/shift are correct.
58 */
59static inline unsigned long long cyc_to_fixed_sched_clock(struct clock_data *cd,
60 u32 cyc, u32 mask, u32 mult, u32 shift)
61{
62 u64 epoch_ns;
63 u32 epoch_cyc;
64
65 /*
66 * Load the epoch_cyc and epoch_ns atomically. We do this by
67 * ensuring that we always write epoch_cyc, epoch_ns and
68 * epoch_cyc_copy in strict order, and read them in strict order.
69 * If epoch_cyc and epoch_cyc_copy are not equal, then we're in
70 * the middle of an update, and we should repeat the load.
71 */
72 do {
73 epoch_cyc = cd->epoch_cyc;
74 smp_rmb();
75 epoch_ns = cd->epoch_ns;
76 smp_rmb();
77 } while (epoch_cyc != cd->epoch_cyc_copy);
78
79 return epoch_ns + cyc_to_ns((cyc - epoch_cyc) & mask, mult, shift);
80}
81
82/*
83 * Otherwise, you need to use this, which will obtain the mult/shift
84 * from the clock_data structure. Use init_sched_clock() with this.
85 */
86static inline unsigned long long cyc_to_sched_clock(struct clock_data *cd,
87 u32 cyc, u32 mask)
88{
89 return cyc_to_fixed_sched_clock(cd, cyc, mask, cd->mult, cd->shift);
90}
91
92/*
93 * Initialize the clock data - calculate the appropriate multiplier
94 * and shift. Also setup a timer to ensure that the epoch is refreshed
95 * at the appropriate time interval, which will call your update
96 * handler.
97 */
98void init_sched_clock(struct clock_data *, void (*)(void),
99 unsigned int, unsigned long);
100
101/*
102 * Use this initialization function rather than init_sched_clock() if
103 * you're using cyc_to_fixed_sched_clock, which will warn if your
104 * constants are incorrect.
105 */
106static inline void init_fixed_sched_clock(struct clock_data *cd,
107 void (*update)(void), unsigned int bits, unsigned long rate,
108 u32 mult, u32 shift)
109{
110 init_sched_clock(cd, update, bits, rate);
111 if (cd->mult != mult || cd->shift != shift) {
112 pr_crit("sched_clock: wrong multiply/shift: %u>>%u vs calculated %u>>%u\n"
113 "sched_clock: fix multiply/shift to avoid scheduler hiccups\n",
114 mult, shift, cd->mult, cd->shift);
115 }
116}
117
118extern void sched_clock_postinit(void); 11extern void sched_clock_postinit(void);
12extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate);
119 13
120#endif 14#endif
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c
index 9a46370fe9da..5416c7c12528 100644
--- a/arch/arm/kernel/sched_clock.c
+++ b/arch/arm/kernel/sched_clock.c
@@ -14,61 +14,153 @@
14 14
15#include <asm/sched_clock.h> 15#include <asm/sched_clock.h>
16 16
17struct clock_data {
18 u64 epoch_ns;
19 u32 epoch_cyc;
20 u32 epoch_cyc_copy;
21 u32 mult;
22 u32 shift;
23};
24
17static void sched_clock_poll(unsigned long wrap_ticks); 25static void sched_clock_poll(unsigned long wrap_ticks);
18static DEFINE_TIMER(sched_clock_timer, sched_clock_poll, 0, 0); 26static DEFINE_TIMER(sched_clock_timer, sched_clock_poll, 0, 0);
19static void (*sched_clock_update_fn)(void); 27
28static struct clock_data cd = {
29 .mult = NSEC_PER_SEC / HZ,
30};
31
32static u32 __read_mostly sched_clock_mask = 0xffffffff;
33
34static u32 notrace jiffy_sched_clock_read(void)
35{
36 return (u32)(jiffies - INITIAL_JIFFIES);
37}
38
39static u32 __read_mostly (*read_sched_clock)(void) = jiffy_sched_clock_read;
40
41static inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift)
42{
43 return (cyc * mult) >> shift;
44}
45
46static unsigned long long cyc_to_sched_clock(u32 cyc, u32 mask)
47{
48 u64 epoch_ns;
49 u32 epoch_cyc;
50
51 /*
52 * Load the epoch_cyc and epoch_ns atomically. We do this by
53 * ensuring that we always write epoch_cyc, epoch_ns and
54 * epoch_cyc_copy in strict order, and read them in strict order.
55 * If epoch_cyc and epoch_cyc_copy are not equal, then we're in
56 * the middle of an update, and we should repeat the load.
57 */
58 do {
59 epoch_cyc = cd.epoch_cyc;
60 smp_rmb();
61 epoch_ns = cd.epoch_ns;
62 smp_rmb();
63 } while (epoch_cyc != cd.epoch_cyc_copy);
64
65 return epoch_ns + cyc_to_ns((cyc - epoch_cyc) & mask, cd.mult, cd.shift);
66}
67
68/*
69 * Atomically update the sched_clock epoch.
70 */
71static void notrace update_sched_clock(void)
72{
73 unsigned long flags;
74 u32 cyc;
75 u64 ns;
76
77 cyc = read_sched_clock();
78 ns = cd.epoch_ns +
79 cyc_to_ns((cyc - cd.epoch_cyc) & sched_clock_mask,
80 cd.mult, cd.shift);
81 /*
82 * Write epoch_cyc and epoch_ns in a way that the update is
83 * detectable in cyc_to_fixed_sched_clock().
84 */
85 raw_local_irq_save(flags);
86 cd.epoch_cyc = cyc;
87 smp_wmb();
88 cd.epoch_ns = ns;
89 smp_wmb();
90 cd.epoch_cyc_copy = cyc;
91 raw_local_irq_restore(flags);
92}
20 93
21static void sched_clock_poll(unsigned long wrap_ticks) 94static void sched_clock_poll(unsigned long wrap_ticks)
22{ 95{
23 mod_timer(&sched_clock_timer, round_jiffies(jiffies + wrap_ticks)); 96 mod_timer(&sched_clock_timer, round_jiffies(jiffies + wrap_ticks));
24 sched_clock_update_fn(); 97 update_sched_clock();
25} 98}
26 99
27void __init init_sched_clock(struct clock_data *cd, void (*update)(void), 100void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
28 unsigned int clock_bits, unsigned long rate)
29{ 101{
30 unsigned long r, w; 102 unsigned long r, w;
31 u64 res, wrap; 103 u64 res, wrap;
32 char r_unit; 104 char r_unit;
33 105
34 sched_clock_update_fn = update; 106 BUG_ON(bits > 32);
107 WARN_ON(!irqs_disabled());
108 WARN_ON(read_sched_clock != jiffy_sched_clock_read);
109 read_sched_clock = read;
110 sched_clock_mask = (1 << bits) - 1;
35 111
36 /* calculate the mult/shift to convert counter ticks to ns. */ 112 /* calculate the mult/shift to convert counter ticks to ns. */
37 clocks_calc_mult_shift(&cd->mult, &cd->shift, rate, NSEC_PER_SEC, 0); 113 clocks_calc_mult_shift(&cd.mult, &cd.shift, rate, NSEC_PER_SEC, 0);
38 114
39 r = rate; 115 r = rate;
40 if (r >= 4000000) { 116 if (r >= 4000000) {
41 r /= 1000000; 117 r /= 1000000;
42 r_unit = 'M'; 118 r_unit = 'M';
43 } else { 119 } else if (r >= 1000) {
44 r /= 1000; 120 r /= 1000;
45 r_unit = 'k'; 121 r_unit = 'k';
46 } 122 } else
123 r_unit = ' ';
47 124
48 /* calculate how many ns until we wrap */ 125 /* calculate how many ns until we wrap */
49 wrap = cyc_to_ns((1ULL << clock_bits) - 1, cd->mult, cd->shift); 126 wrap = cyc_to_ns((1ULL << bits) - 1, cd.mult, cd.shift);
50 do_div(wrap, NSEC_PER_MSEC); 127 do_div(wrap, NSEC_PER_MSEC);
51 w = wrap; 128 w = wrap;
52 129
53 /* calculate the ns resolution of this counter */ 130 /* calculate the ns resolution of this counter */
54 res = cyc_to_ns(1ULL, cd->mult, cd->shift); 131 res = cyc_to_ns(1ULL, cd.mult, cd.shift);
55 pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lums\n", 132 pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lums\n",
56 clock_bits, r, r_unit, res, w); 133 bits, r, r_unit, res, w);
57 134
58 /* 135 /*
59 * Start the timer to keep sched_clock() properly updated and 136 * Start the timer to keep sched_clock() properly updated and
60 * sets the initial epoch. 137 * sets the initial epoch.
61 */ 138 */
62 sched_clock_timer.data = msecs_to_jiffies(w - (w / 10)); 139 sched_clock_timer.data = msecs_to_jiffies(w - (w / 10));
63 update(); 140 update_sched_clock();
64 141
65 /* 142 /*
66 * Ensure that sched_clock() starts off at 0ns 143 * Ensure that sched_clock() starts off at 0ns
67 */ 144 */
68 cd->epoch_ns = 0; 145 cd.epoch_ns = 0;
146
147 pr_debug("Registered %pF as sched_clock source\n", read);
148}
149
150unsigned long long notrace sched_clock(void)
151{
152 u32 cyc = read_sched_clock();
153 return cyc_to_sched_clock(cyc, sched_clock_mask);
69} 154}
70 155
71void __init sched_clock_postinit(void) 156void __init sched_clock_postinit(void)
72{ 157{
158 /*
159 * If no sched_clock function has been provided at that point,
160 * make it the final one one.
161 */
162 if (read_sched_clock == jiffy_sched_clock_read)
163 setup_sched_clock(jiffy_sched_clock_read, 32, HZ);
164
73 sched_clock_poll(sched_clock_timer.data); 165 sched_clock_poll(sched_clock_timer.data);
74} 166}
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index b86a0055ab96..c1b12f945fc9 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -17,7 +17,6 @@
17#include <linux/mm.h> 17#include <linux/mm.h>
18#include <linux/init.h> 18#include <linux/init.h>
19#include <linux/serial.h> 19#include <linux/serial.h>
20#include <linux/sched.h>
21#include <linux/tty.h> 20#include <linux/tty.h>
22#include <linux/platform_device.h> 21#include <linux/platform_device.h>
23#include <linux/serial_core.h> 22#include <linux/serial_core.h>
@@ -403,18 +402,9 @@ void __init ixp4xx_sys_init(void)
403/* 402/*
404 * sched_clock() 403 * sched_clock()
405 */ 404 */
406static DEFINE_CLOCK_DATA(cd); 405static u32 notrace ixp4xx_read_sched_clock(void)
407
408unsigned long long notrace sched_clock(void)
409{ 406{
410 u32 cyc = *IXP4XX_OSTS; 407 return *IXP4XX_OSTS;
411 return cyc_to_sched_clock(&cd, cyc, (u32)~0);
412}
413
414static void notrace ixp4xx_update_sched_clock(void)
415{
416 u32 cyc = *IXP4XX_OSTS;
417 update_sched_clock(&cd, cyc, (u32)~0);
418} 408}
419 409
420/* 410/*
@@ -430,7 +420,7 @@ unsigned long ixp4xx_timer_freq = IXP4XX_TIMER_FREQ;
430EXPORT_SYMBOL(ixp4xx_timer_freq); 420EXPORT_SYMBOL(ixp4xx_timer_freq);
431static void __init ixp4xx_clocksource_init(void) 421static void __init ixp4xx_clocksource_init(void)
432{ 422{
433 init_sched_clock(&cd, ixp4xx_update_sched_clock, 32, ixp4xx_timer_freq); 423 setup_sched_clock(ixp4xx_read_sched_clock, 32, ixp4xx_timer_freq);
434 424
435 clocksource_mmio_init(NULL, "OSTS", ixp4xx_timer_freq, 200, 32, 425 clocksource_mmio_init(NULL, "OSTS", ixp4xx_timer_freq, 200, 32,
436 ixp4xx_clocksource_read); 426 ixp4xx_clocksource_read);
diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c
index 4e91ee6e27c8..71fc4ee4602c 100644
--- a/arch/arm/mach-mmp/time.c
+++ b/arch/arm/mach-mmp/time.c
@@ -25,7 +25,6 @@
25 25
26#include <linux/io.h> 26#include <linux/io.h>
27#include <linux/irq.h> 27#include <linux/irq.h>
28#include <linux/sched.h>
29 28
30#include <asm/sched_clock.h> 29#include <asm/sched_clock.h>
31#include <mach/addr-map.h> 30#include <mach/addr-map.h>
@@ -42,8 +41,6 @@
42#define MAX_DELTA (0xfffffffe) 41#define MAX_DELTA (0xfffffffe)
43#define MIN_DELTA (16) 42#define MIN_DELTA (16)
44 43
45static DEFINE_CLOCK_DATA(cd);
46
47/* 44/*
48 * FIXME: the timer needs some delay to stablize the counter capture 45 * FIXME: the timer needs some delay to stablize the counter capture
49 */ 46 */
@@ -59,16 +56,9 @@ static inline uint32_t timer_read(void)
59 return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(1)); 56 return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(1));
60} 57}
61 58
62unsigned long long notrace sched_clock(void) 59static u32 notrace mmp_read_sched_clock(void)
63{ 60{
64 u32 cyc = timer_read(); 61 return timer_read();
65 return cyc_to_sched_clock(&cd, cyc, (u32)~0);
66}
67
68static void notrace mmp_update_sched_clock(void)
69{
70 u32 cyc = timer_read();
71 update_sched_clock(&cd, cyc, (u32)~0);
72} 62}
73 63
74static irqreturn_t timer_interrupt(int irq, void *dev_id) 64static irqreturn_t timer_interrupt(int irq, void *dev_id)
@@ -201,7 +191,7 @@ void __init timer_init(int irq)
201{ 191{
202 timer_config(); 192 timer_config();
203 193
204 init_sched_clock(&cd, mmp_update_sched_clock, 32, CLOCK_TICK_RATE); 194 setup_sched_clock(mmp_read_sched_clock, 32, CLOCK_TICK_RATE);
205 195
206 ckevt.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt.shift); 196 ckevt.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt.shift);
207 ckevt.max_delta_ns = clockevent_delta2ns(MAX_DELTA, &ckevt); 197 ckevt.max_delta_ns = clockevent_delta2ns(MAX_DELTA, &ckevt);
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index 485a21d31004..b8faffa44f9e 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -37,7 +37,6 @@
37#include <linux/init.h> 37#include <linux/init.h>
38#include <linux/delay.h> 38#include <linux/delay.h>
39#include <linux/interrupt.h> 39#include <linux/interrupt.h>
40#include <linux/sched.h>
41#include <linux/spinlock.h> 40#include <linux/spinlock.h>
42#include <linux/clk.h> 41#include <linux/clk.h>
43#include <linux/err.h> 42#include <linux/err.h>
@@ -190,30 +189,9 @@ static __init void omap_init_mpu_timer(unsigned long rate)
190 * --------------------------------------------------------------------------- 189 * ---------------------------------------------------------------------------
191 */ 190 */
192 191
193static DEFINE_CLOCK_DATA(cd); 192static u32 notrace omap_mpu_read_sched_clock(void)
194
195static inline unsigned long long notrace _omap_mpu_sched_clock(void)
196{
197 u32 cyc = ~omap_mpu_timer_read(1);
198 return cyc_to_sched_clock(&cd, cyc, (u32)~0);
199}
200
201#ifndef CONFIG_OMAP_32K_TIMER
202unsigned long long notrace sched_clock(void)
203{
204 return _omap_mpu_sched_clock();
205}
206#else
207static unsigned long long notrace omap_mpu_sched_clock(void)
208{
209 return _omap_mpu_sched_clock();
210}
211#endif
212
213static void notrace mpu_update_sched_clock(void)
214{ 193{
215 u32 cyc = ~omap_mpu_timer_read(1); 194 return ~omap_mpu_timer_read(1);
216 update_sched_clock(&cd, cyc, (u32)~0);
217} 195}
218 196
219static void __init omap_init_clocksource(unsigned long rate) 197static void __init omap_init_clocksource(unsigned long rate)
@@ -223,7 +201,7 @@ static void __init omap_init_clocksource(unsigned long rate)
223 "%s: can't register clocksource!\n"; 201 "%s: can't register clocksource!\n";
224 202
225 omap_mpu_timer_start(1, ~0, 1); 203 omap_mpu_timer_start(1, ~0, 1);
226 init_sched_clock(&cd, mpu_update_sched_clock, 32, rate); 204 setup_sched_clock(omap_mpu_read_sched_clock, 32, rate);
227 205
228 if (clocksource_mmio_init(&timer->read_tim, "mpu_timer2", rate, 206 if (clocksource_mmio_init(&timer->read_tim, "mpu_timer2", rate,
229 300, 32, clocksource_mmio_readl_down)) 207 300, 32, clocksource_mmio_readl_down))
@@ -254,30 +232,6 @@ static inline void omap_mpu_timer_init(void)
254} 232}
255#endif /* CONFIG_OMAP_MPU_TIMER */ 233#endif /* CONFIG_OMAP_MPU_TIMER */
256 234
257#if defined(CONFIG_OMAP_MPU_TIMER) && defined(CONFIG_OMAP_32K_TIMER)
258static unsigned long long (*preferred_sched_clock)(void);
259
260unsigned long long notrace sched_clock(void)
261{
262 if (!preferred_sched_clock)
263 return 0;
264
265 return preferred_sched_clock();
266}
267
268static inline void preferred_sched_clock_init(bool use_32k_sched_clock)
269{
270 if (use_32k_sched_clock)
271 preferred_sched_clock = omap_32k_sched_clock;
272 else
273 preferred_sched_clock = omap_mpu_sched_clock;
274}
275#else
276static inline void preferred_sched_clock_init(bool use_32k_sched_clcok)
277{
278}
279#endif
280
281static inline int omap_32k_timer_usable(void) 235static inline int omap_32k_timer_usable(void)
282{ 236{
283 int res = false; 237 int res = false;
@@ -299,12 +253,8 @@ static inline int omap_32k_timer_usable(void)
299 */ 253 */
300static void __init omap1_timer_init(void) 254static void __init omap1_timer_init(void)
301{ 255{
302 if (omap_32k_timer_usable()) { 256 if (!omap_32k_timer_usable())
303 preferred_sched_clock_init(1);
304 } else {
305 omap_mpu_timer_init(); 257 omap_mpu_timer_init();
306 preferred_sched_clock_init(0);
307 }
308} 258}
309 259
310struct sys_timer omap1_timer = { 260struct sys_timer omap1_timer = {
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 9edcd520510f..6eeff0e0ae01 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -254,7 +254,6 @@ static struct omap_dm_timer clksrc;
254/* 254/*
255 * clocksource 255 * clocksource
256 */ 256 */
257static DEFINE_CLOCK_DATA(cd);
258static cycle_t clocksource_read_cycles(struct clocksource *cs) 257static cycle_t clocksource_read_cycles(struct clocksource *cs)
259{ 258{
260 return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 1); 259 return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 1);
@@ -268,23 +267,12 @@ static struct clocksource clocksource_gpt = {
268 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 267 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
269}; 268};
270 269
271static void notrace dmtimer_update_sched_clock(void) 270static u32 notrace dmtimer_read_sched_clock(void)
272{ 271{
273 u32 cyc;
274
275 cyc = __omap_dm_timer_read_counter(&clksrc, 1);
276
277 update_sched_clock(&cd, cyc, (u32)~0);
278}
279
280unsigned long long notrace sched_clock(void)
281{
282 u32 cyc = 0;
283
284 if (clksrc.reserved) 272 if (clksrc.reserved)
285 cyc = __omap_dm_timer_read_counter(&clksrc, 1); 273 return __omap_dm_timer_read_counter(clksrc.io_base, 1);
286 274
287 return cyc_to_sched_clock(&cd, cyc, (u32)~0); 275 return 0;
288} 276}
289 277
290/* Setup free-running counter for clocksource */ 278/* Setup free-running counter for clocksource */
@@ -301,7 +289,7 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
301 289
302 __omap_dm_timer_load_start(&clksrc, 290 __omap_dm_timer_load_start(&clksrc,
303 OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1); 291 OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
304 init_sched_clock(&cd, dmtimer_update_sched_clock, 32, clksrc.rate); 292 setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate);
305 293
306 if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) 294 if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
307 pr_err("Could not register clocksource %s\n", 295 pr_err("Could not register clocksource %s\n",
diff --git a/arch/arm/mach-picoxcell/time.c b/arch/arm/mach-picoxcell/time.c
index 90a554ff4499..6c89cf8ab22e 100644
--- a/arch/arm/mach-picoxcell/time.c
+++ b/arch/arm/mach-picoxcell/time.c
@@ -11,7 +11,6 @@
11#include <linux/of.h> 11#include <linux/of.h>
12#include <linux/of_address.h> 12#include <linux/of_address.h>
13#include <linux/of_irq.h> 13#include <linux/of_irq.h>
14#include <linux/sched.h>
15 14
16#include <asm/mach/time.h> 15#include <asm/mach/time.h>
17#include <asm/sched_clock.h> 16#include <asm/sched_clock.h>
@@ -66,21 +65,11 @@ static void picoxcell_add_clocksource(struct device_node *source_timer)
66 dw_apb_clocksource_register(cs); 65 dw_apb_clocksource_register(cs);
67} 66}
68 67
69static DEFINE_CLOCK_DATA(cd);
70static void __iomem *sched_io_base; 68static void __iomem *sched_io_base;
71 69
72unsigned long long notrace sched_clock(void) 70unsigned u32 notrace picoxcell_read_sched_clock(void)
73{ 71{
74 cycle_t cyc = sched_io_base ? __raw_readl(sched_io_base) : 0; 72 return __raw_readl(sched_io_base);
75
76 return cyc_to_sched_clock(&cd, cyc, (u32)~0);
77}
78
79static void notrace picoxcell_update_sched_clock(void)
80{
81 cycle_t cyc = sched_io_base ? __raw_readl(sched_io_base) : 0;
82
83 update_sched_clock(&cd, cyc, (u32)~0);
84} 73}
85 74
86static const struct of_device_id picoxcell_rtc_ids[] __initconst = { 75static const struct of_device_id picoxcell_rtc_ids[] __initconst = {
@@ -100,7 +89,7 @@ static void picoxcell_init_sched_clock(void)
100 timer_get_base_and_rate(sched_timer, &sched_io_base, &rate); 89 timer_get_base_and_rate(sched_timer, &sched_io_base, &rate);
101 of_node_put(sched_timer); 90 of_node_put(sched_timer);
102 91
103 init_sched_clock(&cd, picoxcell_update_sched_clock, 32, rate); 92 setup_sched_clock(picoxcell_read_sched_clock, 32, rate);
104} 93}
105 94
106static const struct of_device_id picoxcell_timer_ids[] __initconst = { 95static const struct of_device_id picoxcell_timer_ids[] __initconst = {
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index de684701449c..b503049d6d26 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -16,7 +16,6 @@
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/interrupt.h> 17#include <linux/interrupt.h>
18#include <linux/clockchips.h> 18#include <linux/clockchips.h>
19#include <linux/sched.h>
20 19
21#include <asm/div64.h> 20#include <asm/div64.h>
22#include <asm/mach/irq.h> 21#include <asm/mach/irq.h>
@@ -32,18 +31,10 @@
32 * long as there is always less than 582 seconds between successive 31 * long as there is always less than 582 seconds between successive
33 * calls to sched_clock() which should always be the case in practice. 32 * calls to sched_clock() which should always be the case in practice.
34 */ 33 */
35static DEFINE_CLOCK_DATA(cd);
36 34
37unsigned long long notrace sched_clock(void) 35static u32 notrace pxa_read_sched_clock(void)
38{ 36{
39 u32 cyc = OSCR; 37 return OSCR;
40 return cyc_to_sched_clock(&cd, cyc, (u32)~0);
41}
42
43static void notrace pxa_update_sched_clock(void)
44{
45 u32 cyc = OSCR;
46 update_sched_clock(&cd, cyc, (u32)~0);
47} 38}
48 39
49 40
@@ -119,7 +110,7 @@ static void __init pxa_timer_init(void)
119 OIER = 0; 110 OIER = 0;
120 OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3; 111 OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3;
121 112
122 init_sched_clock(&cd, pxa_update_sched_clock, 32, clock_tick_rate); 113 setup_sched_clock(pxa_read_sched_clock, 32, clock_tick_rate);
123 114
124 clockevents_calc_mult_shift(&ckevt_pxa_osmr0, clock_tick_rate, 4); 115 clockevents_calc_mult_shift(&ckevt_pxa_osmr0, clock_tick_rate, 4);
125 ckevt_pxa_osmr0.max_delta_ns = 116 ckevt_pxa_osmr0.max_delta_ns =
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index fa6602491d54..1ee6d4ca8dd7 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -12,7 +12,6 @@
12#include <linux/errno.h> 12#include <linux/errno.h>
13#include <linux/interrupt.h> 13#include <linux/interrupt.h>
14#include <linux/irq.h> 14#include <linux/irq.h>
15#include <linux/sched.h> /* just for sched_clock() - funny that */
16#include <linux/timex.h> 15#include <linux/timex.h>
17#include <linux/clockchips.h> 16#include <linux/clockchips.h>
18 17
@@ -20,29 +19,9 @@
20#include <asm/sched_clock.h> 19#include <asm/sched_clock.h>
21#include <mach/hardware.h> 20#include <mach/hardware.h>
22 21
23/* 22static u32 notrace sa100_read_sched_clock(void)
24 * This is the SA11x0 sched_clock implementation.
25 */
26static DEFINE_CLOCK_DATA(cd);
27
28/*
29 * Constants generated by clocks_calc_mult_shift(m, s, 3.6864MHz,
30 * NSEC_PER_SEC, 60).
31 * This gives a resolution of about 271ns and a wrap period of about 19min.
32 */
33#define SC_MULT 2275555556u
34#define SC_SHIFT 23
35
36unsigned long long notrace sched_clock(void)
37{
38 u32 cyc = OSCR;
39 return cyc_to_fixed_sched_clock(&cd, cyc, (u32)~0, SC_MULT, SC_SHIFT);
40}
41
42static void notrace sa1100_update_sched_clock(void)
43{ 23{
44 u32 cyc = OSCR; 24 return OSCR;
45 update_sched_clock(&cd, cyc, (u32)~0);
46} 25}
47 26
48#define MIN_OSCR_DELTA 2 27#define MIN_OSCR_DELTA 2
@@ -109,8 +88,7 @@ static void __init sa1100_timer_init(void)
109 OIER = 0; 88 OIER = 0;
110 OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3; 89 OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3;
111 90
112 init_fixed_sched_clock(&cd, sa1100_update_sched_clock, 32, 91 setup_sched_clock(sa1100_read_sched_clock, 32, 3686400);
113 3686400, SC_MULT, SC_SHIFT);
114 92
115 clockevents_calc_mult_shift(&ckevt_sa1100_osmr0, 3686400, 4); 93 clockevents_calc_mult_shift(&ckevt_sa1100_osmr0, 3686400, 4);
116 ckevt_sa1100_osmr0.max_delta_ns = 94 ckevt_sa1100_osmr0.max_delta_ns =
diff --git a/arch/arm/mach-tegra/timer.c b/arch/arm/mach-tegra/timer.c
index e2272d263a83..732c724008b1 100644
--- a/arch/arm/mach-tegra/timer.c
+++ b/arch/arm/mach-tegra/timer.c
@@ -19,7 +19,6 @@
19 19
20#include <linux/init.h> 20#include <linux/init.h>
21#include <linux/err.h> 21#include <linux/err.h>
22#include <linux/sched.h>
23#include <linux/time.h> 22#include <linux/time.h>
24#include <linux/interrupt.h> 23#include <linux/interrupt.h>
25#include <linux/irq.h> 24#include <linux/irq.h>
@@ -106,25 +105,9 @@ static struct clock_event_device tegra_clockevent = {
106 .set_mode = tegra_timer_set_mode, 105 .set_mode = tegra_timer_set_mode,
107}; 106};
108 107
109static DEFINE_CLOCK_DATA(cd); 108static u32 notrace tegra_read_sched_clock(void)
110
111/*
112 * Constants generated by clocks_calc_mult_shift(m, s, 1MHz, NSEC_PER_SEC, 60).
113 * This gives a resolution of about 1us and a wrap period of about 1h11min.
114 */
115#define SC_MULT 4194304000u
116#define SC_SHIFT 22
117
118unsigned long long notrace sched_clock(void)
119{
120 u32 cyc = timer_readl(TIMERUS_CNTR_1US);
121 return cyc_to_fixed_sched_clock(&cd, cyc, (u32)~0, SC_MULT, SC_SHIFT);
122}
123
124static void notrace tegra_update_sched_clock(void)
125{ 109{
126 u32 cyc = timer_readl(TIMERUS_CNTR_1US); 110 return timer_readl(TIMERUS_CNTR_1US);
127 update_sched_clock(&cd, cyc, (u32)~0);
128} 111}
129 112
130/* 113/*
@@ -218,8 +201,7 @@ static void __init tegra_init_timer(void)
218 WARN(1, "Unknown clock rate"); 201 WARN(1, "Unknown clock rate");
219 } 202 }
220 203
221 init_fixed_sched_clock(&cd, tegra_update_sched_clock, 32, 204 setup_sched_clock(tegra_read_sched_clock, 32, 1000000);
222 1000000, SC_MULT, SC_SHIFT);
223 205
224 if (clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US, 206 if (clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US,
225 "timer_us", 1000000, 300, 32, clocksource_mmio_readl_up)) { 207 "timer_us", 1000000, 300, 32, clocksource_mmio_readl_up)) {
diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c
index 5f51bdeef0ef..bc1c7897e82d 100644
--- a/arch/arm/mach-u300/timer.c
+++ b/arch/arm/mach-u300/timer.c
@@ -9,7 +9,6 @@
9 * Author: Linus Walleij <linus.walleij@stericsson.com> 9 * Author: Linus Walleij <linus.walleij@stericsson.com>
10 */ 10 */
11#include <linux/interrupt.h> 11#include <linux/interrupt.h>
12#include <linux/sched.h>
13#include <linux/time.h> 12#include <linux/time.h>
14#include <linux/timex.h> 13#include <linux/timex.h>
15#include <linux/clockchips.h> 14#include <linux/clockchips.h>
@@ -337,18 +336,10 @@ static struct irqaction u300_timer_irq = {
337 * this wraps around for now, since it is just a relative time 336 * this wraps around for now, since it is just a relative time
338 * stamp. (Inspired by OMAP implementation.) 337 * stamp. (Inspired by OMAP implementation.)
339 */ 338 */
340static DEFINE_CLOCK_DATA(cd);
341 339
342unsigned long long notrace sched_clock(void) 340static u32 notrace u300_read_sched_clock(void)
343{ 341{
344 u32 cyc = readl(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC); 342 return readl(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC);
345 return cyc_to_sched_clock(&cd, cyc, (u32)~0);
346}
347
348static void notrace u300_update_sched_clock(void)
349{
350 u32 cyc = readl(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC);
351 update_sched_clock(&cd, cyc, (u32)~0);
352} 343}
353 344
354 345
@@ -366,7 +357,7 @@ static void __init u300_timer_init(void)
366 clk_enable(clk); 357 clk_enable(clk);
367 rate = clk_get_rate(clk); 358 rate = clk_get_rate(clk);
368 359
369 init_sched_clock(&cd, u300_update_sched_clock, 32, rate); 360 setup_sched_clock(u300_read_sched_clock, 32, rate);
370 361
371 /* 362 /*
372 * Disable the "OS" and "DD" timers - these are designed for Symbian! 363 * Disable the "OS" and "DD" timers - these are designed for Symbian!
diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c
index 568dd0223d17..cbfbbe461788 100644
--- a/arch/arm/plat-iop/time.c
+++ b/arch/arm/plat-iop/time.c
@@ -18,7 +18,6 @@
18#include <linux/time.h> 18#include <linux/time.h>
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/timex.h> 20#include <linux/timex.h>
21#include <linux/sched.h>
22#include <linux/io.h> 21#include <linux/io.h>
23#include <linux/clocksource.h> 22#include <linux/clocksource.h>
24#include <linux/clockchips.h> 23#include <linux/clockchips.h>
@@ -52,21 +51,12 @@ static struct clocksource iop_clocksource = {
52 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 51 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
53}; 52};
54 53
55static DEFINE_CLOCK_DATA(cd);
56
57/* 54/*
58 * IOP sched_clock() implementation via its clocksource. 55 * IOP sched_clock() implementation via its clocksource.
59 */ 56 */
60unsigned long long notrace sched_clock(void) 57static u32 notrace iop_read_sched_clock(void)
61{ 58{
62 u32 cyc = 0xffffffffu - read_tcr1(); 59 return 0xffffffffu - read_tcr1();
63 return cyc_to_sched_clock(&cd, cyc, (u32)~0);
64}
65
66static void notrace iop_update_sched_clock(void)
67{
68 u32 cyc = 0xffffffffu - read_tcr1();
69 update_sched_clock(&cd, cyc, (u32)~0);
70} 60}
71 61
72/* 62/*
@@ -152,7 +142,7 @@ void __init iop_init_time(unsigned long tick_rate)
152{ 142{
153 u32 timer_ctl; 143 u32 timer_ctl;
154 144
155 init_sched_clock(&cd, iop_update_sched_clock, 32, tick_rate); 145 setup_sched_clock(iop_read_sched_clock, 32, tick_rate);
156 146
157 ticks_per_jiffy = DIV_ROUND_CLOSEST(tick_rate, HZ); 147 ticks_per_jiffy = DIV_ROUND_CLOSEST(tick_rate, HZ);
158 iop_tick_rate = tick_rate; 148 iop_tick_rate = tick_rate;
diff --git a/arch/arm/plat-mxc/time.c b/arch/arm/plat-mxc/time.c
index 4b0fe285e83c..1c96cdb4c35e 100644
--- a/arch/arm/plat-mxc/time.c
+++ b/arch/arm/plat-mxc/time.c
@@ -108,18 +108,9 @@ static void gpt_irq_acknowledge(void)
108 108
109static void __iomem *sched_clock_reg; 109static void __iomem *sched_clock_reg;
110 110
111static DEFINE_CLOCK_DATA(cd); 111static u32 notrace mxc_read_sched_clock(void)
112unsigned long long notrace sched_clock(void)
113{ 112{
114 cycle_t cyc = sched_clock_reg ? __raw_readl(sched_clock_reg) : 0; 113 return sched_clock_reg ? __raw_readl(sched_clock_reg) : 0;
115
116 return cyc_to_sched_clock(&cd, cyc, (u32)~0);
117}
118
119static void notrace mxc_update_sched_clock(void)
120{
121 cycle_t cyc = sched_clock_reg ? __raw_readl(sched_clock_reg) : 0;
122 update_sched_clock(&cd, cyc, (u32)~0);
123} 114}
124 115
125static int __init mxc_clocksource_init(struct clk *timer_clk) 116static int __init mxc_clocksource_init(struct clk *timer_clk)
@@ -129,7 +120,7 @@ static int __init mxc_clocksource_init(struct clk *timer_clk)
129 120
130 sched_clock_reg = reg; 121 sched_clock_reg = reg;
131 122
132 init_sched_clock(&cd, mxc_update_sched_clock, 32, c); 123 setup_sched_clock(mxc_read_sched_clock, 32, c);
133 return clocksource_mmio_init(reg, "mxc_timer1", c, 200, 32, 124 return clocksource_mmio_init(reg, "mxc_timer1", c, 200, 32,
134 clocksource_mmio_readl_up); 125 clocksource_mmio_readl_up);
135} 126}
diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c
index 30b6433d910d..ad1b45b605a4 100644
--- a/arch/arm/plat-nomadik/timer.c
+++ b/arch/arm/plat-nomadik/timer.c
@@ -17,7 +17,6 @@
17#include <linux/clk.h> 17#include <linux/clk.h>
18#include <linux/jiffies.h> 18#include <linux/jiffies.h>
19#include <linux/err.h> 19#include <linux/err.h>
20#include <linux/sched.h>
21#include <asm/mach/time.h> 20#include <asm/mach/time.h>
22#include <asm/sched_clock.h> 21#include <asm/sched_clock.h>
23 22
@@ -79,23 +78,12 @@ void __iomem *mtu_base; /* Assigned by machine code */
79 * local implementation which uses the clocksource to get some 78 * local implementation which uses the clocksource to get some
80 * better resolution when scheduling the kernel. 79 * better resolution when scheduling the kernel.
81 */ 80 */
82static DEFINE_CLOCK_DATA(cd); 81static u32 notrace nomadik_read_sched_clock(void)
83
84unsigned long long notrace sched_clock(void)
85{ 82{
86 u32 cyc;
87
88 if (unlikely(!mtu_base)) 83 if (unlikely(!mtu_base))
89 return 0; 84 return 0;
90 85
91 cyc = -readl(mtu_base + MTU_VAL(0)); 86 return -readl(mtu_base + MTU_VAL(0));
92 return cyc_to_sched_clock(&cd, cyc, (u32)~0);
93}
94
95static void notrace nomadik_update_sched_clock(void)
96{
97 u32 cyc = -readl(mtu_base + MTU_VAL(0));
98 update_sched_clock(&cd, cyc, (u32)~0);
99} 87}
100#endif 88#endif
101 89
@@ -231,9 +219,11 @@ void __init nmdk_timer_init(void)
231 rate, 200, 32, clocksource_mmio_readl_down)) 219 rate, 200, 32, clocksource_mmio_readl_down))
232 pr_err("timer: failed to initialize clock source %s\n", 220 pr_err("timer: failed to initialize clock source %s\n",
233 "mtu_0"); 221 "mtu_0");
222
234#ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK 223#ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK
235 init_sched_clock(&cd, nomadik_update_sched_clock, 32, rate); 224 setup_sched_clock(nomadik_read_sched_clock, 32, rate);
236#endif 225#endif
226
237 /* Timer 1 is used for events */ 227 /* Timer 1 is used for events */
238 228
239 clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE); 229 clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE);
diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c
index a6cbb712da51..5f0f2292b7fb 100644
--- a/arch/arm/plat-omap/counter_32k.c
+++ b/arch/arm/plat-omap/counter_32k.c
@@ -17,7 +17,6 @@
17#include <linux/clk.h> 17#include <linux/clk.h>
18#include <linux/err.h> 18#include <linux/err.h>
19#include <linux/io.h> 19#include <linux/io.h>
20#include <linux/sched.h>
21#include <linux/clocksource.h> 20#include <linux/clocksource.h>
22 21
23#include <asm/sched_clock.h> 22#include <asm/sched_clock.h>
@@ -37,41 +36,9 @@ static void __iomem *timer_32k_base;
37 36
38#define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410 37#define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410
39 38
40/* 39static u32 notrace omap_32k_read_sched_clock(void)
41 * Returns current time from boot in nsecs. It's OK for this to wrap
42 * around for now, as it's just a relative time stamp.
43 */
44static DEFINE_CLOCK_DATA(cd);
45
46/*
47 * Constants generated by clocks_calc_mult_shift(m, s, 32768, NSEC_PER_SEC, 60).
48 * This gives a resolution of about 30us and a wrap period of about 36hrs.
49 */
50#define SC_MULT 4000000000u
51#define SC_SHIFT 17
52
53static inline unsigned long long notrace _omap_32k_sched_clock(void)
54{
55 u32 cyc = timer_32k_base ? __raw_readl(timer_32k_base) : 0;
56 return cyc_to_fixed_sched_clock(&cd, cyc, (u32)~0, SC_MULT, SC_SHIFT);
57}
58
59#if defined(CONFIG_OMAP_32K_TIMER) && !defined(CONFIG_OMAP_MPU_TIMER)
60unsigned long long notrace sched_clock(void)
61{
62 return _omap_32k_sched_clock();
63}
64#else
65unsigned long long notrace omap_32k_sched_clock(void)
66{
67 return _omap_32k_sched_clock();
68}
69#endif
70
71static void notrace omap_update_sched_clock(void)
72{ 40{
73 u32 cyc = timer_32k_base ? __raw_readl(timer_32k_base) : 0; 41 return timer_32k_base ? __raw_readl(timer_32k_base) : 0;
74 update_sched_clock(&cd, cyc, (u32)~0);
75} 42}
76 43
77/** 44/**
@@ -147,8 +114,7 @@ int __init omap_init_clocksource_32k(void)
147 clocksource_mmio_readl_up)) 114 clocksource_mmio_readl_up))
148 printk(err, "32k_counter"); 115 printk(err, "32k_counter");
149 116
150 init_fixed_sched_clock(&cd, omap_update_sched_clock, 32, 117 setup_sched_clock(omap_32k_read_sched_clock, 32, 32768);
151 32768, SC_MULT, SC_SHIFT);
152 } 118 }
153 return 0; 119 return 0;
154} 120}
diff --git a/arch/arm/plat-omap/include/plat/common.h b/arch/arm/plat-omap/include/plat/common.h
index 257f9770b2da..b4d7ec3fbfbe 100644
--- a/arch/arm/plat-omap/include/plat/common.h
+++ b/arch/arm/plat-omap/include/plat/common.h
@@ -31,7 +31,6 @@
31#include <plat/omap_hwmod.h> 31#include <plat/omap_hwmod.h>
32 32
33extern int __init omap_init_clocksource_32k(void); 33extern int __init omap_init_clocksource_32k(void);
34extern unsigned long long notrace omap_32k_sched_clock(void);
35 34
36extern void omap_reserve(void); 35extern void omap_reserve(void);
37extern int omap_dss_reset(struct omap_hwmod *); 36extern int omap_dss_reset(struct omap_hwmod *);
diff --git a/arch/arm/plat-orion/time.c b/arch/arm/plat-orion/time.c
index 69a61367e4b8..1ed8d1397fcf 100644
--- a/arch/arm/plat-orion/time.c
+++ b/arch/arm/plat-orion/time.c
@@ -12,7 +12,6 @@
12 */ 12 */
13 13
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include <linux/sched.h>
16#include <linux/timer.h> 15#include <linux/timer.h>
17#include <linux/clockchips.h> 16#include <linux/clockchips.h>
18#include <linux/interrupt.h> 17#include <linux/interrupt.h>
@@ -60,24 +59,10 @@ static u32 ticks_per_jiffy;
60 * Orion's sched_clock implementation. It has a resolution of 59 * Orion's sched_clock implementation. It has a resolution of
61 * at least 7.5ns (133MHz TCLK). 60 * at least 7.5ns (133MHz TCLK).
62 */ 61 */
63static DEFINE_CLOCK_DATA(cd);
64 62
65unsigned long long notrace sched_clock(void) 63static u32 notrace orion_read_sched_clock(void)
66{ 64{
67 u32 cyc = ~readl(timer_base + TIMER0_VAL_OFF); 65 return ~readl(timer_base + TIMER0_VAL_OFF);
68 return cyc_to_sched_clock(&cd, cyc, (u32)~0);
69}
70
71
72static void notrace orion_update_sched_clock(void)
73{
74 u32 cyc = ~readl(timer_base + TIMER0_VAL_OFF);
75 update_sched_clock(&cd, cyc, (u32)~0);
76}
77
78static void __init setup_sched_clock(unsigned long tclk)
79{
80 init_sched_clock(&cd, orion_update_sched_clock, 32, tclk);
81} 66}
82 67
83/* 68/*
@@ -217,7 +202,7 @@ orion_time_init(u32 _bridge_base, u32 _bridge_timer1_clr_mask,
217 /* 202 /*
218 * Set scale and timer for sched_clock. 203 * Set scale and timer for sched_clock.
219 */ 204 */
220 setup_sched_clock(tclk); 205 setup_sched_clock(orion_read_sched_clock, 32, tclk);
221 206
222 /* 207 /*
223 * Setup free-running clocksource timer (interrupts 208 * Setup free-running clocksource timer (interrupts
diff --git a/arch/arm/plat-s5p/s5p-time.c b/arch/arm/plat-s5p/s5p-time.c
index c833e7b57599..17c0a2c58dfd 100644
--- a/arch/arm/plat-s5p/s5p-time.c
+++ b/arch/arm/plat-s5p/s5p-time.c
@@ -10,7 +10,6 @@
10 * published by the Free Software Foundation. 10 * published by the Free Software Foundation.
11*/ 11*/
12 12
13#include <linux/sched.h>
14#include <linux/interrupt.h> 13#include <linux/interrupt.h>
15#include <linux/irq.h> 14#include <linux/irq.h>
16#include <linux/err.h> 15#include <linux/err.h>
@@ -321,26 +320,14 @@ static void __iomem *s5p_timer_reg(void)
321 * this wraps around for now, since it is just a relative time 320 * this wraps around for now, since it is just a relative time
322 * stamp. (Inspired by U300 implementation.) 321 * stamp. (Inspired by U300 implementation.)
323 */ 322 */
324static DEFINE_CLOCK_DATA(cd); 323static u32 notrace s5p_read_sched_clock(void)
325
326unsigned long long notrace sched_clock(void)
327{ 324{
328 void __iomem *reg = s5p_timer_reg(); 325 void __iomem *reg = s5p_timer_reg();
329 326
330 if (!reg) 327 if (!reg)
331 return 0; 328 return 0;
332 329
333 return cyc_to_sched_clock(&cd, ~__raw_readl(reg), (u32)~0); 330 return ~__raw_readl(reg);
334}
335
336static void notrace s5p_update_sched_clock(void)
337{
338 void __iomem *reg = s5p_timer_reg();
339
340 if (!reg)
341 return;
342
343 update_sched_clock(&cd, ~__raw_readl(reg), (u32)~0);
344} 331}
345 332
346static void __init s5p_clocksource_init(void) 333static void __init s5p_clocksource_init(void)
@@ -358,7 +345,7 @@ static void __init s5p_clocksource_init(void)
358 s5p_time_setup(timer_source.source_id, TCNT_MAX); 345 s5p_time_setup(timer_source.source_id, TCNT_MAX);
359 s5p_time_start(timer_source.source_id, PERIODIC); 346 s5p_time_start(timer_source.source_id, PERIODIC);
360 347
361 init_sched_clock(&cd, s5p_update_sched_clock, 32, clock_rate); 348 setup_sched_clock(s5p_read_sched_clock, 32, clock_rate);
362 349
363 if (clocksource_mmio_init(s5p_timer_reg(), "s5p_clocksource_timer", 350 if (clocksource_mmio_init(s5p_timer_reg(), "s5p_clocksource_timer",
364 clock_rate, 250, 32, clocksource_mmio_readl_down)) 351 clock_rate, 250, 32, clocksource_mmio_readl_down))
diff --git a/arch/arm/plat-versatile/sched-clock.c b/arch/arm/plat-versatile/sched-clock.c
index 3d6a4c292cab..b33b74c87232 100644
--- a/arch/arm/plat-versatile/sched-clock.c
+++ b/arch/arm/plat-versatile/sched-clock.c
@@ -18,41 +18,24 @@
18 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 20 */
21#include <linux/kernel.h>
21#include <linux/io.h> 22#include <linux/io.h>
22#include <linux/sched.h>
23 23
24#include <asm/sched_clock.h> 24#include <asm/sched_clock.h>
25#include <plat/sched_clock.h> 25#include <plat/sched_clock.h>
26 26
27static DEFINE_CLOCK_DATA(cd);
28static void __iomem *ctr; 27static void __iomem *ctr;
29 28
30/* 29static u32 notrace versatile_read_sched_clock(void)
31 * Constants generated by clocks_calc_mult_shift(m, s, 24MHz, NSEC_PER_SEC, 60).
32 * This gives a resolution of about 41ns and a wrap period of about 178s.
33 */
34#define SC_MULT 2796202667u
35#define SC_SHIFT 26
36
37unsigned long long notrace sched_clock(void)
38{ 30{
39 if (ctr) { 31 if (ctr)
40 u32 cyc = readl(ctr); 32 return readl(ctr);
41 return cyc_to_fixed_sched_clock(&cd, cyc, (u32)~0,
42 SC_MULT, SC_SHIFT);
43 } else
44 return 0;
45}
46 33
47static void notrace versatile_update_sched_clock(void) 34 return 0;
48{
49 u32 cyc = readl(ctr);
50 update_sched_clock(&cd, cyc, (u32)~0);
51} 35}
52 36
53void __init versatile_sched_clock_init(void __iomem *reg, unsigned long rate) 37void __init versatile_sched_clock_init(void __iomem *reg, unsigned long rate)
54{ 38{
55 ctr = reg; 39 ctr = reg;
56 init_fixed_sched_clock(&cd, versatile_update_sched_clock, 40 setup_sched_clock(versatile_read_sched_clock, 32, rate);
57 32, rate, SC_MULT, SC_SHIFT);
58} 41}