diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-12-15 16:53:02 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-12-22 17:44:48 -0500 |
commit | ec05aa139939d9c7b790041a379f0e752b2f1a4d (patch) | |
tree | d1af6271a2e832e44a1a8c42550484f1ec55c50c /arch/arm/plat-nomadik/timer.c | |
parent | 08f26b1ef25a2f7b52afcb805d260fd5a000a7f6 (diff) |
ARM: nomadik: convert sched_clock() to use new infrastructure
Convert nomadik platforms to use the new sched_clock() infrastructure
for extending 32bit counters to full 64-bit nanoseconds.
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/plat-nomadik/timer.c')
-rw-r--r-- | arch/arm/plat-nomadik/timer.c | 76 |
1 files changed, 9 insertions, 67 deletions
diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c index c3b8a2246b99..41723402006b 100644 --- a/arch/arm/plat-nomadik/timer.c +++ b/arch/arm/plat-nomadik/timer.c | |||
@@ -17,10 +17,9 @@ | |||
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/cnt32_to_63.h> | ||
21 | #include <linux/timer.h> | ||
22 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
23 | #include <asm/mach/time.h> | 21 | #include <asm/mach/time.h> |
22 | #include <asm/sched_clock.h> | ||
24 | 23 | ||
25 | #include <plat/mtu.h> | 24 | #include <plat/mtu.h> |
26 | 25 | ||
@@ -53,81 +52,24 @@ static struct clocksource nmdk_clksrc = { | |||
53 | * Override the global weak sched_clock symbol with this | 52 | * Override the global weak sched_clock symbol with this |
54 | * local implementation which uses the clocksource to get some | 53 | * local implementation which uses the clocksource to get some |
55 | * better resolution when scheduling the kernel. | 54 | * better resolution when scheduling the kernel. |
56 | * | ||
57 | * Because the hardware timer period may be quite short | ||
58 | * (32.3 secs on the 133 MHz MTU timer selection on ux500) | ||
59 | * and because cnt32_to_63() needs to be called at least once per | ||
60 | * half period to work properly, a kernel keepwarm() timer is set up | ||
61 | * to ensure this requirement is always met. | ||
62 | * | ||
63 | * Also the sched_clock timer will wrap around at some point, | ||
64 | * here we set it to run continously for a year. | ||
65 | */ | 55 | */ |
66 | #define SCHED_CLOCK_MIN_WRAP 3600*24*365 | 56 | static DEFINE_CLOCK_DATA(cd); |
67 | static struct timer_list cnt32_to_63_keepwarm_timer; | ||
68 | static u32 sched_mult; | ||
69 | static u32 sched_shift; | ||
70 | 57 | ||
71 | unsigned long long notrace sched_clock(void) | 58 | unsigned long long notrace sched_clock(void) |
72 | { | 59 | { |
73 | u64 cycles; | 60 | u32 cyc; |
74 | 61 | ||
75 | if (unlikely(!mtu_base)) | 62 | if (unlikely(!mtu_base)) |
76 | return 0; | 63 | return 0; |
77 | 64 | ||
78 | cycles = cnt32_to_63(-readl(mtu_base + MTU_VAL(0))); | 65 | cyc = -readl(mtu_base + MTU_VAL(0)); |
79 | /* | 66 | return cyc_to_sched_clock(&cd, cyc, (u32)~0); |
80 | * sched_mult is guaranteed to be even so will | ||
81 | * shift out bit 63 | ||
82 | */ | ||
83 | return (cycles * sched_mult) >> sched_shift; | ||
84 | } | 67 | } |
85 | 68 | ||
86 | /* Just kick sched_clock every so often */ | 69 | static void notrace nomadik_update_sched_clock(void) |
87 | static void cnt32_to_63_keepwarm(unsigned long data) | ||
88 | { | 70 | { |
89 | mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data)); | 71 | u32 cyc = -readl(mtu_base + MTU_VAL(0)); |
90 | (void) sched_clock(); | 72 | update_sched_clock(&cd, cyc, (u32)~0); |
91 | } | ||
92 | |||
93 | /* | ||
94 | * Set up a timer to keep sched_clock():s 32_to_63 algorithm warm | ||
95 | * once in half a 32bit timer wrap interval. | ||
96 | */ | ||
97 | static void __init nmdk_sched_clock_init(unsigned long rate) | ||
98 | { | ||
99 | u32 v; | ||
100 | unsigned long delta; | ||
101 | u64 days; | ||
102 | |||
103 | /* Find the apropriate mult and shift factors */ | ||
104 | clocks_calc_mult_shift(&sched_mult, &sched_shift, | ||
105 | rate, NSEC_PER_SEC, SCHED_CLOCK_MIN_WRAP); | ||
106 | /* We need to multiply by an even number to get rid of bit 63 */ | ||
107 | if (sched_mult & 1) | ||
108 | sched_mult++; | ||
109 | |||
110 | /* Let's see what we get, take max counter and scale it */ | ||
111 | days = (0xFFFFFFFFFFFFFFFFLLU * sched_mult) >> sched_shift; | ||
112 | do_div(days, NSEC_PER_SEC); | ||
113 | do_div(days, (3600*24)); | ||
114 | |||
115 | pr_info("sched_clock: using %d bits @ %lu Hz wrap in %lu days\n", | ||
116 | (64 - sched_shift), rate, (unsigned long) days); | ||
117 | |||
118 | /* | ||
119 | * Program a timer to kick us at half 32bit wraparound | ||
120 | * Formula: seconds per wrap = (2^32) / f | ||
121 | */ | ||
122 | v = 0xFFFFFFFFUL / rate; | ||
123 | /* We want half of the wrap time to keep cnt32_to_63 warm */ | ||
124 | v /= 2; | ||
125 | pr_debug("sched_clock: prescaled timer rate: %lu Hz, " | ||
126 | "initialize keepwarm timer every %d seconds\n", rate, v); | ||
127 | /* Convert seconds to jiffies */ | ||
128 | delta = msecs_to_jiffies(v*1000); | ||
129 | setup_timer(&cnt32_to_63_keepwarm_timer, cnt32_to_63_keepwarm, delta); | ||
130 | mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + delta)); | ||
131 | } | 73 | } |
132 | 74 | ||
133 | /* Clockevent device: use one-shot mode */ | 75 | /* Clockevent device: use one-shot mode */ |
@@ -237,7 +179,7 @@ void __init nmdk_timer_init(void) | |||
237 | pr_err("timer: failed to initialize clock source %s\n", | 179 | pr_err("timer: failed to initialize clock source %s\n", |
238 | nmdk_clksrc.name); | 180 | nmdk_clksrc.name); |
239 | 181 | ||
240 | nmdk_sched_clock_init(rate); | 182 | init_sched_clock(&cd, nomadik_update_sched_clock, 32, rate); |
241 | 183 | ||
242 | /* Timer 1 is used for events */ | 184 | /* Timer 1 is used for events */ |
243 | 185 | ||