Re: [PATCH v4 5/5] iommu/vt-d: Add is_aux_domain support
Hi Alex, On 9/11/20 6:05 AM, Alex Williamson wrote: On Tue, 1 Sep 2020 11:34:22 +0800 Lu Baolu wrote: With subdevice information opt-in through iommu_ops.aux_at(de)tach_dev() interfaces, the vendor iommu driver is able to learn the knowledge about the relationships between the subdevices and the aux-domains. Implement is_aux_domain() support based on the relationship knowledges. Signed-off-by: Lu Baolu --- drivers/iommu/intel/iommu.c | 125 ++-- include/linux/intel-iommu.h | 17 +++-- 2 files changed, 103 insertions(+), 39 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 3c12fd06856c..50431c7b2e71 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -334,6 +334,8 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, struct device *dev); static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova); +static bool intel_iommu_dev_feat_enabled(struct device *dev, +enum iommu_dev_features feat); #ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON int dmar_disabled = 0; @@ -1832,6 +1834,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->subdevices); return domain; } @@ -2580,7 +2583,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, info->iommu = iommu; info->pasid_table = NULL; info->auxd_enabled = 0; - INIT_LIST_HEAD(&info->auxiliary_domains); + INIT_LIST_HEAD(&info->subdevices); if (dev && dev_is_pci(dev)) { struct pci_dev *pdev = to_pci_dev(info->dev); @@ -5137,21 +5140,28 @@ static void intel_iommu_domain_free(struct iommu_domain *domain) domain_exit(to_dmar_domain(domain)); } -/* - * Check whether a @domain could be attached to the @dev through the - * aux-domain attach/detach APIs. - */ -static inline bool -is_aux_domain(struct device *dev, struct iommu_domain *domain) +/* Lookup subdev_info in the domain's subdevice siblings. */ +static struct subdev_info * +subdev_lookup_domain(struct dmar_domain *domain, struct device *dev, +struct device *subdev) { - struct device_domain_info *info = get_domain_info(dev); + struct subdev_info *sinfo = NULL, *tmp; - return info && info->auxd_enabled && - domain->type == IOMMU_DOMAIN_UNMANAGED; + assert_spin_locked(&device_domain_lock); + + list_for_each_entry(tmp, &domain->subdevices, link_domain) { + if ((!dev || tmp->pdev == dev) && tmp->dev == subdev) { + sinfo = tmp; + break; + } + } + + return sinfo; } -static void auxiliary_link_device(struct dmar_domain *domain, - struct device *dev) +static void +subdev_link_device(struct dmar_domain *domain, struct device *dev, + struct subdev_info *sinfo) { struct device_domain_info *info = get_domain_info(dev); @@ -5159,12 +5169,13 @@ static void auxiliary_link_device(struct dmar_domain *domain, if (WARN_ON(!info)) return; - domain->auxd_refcnt++; - list_add(&domain->auxd, &info->auxiliary_domains); + list_add(&info->subdevices, &sinfo->link_phys); + list_add(&domain->subdevices, &sinfo->link_domain); } -static void auxiliary_unlink_device(struct dmar_domain *domain, - struct device *dev) +static void +subdev_unlink_device(struct dmar_domain *domain, struct device *dev, +struct subdev_info *sinfo) { struct device_domain_info *info = get_domain_info(dev); @@ -5172,24 +5183,30 @@ static void auxiliary_unlink_device(struct dmar_domain *domain, if (WARN_ON(!info)) return; - list_del(&domain->auxd); - domain->auxd_refcnt--; + list_del(&sinfo->link_phys); + list_del(&sinfo->link_domain); + kfree(sinfo); - if (!domain->auxd_refcnt && domain->default_pasid > 0) + if (list_empty(&domain->subdevices) && domain->default_pasid > 0) ioasid_free(domain->default_pasid); } -static int aux_domain_add_dev(struct dmar_domain *domain, - struct device *dev) +static int aux_domain_add_dev(struct dmar_domain *domain, struct device *dev, + struct device *subdev) { int ret; unsigned long flags; struct intel_iommu *iommu; + struct subdev_info *sinfo; iommu = device_to_iommu(dev, NULL, NULL); if (!iommu) return -ENODEV; + sinfo = kzalloc(siz
Re: [PATCH v4 5/5] iommu/vt-d: Add is_aux_domain support
On Tue, 1 Sep 2020 11:34:22 +0800 Lu Baolu wrote: > With subdevice information opt-in through iommu_ops.aux_at(de)tach_dev() > interfaces, the vendor iommu driver is able to learn the knowledge about > the relationships between the subdevices and the aux-domains. Implement > is_aux_domain() support based on the relationship knowledges. > > Signed-off-by: Lu Baolu > --- > drivers/iommu/intel/iommu.c | 125 ++-- > include/linux/intel-iommu.h | 17 +++-- > 2 files changed, 103 insertions(+), 39 deletions(-) > > diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c > index 3c12fd06856c..50431c7b2e71 100644 > --- a/drivers/iommu/intel/iommu.c > +++ b/drivers/iommu/intel/iommu.c > @@ -334,6 +334,8 @@ static int intel_iommu_attach_device(struct iommu_domain > *domain, >struct device *dev); > static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain, > dma_addr_t iova); > +static bool intel_iommu_dev_feat_enabled(struct device *dev, > + enum iommu_dev_features feat); > > #ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON > int dmar_disabled = 0; > @@ -1832,6 +1834,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->subdevices); > > return domain; > } > @@ -2580,7 +2583,7 @@ static struct dmar_domain > *dmar_insert_one_dev_info(struct intel_iommu *iommu, > info->iommu = iommu; > info->pasid_table = NULL; > info->auxd_enabled = 0; > - INIT_LIST_HEAD(&info->auxiliary_domains); > + INIT_LIST_HEAD(&info->subdevices); > > if (dev && dev_is_pci(dev)) { > struct pci_dev *pdev = to_pci_dev(info->dev); > @@ -5137,21 +5140,28 @@ static void intel_iommu_domain_free(struct > iommu_domain *domain) > domain_exit(to_dmar_domain(domain)); > } > > -/* > - * Check whether a @domain could be attached to the @dev through the > - * aux-domain attach/detach APIs. > - */ > -static inline bool > -is_aux_domain(struct device *dev, struct iommu_domain *domain) > +/* Lookup subdev_info in the domain's subdevice siblings. */ > +static struct subdev_info * > +subdev_lookup_domain(struct dmar_domain *domain, struct device *dev, > + struct device *subdev) > { > - struct device_domain_info *info = get_domain_info(dev); > + struct subdev_info *sinfo = NULL, *tmp; > > - return info && info->auxd_enabled && > - domain->type == IOMMU_DOMAIN_UNMANAGED; > + assert_spin_locked(&device_domain_lock); > + > + list_for_each_entry(tmp, &domain->subdevices, link_domain) { > + if ((!dev || tmp->pdev == dev) && tmp->dev == subdev) { > + sinfo = tmp; > + break; > + } > + } > + > + return sinfo; > } > > -static void auxiliary_link_device(struct dmar_domain *domain, > - struct device *dev) > +static void > +subdev_link_device(struct dmar_domain *domain, struct device *dev, > +struct subdev_info *sinfo) > { > struct device_domain_info *info = get_domain_info(dev); > > @@ -5159,12 +5169,13 @@ static void auxiliary_link_device(struct dmar_domain > *domain, > if (WARN_ON(!info)) > return; > > - domain->auxd_refcnt++; > - list_add(&domain->auxd, &info->auxiliary_domains); > + list_add(&info->subdevices, &sinfo->link_phys); > + list_add(&domain->subdevices, &sinfo->link_domain); > } > > -static void auxiliary_unlink_device(struct dmar_domain *domain, > - struct device *dev) > +static void > +subdev_unlink_device(struct dmar_domain *domain, struct device *dev, > + struct subdev_info *sinfo) > { > struct device_domain_info *info = get_domain_info(dev); > > @@ -5172,24 +5183,30 @@ static void auxiliary_unlink_device(struct > dmar_domain *domain, > if (WARN_ON(!info)) > return; > > - list_del(&domain->auxd); > - domain->auxd_refcnt--; > + list_del(&sinfo->link_phys); > + list_del(&sinfo->link_domain); > + kfree(sinfo); > > - if (!domain->auxd_refcnt && domain->default_pasid > 0) > + if (list_empty(&domain->subdevices) && domain->default_pasid > 0) > ioasid_free(domain->default_pasid); > } > > -static int aux_domain_add_dev(struct dmar_domain *domain, > - struct device *dev) > +static int aux_domain_add_dev(struct dmar_domain *domain, struct device *dev, > + struct device *subdev) > { > int ret; > unsigned long flags; > struct intel_iommu *iommu; > + struct subdev_info *sinfo; > > iommu = device_to_iommu(dev, NUL