diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index f2ae60d39d66..be38989d8e73 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -368,6 +368,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq); unsigned int cpu, cl, old_cpu, old_cl; unsigned long flags; + bool enabled; /* * The GIC specifies that we can only route an interrupt to one VP(E), @@ -389,15 +390,20 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, raw_spin_lock_irqsave(&gic_lock, flags); /* - * If we're moving affinity between clusters, stop routing the - * interrupt to any VP(E) in the old cluster. + * If we're moving affinity between clusters, save the interrupt's + * mask state, stop routing it to any VP(E) in the old cluster and + * disable it there so it is no longer delivered. */ if (cl != old_cl) { if (gic_irq_lock_cluster(d)) { + enabled = read_gic_redir_mask(irq); write_gic_redir_map_vp(irq, 0); + write_gic_redir_rmask(irq); mips_cm_unlock_other(); } else { + enabled = read_gic_mask(irq); write_gic_map_vp(irq, 0); + write_gic_rmask(irq); } } @@ -409,10 +415,20 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, /* * If we're moving affinity between clusters, configure the interrupt - * trigger type in the new cluster. + * trigger type and, if it was enabled in the old cluster, enable it + * in the new one. */ - if (cl != old_cl) + if (cl != old_cl) { gic_set_type_locked(d, irqd_get_trigger_type(d)); + if (enabled) { + if (gic_irq_lock_cluster(d)) { + write_gic_redir_smask(irq); + mips_cm_unlock_other(); + } else { + write_gic_smask(irq); + } + } + } /* Route the interrupt to its new VP(E) */ if (gic_irq_lock_cluster(d)) {