Message ID | 13-v5-9a37e0c884ce+31e3-smmuv3_newapi_p2_jgg@nvidia.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Update SMMUv3 to the modern iommu API (part 2/3) | expand |
On Tue, Mar 5, 2024 at 7:44 AM Jason Gunthorpe <jgg@nvidia.com> wrote: > > The next patch will need to store the same master twice (with different > SSIDs), so allocate memory for each list element. > > Tested-by: Nicolin Chen <nicolinc@nvidia.com> > Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> > --- > .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 11 ++++-- > drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 39 ++++++++++++++++--- > drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 7 +++- > 3 files changed, 47 insertions(+), 10 deletions(-) > > diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c > index e1fa2074c0b37b..9a285b828e8b12 100644 > --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c > +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c > @@ -38,12 +38,13 @@ static DEFINE_MUTEX(sva_lock); > static void > arm_smmu_update_s1_domain_cd_entry(struct arm_smmu_domain *smmu_domain) > { > - struct arm_smmu_master *master; > + struct arm_smmu_master_domain *master_domain; > struct arm_smmu_cd target_cd; > unsigned long flags; > > spin_lock_irqsave(&smmu_domain->devices_lock, flags); > - list_for_each_entry(master, &smmu_domain->devices, domain_head) { > + list_for_each_entry(master_domain, &smmu_domain->devices, devices_elm) { > + struct arm_smmu_master *master = master_domain->master; > struct arm_smmu_cd *cdptr; > > /* S1 domains only support RID attachment right now */ > @@ -300,7 +301,7 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm) > { > struct arm_smmu_mmu_notifier *smmu_mn = mn_to_smmu(mn); > struct arm_smmu_domain *smmu_domain = smmu_mn->domain; > - struct arm_smmu_master *master; > + struct arm_smmu_master_domain *master_domain; > unsigned long flags; > > mutex_lock(&sva_lock); > @@ -314,7 +315,9 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm) > * but disable translation. > */ > spin_lock_irqsave(&smmu_domain->devices_lock, flags); > - list_for_each_entry(master, &smmu_domain->devices, domain_head) { > + list_for_each_entry(master_domain, &smmu_domain->devices, > + devices_elm) { > + struct arm_smmu_master *master = master_domain->master; > struct arm_smmu_cd target; > struct arm_smmu_cd *cdptr; > > diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c > index 7a0be7dd719793..51a1e7198fd1af 100644 > --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c > +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c > @@ -2031,10 +2031,10 @@ static int arm_smmu_atc_inv_master(struct arm_smmu_master *master) > int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain, int ssid, > unsigned long iova, size_t size) > { > + struct arm_smmu_master_domain *master_domain; > int i; > unsigned long flags; > struct arm_smmu_cmdq_ent cmd; > - struct arm_smmu_master *master; > struct arm_smmu_cmdq_batch cmds; > > if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_ATS)) > @@ -2062,7 +2062,10 @@ int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain, int ssid, > cmds.num = 0; > > spin_lock_irqsave(&smmu_domain->devices_lock, flags); > - list_for_each_entry(master, &smmu_domain->devices, domain_head) { > + list_for_each_entry(master_domain, &smmu_domain->devices, > + devices_elm) { > + struct arm_smmu_master *master = master_domain->master; > + > if (!master->ats_enabled) > continue; > > @@ -2554,9 +2557,26 @@ static void arm_smmu_disable_pasid(struct arm_smmu_master *master) > pci_disable_pasid(pdev); > } > > +static struct arm_smmu_master_domain * > +arm_smmu_find_master_domain(struct arm_smmu_domain *smmu_domain, > + struct arm_smmu_master *master) > +{ > + struct arm_smmu_master_domain *master_domain; > + > + lockdep_assert_held(&smmu_domain->devices_lock); > + > + list_for_each_entry(master_domain, &smmu_domain->devices, > + devices_elm) { > + if (master_domain->master == master) > + return master_domain; > + } > + return NULL; > +} > + > static void arm_smmu_detach_dev(struct arm_smmu_master *master) > { > struct iommu_domain *domain = iommu_get_domain_for_dev(master->dev); > + struct arm_smmu_master_domain *master_domain; > struct arm_smmu_domain *smmu_domain; > unsigned long flags; > > @@ -2567,7 +2587,11 @@ static void arm_smmu_detach_dev(struct arm_smmu_master *master) > arm_smmu_disable_ats(master, smmu_domain); > > spin_lock_irqsave(&smmu_domain->devices_lock, flags); > - list_del_init(&master->domain_head); > + master_domain = arm_smmu_find_master_domain(smmu_domain, master); > + if (master_domain) { > + list_del(&master_domain->devices_elm); > + kfree(master_domain); > + } > spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); > > master->ats_enabled = false; > @@ -2581,6 +2605,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) > struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); > struct arm_smmu_device *smmu; > struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); > + struct arm_smmu_master_domain *master_domain; > struct arm_smmu_master *master; > struct arm_smmu_cd *cdptr; > > @@ -2617,6 +2642,11 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) > return -ENOMEM; > } > > + master_domain = kzalloc(sizeof(*master_domain), GFP_KERNEL); > + if (!master_domain) > + return -ENOMEM; > + master_domain->master = master; > + > /* > * Prevent arm_smmu_share_asid() from trying to change the ASID > * of either the old or new domain while we are working on it. > @@ -2630,7 +2660,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) > master->ats_enabled = arm_smmu_ats_supported(master); > > spin_lock_irqsave(&smmu_domain->devices_lock, flags); > - list_add(&master->domain_head, &smmu_domain->devices); > + list_add(&master_domain->devices_elm, &smmu_domain->devices); > spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); > > switch (smmu_domain->stage) { > @@ -2949,7 +2979,6 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev) > master->dev = dev; > master->smmu = smmu; > INIT_LIST_HEAD(&master->bonds); > - INIT_LIST_HEAD(&master->domain_head); > dev_iommu_priv_set(dev, master); > > ret = arm_smmu_insert_master(smmu, master); > diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h > index ab0a6587e07ec8..c4b79bc52991be 100644 > --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h > +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h > @@ -695,7 +695,6 @@ struct arm_smmu_stream { > struct arm_smmu_master { > struct arm_smmu_device *smmu; > struct device *dev; > - struct list_head domain_head; > struct arm_smmu_stream *streams; > /* Locked by the iommu core using the group mutex */ > struct arm_smmu_ctx_desc_cfg cd_table; > @@ -729,12 +728,18 @@ struct arm_smmu_domain { > > struct iommu_domain domain; > > + /* List of struct arm_smmu_master_domain */ > struct list_head devices; > spinlock_t devices_lock; > > struct list_head mmu_notifiers; > }; > > +struct arm_smmu_master_domain { > + struct list_head devices_elm; > + struct arm_smmu_master *master; > +}; > + > static inline struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom) > { > return container_of(dom, struct arm_smmu_domain, domain); > -- > 2.43.2 > Reviewed-by: Michael Shavit <mshavit@google.com>
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c index e1fa2074c0b37b..9a285b828e8b12 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c @@ -38,12 +38,13 @@ static DEFINE_MUTEX(sva_lock); static void arm_smmu_update_s1_domain_cd_entry(struct arm_smmu_domain *smmu_domain) { - struct arm_smmu_master *master; + struct arm_smmu_master_domain *master_domain; struct arm_smmu_cd target_cd; unsigned long flags; spin_lock_irqsave(&smmu_domain->devices_lock, flags); - list_for_each_entry(master, &smmu_domain->devices, domain_head) { + list_for_each_entry(master_domain, &smmu_domain->devices, devices_elm) { + struct arm_smmu_master *master = master_domain->master; struct arm_smmu_cd *cdptr; /* S1 domains only support RID attachment right now */ @@ -300,7 +301,7 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm) { struct arm_smmu_mmu_notifier *smmu_mn = mn_to_smmu(mn); struct arm_smmu_domain *smmu_domain = smmu_mn->domain; - struct arm_smmu_master *master; + struct arm_smmu_master_domain *master_domain; unsigned long flags; mutex_lock(&sva_lock); @@ -314,7 +315,9 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm) * but disable translation. */ spin_lock_irqsave(&smmu_domain->devices_lock, flags); - list_for_each_entry(master, &smmu_domain->devices, domain_head) { + list_for_each_entry(master_domain, &smmu_domain->devices, + devices_elm) { + struct arm_smmu_master *master = master_domain->master; struct arm_smmu_cd target; struct arm_smmu_cd *cdptr; diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 7a0be7dd719793..51a1e7198fd1af 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -2031,10 +2031,10 @@ static int arm_smmu_atc_inv_master(struct arm_smmu_master *master) int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain, int ssid, unsigned long iova, size_t size) { + struct arm_smmu_master_domain *master_domain; int i; unsigned long flags; struct arm_smmu_cmdq_ent cmd; - struct arm_smmu_master *master; struct arm_smmu_cmdq_batch cmds; if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_ATS)) @@ -2062,7 +2062,10 @@ int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain, int ssid, cmds.num = 0; spin_lock_irqsave(&smmu_domain->devices_lock, flags); - list_for_each_entry(master, &smmu_domain->devices, domain_head) { + list_for_each_entry(master_domain, &smmu_domain->devices, + devices_elm) { + struct arm_smmu_master *master = master_domain->master; + if (!master->ats_enabled) continue; @@ -2554,9 +2557,26 @@ static void arm_smmu_disable_pasid(struct arm_smmu_master *master) pci_disable_pasid(pdev); } +static struct arm_smmu_master_domain * +arm_smmu_find_master_domain(struct arm_smmu_domain *smmu_domain, + struct arm_smmu_master *master) +{ + struct arm_smmu_master_domain *master_domain; + + lockdep_assert_held(&smmu_domain->devices_lock); + + list_for_each_entry(master_domain, &smmu_domain->devices, + devices_elm) { + if (master_domain->master == master) + return master_domain; + } + return NULL; +} + static void arm_smmu_detach_dev(struct arm_smmu_master *master) { struct iommu_domain *domain = iommu_get_domain_for_dev(master->dev); + struct arm_smmu_master_domain *master_domain; struct arm_smmu_domain *smmu_domain; unsigned long flags; @@ -2567,7 +2587,11 @@ static void arm_smmu_detach_dev(struct arm_smmu_master *master) arm_smmu_disable_ats(master, smmu_domain); spin_lock_irqsave(&smmu_domain->devices_lock, flags); - list_del_init(&master->domain_head); + master_domain = arm_smmu_find_master_domain(smmu_domain, master); + if (master_domain) { + list_del(&master_domain->devices_elm); + kfree(master_domain); + } spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); master->ats_enabled = false; @@ -2581,6 +2605,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); struct arm_smmu_device *smmu; struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + struct arm_smmu_master_domain *master_domain; struct arm_smmu_master *master; struct arm_smmu_cd *cdptr; @@ -2617,6 +2642,11 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) return -ENOMEM; } + master_domain = kzalloc(sizeof(*master_domain), GFP_KERNEL); + if (!master_domain) + return -ENOMEM; + master_domain->master = master; + /* * Prevent arm_smmu_share_asid() from trying to change the ASID * of either the old or new domain while we are working on it. @@ -2630,7 +2660,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) master->ats_enabled = arm_smmu_ats_supported(master); spin_lock_irqsave(&smmu_domain->devices_lock, flags); - list_add(&master->domain_head, &smmu_domain->devices); + list_add(&master_domain->devices_elm, &smmu_domain->devices); spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); switch (smmu_domain->stage) { @@ -2949,7 +2979,6 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev) master->dev = dev; master->smmu = smmu; INIT_LIST_HEAD(&master->bonds); - INIT_LIST_HEAD(&master->domain_head); dev_iommu_priv_set(dev, master); ret = arm_smmu_insert_master(smmu, master); diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h index ab0a6587e07ec8..c4b79bc52991be 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -695,7 +695,6 @@ struct arm_smmu_stream { struct arm_smmu_master { struct arm_smmu_device *smmu; struct device *dev; - struct list_head domain_head; struct arm_smmu_stream *streams; /* Locked by the iommu core using the group mutex */ struct arm_smmu_ctx_desc_cfg cd_table; @@ -729,12 +728,18 @@ struct arm_smmu_domain { struct iommu_domain domain; + /* List of struct arm_smmu_master_domain */ struct list_head devices; spinlock_t devices_lock; struct list_head mmu_notifiers; }; +struct arm_smmu_master_domain { + struct list_head devices_elm; + struct arm_smmu_master *master; +}; + static inline struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom) { return container_of(dom, struct arm_smmu_domain, domain);