diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2007-10-11 23:46:09 +0100 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-10-11 23:46:09 +0100 |
commit | ea5804015c0ce67741eb4b156a071fb4f415345f (patch) | |
tree | bc4da66c0d9a531a17159b1cb001ad8e96d24487 /arch/mips/kernel/smtc.c | |
parent | 7bcf7717b6a047c272410d0cd00213185fe6b99d (diff) | |
download | op-kernel-dev-ea5804015c0ce67741eb4b156a071fb4f415345f.zip op-kernel-dev-ea5804015c0ce67741eb4b156a071fb4f415345f.tar.gz |
[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/smtc.c')
-rw-r--r-- | arch/mips/kernel/smtc.c | 67 |
1 files changed, 32 insertions, 35 deletions
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 137183b..4d1ac96 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -1,5 +1,6 @@ /* Copyright (C) 2004 Mips Technologies, Inc */ +#include <linux/clockchips.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/cpumask.h> @@ -62,7 +63,7 @@ asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS]; * Clock interrupt "latch" buffers, per "CPU" */ -unsigned int ipi_timer_latch[NR_CPUS]; +static atomic_t ipi_timer_latch[NR_CPUS]; /* * Number of InterProcessor Interupt (IPI) message buffers to allocate @@ -296,8 +297,10 @@ int __init mipsmt_build_cpu_map(int start_cpu_slot) __cpu_number_map[i] = i; __cpu_logical_map[i] = i; } +#ifdef CONFIG_MIPS_MT_FPAFF /* Initialize map of CPUs with FPUs */ cpus_clear(mt_fpu_cpumask); +#endif /* One of those TC's is the one booting, and not a secondary... */ printk("%i available secondary CPU TC(s)\n", i - 1); @@ -359,7 +362,7 @@ void mipsmt_prepare_cpus(void) IPIQ[i].head = IPIQ[i].tail = NULL; spin_lock_init(&IPIQ[i].lock); IPIQ[i].depth = 0; - ipi_timer_latch[i] = 0; + atomic_set(&ipi_timer_latch[i], 0); } /* cpu_data index starts at zero */ @@ -482,10 +485,12 @@ void mipsmt_prepare_cpus(void) /* Set up coprocessor affinity CPU mask(s) */ +#ifdef CONFIG_MIPS_MT_FPAFF for (tc = 0; tc < ntc; tc++) { if (cpu_data[tc].options & MIPS_CPU_FPU) cpu_set(tc, mt_fpu_cpumask); } +#endif /* set up ipi interrupts... */ @@ -702,7 +707,7 @@ static void smtc_ipi_qdump(void) * be done with the atomic.h primitives). And since this is * MIPS MT, we can assume that we have LL/SC. */ -static __inline__ int atomic_postincrement(unsigned int *pv) +static inline int atomic_postincrement(atomic_t *v) { unsigned long result; @@ -714,8 +719,8 @@ static __inline__ int atomic_postincrement(unsigned int *pv) " sc %1, %2 \n" " beqz %1, 1b \n" __WEAK_LLSC_MB - : "=&r" (result), "=&r" (temp), "=m" (*pv) - : "m" (*pv) + : "=&r" (result), "=&r" (temp), "=m" (v->counter) + : "m" (v->counter) : "memory"); return result; @@ -743,6 +748,8 @@ void smtc_send_ipi(int cpu, int type, unsigned int action) pipi->arg = (void *)action; pipi->dest = cpu; if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) { + if (type == SMTC_CLOCK_TICK) + atomic_inc(&ipi_timer_latch[cpu]); /* If not on same VPE, enqueue and send cross-VPE interupt */ smtc_ipi_nq(&IPIQ[cpu], pipi); LOCK_CORE_PRA(); @@ -784,6 +791,8 @@ void smtc_send_ipi(int cpu, int type, unsigned int action) } smtc_ipi_nq(&IPIQ[cpu], pipi); } else { + if (type == SMTC_CLOCK_TICK) + atomic_inc(&ipi_timer_latch[cpu]); post_direct_ipi(cpu, pipi); write_tc_c0_tchalt(0); UNLOCK_CORE_PRA(); @@ -801,6 +810,7 @@ static void post_direct_ipi(int cpu, struct smtc_ipi *pipi) unsigned long tcrestart; extern u32 kernelsp[NR_CPUS]; extern void __smtc_ipi_vector(void); +//printk("%s: on %d for %d\n", __func__, smp_processor_id(), cpu); /* Extract Status, EPC from halted TC */ tcstatus = read_tc_c0_tcstatus(); @@ -851,25 +861,31 @@ static void ipi_call_interrupt(void) smp_call_function_interrupt(); } +DECLARE_PER_CPU(struct clock_event_device, smtc_dummy_clockevent_device); + void ipi_decode(struct smtc_ipi *pipi) { + unsigned int cpu = smp_processor_id(); + struct clock_event_device *cd; void *arg_copy = pipi->arg; int type_copy = pipi->type; - int dest_copy = pipi->dest; + int ticks; smtc_ipi_nq(&freeIPIq, pipi); switch (type_copy) { case SMTC_CLOCK_TICK: irq_enter(); - kstat_this_cpu.irqs[MIPS_CPU_IRQ_BASE + cp0_compare_irq]++; - /* Invoke Clock "Interrupt" */ - ipi_timer_latch[dest_copy] = 0; -#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG - clock_hang_reported[dest_copy] = 0; -#endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ - local_timer_interrupt(0, NULL); + kstat_this_cpu.irqs[MIPS_CPU_IRQ_BASE + 1]++; + cd = &per_cpu(smtc_dummy_clockevent_device, cpu); + ticks = atomic_read(&ipi_timer_latch[cpu]); + atomic_sub(ticks, &ipi_timer_latch[cpu]); + while (ticks) { + cd->event_handler(cd); + ticks--; + } irq_exit(); break; + case LINUX_SMP_IPI: switch ((int)arg_copy) { case SMP_RESCHEDULE_YOURSELF: @@ -921,25 +937,6 @@ void deferred_smtc_ipi(void) } /* - * Send clock tick to all TCs except the one executing the funtion - */ - -void smtc_timer_broadcast(void) -{ - int cpu; - int myTC = cpu_data[smp_processor_id()].tc_id; - int myVPE = cpu_data[smp_processor_id()].vpe_id; - - smtc_cpu_stats[smp_processor_id()].timerints++; - - for_each_online_cpu(cpu) { - if (cpu_data[cpu].vpe_id == myVPE && - cpu_data[cpu].tc_id != myTC) - smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0); - } -} - -/* * Cross-VPE interrupts in the SMTC prototype use "software interrupts" * set via cross-VPE MTTR manipulation of the Cause register. It would be * in some regards preferable to have external logic for "doorbell" hardware @@ -1180,11 +1177,11 @@ void smtc_idle_loop_hook(void) for (tc = 0; tc < NR_CPUS; tc++) { /* Don't check ourself - we'll dequeue IPIs just below */ if ((tc != smp_processor_id()) && - ipi_timer_latch[tc] > timerq_limit) { + atomic_read(&ipi_timer_latch[tc]) > timerq_limit) { if (clock_hang_reported[tc] == 0) { pdb_msg += sprintf(pdb_msg, "TC %d looks hung with timer latch at %d\n", - tc, ipi_timer_latch[tc]); + tc, atomic_read(&ipi_timer_latch[tc])); clock_hang_reported[tc]++; } } @@ -1225,7 +1222,7 @@ void smtc_soft_dump(void) smtc_ipi_qdump(); printk("Timer IPI Backlogs:\n"); for (i=0; i < NR_CPUS; i++) { - printk("%d: %d\n", i, ipi_timer_latch[i]); + printk("%d: %d\n", i, atomic_read(&ipi_timer_latch[i])); } printk("%d Recoveries of \"stolen\" FPU\n", atomic_read(&smtc_fpu_recoveries)); |