diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index c2c8f37f264ab9e7af0f6630eb49cffb0a7c47c8..5d8658749c8c113965e4bccf9237a6ad3c2089f2 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1356,7 +1356,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, if (!gic_dist_supports_lpis()) return -EPERM; irq_domain_set_info(d, irq, hw, chip, d->host_data, - handle_fasteoi_irq, NULL, NULL); + handle_fasteoi_edge_irq, NULL, NULL); } /* Prevents SW retriggers which mess up the ACK/EOI ordering */ diff --git a/include/linux/irq.h b/include/linux/irq.h index 536f1abc9a8ce4e03d05204c5491642ea939f4f4..ff291f27320046139696a4e20fca76b014ccb441 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -637,6 +637,7 @@ static inline int irq_set_parent(int irq, int parent_irq) */ extern void handle_level_irq(struct irq_desc *desc); extern void handle_fasteoi_irq(struct irq_desc *desc); +extern void handle_fasteoi_edge_irq(struct irq_desc *desc); extern void handle_edge_irq(struct irq_desc *desc); extern void handle_edge_eoi_irq(struct irq_desc *desc); extern void handle_simple_irq(struct irq_desc *desc); diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 6d5c1fe792b53be29ed17afcbc13d91730ab27df..b194d923b3c8f9f820e2a3e03937b8e56dc023df 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -704,6 +704,73 @@ static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip) } } +/** + * handle_fasteoi_edge_irq - irq handler for transparent controllers + * edge type IRQ. + * @desc: the interrupt description structure for this irq + */ +void handle_fasteoi_edge_irq(struct irq_desc *desc) +{ + struct irq_chip *chip = desc->irq_data.chip; + + raw_spin_lock(&desc->lock); + + if (!irq_may_run(desc)) { + desc->istate |= IRQS_PENDING; + mask_irq(desc); + goto out; + } + + desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); + + /* + * If its disabled or no action available + * then mask it and get out of here: + */ + if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { + desc->istate |= IRQS_PENDING; + mask_irq(desc); + goto out; + } + + kstat_incr_irqs_this_cpu(desc); + + if (desc->istate & IRQS_ONESHOT) + mask_irq(desc); + + do { + if (unlikely(!desc->action)) { + mask_irq(desc); + goto out; + } + + /* + * When another irq arrived while we were handling + * one, we could have masked the irq. + * Reenable it, if it was not disabled in meantime. + */ + if (unlikely(desc->istate & IRQS_PENDING)) { + if (!irqd_irq_disabled(&desc->irq_data) && + irqd_irq_masked(&desc->irq_data)) + unmask_irq(desc); + } + + handle_irq_event(desc); + + } while ((desc->istate & IRQS_PENDING) && + !irqd_irq_disabled(&desc->irq_data)); + + cond_unmask_eoi_irq(desc, chip); + + raw_spin_unlock(&desc->lock); + return; +out: + if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED)) + chip->irq_eoi(&desc->irq_data); + raw_spin_unlock(&desc->lock); +} +EXPORT_SYMBOL_GPL(handle_fasteoi_edge_irq); + /** * handle_fasteoi_irq - irq handler for transparent controllers * @desc: the interrupt description structure for this irq