[PATCH v4 07/21] irqchip/riscv-imsic: Compose MSI updates through the hierarchy
From: Andrew Jones
Date: Thu Aug 20 2026 - 17:42:57 EST
imsic_irq_set_affinity() currently writes a newly composed MSI message
directly to the device. This bypasses intermediate irqdomains, so an
IOMMU remapping domain cannot translate the target after an affinity
change.
Compose affinity updates from the top of the hierarchy instead. This
allows each intermediate domain to update the message and any descriptor
state before the device is programmed.
Non-atomic moves temporarily use the old address with the new interrupt
ID before switching to the new vector. Preserve that transition by
composing the temporary message before publishing the new vector, then
compose the final message after publishing it, but before the old vector
is retired.
Signed-off-by: Andrew Jones <andrew.jones@xxxxxxxxxxxxxxxx>
---
drivers/irqchip/irq-riscv-imsic-platform.c | 27 ++++++++--------------
1 file changed, 10 insertions(+), 17 deletions(-)
diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c
index 643c8e459611..5634641dc223 100644
--- a/drivers/irqchip/irq-riscv-imsic-platform.c
+++ b/drivers/irqchip/irq-riscv-imsic-platform.c
@@ -90,19 +90,12 @@ static void imsic_irq_compose_msg(struct irq_data *d, struct msi_msg *msg)
}
#ifdef CONFIG_SMP
-static void imsic_msi_update_msg(struct irq_data *d, struct imsic_vector *vec)
-{
- struct msi_msg msg = { };
-
- imsic_irq_compose_vector_msg(vec, &msg);
- irq_data_get_irq_chip(d)->irq_write_msi_msg(d, &msg);
-}
-
static int imsic_irq_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
bool force)
{
+ struct irq_data *top = irq_get_irq_data(d->irq);
struct imsic_vector *old_vec, *new_vec;
- struct imsic_vector tmp_vec;
+ struct msi_msg msg = { };
/*
* Requirements for the downstream irqdomains (or devices):
@@ -153,20 +146,20 @@ static int imsic_irq_set_affinity(struct irq_data *d, const struct cpumask *mask
*/
if (!irq_can_move_in_process_context(d) &&
new_vec->local_id != old_vec->local_id) {
- /* Setup temporary vector */
- tmp_vec.cpu = old_vec->cpu;
- tmp_vec.local_id = new_vec->local_id;
-
/* Point device to the temporary vector */
- imsic_msi_update_msg(irq_get_irq_data(d->irq), &tmp_vec);
+ BUG_ON(irq_chip_compose_msi_msg(top, &msg));
+ msg.data = new_vec->local_id;
+ irq_data_get_irq_chip(top)->irq_write_msi_msg(top, &msg);
}
- /* Point device to the new vector */
- imsic_msi_update_msg(irq_get_irq_data(d->irq), new_vec);
-
/* Update irq descriptors with the new vector */
d->chip_data = new_vec;
+ /* Point device to the new vector */
+ memset(&msg, 0, sizeof(msg));
+ BUG_ON(irq_chip_compose_msi_msg(top, &msg));
+ irq_data_get_irq_chip(top)->irq_write_msi_msg(top, &msg);
+
/* Update effective affinity */
irq_data_update_effective_affinity(d, cpumask_of(new_vec->cpu));
--
2.43.0