|
|
@@ -1891,6 +1891,50 @@ static int ioapic_set_affinity(struct irq_data *irq_data,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Interrupt shutdown masks the ioapic pin, but the interrupt might already
|
|
|
+ * be in flight, but not yet serviced by the target CPU. That means
|
|
|
+ * __synchronize_hardirq() would return and claim that everything is calmed
|
|
|
+ * down. So free_irq() would proceed and deactivate the interrupt and free
|
|
|
+ * resources.
|
|
|
+ *
|
|
|
+ * Once the target CPU comes around to service it it will find a cleared
|
|
|
+ * vector and complain. While the spurious interrupt is harmless, the full
|
|
|
+ * release of resources might prevent the interrupt from being acknowledged
|
|
|
+ * which keeps the hardware in a weird state.
|
|
|
+ *
|
|
|
+ * Verify that the corresponding Remote-IRR bits are clear.
|
|
|
+ */
|
|
|
+static int ioapic_irq_get_chip_state(struct irq_data *irqd,
|
|
|
+ enum irqchip_irq_state which,
|
|
|
+ bool *state)
|
|
|
+{
|
|
|
+ struct mp_chip_data *mcd = irqd->chip_data;
|
|
|
+ struct IO_APIC_route_entry rentry;
|
|
|
+ struct irq_pin_list *p;
|
|
|
+
|
|
|
+ if (which != IRQCHIP_STATE_ACTIVE)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ *state = false;
|
|
|
+ raw_spin_lock(&ioapic_lock);
|
|
|
+ for_each_irq_pin(p, mcd->irq_2_pin) {
|
|
|
+ rentry = __ioapic_read_entry(p->apic, p->pin);
|
|
|
+ /*
|
|
|
+ * The remote IRR is only valid in level trigger mode. It's
|
|
|
+ * meaning is undefined for edge triggered interrupts and
|
|
|
+ * irrelevant because the IO-APIC treats them as fire and
|
|
|
+ * forget.
|
|
|
+ */
|
|
|
+ if (rentry.irr && rentry.trigger) {
|
|
|
+ *state = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ raw_spin_unlock(&ioapic_lock);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static struct irq_chip ioapic_chip __read_mostly = {
|
|
|
.name = "IO-APIC",
|
|
|
.irq_startup = startup_ioapic_irq,
|
|
|
@@ -1900,6 +1944,7 @@ static struct irq_chip ioapic_chip __read_mostly = {
|
|
|
.irq_eoi = ioapic_ack_level,
|
|
|
.irq_set_affinity = ioapic_set_affinity,
|
|
|
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
|
|
+ .irq_get_irqchip_state = ioapic_irq_get_chip_state,
|
|
|
.flags = IRQCHIP_SKIP_SET_WAKE,
|
|
|
};
|
|
|
|
|
|
@@ -1912,6 +1957,7 @@ static struct irq_chip ioapic_ir_chip __read_mostly = {
|
|
|
.irq_eoi = ioapic_ir_ack_level,
|
|
|
.irq_set_affinity = ioapic_set_affinity,
|
|
|
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
|
|
+ .irq_get_irqchip_state = ioapic_irq_get_chip_state,
|
|
|
.flags = IRQCHIP_SKIP_SET_WAKE,
|
|
|
};
|
|
|
|