aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/irq.c')
-rw-r--r--arch/powerpc/kernel/irq.c140
1 files changed, 93 insertions, 47 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 9040330b0530..64f6f2031c22 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -73,8 +73,10 @@
73#define CREATE_TRACE_POINTS 73#define CREATE_TRACE_POINTS
74#include <asm/trace.h> 74#include <asm/trace.h>
75 75
76DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
77EXPORT_PER_CPU_SYMBOL(irq_stat);
78
76int __irq_offset_value; 79int __irq_offset_value;
77static int ppc_spurious_interrupts;
78 80
79#ifdef CONFIG_PPC32 81#ifdef CONFIG_PPC32
80EXPORT_SYMBOL(__irq_offset_value); 82EXPORT_SYMBOL(__irq_offset_value);
@@ -180,30 +182,64 @@ notrace void raw_local_irq_restore(unsigned long en)
180EXPORT_SYMBOL(raw_local_irq_restore); 182EXPORT_SYMBOL(raw_local_irq_restore);
181#endif /* CONFIG_PPC64 */ 183#endif /* CONFIG_PPC64 */
182 184
185static int show_other_interrupts(struct seq_file *p, int prec)
186{
187 int j;
188
189#if defined(CONFIG_PPC32) && defined(CONFIG_TAU_INT)
190 if (tau_initialized) {
191 seq_printf(p, "%*s: ", prec, "TAU");
192 for_each_online_cpu(j)
193 seq_printf(p, "%10u ", tau_interrupts(j));
194 seq_puts(p, " PowerPC Thermal Assist (cpu temp)\n");
195 }
196#endif /* CONFIG_PPC32 && CONFIG_TAU_INT */
197
198 seq_printf(p, "%*s: ", prec, "LOC");
199 for_each_online_cpu(j)
200 seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs);
201 seq_printf(p, " Local timer interrupts\n");
202
203 seq_printf(p, "%*s: ", prec, "SPU");
204 for_each_online_cpu(j)
205 seq_printf(p, "%10u ", per_cpu(irq_stat, j).spurious_irqs);
206 seq_printf(p, " Spurious interrupts\n");
207
208 seq_printf(p, "%*s: ", prec, "CNT");
209 for_each_online_cpu(j)
210 seq_printf(p, "%10u ", per_cpu(irq_stat, j).pmu_irqs);
211 seq_printf(p, " Performance monitoring interrupts\n");
212
213 seq_printf(p, "%*s: ", prec, "MCE");
214 for_each_online_cpu(j)
215 seq_printf(p, "%10u ", per_cpu(irq_stat, j).mce_exceptions);
216 seq_printf(p, " Machine check exceptions\n");
217
218 return 0;
219}
220
183int show_interrupts(struct seq_file *p, void *v) 221int show_interrupts(struct seq_file *p, void *v)
184{ 222{
185 int i = *(loff_t *)v, j; 223 unsigned long flags, any_count = 0;
224 int i = *(loff_t *) v, j, prec;
186 struct irqaction *action; 225 struct irqaction *action;
187 struct irq_desc *desc; 226 struct irq_desc *desc;
188 unsigned long flags;
189 227
228 if (i > nr_irqs)
229 return 0;
230
231 for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec)
232 j *= 10;
233
234 if (i == nr_irqs)
235 return show_other_interrupts(p, prec);
236
237 /* print header */
190 if (i == 0) { 238 if (i == 0) {
191 seq_puts(p, " "); 239 seq_printf(p, "%*s", prec + 8, "");
192 for_each_online_cpu(j) 240 for_each_online_cpu(j)
193 seq_printf(p, "CPU%d ", j); 241 seq_printf(p, "CPU%-8d", j);
194 seq_putc(p, '\n'); 242 seq_putc(p, '\n');
195 } else if (i == nr_irqs) {
196#if defined(CONFIG_PPC32) && defined(CONFIG_TAU_INT)
197 if (tau_initialized){
198 seq_puts(p, "TAU: ");
199 for_each_online_cpu(j)
200 seq_printf(p, "%10u ", tau_interrupts(j));
201 seq_puts(p, " PowerPC Thermal Assist (cpu temp)\n");
202 }
203#endif /* CONFIG_PPC32 && CONFIG_TAU_INT*/
204 seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts);
205
206 return 0;
207 } 243 }
208 244
209 desc = irq_to_desc(i); 245 desc = irq_to_desc(i);
@@ -211,37 +247,48 @@ int show_interrupts(struct seq_file *p, void *v)
211 return 0; 247 return 0;
212 248
213 raw_spin_lock_irqsave(&desc->lock, flags); 249 raw_spin_lock_irqsave(&desc->lock, flags);
214 250 for_each_online_cpu(j)
251 any_count |= kstat_irqs_cpu(i, j);
215 action = desc->action; 252 action = desc->action;
216 if (!action || !action->handler) 253 if (!action && !any_count)
217 goto skip; 254 goto out;
218 255
219 seq_printf(p, "%3d: ", i); 256 seq_printf(p, "%*d: ", prec, i);
220#ifdef CONFIG_SMP
221 for_each_online_cpu(j) 257 for_each_online_cpu(j)
222 seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); 258 seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
223#else
224 seq_printf(p, "%10u ", kstat_irqs(i));
225#endif /* CONFIG_SMP */
226 259
227 if (desc->chip) 260 if (desc->chip)
228 seq_printf(p, " %s ", desc->chip->name); 261 seq_printf(p, " %-16s", desc->chip->name);
229 else 262 else
230 seq_puts(p, " None "); 263 seq_printf(p, " %-16s", "None");
264 seq_printf(p, " %-8s", (desc->status & IRQ_LEVEL) ? "Level" : "Edge");
231 265
232 seq_printf(p, "%s", (desc->status & IRQ_LEVEL) ? "Level " : "Edge "); 266 if (action) {
233 seq_printf(p, " %s", action->name); 267 seq_printf(p, " %s", action->name);
268 while ((action = action->next) != NULL)
269 seq_printf(p, ", %s", action->name);
270 }
234 271
235 for (action = action->next; action; action = action->next)
236 seq_printf(p, ", %s", action->name);
237 seq_putc(p, '\n'); 272 seq_putc(p, '\n');
238 273out:
239skip:
240 raw_spin_unlock_irqrestore(&desc->lock, flags); 274 raw_spin_unlock_irqrestore(&desc->lock, flags);
241
242 return 0; 275 return 0;
243} 276}
244 277
278/*
279 * /proc/stat helpers
280 */
281u64 arch_irq_stat_cpu(unsigned int cpu)
282{
283 u64 sum = per_cpu(irq_stat, cpu).timer_irqs;
284
285 sum += per_cpu(irq_stat, cpu).pmu_irqs;
286 sum += per_cpu(irq_stat, cpu).mce_exceptions;
287 sum += per_cpu(irq_stat, cpu).spurious_irqs;
288
289 return sum;
290}
291
245#ifdef CONFIG_HOTPLUG_CPU 292#ifdef CONFIG_HOTPLUG_CPU
246void fixup_irqs(cpumask_t map) 293void fixup_irqs(cpumask_t map)
247{ 294{
@@ -353,8 +400,7 @@ void do_IRQ(struct pt_regs *regs)
353 if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) 400 if (irq != NO_IRQ && irq != NO_IRQ_IGNORE)
354 handle_one_irq(irq); 401 handle_one_irq(irq);
355 else if (irq != NO_IRQ_IGNORE) 402 else if (irq != NO_IRQ_IGNORE)
356 /* That's not SMP safe ... but who cares ? */ 403 __get_cpu_var(irq_stat).spurious_irqs++;
357 ppc_spurious_interrupts++;
358 404
359 irq_exit(); 405 irq_exit();
360 set_irq_regs(old_regs); 406 set_irq_regs(old_regs);
@@ -474,7 +520,7 @@ void do_softirq(void)
474 */ 520 */
475 521
476static LIST_HEAD(irq_hosts); 522static LIST_HEAD(irq_hosts);
477static DEFINE_SPINLOCK(irq_big_lock); 523static DEFINE_RAW_SPINLOCK(irq_big_lock);
478static unsigned int revmap_trees_allocated; 524static unsigned int revmap_trees_allocated;
479static DEFINE_MUTEX(revmap_trees_mutex); 525static DEFINE_MUTEX(revmap_trees_mutex);
480struct irq_map_entry irq_map[NR_IRQS]; 526struct irq_map_entry irq_map[NR_IRQS];
@@ -520,14 +566,14 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
520 if (host->ops->match == NULL) 566 if (host->ops->match == NULL)
521 host->ops->match = default_irq_host_match; 567 host->ops->match = default_irq_host_match;
522 568
523 spin_lock_irqsave(&irq_big_lock, flags); 569 raw_spin_lock_irqsave(&irq_big_lock, flags);
524 570
525 /* If it's a legacy controller, check for duplicates and 571 /* If it's a legacy controller, check for duplicates and
526 * mark it as allocated (we use irq 0 host pointer for that 572 * mark it as allocated (we use irq 0 host pointer for that
527 */ 573 */
528 if (revmap_type == IRQ_HOST_MAP_LEGACY) { 574 if (revmap_type == IRQ_HOST_MAP_LEGACY) {
529 if (irq_map[0].host != NULL) { 575 if (irq_map[0].host != NULL) {
530 spin_unlock_irqrestore(&irq_big_lock, flags); 576 raw_spin_unlock_irqrestore(&irq_big_lock, flags);
531 /* If we are early boot, we can't free the structure, 577 /* If we are early boot, we can't free the structure,
532 * too bad... 578 * too bad...
533 * this will be fixed once slab is made available early 579 * this will be fixed once slab is made available early
@@ -541,7 +587,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
541 } 587 }
542 588
543 list_add(&host->link, &irq_hosts); 589 list_add(&host->link, &irq_hosts);
544 spin_unlock_irqrestore(&irq_big_lock, flags); 590 raw_spin_unlock_irqrestore(&irq_big_lock, flags);
545 591
546 /* Additional setups per revmap type */ 592 /* Additional setups per revmap type */
547 switch(revmap_type) { 593 switch(revmap_type) {
@@ -592,13 +638,13 @@ struct irq_host *irq_find_host(struct device_node *node)
592 * the absence of a device node. This isn't a problem so far 638 * the absence of a device node. This isn't a problem so far
593 * yet though... 639 * yet though...
594 */ 640 */
595 spin_lock_irqsave(&irq_big_lock, flags); 641 raw_spin_lock_irqsave(&irq_big_lock, flags);
596 list_for_each_entry(h, &irq_hosts, link) 642 list_for_each_entry(h, &irq_hosts, link)
597 if (h->ops->match(h, node)) { 643 if (h->ops->match(h, node)) {
598 found = h; 644 found = h;
599 break; 645 break;
600 } 646 }
601 spin_unlock_irqrestore(&irq_big_lock, flags); 647 raw_spin_unlock_irqrestore(&irq_big_lock, flags);
602 return found; 648 return found;
603} 649}
604EXPORT_SYMBOL_GPL(irq_find_host); 650EXPORT_SYMBOL_GPL(irq_find_host);
@@ -967,7 +1013,7 @@ unsigned int irq_alloc_virt(struct irq_host *host,
967 if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS)) 1013 if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS))
968 return NO_IRQ; 1014 return NO_IRQ;
969 1015
970 spin_lock_irqsave(&irq_big_lock, flags); 1016 raw_spin_lock_irqsave(&irq_big_lock, flags);
971 1017
972 /* Use hint for 1 interrupt if any */ 1018 /* Use hint for 1 interrupt if any */
973 if (count == 1 && hint >= NUM_ISA_INTERRUPTS && 1019 if (count == 1 && hint >= NUM_ISA_INTERRUPTS &&
@@ -991,7 +1037,7 @@ unsigned int irq_alloc_virt(struct irq_host *host,
991 } 1037 }
992 } 1038 }
993 if (found == NO_IRQ) { 1039 if (found == NO_IRQ) {
994 spin_unlock_irqrestore(&irq_big_lock, flags); 1040 raw_spin_unlock_irqrestore(&irq_big_lock, flags);
995 return NO_IRQ; 1041 return NO_IRQ;
996 } 1042 }
997 hint_found: 1043 hint_found:
@@ -1000,7 +1046,7 @@ unsigned int irq_alloc_virt(struct irq_host *host,
1000 smp_wmb(); 1046 smp_wmb();
1001 irq_map[i].host = host; 1047 irq_map[i].host = host;
1002 } 1048 }
1003 spin_unlock_irqrestore(&irq_big_lock, flags); 1049 raw_spin_unlock_irqrestore(&irq_big_lock, flags);
1004 return found; 1050 return found;
1005} 1051}
1006 1052
@@ -1012,7 +1058,7 @@ void irq_free_virt(unsigned int virq, unsigned int count)
1012 WARN_ON (virq < NUM_ISA_INTERRUPTS); 1058 WARN_ON (virq < NUM_ISA_INTERRUPTS);
1013 WARN_ON (count == 0 || (virq + count) > irq_virq_count); 1059 WARN_ON (count == 0 || (virq + count) > irq_virq_count);
1014 1060
1015 spin_lock_irqsave(&irq_big_lock, flags); 1061 raw_spin_lock_irqsave(&irq_big_lock, flags);
1016 for (i = virq; i < (virq + count); i++) { 1062 for (i = virq; i < (virq + count); i++) {
1017 struct irq_host *host; 1063 struct irq_host *host;
1018 1064
@@ -1025,7 +1071,7 @@ void irq_free_virt(unsigned int virq, unsigned int count)
1025 smp_wmb(); 1071 smp_wmb();
1026 irq_map[i].host = NULL; 1072 irq_map[i].host = NULL;
1027 } 1073 }
1028 spin_unlock_irqrestore(&irq_big_lock, flags); 1074 raw_spin_unlock_irqrestore(&irq_big_lock, flags);
1029} 1075}
1030 1076
1031int arch_early_irq_init(void) 1077int arch_early_irq_init(void)