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 | |
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')
-rw-r--r-- | arch/mips/Kconfig | 4 | ||||
-rw-r--r-- | arch/mips/kernel/smtc.c | 67 | ||||
-rw-r--r-- | arch/mips/kernel/time.c | 111 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/time.c | 1 |
4 files changed, 134 insertions, 49 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index ecce3aab1981..d8c905840af5 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -1368,6 +1368,7 @@ config MIPS_MT_SMTC | |||
1368 | depends on CPU_MIPS32_R2 | 1368 | depends on CPU_MIPS32_R2 |
1369 | #depends on CPU_MIPS64_R2 # once there is hardware ... | 1369 | #depends on CPU_MIPS64_R2 # once there is hardware ... |
1370 | depends on SYS_SUPPORTS_MULTITHREADING | 1370 | depends on SYS_SUPPORTS_MULTITHREADING |
1371 | select GENERIC_CLOCKEVENTS_BROADCAST | ||
1371 | select CPU_MIPSR2_IRQ_VI | 1372 | select CPU_MIPSR2_IRQ_VI |
1372 | select CPU_MIPSR2_IRQ_EI | 1373 | select CPU_MIPSR2_IRQ_EI |
1373 | select CPU_MIPSR2_SRS | 1374 | select CPU_MIPSR2_SRS |
@@ -1537,6 +1538,9 @@ config CPU_HAS_SYNC | |||
1537 | depends on !CPU_R3000 | 1538 | depends on !CPU_R3000 |
1538 | default y | 1539 | default y |
1539 | 1540 | ||
1541 | config GENERIC_CLOCKEVENTS_BROADCAST | ||
1542 | bool | ||
1543 | |||
1540 | # | 1544 | # |
1541 | # Use the generic interrupt handling code in kernel/irq/: | 1545 | # Use the generic interrupt handling code in kernel/irq/: |
1542 | # | 1546 | # |
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 137183bba54f..4d1ac9692dcd 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* Copyright (C) 2004 Mips Technologies, Inc */ | 1 | /* Copyright (C) 2004 Mips Technologies, Inc */ |
2 | 2 | ||
3 | #include <linux/clockchips.h> | ||
3 | #include <linux/kernel.h> | 4 | #include <linux/kernel.h> |
4 | #include <linux/sched.h> | 5 | #include <linux/sched.h> |
5 | #include <linux/cpumask.h> | 6 | #include <linux/cpumask.h> |
@@ -62,7 +63,7 @@ asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS]; | |||
62 | * Clock interrupt "latch" buffers, per "CPU" | 63 | * Clock interrupt "latch" buffers, per "CPU" |
63 | */ | 64 | */ |
64 | 65 | ||
65 | unsigned int ipi_timer_latch[NR_CPUS]; | 66 | static atomic_t ipi_timer_latch[NR_CPUS]; |
66 | 67 | ||
67 | /* | 68 | /* |
68 | * Number of InterProcessor Interupt (IPI) message buffers to allocate | 69 | * Number of InterProcessor Interupt (IPI) message buffers to allocate |
@@ -296,8 +297,10 @@ int __init mipsmt_build_cpu_map(int start_cpu_slot) | |||
296 | __cpu_number_map[i] = i; | 297 | __cpu_number_map[i] = i; |
297 | __cpu_logical_map[i] = i; | 298 | __cpu_logical_map[i] = i; |
298 | } | 299 | } |
300 | #ifdef CONFIG_MIPS_MT_FPAFF | ||
299 | /* Initialize map of CPUs with FPUs */ | 301 | /* Initialize map of CPUs with FPUs */ |
300 | cpus_clear(mt_fpu_cpumask); | 302 | cpus_clear(mt_fpu_cpumask); |
303 | #endif | ||
301 | 304 | ||
302 | /* One of those TC's is the one booting, and not a secondary... */ | 305 | /* One of those TC's is the one booting, and not a secondary... */ |
303 | printk("%i available secondary CPU TC(s)\n", i - 1); | 306 | printk("%i available secondary CPU TC(s)\n", i - 1); |
@@ -359,7 +362,7 @@ void mipsmt_prepare_cpus(void) | |||
359 | IPIQ[i].head = IPIQ[i].tail = NULL; | 362 | IPIQ[i].head = IPIQ[i].tail = NULL; |
360 | spin_lock_init(&IPIQ[i].lock); | 363 | spin_lock_init(&IPIQ[i].lock); |
361 | IPIQ[i].depth = 0; | 364 | IPIQ[i].depth = 0; |
362 | ipi_timer_latch[i] = 0; | 365 | atomic_set(&ipi_timer_latch[i], 0); |
363 | } | 366 | } |
364 | 367 | ||
365 | /* cpu_data index starts at zero */ | 368 | /* cpu_data index starts at zero */ |
@@ -482,10 +485,12 @@ void mipsmt_prepare_cpus(void) | |||
482 | 485 | ||
483 | /* Set up coprocessor affinity CPU mask(s) */ | 486 | /* Set up coprocessor affinity CPU mask(s) */ |
484 | 487 | ||
488 | #ifdef CONFIG_MIPS_MT_FPAFF | ||
485 | for (tc = 0; tc < ntc; tc++) { | 489 | for (tc = 0; tc < ntc; tc++) { |
486 | if (cpu_data[tc].options & MIPS_CPU_FPU) | 490 | if (cpu_data[tc].options & MIPS_CPU_FPU) |
487 | cpu_set(tc, mt_fpu_cpumask); | 491 | cpu_set(tc, mt_fpu_cpumask); |
488 | } | 492 | } |
493 | #endif | ||
489 | 494 | ||
490 | /* set up ipi interrupts... */ | 495 | /* set up ipi interrupts... */ |
491 | 496 | ||
@@ -702,7 +707,7 @@ static void smtc_ipi_qdump(void) | |||
702 | * be done with the atomic.h primitives). And since this is | 707 | * be done with the atomic.h primitives). And since this is |
703 | * MIPS MT, we can assume that we have LL/SC. | 708 | * MIPS MT, we can assume that we have LL/SC. |
704 | */ | 709 | */ |
705 | static __inline__ int atomic_postincrement(unsigned int *pv) | 710 | static inline int atomic_postincrement(atomic_t *v) |
706 | { | 711 | { |
707 | unsigned long result; | 712 | unsigned long result; |
708 | 713 | ||
@@ -714,8 +719,8 @@ static __inline__ int atomic_postincrement(unsigned int *pv) | |||
714 | " sc %1, %2 \n" | 719 | " sc %1, %2 \n" |
715 | " beqz %1, 1b \n" | 720 | " beqz %1, 1b \n" |
716 | __WEAK_LLSC_MB | 721 | __WEAK_LLSC_MB |
717 | : "=&r" (result), "=&r" (temp), "=m" (*pv) | 722 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) |
718 | : "m" (*pv) | 723 | : "m" (v->counter) |
719 | : "memory"); | 724 | : "memory"); |
720 | 725 | ||
721 | return result; | 726 | return result; |
@@ -743,6 +748,8 @@ void smtc_send_ipi(int cpu, int type, unsigned int action) | |||
743 | pipi->arg = (void *)action; | 748 | pipi->arg = (void *)action; |
744 | pipi->dest = cpu; | 749 | pipi->dest = cpu; |
745 | if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) { | 750 | if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) { |
751 | if (type == SMTC_CLOCK_TICK) | ||
752 | atomic_inc(&ipi_timer_latch[cpu]); | ||
746 | /* If not on same VPE, enqueue and send cross-VPE interupt */ | 753 | /* If not on same VPE, enqueue and send cross-VPE interupt */ |
747 | smtc_ipi_nq(&IPIQ[cpu], pipi); | 754 | smtc_ipi_nq(&IPIQ[cpu], pipi); |
748 | LOCK_CORE_PRA(); | 755 | LOCK_CORE_PRA(); |
@@ -784,6 +791,8 @@ void smtc_send_ipi(int cpu, int type, unsigned int action) | |||
784 | } | 791 | } |
785 | smtc_ipi_nq(&IPIQ[cpu], pipi); | 792 | smtc_ipi_nq(&IPIQ[cpu], pipi); |
786 | } else { | 793 | } else { |
794 | if (type == SMTC_CLOCK_TICK) | ||
795 | atomic_inc(&ipi_timer_latch[cpu]); | ||
787 | post_direct_ipi(cpu, pipi); | 796 | post_direct_ipi(cpu, pipi); |
788 | write_tc_c0_tchalt(0); | 797 | write_tc_c0_tchalt(0); |
789 | UNLOCK_CORE_PRA(); | 798 | UNLOCK_CORE_PRA(); |
@@ -801,6 +810,7 @@ static void post_direct_ipi(int cpu, struct smtc_ipi *pipi) | |||
801 | unsigned long tcrestart; | 810 | unsigned long tcrestart; |
802 | extern u32 kernelsp[NR_CPUS]; | 811 | extern u32 kernelsp[NR_CPUS]; |
803 | extern void __smtc_ipi_vector(void); | 812 | extern void __smtc_ipi_vector(void); |
813 | //printk("%s: on %d for %d\n", __func__, smp_processor_id(), cpu); | ||
804 | 814 | ||
805 | /* Extract Status, EPC from halted TC */ | 815 | /* Extract Status, EPC from halted TC */ |
806 | tcstatus = read_tc_c0_tcstatus(); | 816 | tcstatus = read_tc_c0_tcstatus(); |
@@ -851,25 +861,31 @@ static void ipi_call_interrupt(void) | |||
851 | smp_call_function_interrupt(); | 861 | smp_call_function_interrupt(); |
852 | } | 862 | } |
853 | 863 | ||
864 | DECLARE_PER_CPU(struct clock_event_device, smtc_dummy_clockevent_device); | ||
865 | |||
854 | void ipi_decode(struct smtc_ipi *pipi) | 866 | void ipi_decode(struct smtc_ipi *pipi) |
855 | { | 867 | { |
868 | unsigned int cpu = smp_processor_id(); | ||
869 | struct clock_event_device *cd; | ||
856 | void *arg_copy = pipi->arg; | 870 | void *arg_copy = pipi->arg; |
857 | int type_copy = pipi->type; | 871 | int type_copy = pipi->type; |
858 | int dest_copy = pipi->dest; | 872 | int ticks; |
859 | 873 | ||
860 | smtc_ipi_nq(&freeIPIq, pipi); | 874 | smtc_ipi_nq(&freeIPIq, pipi); |
861 | switch (type_copy) { | 875 | switch (type_copy) { |
862 | case SMTC_CLOCK_TICK: | 876 | case SMTC_CLOCK_TICK: |
863 | irq_enter(); | 877 | irq_enter(); |
864 | kstat_this_cpu.irqs[MIPS_CPU_IRQ_BASE + cp0_compare_irq]++; | 878 | kstat_this_cpu.irqs[MIPS_CPU_IRQ_BASE + 1]++; |
865 | /* Invoke Clock "Interrupt" */ | 879 | cd = &per_cpu(smtc_dummy_clockevent_device, cpu); |
866 | ipi_timer_latch[dest_copy] = 0; | 880 | ticks = atomic_read(&ipi_timer_latch[cpu]); |
867 | #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG | 881 | atomic_sub(ticks, &ipi_timer_latch[cpu]); |
868 | clock_hang_reported[dest_copy] = 0; | 882 | while (ticks) { |
869 | #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ | 883 | cd->event_handler(cd); |
870 | local_timer_interrupt(0, NULL); | 884 | ticks--; |
885 | } | ||
871 | irq_exit(); | 886 | irq_exit(); |
872 | break; | 887 | break; |
888 | |||
873 | case LINUX_SMP_IPI: | 889 | case LINUX_SMP_IPI: |
874 | switch ((int)arg_copy) { | 890 | switch ((int)arg_copy) { |
875 | case SMP_RESCHEDULE_YOURSELF: | 891 | case SMP_RESCHEDULE_YOURSELF: |
@@ -921,25 +937,6 @@ void deferred_smtc_ipi(void) | |||
921 | } | 937 | } |
922 | 938 | ||
923 | /* | 939 | /* |
924 | * Send clock tick to all TCs except the one executing the funtion | ||
925 | */ | ||
926 | |||
927 | void smtc_timer_broadcast(void) | ||
928 | { | ||
929 | int cpu; | ||
930 | int myTC = cpu_data[smp_processor_id()].tc_id; | ||
931 | int myVPE = cpu_data[smp_processor_id()].vpe_id; | ||
932 | |||
933 | smtc_cpu_stats[smp_processor_id()].timerints++; | ||
934 | |||
935 | for_each_online_cpu(cpu) { | ||
936 | if (cpu_data[cpu].vpe_id == myVPE && | ||
937 | cpu_data[cpu].tc_id != myTC) | ||
938 | smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0); | ||
939 | } | ||
940 | } | ||
941 | |||
942 | /* | ||
943 | * Cross-VPE interrupts in the SMTC prototype use "software interrupts" | 940 | * Cross-VPE interrupts in the SMTC prototype use "software interrupts" |
944 | * set via cross-VPE MTTR manipulation of the Cause register. It would be | 941 | * set via cross-VPE MTTR manipulation of the Cause register. It would be |
945 | * in some regards preferable to have external logic for "doorbell" hardware | 942 | * in some regards preferable to have external logic for "doorbell" hardware |
@@ -1180,11 +1177,11 @@ void smtc_idle_loop_hook(void) | |||
1180 | for (tc = 0; tc < NR_CPUS; tc++) { | 1177 | for (tc = 0; tc < NR_CPUS; tc++) { |
1181 | /* Don't check ourself - we'll dequeue IPIs just below */ | 1178 | /* Don't check ourself - we'll dequeue IPIs just below */ |
1182 | if ((tc != smp_processor_id()) && | 1179 | if ((tc != smp_processor_id()) && |
1183 | ipi_timer_latch[tc] > timerq_limit) { | 1180 | atomic_read(&ipi_timer_latch[tc]) > timerq_limit) { |
1184 | if (clock_hang_reported[tc] == 0) { | 1181 | if (clock_hang_reported[tc] == 0) { |
1185 | pdb_msg += sprintf(pdb_msg, | 1182 | pdb_msg += sprintf(pdb_msg, |
1186 | "TC %d looks hung with timer latch at %d\n", | 1183 | "TC %d looks hung with timer latch at %d\n", |
1187 | tc, ipi_timer_latch[tc]); | 1184 | tc, atomic_read(&ipi_timer_latch[tc])); |
1188 | clock_hang_reported[tc]++; | 1185 | clock_hang_reported[tc]++; |
1189 | } | 1186 | } |
1190 | } | 1187 | } |
@@ -1225,7 +1222,7 @@ void smtc_soft_dump(void) | |||
1225 | smtc_ipi_qdump(); | 1222 | smtc_ipi_qdump(); |
1226 | printk("Timer IPI Backlogs:\n"); | 1223 | printk("Timer IPI Backlogs:\n"); |
1227 | for (i=0; i < NR_CPUS; i++) { | 1224 | for (i=0; i < NR_CPUS; i++) { |
1228 | printk("%d: %d\n", i, ipi_timer_latch[i]); | 1225 | printk("%d: %d\n", i, atomic_read(&ipi_timer_latch[i])); |
1229 | } | 1226 | } |
1230 | printk("%d Recoveries of \"stolen\" FPU\n", | 1227 | printk("%d Recoveries of \"stolen\" FPU\n", |
1231 | atomic_read(&smtc_fpu_recoveries)); | 1228 | atomic_read(&smtc_fpu_recoveries)); |
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) { |
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index 2c8db3e0f4b7..cf55ecd96bf4 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c | |||
@@ -55,7 +55,6 @@ unsigned long cpu_khz; | |||
55 | 55 | ||
56 | static int mips_cpu_timer_irq; | 56 | static int mips_cpu_timer_irq; |
57 | extern int cp0_perfcount_irq; | 57 | extern int cp0_perfcount_irq; |
58 | extern void smtc_timer_broadcast(void); | ||
59 | 58 | ||
60 | static void mips_timer_dispatch(void) | 59 | static void mips_timer_dispatch(void) |
61 | { | 60 | { |