in irq-mips-gic.c [465:542]
static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hwirq)
{
struct gic_all_vpes_chip_data *cd;
unsigned long flags;
unsigned int intr;
int err, cpu;
u32 map;
if (hwirq >= GIC_SHARED_HWIRQ_BASE) {
/* verify that shared irqs don't conflict with an IPI irq */
if (test_bit(GIC_HWIRQ_TO_SHARED(hwirq), ipi_resrv))
return -EBUSY;
err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
&gic_level_irq_controller,
NULL);
if (err)
return err;
irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq)));
return gic_shared_irq_domain_map(d, virq, hwirq, 0);
}
intr = GIC_HWIRQ_TO_LOCAL(hwirq);
map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;
/*
* If adding support for more per-cpu interrupts, keep the the
* array in gic_all_vpes_irq_cpu_online() in sync.
*/
switch (intr) {
case GIC_LOCAL_INT_TIMER:
/* CONFIG_MIPS_CMP workaround (see __gic_init) */
map = GIC_MAP_PIN_MAP_TO_PIN | timer_cpu_pin;
fallthrough;
case GIC_LOCAL_INT_PERFCTR:
case GIC_LOCAL_INT_FDC:
/*
* HACK: These are all really percpu interrupts, but
* the rest of the MIPS kernel code does not use the
* percpu IRQ API for them.
*/
cd = &gic_all_vpes_chip_data[intr];
cd->map = map;
err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
&gic_all_vpes_local_irq_controller,
cd);
if (err)
return err;
irq_set_handler(virq, handle_percpu_irq);
break;
default:
err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
&gic_local_irq_controller,
NULL);
if (err)
return err;
irq_set_handler(virq, handle_percpu_devid_irq);
irq_set_percpu_devid(virq);
break;
}
if (!gic_local_irq_is_routable(intr))
return -EPERM;
spin_lock_irqsave(&gic_lock, flags);
for_each_online_cpu(cpu) {
write_gic_vl_other(mips_cm_vp_id(cpu));
write_gic_vo_map(mips_gic_vx_map_reg(intr), map);
}
spin_unlock_irqrestore(&gic_lock, flags);
return 0;
}