Re: [PATCH v4 5/5] iommu/vt-d: Add is_aux_domain support

2020-09-13 Thread Lu Baolu

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(>devices);
+   INIT_LIST_HEAD(>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(>auxiliary_domains);
+   INIT_LIST_HEAD(>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(_domain_lock);
+
+   list_for_each_entry(tmp, >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(>auxd, >auxiliary_domains);
+   list_add(>subdevices, >link_phys);
+   list_add(>subdevices, >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(>auxd);

-   domain->auxd_refcnt--;
+   list_del(>link_phys);
+   list_del(>link_domain);
+   kfree(sinfo);
  
-	if (!domain->auxd_refcnt && domain->default_pasid > 0)

+   if (list_empty(>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(sizeof(*sinfo), GFP_KERNEL);

+   if (!sinfo)
+   return -ENOMEM;
+
if (domain->default_pasid 

Re: [PATCH v4 5/5] iommu/vt-d: Add is_aux_domain support

2020-09-10 Thread Alex Williamson
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(>devices);
> + INIT_LIST_HEAD(>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(>auxiliary_domains);
> + INIT_LIST_HEAD(>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(_domain_lock);
> +
> + list_for_each_entry(tmp, >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(>auxd, >auxiliary_domains);
> + list_add(>subdevices, >link_phys);
> + list_add(>subdevices, >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(>auxd);
> - domain->auxd_refcnt--;
> + list_del(>link_phys);
> + list_del(>link_domain);
> + kfree(sinfo);
>  
> - if (!domain->auxd_refcnt && domain->default_pasid > 0)
> + if (list_empty(>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(sizeof(*sinfo),