irqchip/gic-v3-its: Fix GICv4.1 VPE affinity update

When updating the affinity of a VPE, the VMOVP command is currently skipped
if the two CPUs are part of the same VPE affinity.

But this is wrong, as the doorbell corresponding to this VPE is still
delivered on the 'old' CPU, which screws up the balancing. Furthermore,
offlining that 'old' CPU results in doorbell interrupts generated for this
VPE being discarded.

The harsh reality is that VMOVP cannot be elided when a set_affinity()
request occurs. It needs to be obeyed, and if an optimisation is to be
made, it is at the point where the affinity change request is made (such as
in KVM).

Drop the VMOVP elision altogether, and only use the vpe_table_mask
to try and stay within the same ITS affinity group if at all possible.

Fixes: dd3f050a216e (irqchip/gic-v4.1: Implement the v4.1 flavour of VMOVP)
Reported-by: Kunkun Jiang <jiangkunkun@huawei.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20240213101206.2137483-4-maz@kernel.org

authored by Marc Zyngier and committed by Thomas Gleixner af9acbfc 8b02da04

Changed files
+13 -9
drivers
+13 -9
drivers/irqchip/irq-gic-v3-its.c
··· 3826 3826 bool force) 3827 3827 { 3828 3828 struct its_vpe *vpe = irq_data_get_irq_chip_data(d); 3829 - int from, cpu = cpumask_first(mask_val); 3829 + struct cpumask common, *table_mask; 3830 3830 unsigned long flags; 3831 + int from, cpu; 3831 3832 3832 3833 /* 3833 3834 * Changing affinity is mega expensive, so let's be as lazy as ··· 3844 3843 * taken on any vLPI handling path that evaluates vpe->col_idx. 3845 3844 */ 3846 3845 from = vpe_to_cpuid_lock(vpe, &flags); 3846 + table_mask = gic_data_rdist_cpu(from)->vpe_table_mask; 3847 + 3848 + /* 3849 + * If we are offered another CPU in the same GICv4.1 ITS 3850 + * affinity, pick this one. Otherwise, any CPU will do. 3851 + */ 3852 + if (table_mask && cpumask_and(&common, mask_val, table_mask)) 3853 + cpu = cpumask_test_cpu(from, &common) ? from : cpumask_first(&common); 3854 + else 3855 + cpu = cpumask_first(mask_val); 3856 + 3847 3857 if (from == cpu) 3848 3858 goto out; 3849 3859 3850 3860 vpe->col_idx = cpu; 3851 - 3852 - /* 3853 - * GICv4.1 allows us to skip VMOVP if moving to a cpu whose RD 3854 - * is sharing its VPE table with the current one. 3855 - */ 3856 - if (gic_data_rdist_cpu(cpu)->vpe_table_mask && 3857 - cpumask_test_cpu(from, gic_data_rdist_cpu(cpu)->vpe_table_mask)) 3858 - goto out; 3859 3861 3860 3862 its_send_vmovp(vpe); 3861 3863 its_vpe_db_proxy_move(vpe, from, cpu);