Hi Yi,

On Sun, 20 Dec 2020 08:03:51 +0800, Liu Yi L <yi.l....@intel.com> wrote:

> In existing code, if wanting to loop all devices attached to a domain,
> current code can only loop the devices which are attached to the domain
> via normal manner. While for devices attached via auxiliary manner, this
> is subdevice, they are not tracked in the domain. This patch adds struct
How about "In the existing code, loop all devices attached to a domain does
not include sub-devices attached via iommu_aux_attach_device()."

> subdevice_domain_info which is created per domain attachment via auxiliary
> manner. So that such devices are also tracked in domain.
> 
> This was found by when I'm working on the belwo patch, There is no device
> in domain->devices, thus unable to get the cap and ecap of iommu unit. But
> this domain actually has one sub-device which is attached via aux-manner.
> This patch fixes the issue.
> 
> https://lore.kernel.org/kvm/1599734733-6431-17-git-send-email-yi.l....@intel.com/
> 
> But looks like, it doesn't affect me only. Such auxiliary track should be
> there for example if wanting to flush device_iotlb for a domain which has
> devices attached by auxiliray manner, then this fix is also necessary.
Perhaps:
This fix goes beyond the patch above, such sub-device tracking is
necessary for other cases. For example, flushing device_iotlb for a domain
which has sub-devices attached by auxiliary manner.

> This issue will also be fixed by another patch in this series with some
> additional changes based on the sudevice tracking framework introduced in
> this patch.
> 
> Co-developed-by: Xin Zeng <xin.z...@intel.com>
> Signed-off-by: Xin Zeng <xin.z...@intel.com>
> Co-developed-by: Liu Yi L <yi.l....@intel.com>
> Signed-off-by: Liu Yi L <yi.l....@intel.com>
> Co-developed-by: Lu Baolu <baolu...@linux.intel.com>
> Signed-off-by: Lu Baolu <baolu...@linux.intel.com>
> ---
>  drivers/iommu/intel/iommu.c | 92 ++++++++++++++++++++++++++++++++-----
>  include/linux/intel-iommu.h | 11 ++++-
>  2 files changed, 90 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index a49afa11673c..4274b4acc325 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -1881,6 +1881,7 @@ static struct dmar_domain *alloc_domain(int flags)
>               domain->flags |= DOMAIN_FLAG_USE_FIRST_LEVEL;
>       domain->has_iotlb_device = false;
>       INIT_LIST_HEAD(&domain->devices);
> +     INIT_LIST_HEAD(&domain->sub_devices);
>  
>       return domain;
>  }
> @@ -5172,33 +5173,79 @@ is_aux_domain(struct device *dev, struct
> iommu_domain *domain) domain->type == IOMMU_DOMAIN_UNMANAGED;
>  }
>  
> +static inline
> +void _auxiliary_link_device(struct dmar_domain *domain,
> +                         struct subdevice_domain_info *subinfo,
> +                         struct device *dev)
> +{
> +     subinfo->users++;
> +}
> +
why pass in more arguments than subinfo? the function name does not match
what it does, seems just refcount inc.

