[PATCH v4 10/21] iommu/riscv: Prepare info->domain for concurrent RCU read access
Andrew Jones <[email protected]>
| Newsgroups | org.infradead.lists.linux-riscv,dev.linux.lists.iommu,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- 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 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv