aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/irq.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2011-05-23 23:05:26 -0400
committerPaul Mundt <lethal@linux-sh.org>2011-05-23 23:05:26 -0400
commit8b1aaeaf54f1bcaa0bbec6bb170db367c998d27c (patch)
tree2478e1708f5a3da261597f4aa1011d4d41c2cc84 /arch/powerpc/kernel/irq.c
parentbca606a646a2b1f4fa1ae2b22a0ac707505d7297 (diff)
parent5e152b4c9e0fce6149c74406346a7ae7e7a17727 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into rmobile-latest
Diffstat (limited to 'arch/powerpc/kernel/irq.c')
-rw-r--r--arch/powerpc/kernel/irq.c166
1 files changed, 63 insertions, 103 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index f621b7d2d869..a24d37d4cf51 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -66,7 +66,6 @@
66#include <asm/ptrace.h> 66#include <asm/ptrace.h>
67#include <asm/machdep.h> 67#include <asm/machdep.h>
68#include <asm/udbg.h> 68#include <asm/udbg.h>
69#include <asm/dbell.h>
70#include <asm/smp.h> 69#include <asm/smp.h>
71 70
72#ifdef CONFIG_PPC64 71#ifdef CONFIG_PPC64
@@ -160,7 +159,8 @@ notrace void arch_local_irq_restore(unsigned long en)
160 159
161#if defined(CONFIG_BOOKE) && defined(CONFIG_SMP) 160#if defined(CONFIG_BOOKE) && defined(CONFIG_SMP)
162 /* Check for pending doorbell interrupts and resend to ourself */ 161 /* Check for pending doorbell interrupts and resend to ourself */
163 doorbell_check_self(); 162 if (cpu_has_feature(CPU_FTR_DBELL))
163 smp_muxed_ipi_resend();
164#endif 164#endif
165 165
166 /* 166 /*
@@ -397,24 +397,28 @@ struct thread_info *mcheckirq_ctx[NR_CPUS] __read_mostly;
397void exc_lvl_ctx_init(void) 397void exc_lvl_ctx_init(void)
398{ 398{
399 struct thread_info *tp; 399 struct thread_info *tp;
400 int i, hw_cpu; 400 int i, cpu_nr;
401 401
402 for_each_possible_cpu(i) { 402 for_each_possible_cpu(i) {
403 hw_cpu = get_hard_smp_processor_id(i); 403#ifdef CONFIG_PPC64
404 memset((void *)critirq_ctx[hw_cpu], 0, THREAD_SIZE); 404 cpu_nr = i;
405 tp = critirq_ctx[hw_cpu]; 405#else
406 tp->cpu = i; 406 cpu_nr = get_hard_smp_processor_id(i);
407#endif
408 memset((void *)critirq_ctx[cpu_nr], 0, THREAD_SIZE);
409 tp = critirq_ctx[cpu_nr];
410 tp->cpu = cpu_nr;
407 tp->preempt_count = 0; 411 tp->preempt_count = 0;
408 412
409#ifdef CONFIG_BOOKE 413#ifdef CONFIG_BOOKE
410 memset((void *)dbgirq_ctx[hw_cpu], 0, THREAD_SIZE); 414 memset((void *)dbgirq_ctx[cpu_nr], 0, THREAD_SIZE);
411 tp = dbgirq_ctx[hw_cpu]; 415 tp = dbgirq_ctx[cpu_nr];
412 tp->cpu = i; 416 tp->cpu = cpu_nr;
413 tp->preempt_count = 0; 417 tp->preempt_count = 0;
414 418
415 memset((void *)mcheckirq_ctx[hw_cpu], 0, THREAD_SIZE); 419 memset((void *)mcheckirq_ctx[cpu_nr], 0, THREAD_SIZE);
416 tp = mcheckirq_ctx[hw_cpu]; 420 tp = mcheckirq_ctx[cpu_nr];
417 tp->cpu = i; 421 tp->cpu = cpu_nr;
418 tp->preempt_count = HARDIRQ_OFFSET; 422 tp->preempt_count = HARDIRQ_OFFSET;
419#endif 423#endif
420 } 424 }
@@ -477,20 +481,41 @@ void do_softirq(void)
477 * IRQ controller and virtual interrupts 481 * IRQ controller and virtual interrupts
478 */ 482 */
479 483
484/* The main irq map itself is an array of NR_IRQ entries containing the
485 * associate host and irq number. An entry with a host of NULL is free.
486 * An entry can be allocated if it's free, the allocator always then sets
487 * hwirq first to the host's invalid irq number and then fills ops.
488 */
489struct irq_map_entry {
490 irq_hw_number_t hwirq;
491 struct irq_host *host;
492};
493
480static LIST_HEAD(irq_hosts); 494static LIST_HEAD(irq_hosts);
481static DEFINE_RAW_SPINLOCK(irq_big_lock); 495static DEFINE_RAW_SPINLOCK(irq_big_lock);
482static unsigned int revmap_trees_allocated;
483static DEFINE_MUTEX(revmap_trees_mutex); 496static DEFINE_MUTEX(revmap_trees_mutex);
484struct irq_map_entry irq_map[NR_IRQS]; 497static struct irq_map_entry irq_map[NR_IRQS];
485static unsigned int irq_virq_count = NR_IRQS; 498static unsigned int irq_virq_count = NR_IRQS;
486static struct irq_host *irq_default_host; 499static struct irq_host *irq_default_host;
487 500
501irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
502{
503 return irq_map[d->irq].hwirq;
504}
505EXPORT_SYMBOL_GPL(irqd_to_hwirq);
506
488irq_hw_number_t virq_to_hw(unsigned int virq) 507irq_hw_number_t virq_to_hw(unsigned int virq)
489{ 508{
490 return irq_map[virq].hwirq; 509 return irq_map[virq].hwirq;
491} 510}
492EXPORT_SYMBOL_GPL(virq_to_hw); 511EXPORT_SYMBOL_GPL(virq_to_hw);
493 512
513bool virq_is_host(unsigned int virq, struct irq_host *host)
514{
515 return irq_map[virq].host == host;
516}
517EXPORT_SYMBOL_GPL(virq_is_host);
518
494static int default_irq_host_match(struct irq_host *h, struct device_node *np) 519static int default_irq_host_match(struct irq_host *h, struct device_node *np)
495{ 520{
496 return h->of_node != NULL && h->of_node == np; 521 return h->of_node != NULL && h->of_node == np;
@@ -511,7 +536,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
511 /* Allocate structure and revmap table if using linear mapping */ 536 /* Allocate structure and revmap table if using linear mapping */
512 if (revmap_type == IRQ_HOST_MAP_LINEAR) 537 if (revmap_type == IRQ_HOST_MAP_LINEAR)
513 size += revmap_arg * sizeof(unsigned int); 538 size += revmap_arg * sizeof(unsigned int);
514 host = zalloc_maybe_bootmem(size, GFP_KERNEL); 539 host = kzalloc(size, GFP_KERNEL);
515 if (host == NULL) 540 if (host == NULL)
516 return NULL; 541 return NULL;
517 542
@@ -561,14 +586,14 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
561 irq_map[i].host = host; 586 irq_map[i].host = host;
562 smp_wmb(); 587 smp_wmb();
563 588
564 /* Clear norequest flags */
565 irq_clear_status_flags(i, IRQ_NOREQUEST);
566
567 /* Legacy flags are left to default at this point, 589 /* Legacy flags are left to default at this point,
568 * one can then use irq_create_mapping() to 590 * one can then use irq_create_mapping() to
569 * explicitly change them 591 * explicitly change them
570 */ 592 */
571 ops->map(host, i, i); 593 ops->map(host, i, i);
594
595 /* Clear norequest flags */
596 irq_clear_status_flags(i, IRQ_NOREQUEST);
572 } 597 }
573 break; 598 break;
574 case IRQ_HOST_MAP_LINEAR: 599 case IRQ_HOST_MAP_LINEAR:
@@ -579,6 +604,9 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
579 smp_wmb(); 604 smp_wmb();
580 host->revmap_data.linear.revmap = rmap; 605 host->revmap_data.linear.revmap = rmap;
581 break; 606 break;
607 case IRQ_HOST_MAP_TREE:
608 INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL);
609 break;
582 default: 610 default:
583 break; 611 break;
584 } 612 }
@@ -636,8 +664,6 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq,
636 goto error; 664 goto error;
637 } 665 }
638 666
639 irq_clear_status_flags(virq, IRQ_NOREQUEST);
640
641 /* map it */ 667 /* map it */
642 smp_wmb(); 668 smp_wmb();
643 irq_map[virq].hwirq = hwirq; 669 irq_map[virq].hwirq = hwirq;
@@ -648,6 +674,8 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq,
648 goto errdesc; 674 goto errdesc;
649 } 675 }
650 676
677 irq_clear_status_flags(virq, IRQ_NOREQUEST);
678
651 return 0; 679 return 0;
652 680
653errdesc: 681errdesc:
@@ -704,8 +732,6 @@ unsigned int irq_create_mapping(struct irq_host *host,
704 */ 732 */
705 virq = irq_find_mapping(host, hwirq); 733 virq = irq_find_mapping(host, hwirq);
706 if (virq != NO_IRQ) { 734 if (virq != NO_IRQ) {
707 if (host->ops->remap)
708 host->ops->remap(host, virq, hwirq);
709 pr_debug("irq: -> existing mapping on virq %d\n", virq); 735 pr_debug("irq: -> existing mapping on virq %d\n", virq);
710 return virq; 736 return virq;
711 } 737 }
@@ -786,14 +812,15 @@ void irq_dispose_mapping(unsigned int virq)
786 return; 812 return;
787 813
788 host = irq_map[virq].host; 814 host = irq_map[virq].host;
789 WARN_ON (host == NULL); 815 if (WARN_ON(host == NULL))
790 if (host == NULL)
791 return; 816 return;
792 817
793 /* Never unmap legacy interrupts */ 818 /* Never unmap legacy interrupts */
794 if (host->revmap_type == IRQ_HOST_MAP_LEGACY) 819 if (host->revmap_type == IRQ_HOST_MAP_LEGACY)
795 return; 820 return;
796 821
822 irq_set_status_flags(virq, IRQ_NOREQUEST);
823
797 /* remove chip and handler */ 824 /* remove chip and handler */
798 irq_set_chip_and_handler(virq, NULL, NULL); 825 irq_set_chip_and_handler(virq, NULL, NULL);
799 826
@@ -813,13 +840,6 @@ void irq_dispose_mapping(unsigned int virq)
813 host->revmap_data.linear.revmap[hwirq] = NO_IRQ; 840 host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
814 break; 841 break;
815 case IRQ_HOST_MAP_TREE: 842 case IRQ_HOST_MAP_TREE:
816 /*
817 * Check if radix tree allocated yet, if not then nothing to
818 * remove.
819 */
820 smp_rmb();
821 if (revmap_trees_allocated < 1)
822 break;
823 mutex_lock(&revmap_trees_mutex); 843 mutex_lock(&revmap_trees_mutex);
824 radix_tree_delete(&host->revmap_data.tree, hwirq); 844 radix_tree_delete(&host->revmap_data.tree, hwirq);
825 mutex_unlock(&revmap_trees_mutex); 845 mutex_unlock(&revmap_trees_mutex);
@@ -830,8 +850,6 @@ void irq_dispose_mapping(unsigned int virq)
830 smp_mb(); 850 smp_mb();
831 irq_map[virq].hwirq = host->inval_irq; 851 irq_map[virq].hwirq = host->inval_irq;
832 852
833 irq_set_status_flags(virq, IRQ_NOREQUEST);
834
835 irq_free_descs(virq, 1); 853 irq_free_descs(virq, 1);
836 /* Free it */ 854 /* Free it */
837 irq_free_virt(virq, 1); 855 irq_free_virt(virq, 1);
@@ -877,16 +895,9 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host,
877 struct irq_map_entry *ptr; 895 struct irq_map_entry *ptr;
878 unsigned int virq; 896 unsigned int virq;
879 897
880 WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE); 898 if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE))
881
882 /*
883 * Check if the radix tree exists and has bee initialized.
884 * If not, we fallback to slow mode
885 */
886 if (revmap_trees_allocated < 2)
887 return irq_find_mapping(host, hwirq); 899 return irq_find_mapping(host, hwirq);
888 900
889 /* Now try to resolve */
890 /* 901 /*
891 * No rcu_read_lock(ing) needed, the ptr returned can't go under us 902 * No rcu_read_lock(ing) needed, the ptr returned can't go under us
892 * as it's referencing an entry in the static irq_map table. 903 * as it's referencing an entry in the static irq_map table.
@@ -909,16 +920,7 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host,
909void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, 920void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
910 irq_hw_number_t hwirq) 921 irq_hw_number_t hwirq)
911{ 922{
912 923 if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE))
913 WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
914
915 /*
916 * Check if the radix tree exists yet.
917 * If not, then the irq will be inserted into the tree when it gets
918 * initialized.
919 */
920 smp_rmb();
921 if (revmap_trees_allocated < 1)
922 return; 924 return;
923 925
924 if (virq != NO_IRQ) { 926 if (virq != NO_IRQ) {
@@ -934,7 +936,8 @@ unsigned int irq_linear_revmap(struct irq_host *host,
934{ 936{
935 unsigned int *revmap; 937 unsigned int *revmap;
936 938
937 WARN_ON(host->revmap_type != IRQ_HOST_MAP_LINEAR); 939 if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR))
940 return irq_find_mapping(host, hwirq);
938 941
939 /* Check revmap bounds */ 942 /* Check revmap bounds */
940 if (unlikely(hwirq >= host->revmap_data.linear.size)) 943 if (unlikely(hwirq >= host->revmap_data.linear.size))
@@ -1028,53 +1031,6 @@ int arch_early_irq_init(void)
1028 return 0; 1031 return 0;
1029} 1032}
1030 1033
1031/* We need to create the radix trees late */
1032static int irq_late_init(void)
1033{
1034 struct irq_host *h;
1035 unsigned int i;
1036
1037 /*
1038 * No mutual exclusion with respect to accessors of the tree is needed
1039 * here as the synchronization is done via the state variable
1040 * revmap_trees_allocated.
1041 */
1042 list_for_each_entry(h, &irq_hosts, link) {
1043 if (h->revmap_type == IRQ_HOST_MAP_TREE)
1044 INIT_RADIX_TREE(&h->revmap_data.tree, GFP_KERNEL);
1045 }
1046
1047 /*
1048 * Make sure the radix trees inits are visible before setting
1049 * the flag
1050 */
1051 smp_wmb();
1052 revmap_trees_allocated = 1;
1053
1054 /*
1055 * Insert the reverse mapping for those interrupts already present
1056 * in irq_map[].
1057 */
1058 mutex_lock(&revmap_trees_mutex);
1059 for (i = 0; i < irq_virq_count; i++) {
1060 if (irq_map[i].host &&
1061 (irq_map[i].host->revmap_type == IRQ_HOST_MAP_TREE))
1062 radix_tree_insert(&irq_map[i].host->revmap_data.tree,
1063 irq_map[i].hwirq, &irq_map[i]);
1064 }
1065 mutex_unlock(&revmap_trees_mutex);
1066
1067 /*
1068 * Make sure the radix trees insertions are visible before setting
1069 * the flag
1070 */
1071 smp_wmb();
1072 revmap_trees_allocated = 2;
1073
1074 return 0;
1075}
1076arch_initcall(irq_late_init);
1077
1078#ifdef CONFIG_VIRQ_DEBUG 1034#ifdef CONFIG_VIRQ_DEBUG
1079static int virq_debug_show(struct seq_file *m, void *private) 1035static int virq_debug_show(struct seq_file *m, void *private)
1080{ 1036{
@@ -1082,10 +1038,11 @@ static int virq_debug_show(struct seq_file *m, void *private)
1082 struct irq_desc *desc; 1038 struct irq_desc *desc;
1083 const char *p; 1039 const char *p;
1084 static const char none[] = "none"; 1040 static const char none[] = "none";
1041 void *data;
1085 int i; 1042 int i;
1086 1043
1087 seq_printf(m, "%-5s %-7s %-15s %s\n", "virq", "hwirq", 1044 seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq",
1088 "chip name", "host name"); 1045 "chip name", "chip data", "host name");
1089 1046
1090 for (i = 1; i < nr_irqs; i++) { 1047 for (i = 1; i < nr_irqs; i++) {
1091 desc = irq_to_desc(i); 1048 desc = irq_to_desc(i);
@@ -1098,7 +1055,7 @@ static int virq_debug_show(struct seq_file *m, void *private)
1098 struct irq_chip *chip; 1055 struct irq_chip *chip;
1099 1056
1100 seq_printf(m, "%5d ", i); 1057 seq_printf(m, "%5d ", i);
1101 seq_printf(m, "0x%05lx ", virq_to_hw(i)); 1058 seq_printf(m, "0x%05lx ", irq_map[i].hwirq);
1102 1059
1103 chip = irq_desc_get_chip(desc); 1060 chip = irq_desc_get_chip(desc);
1104 if (chip && chip->name) 1061 if (chip && chip->name)
@@ -1107,6 +1064,9 @@ static int virq_debug_show(struct seq_file *m, void *private)
1107 p = none; 1064 p = none;
1108 seq_printf(m, "%-15s ", p); 1065 seq_printf(m, "%-15s ", p);
1109 1066
1067 data = irq_desc_get_chip_data(desc);
1068 seq_printf(m, "0x%16p ", data);
1069
1110 if (irq_map[i].host && irq_map[i].host->of_node) 1070 if (irq_map[i].host && irq_map[i].host->of_node)
1111 p = irq_map[i].host->of_node->full_name; 1071 p = irq_map[i].host->of_node->full_name;
1112 else 1072 else