> +static inline
> +int _auxiliary_unlink_device(struct dmar_domain *domain,
> +                          struct subdevice_domain_info *subinfo,
> +                          struct device *dev)
> +{
> +     subinfo->users--;
> +     return subinfo->users;
ditto. why not just
        return subinfo->users--;

> +}
> +
>  static void auxiliary_link_device(struct dmar_domain *domain,
>                                 struct device *dev)
>  {
>       struct device_domain_info *info = get_domain_info(dev);
> +     struct subdevice_domain_info *subinfo;
>  
>       assert_spin_locked(&device_domain_lock);
>       if (WARN_ON(!info))
>               return;
>  
> +     subinfo = kzalloc(sizeof(*subinfo), GFP_ATOMIC);
> +     if (!subinfo)
> +             return;
> +
> +     subinfo->domain = domain;
> +     subinfo->dev = dev;
> +     list_add(&subinfo->link_domain, &info->auxiliary_domains);
> +     list_add(&subinfo->link_phys, &domain->sub_devices);
> +     _auxiliary_link_device(domain, subinfo, dev);
or just opencode subinfo->users++?
>       domain->auxd_refcnt++;
> -     list_add(&domain->auxd, &info->auxiliary_domains);
>  }
>  
> -static void auxiliary_unlink_device(struct dmar_domain *domain,
> -                                 struct device *dev)
> +static struct subdevice_domain_info *
> +subdevice_domain_info_lookup(struct dmar_domain *domain, struct device
> *dev) +{
> +     struct subdevice_domain_info *subinfo;
> +
> +     assert_spin_locked(&device_domain_lock);
> +
> +     list_for_each_entry(subinfo, &domain->sub_devices, link_phys)
> +             if (subinfo->dev == dev)
> +                     return subinfo;
> +
> +     return NULL;
> +}
> +
> +static int auxiliary_unlink_device(struct dmar_domain *domain,
> +                                struct subdevice_domain_info *subinfo,
> +                                struct device *dev)
>  {
>       struct device_domain_info *info = get_domain_info(dev);
> +     int ret;
>  
>       assert_spin_locked(&device_domain_lock);
>       if (WARN_ON(!info))
> -             return;
> +             return -EINVAL;
>  
> -     list_del(&domain->auxd);
> +     ret = _auxiliary_unlink_device(domain, subinfo, dev);
> +     if (ret == 0) {
> +             list_del(&subinfo->link_domain);
> +             list_del(&subinfo->link_phys);
> +             kfree(subinfo);
> +     }
>       domain->auxd_refcnt--;
>  
> -     if (!domain->auxd_refcnt && domain->default_pasid > 0)
> -             ioasid_free(domain->default_pasid);
> +     return ret;
>  }
>  
>  static int aux_domain_add_dev(struct dmar_domain *domain,
> @@ -5207,6 +5254,8 @@ static int aux_domain_add_dev(struct dmar_domain
> *domain, int ret;
>       unsigned long flags;
>       struct intel_iommu *iommu;
> +     struct device_domain_info *info = get_domain_info(dev);
> +     struct subdevice_domain_info *subinfo;
>  
>       iommu = device_to_iommu(dev, NULL, NULL);
>       if (!iommu)
> @@ -5227,6 +5276,12 @@ static int aux_domain_add_dev(struct dmar_domain
> *domain, }
>  
>       spin_lock_irqsave(&device_domain_lock, flags);
> +     subinfo = subdevice_domain_info_lookup(domain, dev);
> +     if (subinfo) {
> +             _auxiliary_link_device(domain, subinfo, dev);
> +             spin_unlock_irqrestore(&device_domain_lock, flags);
> +             return 0;
> +     }
>       /*
>        * iommu->lock must be held to attach domain to iommu and setup
> the
>        * pasid entry for second level translation.
> @@ -5270,6 +5325,7 @@ static void aux_domain_remove_dev(struct
> dmar_domain *domain, struct device_domain_info *info;
>       struct intel_iommu *iommu;
>       unsigned long flags;
> +     struct subdevice_domain_info *subinfo;
>  
>       if (!is_aux_domain(dev, &domain->domain))
>               return;
> @@ -5278,14 +5334,26 @@ static void aux_domain_remove_dev(struct
> dmar_domain *domain, info = get_domain_info(dev);
>       iommu = info->iommu;
>  
> -     auxiliary_unlink_device(domain, dev);
> +     subinfo = subdevice_domain_info_lookup(domain, dev);
> +     if (!subinfo) {
> +             spin_unlock_irqrestore(&device_domain_lock, flags);
> +             return;
> +     }
>  
> -     spin_lock(&iommu->lock);
> -     intel_pasid_tear_down_entry(iommu, dev, domain->default_pasid,
> false);
> -     domain_detach_iommu(domain, iommu);
> -     spin_unlock(&iommu->lock);
> +     if (auxiliary_unlink_device(domain, subinfo, dev) == 0) {
> +             spin_lock(&iommu->lock);
> +             intel_pasid_tear_down_entry(iommu,
> +                                         dev,
> +                                         domain->default_pasid,
> +                                         false);
> +             domain_detach_iommu(domain, iommu);
> +             spin_unlock(&iommu->lock);
> +     }
>  
>       spin_unlock_irqrestore(&device_domain_lock, flags);
> +
> +     if (!domain->auxd_refcnt && domain->default_pasid > 0)
> +             ioasid_free(domain->default_pasid);
>  }
>  
>  static int prepare_domain_attach_device(struct iommu_domain *domain,
> diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
> index 94522685a0d9..1fb3d6ab719a 100644
> --- a/include/linux/intel-iommu.h
> +++ b/include/linux/intel-iommu.h
> @@ -537,7 +537,7 @@ struct dmar_domain {
>  
>       bool has_iotlb_device;
>       struct list_head devices;       /* all devices' list */
> -     struct list_head auxd;          /* link to device's
> auxiliary list */
> +     struct list_head sub_devices;   /* all devices' list
> attached via aux-attach */ struct iova_domain iovad;  /* iova's
> that belong to this domain */ 
>       struct dma_pte  *pgd;           /* virtual address */
> @@ -636,6 +636,15 @@ struct device_domain_info {
>       struct pasid_table *pasid_table; /* pasid table */
>  };
>  
> +/* Aux attach device domain info */
> +struct subdevice_domain_info {
> +     struct device *dev;
> +     struct dmar_domain *domain;
> +     struct list_head link_phys;     /* link to phys device
> siblings */
> +     struct list_head link_domain;   /* link to domain siblings
> */
> +     int users;
> +};
> +
>  static inline void __iommu_flush_cache(
>       struct intel_iommu *iommu, void *addr, int size)
>  {


Thanks,

Jacob
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to