| From: Thomas Gleixner <tglx@linutronix.de> |
| Date: Tue, 17 Jul 2018 18:25:31 +0200 |
| Subject: [PATCH] x86/ioapic: Don't let setaffinity unmask threaded EOI |
| interrupt too early |
| |
| 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 71e912d73c3d..75cff68944e6 100644 |
| --- a/arch/x86/kernel/apic/io_apic.c |
| +++ b/arch/x86/kernel/apic/io_apic.c |
| @@ -1729,19 +1729,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 |
| @@ -1770,15 +1771,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 |
| @@ -1787,11 +1790,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 |
| @@ -1846,7 +1849,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.18.0 |
| |