[PATCH v4 10/21] iommu/riscv: Prepare info->domain for concurrent RCU read access

From: Andrew Jones

Date: Thu Aug 20 2026 - 17:49:22 EST


An upcoming compose_msi_msg() implementation reads info->domain from
potentially atomic context, concurrent with domain switches. Apply
RCU in preparation.

Signed-off-by: Andrew Jones <andrew.jones@xxxxxxxxxxxxxxxx>
---
drivers/iommu/riscv/iommu.c | 26 ++++++++++++++++----------
drivers/iommu/riscv/iommu.h | 3 ++-
2 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index bfe606a0cb9a..4e14c8412abc 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -865,17 +865,21 @@ static int riscv_iommu_bond_link(struct riscv_iommu_domain *domain,
return 0;
}

-static void riscv_iommu_bond_unlink(struct riscv_iommu_domain *domain,
+static void riscv_iommu_bond_unlink(struct iommu_domain *iommu_domain,
struct device *dev)
{
- struct riscv_iommu_device *iommu = dev_to_iommu(dev);
+ struct riscv_iommu_domain *domain;
+ struct riscv_iommu_device *iommu;
struct riscv_iommu_bond *bond, *found = NULL;
struct riscv_iommu_command cmd;
int count = 0;

- if (!domain)
+ if (!iommu_domain || !(iommu_domain->type & __IOMMU_DOMAIN_PAGING))
return;

+ domain = iommu_domain_to_riscv(iommu_domain);
+ iommu = dev_to_iommu(dev);
+
spin_lock(&domain->lock);
list_for_each_entry(bond, &domain->bonds, list) {
if (found && count)
@@ -1241,6 +1245,8 @@ static void riscv_iommu_free_paging_domain(struct iommu_domain *iommu_domain)

WARN_ON(!list_empty(&domain->bonds));

+ synchronize_rcu();
+
riscv_iommu_ir_free_paging_domain(iommu_domain);

if ((int)domain->pscid > 0)
@@ -1291,13 +1297,13 @@ static int riscv_iommu_attach_paging_domain(struct iommu_domain *iommu_domain,

ret = riscv_iommu_ir_attach_paging_domain(iommu_domain, dev, old);
if (ret) {
- riscv_iommu_bond_unlink(domain, dev);
+ riscv_iommu_bond_unlink(iommu_domain, dev);
return ret;
}

riscv_iommu_iodir_update(iommu, dev, fsc, ta);
- riscv_iommu_bond_unlink(info->domain, dev);
- info->domain = domain;
+ riscv_iommu_bond_unlink(old, dev);
+ rcu_assign_pointer(info->domain, domain);

return 0;
}
@@ -1373,8 +1379,8 @@ static int riscv_iommu_attach_blocking_domain(struct iommu_domain *iommu_domain,

/* Make device context invalid, translation requests will fault w/ #258 */
riscv_iommu_iodir_update(iommu, dev, RISCV_IOMMU_FSC_BARE, 0);
- riscv_iommu_bond_unlink(info->domain, dev);
- info->domain = NULL;
+ riscv_iommu_bond_unlink(old, dev);
+ rcu_assign_pointer(info->domain, NULL);

return 0;
}
@@ -1394,8 +1400,8 @@ static int riscv_iommu_attach_identity_domain(struct iommu_domain *iommu_domain,
struct riscv_iommu_info *info = dev_iommu_priv_get(dev);

riscv_iommu_iodir_update(iommu, dev, RISCV_IOMMU_FSC_BARE, RISCV_IOMMU_PC_TA_V);
- riscv_iommu_bond_unlink(info->domain, dev);
- info->domain = NULL;
+ riscv_iommu_bond_unlink(old, dev);
+ rcu_assign_pointer(info->domain, NULL);

return 0;
}
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 5d83537911b6..ded18aec8010 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -15,6 +15,7 @@
#include <linux/types.h>
#include <linux/iopoll.h>
#include <linux/irqdomain.h>
+#include <linux/rcupdate.h>
#include <linux/generic_pt/iommu.h>

#include "iommu-bits.h"
@@ -33,7 +34,7 @@ PT_IOMMU_CHECK_DOMAIN(struct riscv_iommu_domain, riscvpt.iommu, domain);

/* Private IOMMU data for managed devices, dev_iommu_priv_* */
struct riscv_iommu_info {
- struct riscv_iommu_domain *domain;
+ struct riscv_iommu_domain __rcu *domain;
struct irq_domain *irqdomain;
};

--
2.43.0