diff options
author | Chris Dearman <chris@mips.com> | 2007-05-24 17:24:20 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-06-14 13:25:15 -0400 |
commit | ffe9ee4709cf513fb80e9b7e04d214dd8b76a10d (patch) | |
tree | 07453e5644806b9c755159e5a4c1fe11dacfcab0 /arch/mips/kernel/time.c | |
parent | b72c05262298cc2ac92edb657f5ea3a97ad5ea3d (diff) |
[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/time.c')
-rw-r--r-- | arch/mips/kernel/time.c | 44 |
1 files changed, 31 insertions, 13 deletions
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; | |||
199 | EXPORT_SYMBOL(null_perf_irq); | 199 | EXPORT_SYMBOL(null_perf_irq); |
200 | EXPORT_SYMBOL(perf_irq); | 200 | EXPORT_SYMBOL(perf_irq); |
201 | 201 | ||
202 | /* | ||
203 | * Performance counter IRQ or -1 if shared with timer | ||
204 | */ | ||
205 | int mipsxx_perfcount_irq; | ||
206 | EXPORT_SYMBOL(mipsxx_perfcount_irq); | ||
207 | |||
208 | /* | ||
209 | * Possibly handle a performance counter interrupt. | ||
210 | * Return true if the timer interrupt should not be checked | ||
211 | */ | ||
212 | static inline int handle_perf_irq (int r2) | ||
213 | { | ||
214 | /* | ||
215 | * The performance counter overflow interrupt may be shared with the | ||
216 | * timer interrupt (mipsxx_perfcount_irq < 0). If it is and a | ||
217 | * performance counter has overflowed (perf_irq() == IRQ_HANDLED) | ||
218 | * and we can't reliably determine if a counter interrupt has also | ||
219 | * happened (!r2) then don't check for a timer interrupt. | ||
220 | */ | ||
221 | return (mipsxx_perfcount_irq < 0) && | ||
222 | perf_irq() == IRQ_HANDLED && | ||
223 | !r2; | ||
224 | } | ||
225 | |||
202 | asmlinkage void ll_timer_interrupt(int irq) | 226 | asmlinkage void ll_timer_interrupt(int irq) |
203 | { | 227 | { |
204 | int r2 = cpu_has_mips_r2; | 228 | int r2 = cpu_has_mips_r2; |
@@ -206,19 +230,13 @@ asmlinkage void ll_timer_interrupt(int irq) | |||
206 | irq_enter(); | 230 | irq_enter(); |
207 | kstat_this_cpu.irqs[irq]++; | 231 | kstat_this_cpu.irqs[irq]++; |
208 | 232 | ||
209 | /* | 233 | if (handle_perf_irq(r2)) |
210 | * Suckage alert: | 234 | goto out; |
211 | * Before R2 of the architecture there was no way to see if a | ||
212 | * performance counter interrupt was pending, so we have to run the | ||
213 | * performance counter interrupt handler anyway. | ||
214 | */ | ||
215 | if (!r2 || (read_c0_cause() & (1 << 26))) | ||
216 | if (perf_irq()) | ||
217 | goto out; | ||
218 | 235 | ||
219 | /* we keep interrupt disabled all the time */ | 236 | if (r2 && ((read_c0_cause() & (1 << 30)) == 0)) |
220 | if (!r2 || (read_c0_cause() & (1 << 30))) | 237 | goto out; |
221 | timer_interrupt(irq, NULL); | 238 | |
239 | timer_interrupt(irq, NULL); | ||
222 | 240 | ||
223 | out: | 241 | out: |
224 | irq_exit(); | 242 | irq_exit(); |
@@ -258,7 +276,7 @@ unsigned int mips_hpt_frequency; | |||
258 | 276 | ||
259 | static struct irqaction timer_irqaction = { | 277 | static struct irqaction timer_irqaction = { |
260 | .handler = timer_interrupt, | 278 | .handler = timer_interrupt, |
261 | .flags = IRQF_DISABLED, | 279 | .flags = IRQF_DISABLED | IRQF_PERCPU, |
262 | .name = "timer", | 280 | .name = "timer", |
263 | }; | 281 | }; |
264 | 282 | ||