Commit 846acaa2 authored by Kevin D. Kissell's avatar Kevin D. Kissell Committed by Ralf Baechle

[MIPS] Patch to arch/mips/mips-boards/generic/time.c

In hooking up the perf counter overflow interrupt to the experimental
deprecated-real-soon-now /proc/perf interface last night, I had to
revisit arch/mips/mips-boards/generic/time.c, and discovered that
when the 2.6.9-based SMTC prototype was merged with the more
recent tree, it was missed that arch/mips/kernel/time.c had changed
so that even in SMP kernels, timer_interrupt() calls
local_timer_interrupt(), so there is no longer a need to invoke it
directly from mips_timer_interrupt() in those cases where
timer_interrupt() has been called.  So I got rid of that, and added the
invocation of perf_irq() if Cause.PCI is set, more-or-less following the
same logic as in the non-SMTC case, with the modifications that (a) a
runtime check for Release 2 isn't done, because it's redundant in SMTC),
and (b) we check for a clock interrupt regardless of the value returned
by the perf counter service - I don't understand why we'd want to control
that with perf_irq(), but maybe one of you knows the story.  I also got
rid of the stupid warning about the unused variable when compiled for
SMTC (another artifact of the merge). The result hasn't been beaten to
death, but boots, seems stable, and supports extended precision event
counting.
Signed-off-by: default avatarKevin D. Kissell <kevink@mips.com>
Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 60a6c377
...@@ -92,7 +92,6 @@ extern int (*perf_irq)(struct pt_regs *regs); ...@@ -92,7 +92,6 @@ extern int (*perf_irq)(struct pt_regs *regs);
irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
int cpu = smp_processor_id(); int cpu = smp_processor_id();
int r2 = cpu_has_mips_r2;
#ifdef CONFIG_MIPS_MT_SMTC #ifdef CONFIG_MIPS_MT_SMTC
/* /*
...@@ -108,29 +107,46 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -108,29 +107,46 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* the general MIPS timer_interrupt routine. * the general MIPS timer_interrupt routine.
*/ */
int vpflags;
/*
* We could be here due to timer interrupt,
* perf counter overflow, or both.
*/
if (read_c0_cause() & (1 << 26))
perf_irq(regs);
if (read_c0_cause() & (1 << 30)) {
/* If timer interrupt, make it de-assert */
write_c0_compare (read_c0_count() - 1);
/* /*
* DVPE is necessary so long as cross-VPE interrupts * DVPE is necessary so long as cross-VPE interrupts
* are done via read-modify-write of Cause register. * are done via read-modify-write of Cause register.
*/ */
int vpflags = dvpe(); vpflags = dvpe();
write_c0_compare (read_c0_count() - 1);
clear_c0_cause(CPUCTR_IMASKBIT); clear_c0_cause(CPUCTR_IMASKBIT);
evpe(vpflags); evpe(vpflags);
if (cpu_data[cpu].vpe_id == 0) {
timer_interrupt(irq, dev_id, regs);
scroll_display_message();
} else
write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
smtc_timer_broadcast(cpu_data[cpu].vpe_id);
if (cpu != 0)
/* /*
* Other CPUs should do profiling and process accounting * There are things we only want to do once per tick
* in an "MP" system. One TC of each VPE will take
* the actual timer interrupt. The others will get
* timer broadcast IPIs. We use whoever it is that takes
* the tick on VPE 0 to run the full timer_interrupt().
*/ */
if (cpu_data[cpu].vpe_id == 0) {
timer_interrupt(irq, NULL, regs);
smtc_timer_broadcast(cpu_data[cpu].vpe_id);
scroll_display_message();
} else {
write_c0_compare(read_c0_count() +
(mips_hpt_frequency/HZ));
local_timer_interrupt(irq, dev_id, regs); local_timer_interrupt(irq, dev_id, regs);
smtc_timer_broadcast(cpu_data[cpu].vpe_id);
}
}
#else /* CONFIG_MIPS_MT_SMTC */ #else /* CONFIG_MIPS_MT_SMTC */
int r2 = cpu_has_mips_r2;
if (cpu == 0) { if (cpu == 0) {
/* /*
* CPU 0 handles the global timer interrupt job and process * CPU 0 handles the global timer interrupt job and process
...@@ -161,9 +177,8 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -161,9 +177,8 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
*/ */
local_timer_interrupt(irq, dev_id, regs); local_timer_interrupt(irq, dev_id, regs);
} }
#endif /* CONFIG_MIPS_MT_SMTC */
out: out:
#endif /* CONFIG_MIPS_MT_SMTC */
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment