From 68dda501d9889ae93008e43d9d558ad9e730fa42 Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Fri, 24 Oct 2025 09:22:08 +0200 Subject: [PATCH] x86/irq: set accurate cpu_mask for high priority vectors used by external interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting the irq descriptor target CPU mask of high priority interrupts to contain all online CPUs is not accurate. External interrupts are exclusively delivered using physical destination mode, and hence can only target a single CPU. Setting the descriptor CPU mask to contain all online CPUs makes it impossible for Xen to figure out which CPU the interrupt is really targeting. Instead handle high priority vectors used by external interrupts similarly to normal vectors, keeping the target CPU mask accurate. Introduce specific code in _assign_irq_vector() to deal with moving high priority vectors across CPUs, this is needed at least for fixup_irqs() to be able to evacuate those if the target CPU goes offline. Fixes: fc0c3fa2ad5c ("x86/IO-APIC: fix setup of Xen internally used IRQs (take 2)") Signed-off-by: Roger Pau Monné Reviewed-by: Jan Beulich --- xen/arch/x86/irq.c | 30 ++++++++++++++++++++++++------ xen/arch/x86/smpboot.c | 3 ++- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index fd34cd4cbe..92b8604dc8 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -547,6 +547,20 @@ static int _assign_irq_vector(struct irq_desc *desc, const cpumask_t *mask) cpumask_t tmp_mask; cpumask_and(&tmp_mask, mask, &cpu_online_map); + + /* + * High priority vectors are reserved on all CPUs, hence moving them + * just requires changing the target CPU. There's no need for vector + * allocation on the destination. + */ + if ( old_vector >= FIRST_HIPRIORITY_VECTOR && + old_vector <= LAST_HIPRIORITY_VECTOR ) + { + cpumask_copy(desc->arch.cpu_mask, + cpumask_of(cpumask_any(&tmp_mask))); + return 0; + } + if (cpumask_intersects(&tmp_mask, desc->arch.cpu_mask)) { desc->arch.vector = old_vector; return 0; @@ -756,12 +770,16 @@ void setup_vector_irq(unsigned int cpu) if ( !irq_desc_initialized(desc) ) continue; vector = irq_to_vector(irq); - if ( vector >= FIRST_HIPRIORITY_VECTOR && - vector <= LAST_HIPRIORITY_VECTOR ) - cpumask_set_cpu(cpu, desc->arch.cpu_mask); - else if ( !cpumask_test_cpu(cpu, desc->arch.cpu_mask) ) - continue; - per_cpu(vector_irq, cpu)[vector] = irq; + if ( cpumask_test_cpu(cpu, desc->arch.cpu_mask) || + /* + * High-priority vectors are reserved on all CPUs. Set + * the vector to IRQ assignment on all CPUs, even if the + * interrupt is not targeting this CPU. That makes + * shuffling those interrupts around CPUs easier. + */ + (vector >= FIRST_HIPRIORITY_VECTOR && + vector <= LAST_HIPRIORITY_VECTOR) ) + per_cpu(vector_irq, cpu)[vector] = irq; } } diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index 7fab555233..69cc9bbc6e 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -1464,7 +1464,8 @@ void __init smp_intr_init(void) desc = irq_to_desc(irq); desc->arch.vector = vector; - cpumask_copy(desc->arch.cpu_mask, &cpu_online_map); + cpumask_copy(desc->arch.cpu_mask, cpumask_of(cpu)); + cpumask_setall(desc->affinity); } /* Direct IPI vectors. */