diff options
Diffstat (limited to 'arch/powerpc/kernel/irq.c')
-rw-r--r-- | arch/powerpc/kernel/irq.c | 97 |
1 files changed, 82 insertions, 15 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 24bea97c736c..151b13119208 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -52,6 +52,7 @@ | |||
52 | #include <linux/mutex.h> | 52 | #include <linux/mutex.h> |
53 | #include <linux/bootmem.h> | 53 | #include <linux/bootmem.h> |
54 | #include <linux/pci.h> | 54 | #include <linux/pci.h> |
55 | #include <linux/debugfs.h> | ||
55 | 56 | ||
56 | #include <asm/uaccess.h> | 57 | #include <asm/uaccess.h> |
57 | #include <asm/system.h> | 58 | #include <asm/system.h> |
@@ -272,7 +273,7 @@ void do_IRQ(struct pt_regs *regs) | |||
272 | struct thread_info *curtp, *irqtp; | 273 | struct thread_info *curtp, *irqtp; |
273 | #endif | 274 | #endif |
274 | 275 | ||
275 | irq_enter(); | 276 | irq_enter(); |
276 | 277 | ||
277 | #ifdef CONFIG_DEBUG_STACKOVERFLOW | 278 | #ifdef CONFIG_DEBUG_STACKOVERFLOW |
278 | /* Debugging check for stack overflow: is there less than 2KB free? */ | 279 | /* Debugging check for stack overflow: is there less than 2KB free? */ |
@@ -321,7 +322,7 @@ void do_IRQ(struct pt_regs *regs) | |||
321 | /* That's not SMP safe ... but who cares ? */ | 322 | /* That's not SMP safe ... but who cares ? */ |
322 | ppc_spurious_interrupts++; | 323 | ppc_spurious_interrupts++; |
323 | 324 | ||
324 | irq_exit(); | 325 | irq_exit(); |
325 | set_irq_regs(old_regs); | 326 | set_irq_regs(old_regs); |
326 | 327 | ||
327 | #ifdef CONFIG_PPC_ISERIES | 328 | #ifdef CONFIG_PPC_ISERIES |
@@ -418,10 +419,16 @@ irq_hw_number_t virq_to_hw(unsigned int virq) | |||
418 | } | 419 | } |
419 | EXPORT_SYMBOL_GPL(virq_to_hw); | 420 | EXPORT_SYMBOL_GPL(virq_to_hw); |
420 | 421 | ||
421 | __init_refok struct irq_host *irq_alloc_host(unsigned int revmap_type, | 422 | static int default_irq_host_match(struct irq_host *h, struct device_node *np) |
422 | unsigned int revmap_arg, | 423 | { |
423 | struct irq_host_ops *ops, | 424 | return h->of_node != NULL && h->of_node == np; |
424 | irq_hw_number_t inval_irq) | 425 | } |
426 | |||
427 | struct irq_host *irq_alloc_host(struct device_node *of_node, | ||
428 | unsigned int revmap_type, | ||
429 | unsigned int revmap_arg, | ||
430 | struct irq_host_ops *ops, | ||
431 | irq_hw_number_t inval_irq) | ||
425 | { | 432 | { |
426 | struct irq_host *host; | 433 | struct irq_host *host; |
427 | unsigned int size = sizeof(struct irq_host); | 434 | unsigned int size = sizeof(struct irq_host); |
@@ -432,13 +439,7 @@ __init_refok struct irq_host *irq_alloc_host(unsigned int revmap_type, | |||
432 | /* Allocate structure and revmap table if using linear mapping */ | 439 | /* Allocate structure and revmap table if using linear mapping */ |
433 | if (revmap_type == IRQ_HOST_MAP_LINEAR) | 440 | if (revmap_type == IRQ_HOST_MAP_LINEAR) |
434 | size += revmap_arg * sizeof(unsigned int); | 441 | size += revmap_arg * sizeof(unsigned int); |
435 | if (mem_init_done) | 442 | host = zalloc_maybe_bootmem(size, GFP_KERNEL); |
436 | host = kzalloc(size, GFP_KERNEL); | ||
437 | else { | ||
438 | host = alloc_bootmem(size); | ||
439 | if (host) | ||
440 | memset(host, 0, size); | ||
441 | } | ||
442 | if (host == NULL) | 443 | if (host == NULL) |
443 | return NULL; | 444 | return NULL; |
444 | 445 | ||
@@ -446,6 +447,10 @@ __init_refok struct irq_host *irq_alloc_host(unsigned int revmap_type, | |||
446 | host->revmap_type = revmap_type; | 447 | host->revmap_type = revmap_type; |
447 | host->inval_irq = inval_irq; | 448 | host->inval_irq = inval_irq; |
448 | host->ops = ops; | 449 | host->ops = ops; |
450 | host->of_node = of_node; | ||
451 | |||
452 | if (host->ops->match == NULL) | ||
453 | host->ops->match = default_irq_host_match; | ||
449 | 454 | ||
450 | spin_lock_irqsave(&irq_big_lock, flags); | 455 | spin_lock_irqsave(&irq_big_lock, flags); |
451 | 456 | ||
@@ -477,7 +482,7 @@ __init_refok struct irq_host *irq_alloc_host(unsigned int revmap_type, | |||
477 | host->inval_irq = 0; | 482 | host->inval_irq = 0; |
478 | /* setup us as the host for all legacy interrupts */ | 483 | /* setup us as the host for all legacy interrupts */ |
479 | for (i = 1; i < NUM_ISA_INTERRUPTS; i++) { | 484 | for (i = 1; i < NUM_ISA_INTERRUPTS; i++) { |
480 | irq_map[i].hwirq = 0; | 485 | irq_map[i].hwirq = i; |
481 | smp_wmb(); | 486 | smp_wmb(); |
482 | irq_map[i].host = host; | 487 | irq_map[i].host = host; |
483 | smp_wmb(); | 488 | smp_wmb(); |
@@ -521,7 +526,7 @@ struct irq_host *irq_find_host(struct device_node *node) | |||
521 | */ | 526 | */ |
522 | spin_lock_irqsave(&irq_big_lock, flags); | 527 | spin_lock_irqsave(&irq_big_lock, flags); |
523 | list_for_each_entry(h, &irq_hosts, link) | 528 | list_for_each_entry(h, &irq_hosts, link) |
524 | if (h->ops->match == NULL || h->ops->match(h, node)) { | 529 | if (h->ops->match(h, node)) { |
525 | found = h; | 530 | found = h; |
526 | break; | 531 | break; |
527 | } | 532 | } |
@@ -996,6 +1001,68 @@ static int irq_late_init(void) | |||
996 | } | 1001 | } |
997 | arch_initcall(irq_late_init); | 1002 | arch_initcall(irq_late_init); |
998 | 1003 | ||
1004 | #ifdef CONFIG_VIRQ_DEBUG | ||
1005 | static int virq_debug_show(struct seq_file *m, void *private) | ||
1006 | { | ||
1007 | unsigned long flags; | ||
1008 | irq_desc_t *desc; | ||
1009 | const char *p; | ||
1010 | char none[] = "none"; | ||
1011 | int i; | ||
1012 | |||
1013 | seq_printf(m, "%-5s %-7s %-15s %s\n", "virq", "hwirq", | ||
1014 | "chip name", "host name"); | ||
1015 | |||
1016 | for (i = 1; i < NR_IRQS; i++) { | ||
1017 | desc = get_irq_desc(i); | ||
1018 | spin_lock_irqsave(&desc->lock, flags); | ||
1019 | |||
1020 | if (desc->action && desc->action->handler) { | ||
1021 | seq_printf(m, "%5d ", i); | ||
1022 | seq_printf(m, "0x%05lx ", virq_to_hw(i)); | ||
1023 | |||
1024 | if (desc->chip && desc->chip->typename) | ||
1025 | p = desc->chip->typename; | ||
1026 | else | ||
1027 | p = none; | ||
1028 | seq_printf(m, "%-15s ", p); | ||
1029 | |||
1030 | if (irq_map[i].host && irq_map[i].host->of_node) | ||
1031 | p = irq_map[i].host->of_node->full_name; | ||
1032 | else | ||
1033 | p = none; | ||
1034 | seq_printf(m, "%s\n", p); | ||
1035 | } | ||
1036 | |||
1037 | spin_unlock_irqrestore(&desc->lock, flags); | ||
1038 | } | ||
1039 | |||
1040 | return 0; | ||
1041 | } | ||
1042 | |||
1043 | static int virq_debug_open(struct inode *inode, struct file *file) | ||
1044 | { | ||
1045 | return single_open(file, virq_debug_show, inode->i_private); | ||
1046 | } | ||
1047 | |||
1048 | static const struct file_operations virq_debug_fops = { | ||
1049 | .open = virq_debug_open, | ||
1050 | .read = seq_read, | ||
1051 | .llseek = seq_lseek, | ||
1052 | .release = single_release, | ||
1053 | }; | ||
1054 | |||
1055 | static int __init irq_debugfs_init(void) | ||
1056 | { | ||
1057 | if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, | ||
1058 | NULL, &virq_debug_fops)) | ||
1059 | return -ENOMEM; | ||
1060 | |||
1061 | return 0; | ||
1062 | } | ||
1063 | __initcall(irq_debugfs_init); | ||
1064 | #endif /* CONFIG_VIRQ_DEBUG */ | ||
1065 | |||
999 | #endif /* CONFIG_PPC_MERGE */ | 1066 | #endif /* CONFIG_PPC_MERGE */ |
1000 | 1067 | ||
1001 | #ifdef CONFIG_PPC64 | 1068 | #ifdef CONFIG_PPC64 |