[PATCH v2 3/5] irqchip/mips-gic: Enable interrupt when moving affinity across clusters
Benoît Monin <[email protected]>
| Newsgroups | org.kernel.vger.linux-mips,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
When an interrupt's affinity is moved to a CPU in another cluster,
gic_set_affinity() updates the routing (GIC_SH_MAP_VP) and trigger type
in the destination cluster, but never touched the interrupt's mask state.
The interrupt mask is per-cluster. After such a move the interrupt was
left disabled in the destination cluster, so it never fires despite
being correctly routed to its new VP.
Handle the mask explicitly on a cross-cluster affinity change: in the
old cluster, write GIC_SH_RMASK to disable the interrupt while clearing
the route so it is no longer delivered. And in the new cluster, set the
mask to enable the interrupt along with reconfiguring the trigger type.
Fixes: 322a90638768 ("irqchip/mips-gic: Multi-cluster support")
Signed-off-by: Benoît Monin <[email protected]>
---
drivers/irqchip/irq-mips-gic.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index f2ae60d39d66..4b76a65f12c9 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -390,14 +390,17 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
/*
* If we're moving affinity between clusters, stop routing the
- * interrupt to any VP(E) in the old cluster.
+ * interrupt to any VP(E) in the old cluster and disable
+ * the interrupt in that cluster.
*/
if (cl != old_cl) {
if (gic_irq_lock_cluster(d)) {
write_gic_redir_map_vp(irq, 0);
+ write_gic_redir_rmask(irq);
mips_cm_unlock_other();
} else {
write_gic_map_vp(irq, 0);
+ write_gic_rmask(irq);
}
}
@@ -409,10 +412,17 @@ 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 enable the interrupt in the new cluster.
*/
- if (cl != old_cl)
+ if (cl != old_cl) {
gic_set_type_locked(d, irqd_get_trigger_type(d));
+ 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)) {
--
2.55.0