IRQ migrations did not work. Writing a new IRQ SMP affinity into
/proc/irq/<irq>/smp_affinity had no effect.

It turned out that the pending migration was never handled. With
commit d4637fc8663b ("x86/ipipe: fix chained irq handling") do_IRQ() is
bypassed because it is not able to deal with chained IRQs and
generic_handle_irq_desc() is directly called instead.

The bypass forgot to take care about pending IRQ migrations. As
do_IRQ() is no longer used when ipipe is enabled, we can restore it to
the Linux version and move the call of __ipipe_move_root_irq() to
__ipipe_do_IRQ(). With that change applied the first part of the IRQ
migration is working again. IRQs arrive at the new target CPU.

The second part of the IRQ migration (cleanup of the old vector at the
previous target CPU) was broken because __ipipe_do_IRQ() injects the
registers from the last timer tick, so apicd->vector is always -1.
Removing the vector == apicd->vector check allows triggering the
cleanup IPI. This part is now synchronized with Linux >= 5.8.

Fixes: d4637fc8663b ("x86/ipipe: fix chained irq handling")

Signed-off-by: Florian Bezdeka <florian.bezd...@siemens.com>
---
 arch/x86/kernel/apic/vector.c |  8 +++++++-
 arch/x86/kernel/irq.c         |  3 +--
 arch/x86/kernel/irq_64.c      | 10 +++++-----
 3 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index a744b78eaa94..32889c2ef4a1 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -949,7 +949,13 @@ static void __irq_complete_move(struct irq_cfg *cfg, 
unsigned vector)
        if (likely(!apicd->move_in_progress))
                return;
 
-       if (vector == apicd->vector && apicd->cpu == smp_processor_id())
+       /*
+        * If the interrupt arrived on the new target CPU, cleanup the
+        * vector on the old target CPU. A vector check is not required
+        * because an interrupt can never move from one vector to another
+        * on the same CPU.
+        */
+       if (apicd->cpu == smp_processor_id())
                __send_cleanup_vector(apicd);
 }
 
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index f946bc4387e4..7077388e4f1c 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -237,13 +237,12 @@ __visible unsigned int __irq_entry do_IRQ(struct pt_regs 
*regs)
        /* high bit used in ret_from_ code  */
        unsigned vector = ~regs->orig_ax;
 
-       desc = __this_cpu_read(vector_irq[vector]);
-       __ipipe_move_root_irq(desc);
        entering_irq();
 
        /* entering_irq() tells RCU that we're not quiescent.  Check it. */
        RCU_LOCKDEP_WARN(!rcu_is_watching(), "IRQ failed to wake up RCU");
 
+       desc = __this_cpu_read(vector_irq[vector]);
        if (likely(!IS_ERR_OR_NULL(desc))) {
                if (IS_ENABLED(CONFIG_X86_32))
                        handle_irq(desc, regs);
diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c
index b998d982cb4a..16ea3c5aed6d 100644
--- a/arch/x86/kernel/irq_64.c
+++ b/arch/x86/kernel/irq_64.c
@@ -76,20 +76,20 @@ int irq_init_percpu_irqstack(unsigned int cpu)
 void __ipipe_do_IRQ(unsigned int irq, void *cookie)
 {
        struct pt_regs *regs = raw_cpu_ptr(&ipipe_percpu.tick_regs);
+       struct irq_desc *desc = irq_to_desc(irq);
        struct pt_regs *old_regs = set_irq_regs(regs);
        unsigned int (*handler)(struct pt_regs *regs);
-       struct irq_desc *desc;
 
        handler = (typeof(handler))cookie;
 
+       __ipipe_move_root_irq(desc);
+
        entering_irq();
 
-       if (handler == do_IRQ) {
-               desc = irq_to_desc(irq);
+       if (handler == do_IRQ)
                generic_handle_irq_desc(desc);
-       } else {
+       else
                handler(regs);
-       }
 
        exiting_irq();
 
-- 
2.30.2


Reply via email to