diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2007-10-11 18:46:09 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-10-11 18:46:09 -0400 |
commit | ea5804015c0ce67741eb4b156a071fb4f415345f (patch) | |
tree | bc4da66c0d9a531a17159b1cb001ad8e96d24487 /arch/mips/kernel/time.c | |
parent | 7bcf7717b6a047c272410d0cd00213185fe6b99d (diff) |
[MIPS] Dyntick support for SMTC:
The kernel currently only supports broadcasting of the timer interrupt
from a single timer, not multicasting into two multicast groups of
processors. So the implemented mechanism for SMTC works by broadcasting
the cp0 compare interrupt on VPE 0 and ignoring it on any additional VPEs.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/time.c')
-rw-r--r-- | arch/mips/kernel/time.c | 111 |
1 files changed, 98 insertions, 13 deletions
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 35988847c98a..369a5f9ad268 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/kallsyms.h> | ||
28 | 29 | ||
29 | #include <asm/bootinfo.h> | 30 | #include <asm/bootinfo.h> |
30 | #include <asm/cache.h> | 31 | #include <asm/cache.h> |
@@ -33,6 +34,7 @@ | |||
33 | #include <asm/cpu-features.h> | 34 | #include <asm/cpu-features.h> |
34 | #include <asm/div64.h> | 35 | #include <asm/div64.h> |
35 | #include <asm/sections.h> | 36 | #include <asm/sections.h> |
37 | #include <asm/smtc_ipi.h> | ||
36 | #include <asm/time.h> | 38 | #include <asm/time.h> |
37 | 39 | ||
38 | #include <irq.h> | 40 | #include <irq.h> |
@@ -230,12 +232,24 @@ static int mips_next_event(unsigned long delta, | |||
230 | struct clock_event_device *evt) | 232 | struct clock_event_device *evt) |
231 | { | 233 | { |
232 | unsigned int cnt; | 234 | unsigned int cnt; |
235 | int res; | ||
233 | 236 | ||
237 | #ifdef CONFIG_MIPS_MT_SMTC | ||
238 | { | ||
239 | unsigned long flags, vpflags; | ||
240 | local_irq_save(flags); | ||
241 | vpflags = dvpe(); | ||
242 | #endif | ||
234 | cnt = read_c0_count(); | 243 | cnt = read_c0_count(); |
235 | cnt += delta; | 244 | cnt += delta; |
236 | write_c0_compare(cnt); | 245 | write_c0_compare(cnt); |
237 | 246 | res = ((long)(read_c0_count() - cnt ) > 0) ? -ETIME : 0; | |
238 | return ((long)(read_c0_count() - cnt ) > 0) ? -ETIME : 0; | 247 | #ifdef CONFIG_MIPS_MT_SMTC |
248 | evpe(vpflags); | ||
249 | local_irq_restore(flags); | ||
250 | } | ||
251 | #endif | ||
252 | return res; | ||
239 | } | 253 | } |
240 | 254 | ||
241 | static void mips_set_mode(enum clock_event_mode mode, | 255 | static void mips_set_mode(enum clock_event_mode mode, |
@@ -244,9 +258,7 @@ static void mips_set_mode(enum clock_event_mode mode, | |||
244 | /* Nothing to do ... */ | 258 | /* Nothing to do ... */ |
245 | } | 259 | } |
246 | 260 | ||
247 | struct clock_event_device mips_clockevent; | 261 | static DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); |
248 | |||
249 | static struct clock_event_device *global_cd[NR_CPUS]; | ||
250 | static int cp0_timer_irq_installed; | 262 | static int cp0_timer_irq_installed; |
251 | 263 | ||
252 | static irqreturn_t timer_interrupt(int irq, void *dev_id) | 264 | static irqreturn_t timer_interrupt(int irq, void *dev_id) |
@@ -271,7 +283,12 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) | |||
271 | */ | 283 | */ |
272 | if (!r2 || (read_c0_cause() & (1 << 30))) { | 284 | if (!r2 || (read_c0_cause() & (1 << 30))) { |
273 | c0_timer_ack(); | 285 | c0_timer_ack(); |
274 | cd = global_cd[cpu]; | 286 | #ifdef CONFIG_MIPS_MT_SMTC |
287 | if (cpu_data[cpu].vpe_id) | ||
288 | goto out; | ||
289 | cpu = 0; | ||
290 | #endif | ||
291 | cd = &per_cpu(mips_clockevent_device, cpu); | ||
275 | cd->event_handler(cd); | 292 | cd->event_handler(cd); |
276 | } | 293 | } |
277 | 294 | ||
@@ -281,7 +298,11 @@ out: | |||
281 | 298 | ||
282 | static struct irqaction timer_irqaction = { | 299 | static struct irqaction timer_irqaction = { |
283 | .handler = timer_interrupt, | 300 | .handler = timer_interrupt, |
301 | #ifdef CONFIG_MIPS_MT_SMTC | ||
302 | .flags = IRQF_DISABLED, | ||
303 | #else | ||
284 | .flags = IRQF_DISABLED | IRQF_PERCPU, | 304 | .flags = IRQF_DISABLED | IRQF_PERCPU, |
305 | #endif | ||
285 | .name = "timer", | 306 | .name = "timer", |
286 | }; | 307 | }; |
287 | 308 | ||
@@ -316,6 +337,60 @@ void __init __weak plat_timer_setup(struct irqaction *irq) | |||
316 | { | 337 | { |
317 | } | 338 | } |
318 | 339 | ||
340 | #ifdef CONFIG_MIPS_MT_SMTC | ||
341 | DEFINE_PER_CPU(struct clock_event_device, smtc_dummy_clockevent_device); | ||
342 | |||
343 | static void smtc_set_mode(enum clock_event_mode mode, | ||
344 | struct clock_event_device *evt) | ||
345 | { | ||
346 | } | ||
347 | |||
348 | int dummycnt[NR_CPUS]; | ||
349 | |||
350 | static void mips_broadcast(cpumask_t mask) | ||
351 | { | ||
352 | unsigned int cpu; | ||
353 | |||
354 | for_each_cpu_mask(cpu, mask) | ||
355 | smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0); | ||
356 | } | ||
357 | |||
358 | static void setup_smtc_dummy_clockevent_device(void) | ||
359 | { | ||
360 | //uint64_t mips_freq = mips_hpt_^frequency; | ||
361 | unsigned int cpu = smp_processor_id(); | ||
362 | struct clock_event_device *cd; | ||
363 | |||
364 | cd = &per_cpu(smtc_dummy_clockevent_device, cpu); | ||
365 | |||
366 | cd->name = "SMTC"; | ||
367 | cd->features = CLOCK_EVT_FEAT_DUMMY; | ||
368 | |||
369 | /* Calculate the min / max delta */ | ||
370 | cd->mult = 0; //div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32); | ||
371 | cd->shift = 0; //32; | ||
372 | cd->max_delta_ns = 0; //clockevent_delta2ns(0x7fffffff, cd); | ||
373 | cd->min_delta_ns = 0; //clockevent_delta2ns(0x30, cd); | ||
374 | |||
375 | cd->rating = 200; | ||
376 | cd->irq = 17; //-1; | ||
377 | // if (cpu) | ||
378 | // cd->cpumask = CPU_MASK_ALL; // cpumask_of_cpu(cpu); | ||
379 | // else | ||
380 | cd->cpumask = cpumask_of_cpu(cpu); | ||
381 | |||
382 | cd->set_mode = smtc_set_mode; | ||
383 | |||
384 | cd->broadcast = mips_broadcast; | ||
385 | |||
386 | clockevents_register_device(cd); | ||
387 | } | ||
388 | #endif | ||
389 | |||
390 | static void mips_event_handler(struct clock_event_device *dev) | ||
391 | { | ||
392 | } | ||
393 | |||
319 | void __cpuinit mips_clockevent_init(void) | 394 | void __cpuinit mips_clockevent_init(void) |
320 | { | 395 | { |
321 | uint64_t mips_freq = mips_hpt_frequency; | 396 | uint64_t mips_freq = mips_hpt_frequency; |
@@ -326,12 +401,18 @@ void __cpuinit mips_clockevent_init(void) | |||
326 | if (!cpu_has_counter) | 401 | if (!cpu_has_counter) |
327 | return; | 402 | return; |
328 | 403 | ||
329 | if (cpu == 0) | 404 | #ifdef CONFIG_MIPS_MT_SMTC |
330 | cd = &mips_clockevent; | 405 | setup_smtc_dummy_clockevent_device(); |
331 | else | 406 | |
332 | cd = kzalloc(sizeof(*cd), GFP_ATOMIC); | 407 | /* |
333 | if (!cd) | 408 | * On SMTC we only register VPE0's compare interrupt as clockevent |
334 | return; /* We're probably roadkill ... */ | 409 | * device. |
410 | */ | ||
411 | if (cpu) | ||
412 | return; | ||
413 | #endif | ||
414 | |||
415 | cd = &per_cpu(mips_clockevent_device, cpu); | ||
335 | 416 | ||
336 | cd->name = "MIPS"; | 417 | cd->name = "MIPS"; |
337 | cd->features = CLOCK_EVT_FEAT_ONESHOT; | 418 | cd->features = CLOCK_EVT_FEAT_ONESHOT; |
@@ -344,11 +425,15 @@ void __cpuinit mips_clockevent_init(void) | |||
344 | 425 | ||
345 | cd->rating = 300; | 426 | cd->rating = 300; |
346 | cd->irq = irq; | 427 | cd->irq = irq; |
428 | #ifdef CONFIG_MIPS_MT_SMTC | ||
429 | cd->cpumask = CPU_MASK_ALL; | ||
430 | #else | ||
347 | cd->cpumask = cpumask_of_cpu(cpu); | 431 | cd->cpumask = cpumask_of_cpu(cpu); |
432 | #endif | ||
348 | cd->set_next_event = mips_next_event; | 433 | cd->set_next_event = mips_next_event; |
349 | cd->set_mode = mips_set_mode; | 434 | cd->set_mode = mips_set_mode; |
435 | cd->event_handler = mips_event_handler; | ||
350 | 436 | ||
351 | global_cd[cpu] = cd; | ||
352 | clockevents_register_device(cd); | 437 | clockevents_register_device(cd); |
353 | 438 | ||
354 | if (!cp0_timer_irq_installed) { | 439 | if (!cp0_timer_irq_installed) { |