[PATCH v2 06/14] irqchip/riscv-imsic: Compose MSI updates through the hierarchy
Andrew Jones <[email protected]> Fri, 24 Jul 2026 17:12:10 +0200
| Newsgroups | dev.linux.lists.iommu,org.infradead.lists.linux-riscv,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- 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