[PATCH v5 13/27] iommu/arm-smmu-v3: Make smmu_domain->devices into an allocated list

Michael Shavit mshavit at google.com
Tue Mar 19 06:09:03 PDT 2024


On Tue, Mar 5, 2024 at 7:44 AM Jason Gunthorpe <jgg at 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 at nvidia.com>
> Signed-off-by: Jason Gunthorpe <jgg at 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 at google.com>



More information about the linux-arm-kernel mailing list