From d9f82930a5b41f28fadb1e4838b877ae528456d3 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 21 Sep 2017 23:24:40 -0700 Subject: [PATCH] irqchip/mips-gic: Use effective affinity to unmask Commit 7778c4b27cbe ("irqchip: mips-gic: Use pcpu_masks to avoid reading GIC_SH_MASK*") adjusted the way we handle masking interrupts to set & clear the interrupt's bit in each pcpu_mask. This allows us to avoid needing to read the GIC mask registers and perform a bitwise and of their values with the pending & pcpu_masks. Unfortunately this didn't quite work for IPIs, which were mapped to a particular CPU/VP during initialisation but never set the affinity or effective_affinity fields of their struct irq_desc. This led to them losing their affinity when gic_unmask_irq() was called for them, and they'd all become affine to cpu0. Fix this by: 1) Setting the effective affinity of interrupts in gic_shared_irq_domain_map(), which is where we actually map an interrupt to a CPU/VP. This ensures that the effective affinity mask is always valid, not just after explicitly setting affinity. 2) Using an interrupt's effective affinity when unmasking it, which prevents gic_unmask_irq() from unintentionally changing which pcpu_mask includes an interrupt. Fixes: 7778c4b27cbe ("irqchip: mips-gic: Use pcpu_masks to avoid reading GIC_SH_MASK*") Signed-off-by: Paul Burton Signed-off-by: Thomas Gleixner Cc: Marc Zyngier Cc: Jason Cooper Link: https://lkml.kernel.org/r/20170922062440.23701-3-paul.burton@imgtec.com --- drivers/irqchip/irq-mips-gic.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 0022b31ad2c5..c90976d7e53c 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -175,14 +175,13 @@ static void gic_mask_irq(struct irq_data *d) static void gic_unmask_irq(struct irq_data *d) { - struct cpumask *affinity = irq_data_get_affinity_mask(d); unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq); unsigned int cpu; write_gic_smask(intr); gic_clear_pcpu_masks(intr); - cpu = cpumask_first_and(affinity, cpu_online_mask); + cpu = cpumask_first(irq_data_get_effective_affinity_mask(d)); set_bit(intr, per_cpu_ptr(pcpu_masks, cpu)); } @@ -420,13 +419,17 @@ static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw, unsigned int cpu) { int intr = GIC_HWIRQ_TO_SHARED(hw); + struct irq_data *data; unsigned long flags; + data = irq_get_irq_data(virq); + spin_lock_irqsave(&gic_lock, flags); write_gic_map_pin(intr, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin); write_gic_map_vp(intr, BIT(mips_cm_vp_id(cpu))); gic_clear_pcpu_masks(intr); set_bit(intr, per_cpu_ptr(pcpu_masks, cpu)); + irq_data_update_effective_affinity(data, cpumask_of(cpu)); spin_unlock_irqrestore(&gic_lock, flags); return 0;