]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
sh: intc: Handle early lookups of subgroup IRQs.
authorPaul Mundt <lethal@linux-sh.org>
Tue, 5 Oct 2010 09:13:23 +0000 (18:13 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Tue, 5 Oct 2010 09:13:23 +0000 (18:13 +0900)
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>
drivers/sh/intc.c
include/linux/sh_intc.h

index c81fe23db7f74a6cc4cc17f174e375b34912eac4..d4325c70cf6197b4dcf283c0586ceccb1214d008 100644 (file)
@@ -927,19 +927,35 @@ static unsigned int __init intc_sense_data(struct intc_desc *desc,
        return 0;
 }
 
-unsigned int intc_irq_lookup(const char *chipname, intc_enum enum_id)
+#define INTC_TAG_VIRQ_NEEDS_ALLOC      0
+
+int intc_irq_lookup(const char *chipname, intc_enum enum_id)
 {
        struct intc_map_entry *ptr;
        struct intc_desc_int *d;
-       unsigned int irq = 0;
+       int irq = -1;
 
        list_for_each_entry(d, &intc_list, list) {
-               if (strcmp(d->chip.name, chipname) == 0) {
-                       ptr = radix_tree_lookup(&d->tree, enum_id);
-                       if (ptr) {
-                               irq = ptr - intc_irq_xlate;
-                               break;
-                       }
+               int tagged;
+
+               if (strcmp(d->chip.name, chipname) != 0)
+                       continue;
+
+               /*
+                * Catch early lookups for subgroup VIRQs that have not
+                * yet been allocated an IRQ. This already includes a
+                * fast-path out if the tree is untagged, so there is no
+                * need to explicitly test the root tree.
+                */
+               tagged = radix_tree_tag_get(&d->tree, enum_id,
+                                           INTC_TAG_VIRQ_NEEDS_ALLOC);
+               if (unlikely(tagged))
+                       break;
+
+               ptr = radix_tree_lookup(&d->tree, enum_id);
+               if (ptr) {
+                       irq = ptr - intc_irq_xlate;
+                       break;
                }
        }
 
@@ -1003,8 +1019,6 @@ static unsigned long __init intc_subgroup_data(struct intc_subgroup *subgroup,
                        0, 1, (subgroup->reg_width - 1) - index);
 }
 
-#define INTC_TAG_VIRQ_NEEDS_ALLOC      0
-
 static void __init intc_subgroup_init_one(struct intc_desc *desc,
                                          struct intc_desc_int *d,
                                          struct intc_subgroup *subgroup)
index 04134a6c7b52b638c163de9ce72e6275f7410056..1fc69701e0f8e7db4670fd9a03e2a87edec82fdc 100644 (file)
@@ -117,7 +117,7 @@ struct intc_desc symbol __initdata = {                                      \
 int __init register_intc_controller(struct intc_desc *desc);
 void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs);
 int intc_set_priority(unsigned int irq, unsigned int prio);
-unsigned int intc_irq_lookup(const char *chipname, intc_enum enum_id);
+int intc_irq_lookup(const char *chipname, intc_enum enum_id);
 void intc_finalize(void);
 
 #ifdef CONFIG_INTC_USERIMASK