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 | |
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')
-rw-r--r-- | arch/mips/kernel/smp-mt.c | 12 | ||||
-rw-r--r-- | arch/mips/kernel/time.c | 44 |
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) | |||
129 | 129 | ||
130 | static struct irqaction irq_resched = { | 130 | static struct irqaction irq_resched = { |
131 | .handler = ipi_resched_interrupt, | 131 | .handler = ipi_resched_interrupt, |
132 | .flags = IRQF_DISABLED, | 132 | .flags = IRQF_DISABLED|IRQF_PERCPU, |
133 | .name = "IPI_resched" | 133 | .name = "IPI_resched" |
134 | }; | 134 | }; |
135 | 135 | ||
136 | static struct irqaction irq_call = { | 136 | static struct irqaction irq_call = { |
137 | .handler = ipi_call_interrupt, | 137 | .handler = ipi_call_interrupt, |
138 | .flags = IRQF_DISABLED, | 138 | .flags = IRQF_DISABLED|IRQF_PERCPU, |
139 | .name = "IPI_call" | 139 | .name = "IPI_call" |
140 | }; | 140 | }; |
141 | 141 | ||
@@ -275,10 +275,7 @@ void __init plat_prepare_cpus(unsigned int max_cpus) | |||
275 | setup_irq(cpu_ipi_resched_irq, &irq_resched); | 275 | setup_irq(cpu_ipi_resched_irq, &irq_resched); |
276 | setup_irq(cpu_ipi_call_irq, &irq_call); | 276 | setup_irq(cpu_ipi_call_irq, &irq_call); |
277 | 277 | ||
278 | /* need to mark IPI's as IRQ_PER_CPU */ | ||
279 | irq_desc[cpu_ipi_resched_irq].status |= IRQ_PER_CPU; | ||
280 | set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq); | 278 | set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq); |
281 | irq_desc[cpu_ipi_call_irq].status |= IRQ_PER_CPU; | ||
282 | set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq); | 279 | set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq); |
283 | } | 280 | } |
284 | 281 | ||
@@ -326,8 +323,11 @@ void prom_boot_secondary(int cpu, struct task_struct *idle) | |||
326 | 323 | ||
327 | void prom_init_secondary(void) | 324 | void prom_init_secondary(void) |
328 | { | 325 | { |
326 | /* Enable per-cpu interrupts */ | ||
327 | |||
328 | /* This is Malta specific: IPI,performance and timer inetrrupts */ | ||
329 | write_c0_status((read_c0_status() & ~ST0_IM ) | | 329 | write_c0_status((read_c0_status() & ~ST0_IM ) | |
330 | (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP7)); | 330 | (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP6 | STATUSF_IP7)); |
331 | } | 331 | } |
332 | 332 | ||
333 | void prom_smp_finish(void) | 333 | 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; | |||
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 | ||