[PATCH v2 06/14] irqchip/riscv-imsic: Compose MSI updates through the hierarchy

From: Andrew Jones

Date: Fri Jul 24 2026 - 11:31:38 EST


imsic_irq_set_affinity() wrote the new IMSIC target straight to the
device via imsic_msi_update_msg(), bypassing the irqdomain hierarchy.
That skips any intermediate IOMMU irqdomain sitting between IMSIC and
the device, so a remapped device would keep the pre-remap physical
address after every affinity change.

Compose MSI updates via irq_chip_compose_msi_msg() starting from the
top of the hierarchy instead, so an intermediate remap domain gets to
translate the target before the device is written.

For the temporary vector used by non-atomic affinity updates, compose
the current vector through the hierarchy before d->chip_data is switched
to the new vector, then replace only msg.data with the new local ID.
This preserves the required old-address/new-data temporary target while
also allowing an intermediate remap domain to refresh or clear any MSI
IOVA state cached on the device's MSI descriptor.

Moving the final write to after d->chip_data = new_vec is required
because irq_chip_compose_msi_msg() reads d->chip_data. Keep it before
updating effective affinity and migrating vector state so the device is
retargeted before the old vector is disabled.

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