diff options
author | Rabin Vincent <rabin@rab.in> | 2015-03-08 11:29:12 -0400 |
---|---|---|
committer | Jesper Nilsson <jespern@axis.com> | 2015-03-25 06:03:40 -0400 |
commit | ed9fd3ff0251783cb3943e71aac398b9064efae6 (patch) | |
tree | 37082935bde7a51e91e42ff8521e9ea89780f3b7 /arch/cris/arch-v32 | |
parent | 16428f943d192390b4673612b1d3fb81772323d9 (diff) |
CRISv32: use generic clockevents
Implement a oneshot-capable clockevents device so we get support for
things like hrtimers and NOHZ.
Signed-off-by: Rabin Vincent <rabin@rab.in>
Signed-off-by: Jesper Nilsson <jespern@axis.com>
Diffstat (limited to 'arch/cris/arch-v32')
-rw-r--r-- | arch/cris/arch-v32/kernel/time.c | 145 |
1 files changed, 85 insertions, 60 deletions
diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c index aa2d94b7fb61..77e241d6fa3d 100644 --- a/arch/cris/arch-v32/kernel/time.c +++ b/arch/cris/arch-v32/kernel/time.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/timex.h> | 8 | #include <linux/timex.h> |
9 | #include <linux/time.h> | 9 | #include <linux/time.h> |
10 | #include <linux/clocksource.h> | 10 | #include <linux/clocksource.h> |
11 | #include <linux/clockchips.h> | ||
11 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
12 | #include <linux/swap.h> | 13 | #include <linux/swap.h> |
13 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
@@ -36,6 +37,8 @@ | |||
36 | /* Number of 763 counts before watchdog bites */ | 37 | /* Number of 763 counts before watchdog bites */ |
37 | #define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1) | 38 | #define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1) |
38 | 39 | ||
40 | #define CRISV32_TIMER_FREQ (100000000lu) | ||
41 | |||
39 | /* Register the continuos readonly timer available in FS and ARTPEC-3. */ | 42 | /* Register the continuos readonly timer available in FS and ARTPEC-3. */ |
40 | static cycle_t read_cont_rotime(struct clocksource *cs) | 43 | static cycle_t read_cont_rotime(struct clocksource *cs) |
41 | { | 44 | { |
@@ -186,81 +189,99 @@ void handle_watchdog_bite(struct pt_regs *regs) | |||
186 | #endif | 189 | #endif |
187 | } | 190 | } |
188 | 191 | ||
189 | /* | 192 | extern void cris_profile_sample(struct pt_regs *regs); |
190 | * timer_interrupt() needs to keep up the real-time clock, | 193 | static void __iomem *timer_base; |
191 | * as well as call the "xtime_update()" routine every clocktick. | ||
192 | */ | ||
193 | extern void cris_do_profile(struct pt_regs *regs); | ||
194 | 194 | ||
195 | static inline irqreturn_t timer_interrupt(int irq, void *dev_id) | 195 | static void crisv32_clkevt_mode(enum clock_event_mode mode, |
196 | struct clock_event_device *dev) | ||
196 | { | 197 | { |
197 | struct pt_regs *regs = get_irq_regs(); | 198 | reg_timer_rw_tmr0_ctrl ctrl = { |
198 | int cpu = smp_processor_id(); | 199 | .op = regk_timer_hold, |
199 | reg_timer_r_masked_intr masked_intr; | 200 | .freq = regk_timer_f100, |
200 | reg_timer_rw_ack_intr ack_intr = { 0 }; | 201 | }; |
201 | |||
202 | /* Check if the timer interrupt is for us (a tmr0 int) */ | ||
203 | masked_intr = REG_RD(timer, timer_regs[cpu], r_masked_intr); | ||
204 | if (!masked_intr.tmr0) | ||
205 | return IRQ_NONE; | ||
206 | 202 | ||
207 | /* Acknowledge the timer irq. */ | 203 | REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); |
208 | ack_intr.tmr0 = 1; | 204 | } |
209 | REG_WR(timer, timer_regs[cpu], rw_ack_intr, ack_intr); | ||
210 | 205 | ||
211 | /* Reset watchdog otherwise it resets us! */ | 206 | static int crisv32_clkevt_next_event(unsigned long evt, |
212 | reset_watchdog(); | 207 | struct clock_event_device *dev) |
208 | { | ||
209 | reg_timer_rw_tmr0_ctrl ctrl = { | ||
210 | .op = regk_timer_ld, | ||
211 | .freq = regk_timer_f100, | ||
212 | }; | ||
213 | |||
214 | REG_WR(timer, timer_base, rw_tmr0_div, evt); | ||
215 | REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); | ||
216 | |||
217 | ctrl.op = regk_timer_run; | ||
218 | REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); | ||
219 | |||
220 | return 0; | ||
221 | } | ||
213 | 222 | ||
214 | /* Update statistics. */ | 223 | static irqreturn_t crisv32_timer_interrupt(int irq, void *dev_id) |
215 | update_process_times(user_mode(regs)); | 224 | { |
225 | struct clock_event_device *evt = dev_id; | ||
226 | reg_timer_rw_tmr0_ctrl ctrl = { | ||
227 | .op = regk_timer_hold, | ||
228 | .freq = regk_timer_f100, | ||
229 | }; | ||
230 | reg_timer_rw_ack_intr ack = { .tmr0 = 1 }; | ||
231 | reg_timer_r_masked_intr intr; | ||
232 | |||
233 | intr = REG_RD(timer, timer_base, r_masked_intr); | ||
234 | if (!intr.tmr0) | ||
235 | return IRQ_NONE; | ||
236 | |||
237 | REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); | ||
238 | REG_WR(timer, timer_base, rw_ack_intr, ack); | ||
216 | 239 | ||
217 | cris_do_profile(regs); /* Save profiling information */ | 240 | reset_watchdog(); |
241 | #ifdef CONFIG_SYSTEM_PROFILER | ||
242 | cris_profile_sample(get_irq_regs()); | ||
243 | #endif | ||
218 | 244 | ||
219 | /* The master CPU is responsible for the time keeping. */ | 245 | evt->event_handler(evt); |
220 | if (cpu != 0) | ||
221 | return IRQ_HANDLED; | ||
222 | 246 | ||
223 | /* Call the real timer interrupt handler */ | ||
224 | xtime_update(1); | ||
225 | return IRQ_HANDLED; | 247 | return IRQ_HANDLED; |
226 | } | 248 | } |
227 | 249 | ||
250 | static struct clock_event_device crisv32_clockevent = { | ||
251 | .name = "crisv32-timer", | ||
252 | .rating = 300, | ||
253 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
254 | .set_mode = crisv32_clkevt_mode, | ||
255 | .set_next_event = crisv32_clkevt_next_event, | ||
256 | }; | ||
257 | |||
228 | /* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. */ | 258 | /* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. */ |
229 | static struct irqaction irq_timer = { | 259 | static struct irqaction irq_timer = { |
230 | .handler = timer_interrupt, | 260 | .handler = crisv32_timer_interrupt, |
231 | .flags = IRQF_SHARED, | 261 | .flags = IRQF_TIMER | IRQF_SHARED, |
232 | .name = "timer" | 262 | .name = "crisv32-timer", |
263 | .dev_id = &crisv32_clockevent, | ||
233 | }; | 264 | }; |
234 | 265 | ||
235 | void __init cris_timer_init(void) | 266 | static void __init crisv32_timer_init(void) |
236 | { | 267 | { |
237 | int cpu = smp_processor_id(); | ||
238 | reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 }; | ||
239 | reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV; | ||
240 | reg_timer_rw_intr_mask timer_intr_mask; | 268 | reg_timer_rw_intr_mask timer_intr_mask; |
269 | reg_timer_rw_tmr0_ctrl ctrl = { | ||
270 | .op = regk_timer_hold, | ||
271 | .freq = regk_timer_f100, | ||
272 | }; | ||
241 | 273 | ||
242 | /* Setup the etrax timers. | 274 | REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); |
243 | * Base frequency is 100MHz, divider 1000000 -> 100 HZ | ||
244 | * We use timer0, so timer1 is free. | ||
245 | * The trig timer is used by the fasttimer API if enabled. | ||
246 | */ | ||
247 | |||
248 | tmr0_ctrl.op = regk_timer_ld; | ||
249 | tmr0_ctrl.freq = regk_timer_f100; | ||
250 | REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div); | ||
251 | REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */ | ||
252 | tmr0_ctrl.op = regk_timer_run; | ||
253 | REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */ | ||
254 | 275 | ||
255 | /* Enable the timer irq. */ | 276 | timer_intr_mask = REG_RD(timer, timer_base, rw_intr_mask); |
256 | timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask); | ||
257 | timer_intr_mask.tmr0 = 1; | 277 | timer_intr_mask.tmr0 = 1; |
258 | REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask); | 278 | REG_WR(timer, timer_base, rw_intr_mask, timer_intr_mask); |
259 | } | 279 | } |
260 | 280 | ||
261 | void __init time_init(void) | 281 | void __init time_init(void) |
262 | { | 282 | { |
263 | reg_intr_vect_rw_mask intr_mask; | 283 | int irq; |
284 | int ret; | ||
264 | 285 | ||
265 | /* Probe for the RTC and read it if it exists. | 286 | /* Probe for the RTC and read it if it exists. |
266 | * Before the RTC can be probed the loops_per_usec variable needs | 287 | * Before the RTC can be probed the loops_per_usec variable needs |
@@ -270,17 +291,21 @@ void __init time_init(void) | |||
270 | */ | 291 | */ |
271 | loops_per_usec = 50; | 292 | loops_per_usec = 50; |
272 | 293 | ||
273 | /* Start CPU local timer. */ | 294 | irq = TIMER0_INTR_VECT; |
274 | cris_timer_init(); | 295 | timer_base = (void __iomem *) regi_timer0; |
296 | |||
297 | crisv32_timer_init(); | ||
298 | |||
299 | crisv32_clockevent.cpumask = cpu_possible_mask; | ||
300 | crisv32_clockevent.irq = irq; | ||
275 | 301 | ||
276 | /* Enable the timer irq in global config. */ | 302 | ret = setup_irq(irq, &irq_timer); |
277 | intr_mask = REG_RD_VECT(intr_vect, regi_irq, rw_mask, 1); | 303 | if (ret) |
278 | intr_mask.timer0 = 1; | 304 | pr_warn("failed to setup irq %d\n", irq); |
279 | REG_WR_VECT(intr_vect, regi_irq, rw_mask, 1, intr_mask); | ||
280 | 305 | ||
281 | /* Now actually register the timer irq handler that calls | 306 | clockevents_config_and_register(&crisv32_clockevent, |
282 | * timer_interrupt(). */ | 307 | CRISV32_TIMER_FREQ, |
283 | setup_irq(TIMER0_INTR_VECT, &irq_timer); | 308 | 2, 0xffffffff); |
284 | 309 | ||
285 | /* Enable watchdog if we should use one. */ | 310 | /* Enable watchdog if we should use one. */ |
286 | 311 | ||