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 | |
| 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')
| -rw-r--r-- | arch/cris/Kconfig | 1 | ||||
| -rw-r--r-- | arch/cris/arch-v32/kernel/time.c | 145 |
2 files changed, 86 insertions, 60 deletions
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 97d3936ffe92..366dc83019a5 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig | |||
| @@ -55,6 +55,7 @@ config CRIS | |||
| 55 | select IRQ_DOMAIN if ETRAX_ARCH_V32 | 55 | select IRQ_DOMAIN if ETRAX_ARCH_V32 |
| 56 | select OF if ETRAX_ARCH_V32 | 56 | select OF if ETRAX_ARCH_V32 |
| 57 | select OF_EARLY_FLATTREE if ETRAX_ARCH_V32 | 57 | select OF_EARLY_FLATTREE if ETRAX_ARCH_V32 |
| 58 | select GENERIC_CLOCKEVENTS if ETRAX_ARCH_V32 | ||
| 58 | 59 | ||
| 59 | config HZ | 60 | config HZ |
| 60 | int | 61 | int |
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 | ||
