|
@@ -1092,6 +1092,112 @@ void irq_cpu_offline(void)
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
|
|
|
+
|
|
|
+#ifdef CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS
|
|
|
+/**
|
|
|
+ * handle_fasteoi_ack_irq - irq handler for edge hierarchy
|
|
|
+ * stacked on transparent controllers
|
|
|
+ *
|
|
|
+ * @desc: the interrupt description structure for this irq
|
|
|
+ *
|
|
|
+ * Like handle_fasteoi_irq(), but for use with hierarchy where
|
|
|
+ * the irq_chip also needs to have its ->irq_ack() function
|
|
|
+ * called.
|
|
|
+ */
|
|
|
+void handle_fasteoi_ack_irq(struct irq_desc *desc)
|
|
|
+{
|
|
|
+ struct irq_chip *chip = desc->irq_data.chip;
|
|
|
+
|
|
|
+ raw_spin_lock(&desc->lock);
|
|
|
+
|
|
|
+ if (!irq_may_run(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);
|
|
|
+
|
|
|
+ /* Start handling the irq */
|
|
|
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
|
|
|
+
|
|
|
+ preflow_handler(desc);
|
|
|
+ handle_irq_event(desc);
|
|
|
+
|
|
|
+ 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_ack_irq);
|
|
|
+
|
|
|
+/**
|
|
|
+ * handle_fasteoi_mask_irq - irq handler for level hierarchy
|
|
|
+ * stacked on transparent controllers
|
|
|
+ *
|
|
|
+ * @desc: the interrupt description structure for this irq
|
|
|
+ *
|
|
|
+ * Like handle_fasteoi_irq(), but for use with hierarchy where
|
|
|
+ * the irq_chip also needs to have its ->irq_mask_ack() function
|
|
|
+ * called.
|
|
|
+ */
|
|
|
+void handle_fasteoi_mask_irq(struct irq_desc *desc)
|
|
|
+{
|
|
|
+ struct irq_chip *chip = desc->irq_data.chip;
|
|
|
+
|
|
|
+ raw_spin_lock(&desc->lock);
|
|
|
+ mask_ack_irq(desc);
|
|
|
+
|
|
|
+ if (!irq_may_run(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);
|
|
|
+
|
|
|
+ preflow_handler(desc);
|
|
|
+ handle_irq_event(desc);
|
|
|
+
|
|
|
+ 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_mask_irq);
|
|
|
+
|
|
|
+#endif /* CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS */
|
|
|
+
|
|
|
/**
|
|
|
* irq_chip_enable_parent - Enable the parent interrupt (defaults to unmask if
|
|
|
* NULL)
|