in intc/virq.c [201:260]
static void __init intc_subgroup_map(struct intc_desc_int *d)
{
struct intc_subgroup_entry *entries[32];
unsigned long flags;
unsigned int nr_found;
int i;
raw_spin_lock_irqsave(&d->lock, flags);
restart:
nr_found = radix_tree_gang_lookup_tag_slot(&d->tree,
(void ***)entries, 0, ARRAY_SIZE(entries),
INTC_TAG_VIRQ_NEEDS_ALLOC);
for (i = 0; i < nr_found; i++) {
struct intc_subgroup_entry *entry;
int irq;
entry = radix_tree_deref_slot((void **)entries[i]);
if (unlikely(!entry))
continue;
if (radix_tree_deref_retry(entry))
goto restart;
irq = irq_alloc_desc(numa_node_id());
if (unlikely(irq < 0)) {
pr_err("no more free IRQs, bailing..\n");
break;
}
activate_irq(irq);
pr_info("Setting up a chained VIRQ from %d -> %d\n",
irq, entry->pirq);
intc_irq_xlate_set(irq, entry->enum_id, d);
irq_set_chip_and_handler_name(irq, irq_get_chip(entry->pirq),
handle_simple_irq, "virq");
irq_set_chip_data(irq, irq_get_chip_data(entry->pirq));
irq_set_handler_data(irq, (void *)entry->handle);
/*
* Set the virtual IRQ as non-threadable.
*/
irq_set_nothread(irq);
/* Set handler data before installing the handler */
add_virq_to_pirq(entry->pirq, irq);
irq_set_chained_handler(entry->pirq, intc_virq_handler);
radix_tree_tag_clear(&d->tree, entry->enum_id,
INTC_TAG_VIRQ_NEEDS_ALLOC);
radix_tree_replace_slot(&d->tree, (void **)entries[i],
&intc_irq_xlate[irq]);
}
raw_spin_unlock_irqrestore(&d->lock, flags);
}