Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+25 -11
+24 -10
drivers/sh/intc.c
··· 927 927 return 0; 928 928 } 929 929 930 - unsigned int intc_irq_lookup(const char *chipname, intc_enum enum_id) 930 + #define INTC_TAG_VIRQ_NEEDS_ALLOC 0 931 + 932 + int intc_irq_lookup(const char *chipname, intc_enum enum_id) 931 933 { 932 934 struct intc_map_entry *ptr; 933 935 struct intc_desc_int *d; 934 - unsigned int irq = 0; 936 + int irq = -1; 935 937 936 938 list_for_each_entry(d, &intc_list, list) { 937 - if (strcmp(d->chip.name, chipname) == 0) { 938 - ptr = radix_tree_lookup(&d->tree, enum_id); 939 - if (ptr) { 940 - irq = ptr - intc_irq_xlate; 941 - break; 942 - } 939 + int tagged; 940 + 941 + if (strcmp(d->chip.name, chipname) != 0) 942 + continue; 943 + 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 ··· 1018 1002 return _INTC_MK(fn, MODE_ENABLE_REG, intc_get_reg(d, subgroup->reg), 1019 1003 0, 1, (subgroup->reg_width - 1) - index); 1020 1004 } 1021 - 1022 - #define INTC_TAG_VIRQ_NEEDS_ALLOC 0 1023 1005 1024 1006 static void __init intc_subgroup_init_one(struct intc_desc *desc, 1025 1007 struct intc_desc_int *d,
+1 -1
include/linux/sh_intc.h
··· 117 117 int __init register_intc_controller(struct intc_desc *desc); 118 118 void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs); 119 119 int intc_set_priority(unsigned int irq, unsigned int prio); 120 - unsigned int intc_irq_lookup(const char *chipname, intc_enum enum_id); 120 + int intc_irq_lookup(const char *chipname, intc_enum enum_id); 121 121 void intc_finalize(void); 122 122 123 123 #ifdef CONFIG_INTC_USERIMASK