diff options
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 | ||
