summaryrefslogtreecommitdiff
path: root/arch/x86_64/kernel/io_apic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/kernel/io_apic.c')
-rw-r--r--arch/x86_64/kernel/io_apic.c36
1 files changed, 33 insertions, 3 deletions
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index e1d1b4217cb2..12dd938f5d54 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -1254,18 +1254,48 @@ static int ioapic_retrigger_vector(unsigned int vector)
* races.
*/
-static void ack_apic(unsigned int vector)
+static void ack_apic(unsigned int irq)
{
ack_APIC_irq();
}
+static void ack_apic_edge(unsigned int irq)
+{
+ move_native_irq(irq);
+ ack_APIC_irq();
+}
+
+static void ack_apic_level(unsigned int irq)
+{
+ int do_unmask_irq = 0;
+
+#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
+ /* If we are moving the irq we need to mask it */
+ if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) {
+ do_unmask_irq = 1;
+ mask_IO_APIC_irq(irq);
+ }
+#endif
+
+ /*
+ * We must acknowledge the irq before we move it or the acknowledge will
+ * not propogate properly.
+ */
+ ack_APIC_irq();
+
+ /* Now we can move and renable the irq */
+ move_masked_irq(irq);
+ if (unlikely(do_unmask_irq))
+ unmask_IO_APIC_irq(irq);
+}
+
static struct irq_chip ioapic_chip __read_mostly = {
.name = "IO-APIC",
.startup = startup_ioapic_vector,
.mask = mask_ioapic_vector,
.unmask = unmask_ioapic_vector,
- .ack = ack_apic,
- .eoi = ack_apic,
+ .ack = ack_apic_edge,
+ .eoi = ack_apic_level,
#ifdef CONFIG_SMP
.set_affinity = set_ioapic_affinity_vector,
#endif