diff options
Diffstat (limited to 'drivers/irqchip/irq-or1k-pic.c')
| -rw-r--r-- | drivers/irqchip/irq-or1k-pic.c | 27 |
1 files changed, 26 insertions, 1 deletions
diff --git a/drivers/irqchip/irq-or1k-pic.c b/drivers/irqchip/irq-or1k-pic.c index 48126067c54b..73dc99c71d40 100644 --- a/drivers/irqchip/irq-or1k-pic.c +++ b/drivers/irqchip/irq-or1k-pic.c @@ -118,11 +118,36 @@ static void or1k_pic_handle_irq(struct pt_regs *regs) generic_handle_domain_irq(root_domain, irq); } +/* + * The OR1K PIC is a cpu-local interrupt controller and does not distinguish or + * use distinct irq number ranges for per-cpu event interrupts (IPI). Since + * information to determine whether a particular irq number should be treated as + * per-cpu is not available at mapping time, we use a wrapper handler function + * which chooses the right handler at runtime based on whether IRQF_PERCPU was + * used when requesting the irq. Borrowed from J-Core AIC. + */ +static void or1k_irq_flow_handler(struct irq_desc *desc) +{ +#ifdef CONFIG_SMP + struct irq_data *data = irq_desc_get_irq_data(desc); + struct or1k_pic_dev *pic = data->domain->host_data; + + if (irqd_is_per_cpu(data)) + handle_percpu_devid_irq(desc); + else + pic->handle(desc); +#endif +} + static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { struct or1k_pic_dev *pic = d->host_data; - irq_set_chip_and_handler(irq, &pic->chip, pic->handle); + if (IS_ENABLED(CONFIG_SMP)) + irq_set_chip_and_handler(irq, &pic->chip, or1k_irq_flow_handler); + else + irq_set_chip_and_handler(irq, &pic->chip, pic->handle); + irq_set_status_flags(irq, pic->flags); return 0; |
