[PATCH v3 12/19] iommu/riscv: Gate identity boundary switches with live MSIs

Andrew Jones <[email protected]>
Newsgroups dev.linux.lists.iommu,org.infradead.lists.linux-riscv,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Reject identity-boundary domain transitions while a device still has
allocated MSIs.

The RISC-V IOMMU MSI compose path can run concurrently with domain
attach and derives the MSI address rewrite policy from info->domain.
Across an identity boundary, a stale decision can turn into a wrong
addressing mode (IOVA vs PA), so require nr_msis == 0 when crossing
between paging and identity domains.

This is just a defensive guard since MSI state should be quiesced
before crossing the identity boundary anyway.

Do not gate paging <-> blocking: blocking is the fail-stop mode and
must become available immediately, even with live MSIs.

Do not gate paging -> paging: that path already uses nr_msis to
ensure new-domain MSI table readiness before install.

Signed-off-by: Andrew Jones <[email protected]>
---
 drivers/iommu/riscv/iommu.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index 07287c0e72e7..f40db2cda417 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -1272,10 +1272,14 @@ static int riscv_iommu_attach_paging_domain(struct iommu_domain *iommu_domain,
 	struct riscv_iommu_domain *domain = iommu_domain_to_riscv(iommu_domain);
 	struct riscv_iommu_device *iommu = dev_to_iommu(dev);
 	struct riscv_iommu_info *info = dev_iommu_priv_get(dev);
+	bool old_identity = old && old->type == IOMMU_DOMAIN_IDENTITY;
 	struct pt_iommu_riscv_64_hw_info pt_info;
 	u64 fsc, ta;
 	int ret;
 
+	if (old_identity && info->nr_msis)
+		return -EBUSY;
+
 	pt_iommu_riscv_64_hw_info(&domain->riscvpt, &pt_info);
 
 	if (!riscv_iommu_pt_supported(iommu, pt_info.fsc_iosatp_mode))
@@ -1394,6 +1398,10 @@ static int riscv_iommu_attach_identity_domain(struct iommu_domain *iommu_domain,
 {
 	struct riscv_iommu_device *iommu = dev_to_iommu(dev);
 	struct riscv_iommu_info *info = dev_iommu_priv_get(dev);
+	bool old_paging = old && (old->type & __IOMMU_DOMAIN_PAGING);
+
+	if (old_paging && info->nr_msis)
+		return -EBUSY;
 
 	riscv_iommu_iodir_update(iommu, dev, RISCV_IOMMU_FSC_BARE, RISCV_IOMMU_PC_TA_V);
 	riscv_iommu_bond_unlink(rcu_access_pointer(info->domain), dev);
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.