[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>
This commit is contained in:
Chris Dearman
2007-05-24 22:24:20 +01:00
committed by Ralf Baechle
parent b72c052622
commit ffe9ee4709
4 changed files with 136 additions and 47 deletions

View File

@@ -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)

View File

@@ -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",
};