113 lines
3.6 KiB
Diff
113 lines
3.6 KiB
Diff
From 4debab2aa3d29fcdb5b9cd132416094c54e9361b Mon Sep 17 00:00:00 2001
|
|
From: Thomas Gleixner <tglx@linutronix.de>
|
|
Date: Tue, 17 Jul 2018 18:25:31 +0200
|
|
Subject: [PATCH 013/264] x86/ioapic: Don't let setaffinity unmask threaded EOI
|
|
interrupt too early
|
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.19/older/patches-4.19.37-rt19.tar.xz
|
|
|
|
There is an issue with threaded interrupts which are marked ONESHOT
|
|
and using the fasteoi handler.
|
|
|
|
if (IS_ONESHOT())
|
|
mask_irq();
|
|
|
|
....
|
|
....
|
|
|
|
cond_unmask_eoi_irq()
|
|
chip->irq_eoi();
|
|
|
|
So if setaffinity is pending then the interrupt will be moved and then
|
|
unmasked, which is wrong as it should be kept masked up to the point where
|
|
the threaded handler finished. It's not a real problem, the interrupt will
|
|
just be able to fire before the threaded handler has finished, though the irq
|
|
masked state will be wrong for a bit.
|
|
|
|
The patch below should cure the issue. It also renames the horribly
|
|
misnomed functions so it becomes clear what they are supposed to do.
|
|
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
[bigeasy: add the body of the patch, use the same functions in both
|
|
ifdef paths (spotted by Andy Shevchenko)]
|
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
---
|
|
arch/x86/kernel/apic/io_apic.c | 23 +++++++++++++----------
|
|
1 file changed, 13 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
|
|
index ff0d14cd9e82..c2bd6e0433f8 100644
|
|
--- a/arch/x86/kernel/apic/io_apic.c
|
|
+++ b/arch/x86/kernel/apic/io_apic.c
|
|
@@ -1722,19 +1722,20 @@ static bool io_apic_level_ack_pending(struct mp_chip_data *data)
|
|
return false;
|
|
}
|
|
|
|
-static inline bool ioapic_irqd_mask(struct irq_data *data)
|
|
+static inline bool ioapic_prepare_move(struct irq_data *data)
|
|
{
|
|
/* If we are moving the irq we need to mask it */
|
|
if (unlikely(irqd_is_setaffinity_pending(data))) {
|
|
- mask_ioapic_irq(data);
|
|
+ if (!irqd_irq_masked(data))
|
|
+ mask_ioapic_irq(data);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
-static inline void ioapic_irqd_unmask(struct irq_data *data, bool masked)
|
|
+static inline void ioapic_finish_move(struct irq_data *data, bool moveit)
|
|
{
|
|
- if (unlikely(masked)) {
|
|
+ if (unlikely(moveit)) {
|
|
/* Only migrate the irq if the ack has been received.
|
|
*
|
|
* On rare occasions the broadcast level triggered ack gets
|
|
@@ -1763,15 +1764,17 @@ static inline void ioapic_irqd_unmask(struct irq_data *data, bool masked)
|
|
*/
|
|
if (!io_apic_level_ack_pending(data->chip_data))
|
|
irq_move_masked_irq(data);
|
|
- unmask_ioapic_irq(data);
|
|
+ /* If the irq is masked in the core, leave it */
|
|
+ if (!irqd_irq_masked(data))
|
|
+ unmask_ioapic_irq(data);
|
|
}
|
|
}
|
|
#else
|
|
-static inline bool ioapic_irqd_mask(struct irq_data *data)
|
|
+static inline bool ioapic_prepare_move(struct irq_data *data)
|
|
{
|
|
return false;
|
|
}
|
|
-static inline void ioapic_irqd_unmask(struct irq_data *data, bool masked)
|
|
+static inline void ioapic_finish_move(struct irq_data *data, bool moveit)
|
|
{
|
|
}
|
|
#endif
|
|
@@ -1780,11 +1783,11 @@ static void ioapic_ack_level(struct irq_data *irq_data)
|
|
{
|
|
struct irq_cfg *cfg = irqd_cfg(irq_data);
|
|
unsigned long v;
|
|
- bool masked;
|
|
+ bool moveit;
|
|
int i;
|
|
|
|
irq_complete_move(cfg);
|
|
- masked = ioapic_irqd_mask(irq_data);
|
|
+ moveit = ioapic_prepare_move(irq_data);
|
|
|
|
/*
|
|
* It appears there is an erratum which affects at least version 0x11
|
|
@@ -1839,7 +1842,7 @@ static void ioapic_ack_level(struct irq_data *irq_data)
|
|
eoi_ioapic_pin(cfg->vector, irq_data->chip_data);
|
|
}
|
|
|
|
- ioapic_irqd_unmask(irq_data, masked);
|
|
+ ioapic_finish_move(irq_data, moveit);
|
|
}
|
|
|
|
static void ioapic_ir_ack_level(struct irq_data *irq_data)
|
|
--
|
|
2.20.1
|
|
|