summaryrefslogtreecommitdiff
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorChris Dearman <chris@mips.com>2007-05-25 01:24:20 +0400
committerRalf Baechle <ralf@linux-mips.org>2007-06-14 21:25:15 +0400
commitffe9ee4709cf513fb80e9b7e04d214dd8b76a10d (patch)
tree07453e5644806b9c755159e5a4c1fe11dacfcab0 /arch/mips/kernel
parentb72c05262298cc2ac92edb657f5ea3a97ad5ea3d (diff)
downloadlinux-ffe9ee4709cf513fb80e9b7e04d214dd8b76a10d.tar.xz
[MIPS] Separate performance counter interrupts
Support for performance counter overflow interrupt that is on a separate interrupt from the timer. Signed-off-by: Chris Dearman <chris@mips.com> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/smp-mt.c12
-rw-r--r--arch/mips/kernel/time.c44
2 files changed, 37 insertions, 19 deletions
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c
index 64b62bdfb4f6..b8fa7ddd78f6 100644
--- a/arch/mips/kernel/smp-mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -129,13 +129,13 @@ static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
static struct irqaction irq_resched = {
.handler = ipi_resched_interrupt,
- .flags = IRQF_DISABLED,
+ .flags = IRQF_DISABLED|IRQF_PERCPU,
.name = "IPI_resched"
};
static struct irqaction irq_call = {
.handler = ipi_call_interrupt,
- .flags = IRQF_DISABLED,
+ .flags = IRQF_DISABLED|IRQF_PERCPU,
.name = "IPI_call"
};
@@ -275,10 +275,7 @@ void __init plat_prepare_cpus(unsigned int max_cpus)
setup_irq(cpu_ipi_resched_irq, &irq_resched);
setup_irq(cpu_ipi_call_irq, &irq_call);
- /* need to mark IPI's as IRQ_PER_CPU */
- irq_desc[cpu_ipi_resched_irq].status |= IRQ_PER_CPU;
set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq);
- irq_desc[cpu_ipi_call_irq].status |= IRQ_PER_CPU;
set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq);
}
@@ -326,8 +323,11 @@ void prom_boot_secondary(int cpu, struct task_struct *idle)
void prom_init_secondary(void)
{
+ /* Enable per-cpu interrupts */
+
+ /* This is Malta specific: IPI,performance and timer inetrrupts */
write_c0_status((read_c0_status() & ~ST0_IM ) |
- (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP7));
+ (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP6 | STATUSF_IP7));
}
void prom_smp_finish(void)
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 751b4a18b133..7def1ff3da94 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -199,6 +199,30 @@ int (*perf_irq)(void) = null_perf_irq;
EXPORT_SYMBOL(null_perf_irq);
EXPORT_SYMBOL(perf_irq);
+/*
+ * Performance counter IRQ or -1 if shared with timer
+ */
+int mipsxx_perfcount_irq;
+EXPORT_SYMBOL(mipsxx_perfcount_irq);
+
+/*
+ * Possibly handle a performance counter interrupt.
+ * Return true if the timer interrupt should not be checked
+ */
+static inline int handle_perf_irq (int r2)
+{
+ /*
+ * The performance counter overflow interrupt may be shared with the
+ * timer interrupt (mipsxx_perfcount_irq < 0). If it is and a
+ * performance counter has overflowed (perf_irq() == IRQ_HANDLED)
+ * and we can't reliably determine if a counter interrupt has also
+ * happened (!r2) then don't check for a timer interrupt.
+ */
+ return (mipsxx_perfcount_irq < 0) &&
+ perf_irq() == IRQ_HANDLED &&
+ !r2;
+}
+
asmlinkage void ll_timer_interrupt(int irq)
{
int r2 = cpu_has_mips_r2;
@@ -206,19 +230,13 @@ asmlinkage void ll_timer_interrupt(int irq)
irq_enter();
kstat_this_cpu.irqs[irq]++;
- /*
- * Suckage alert:
- * Before R2 of the architecture there was no way to see if a
- * performance counter interrupt was pending, so we have to run the
- * performance counter interrupt handler anyway.
- */
- if (!r2 || (read_c0_cause() & (1 << 26)))
- if (perf_irq())
- goto out;
+ if (handle_perf_irq(r2))
+ goto out;
- /* we keep interrupt disabled all the time */
- if (!r2 || (read_c0_cause() & (1 << 30)))
- timer_interrupt(irq, NULL);
+ if (r2 && ((read_c0_cause() & (1 << 30)) == 0))
+ goto out;
+
+ timer_interrupt(irq, NULL);
out:
irq_exit();
@@ -258,7 +276,7 @@ unsigned int mips_hpt_frequency;
static struct irqaction timer_irqaction = {
.handler = timer_interrupt,
- .flags = IRQF_DISABLED,
+ .flags = IRQF_DISABLED | IRQF_PERCPU,
.name = "timer",
};