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, 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) 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 = { \ 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