aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-10-05 05:13:23 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-10-05 05:13:23 -0400
commitd74310d3b18aabbb7d0549ea9e3fd3259c1dce00 (patch)
treed31d696a25aa22e8f2490edf287fe28c3a3b98d5
parentc1e30ad98fe210688edca872686db4a715c2fb23 (diff)
sh: intc: Handle early lookups of subgroup IRQs.
If lookups happen while the radix node still points to a subgroup mapping, an IRQ hasn't yet been made available for the specified id, so error out accordingly. Once the slot is replaced with an IRQ mapping and the tag is discarded, lookup can commence as normal. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r--drivers/sh/intc.c34
-rw-r--r--include/linux/sh_intc.h2
2 files changed, 25 insertions, 11 deletions
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index c81fe23db7f7..d4325c70cf61 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -927,19 +927,35 @@ static unsigned int __init intc_sense_data(struct intc_desc *desc,
927 return 0; 927 return 0;
928} 928}
929 929
930unsigned int intc_irq_lookup(const char *chipname, intc_enum enum_id) 930#define INTC_TAG_VIRQ_NEEDS_ALLOC 0
931
932int intc_irq_lookup(const char *chipname, intc_enum enum_id)
931{ 933{
932 struct intc_map_entry *ptr; 934 struct intc_map_entry *ptr;
933 struct intc_desc_int *d; 935 struct intc_desc_int *d;
934 unsigned int irq = 0; 936 int irq = -1;
935 937
936 list_for_each_entry(d, &intc_list, list) { 938 list_for_each_entry(d, &intc_list, list) {
937 if (strcmp(d->chip.name, chipname) == 0) { 939 int tagged;
938 ptr = radix_tree_lookup(&d->tree, enum_id); 940
939 if (ptr) { 941 if (strcmp(d->chip.name, chipname) != 0)
940 irq = ptr - intc_irq_xlate; 942 continue;
941 break; 943
942 } 944 /*
945 * Catch early lookups for subgroup VIRQs that have not
946 * yet been allocated an IRQ. This already includes a
947 * fast-path out if the tree is untagged, so there is no
948 * need to explicitly test the root tree.
949 */
950 tagged = radix_tree_tag_get(&d->tree, enum_id,
951 INTC_TAG_VIRQ_NEEDS_ALLOC);
952 if (unlikely(tagged))
953 break;
954
955 ptr = radix_tree_lookup(&d->tree, enum_id);
956 if (ptr) {
957 irq = ptr - intc_irq_xlate;
958 break;
943 } 959 }
944 } 960 }
945 961
@@ -1003,8 +1019,6 @@ static unsigned long __init intc_subgroup_data(struct intc_subgroup *subgroup,
1003 0, 1, (subgroup->reg_width - 1) - index); 1019 0, 1, (subgroup->reg_width - 1) - index);
1004} 1020}
1005 1021
1006#define INTC_TAG_VIRQ_NEEDS_ALLOC 0
1007
1008static void __init intc_subgroup_init_one(struct intc_desc *desc, 1022static void __init intc_subgroup_init_one(struct intc_desc *desc,
1009 struct intc_desc_int *d, 1023 struct intc_desc_int *d,
1010 struct intc_subgroup *subgroup) 1024 struct intc_subgroup *subgroup)
diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h
index 04134a6c7b52..1fc69701e0f8 100644
--- a/include/linux/sh_intc.h
+++ b/include/linux/sh_intc.h
@@ -117,7 +117,7 @@ struct intc_desc symbol __initdata = { \
117int __init register_intc_controller(struct intc_desc *desc); 117int __init register_intc_controller(struct intc_desc *desc);
118void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs); 118void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs);
119int intc_set_priority(unsigned int irq, unsigned int prio); 119int intc_set_priority(unsigned int irq, unsigned int prio);
120unsigned int intc_irq_lookup(const char *chipname, intc_enum enum_id); 120int intc_irq_lookup(const char *chipname, intc_enum enum_id);
121void intc_finalize(void); 121void intc_finalize(void);
122 122
123#ifdef CONFIG_INTC_USERIMASK 123#ifdef CONFIG_INTC_USERIMASK