All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/3] iommu/vt-d: Misc fixes on scalable mode
@ 2020-12-29  3:25 ` Liu Yi L
  0 siblings, 0 replies; 26+ messages in thread
From: Liu Yi L @ 2020-12-29  3:25 UTC (permalink / raw)
  To: baolu.lu, joro, will
  Cc: kevin.tian, jacob.jun.pan, ashok.raj, yi.l.liu, jun.j.tian,
	yi.y.sun, iommu, linux-kernel

Hi Baolu, Joerg, Will,

This patchset aims to fix a bug regards to native SVM usage, and
also several bugs around subdevice (attached to device via auxiliary
manner) tracking and ineffective device_tlb flush.

v2 -> v3:
- Address comments from Baolu Lu against v2
- Rebased to 5.11-rc1
v2: https://lore.kernel.org/linux-iommu/20201223062720.29364-1-yi.l.liu@intel.com/

v1 -> v2:
- Use a more recent Fix tag in "iommu/vt-d: Move intel_iommu info from struct intel_svm to struct intel_svm_dev"
- Refined the "iommu/vt-d: Track device aux-attach with subdevice_domain_info"
- Rename "iommu/vt-d: A fix to iommu_flush_dev_iotlb() for aux-domain" to be
  "iommu/vt-d: Fix ineffective devTLB invalidation for subdevices"
- Refined the commit messages
v1: https://lore.kernel.org/linux-iommu/20201220000352.183523-1-yi.l.liu@intel.com/

Liu Yi L (3):
  iommu/vt-d: Move intel_iommu info from struct intel_svm to struct
    intel_svm_dev
  iommu/vt-d: Track device aux-attach with subdevice_domain_info
  iommu/vt-d: Fix ineffective devTLB invalidation for subdevices

 drivers/iommu/intel/iommu.c | 148 ++++++++++++++++++++++++++----------
 drivers/iommu/intel/svm.c   |   9 ++-
 include/linux/intel-iommu.h |  18 +++--
 3 files changed, 125 insertions(+), 50 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v3 0/3] iommu/vt-d: Misc fixes on scalable mode
@ 2020-12-29  3:25 ` Liu Yi L
  0 siblings, 0 replies; 26+ messages in thread
From: Liu Yi L @ 2020-12-29  3:25 UTC (permalink / raw)
  To: baolu.lu, joro, will
  Cc: kevin.tian, ashok.raj, jun.j.tian, iommu, linux-kernel, yi.y.sun

Hi Baolu, Joerg, Will,

This patchset aims to fix a bug regards to native SVM usage, and
also several bugs around subdevice (attached to device via auxiliary
manner) tracking and ineffective device_tlb flush.

v2 -> v3:
- Address comments from Baolu Lu against v2
- Rebased to 5.11-rc1
v2: https://lore.kernel.org/linux-iommu/20201223062720.29364-1-yi.l.liu@intel.com/

v1 -> v2:
- Use a more recent Fix tag in "iommu/vt-d: Move intel_iommu info from struct intel_svm to struct intel_svm_dev"
- Refined the "iommu/vt-d: Track device aux-attach with subdevice_domain_info"
- Rename "iommu/vt-d: A fix to iommu_flush_dev_iotlb() for aux-domain" to be
  "iommu/vt-d: Fix ineffective devTLB invalidation for subdevices"
- Refined the commit messages
v1: https://lore.kernel.org/linux-iommu/20201220000352.183523-1-yi.l.liu@intel.com/

Liu Yi L (3):
  iommu/vt-d: Move intel_iommu info from struct intel_svm to struct
    intel_svm_dev
  iommu/vt-d: Track device aux-attach with subdevice_domain_info
  iommu/vt-d: Fix ineffective devTLB invalidation for subdevices

 drivers/iommu/intel/iommu.c | 148 ++++++++++++++++++++++++++----------
 drivers/iommu/intel/svm.c   |   9 ++-
 include/linux/intel-iommu.h |  18 +++--
 3 files changed, 125 insertions(+), 50 deletions(-)

-- 
2.25.1

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

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v3 1/3] iommu/vt-d: Move intel_iommu info from struct intel_svm to struct intel_svm_dev
  2020-12-29  3:25 ` Liu Yi L
@ 2020-12-29  3:25   ` Liu Yi L
  -1 siblings, 0 replies; 26+ messages in thread
From: Liu Yi L @ 2020-12-29  3:25 UTC (permalink / raw)
  To: baolu.lu, joro, will
  Cc: kevin.tian, jacob.jun.pan, ashok.raj, yi.l.liu, jun.j.tian,
	yi.y.sun, iommu, linux-kernel, David Woodhouse, Guo Kaijie,
	Xin Zeng

Current struct intel_svm has a field to record the struct intel_iommu
pointer for a PASID bind. And struct intel_svm will be shared by all
the devices bind to the same process. The devices may be behind different
DMAR units. As the iommu driver code uses the intel_iommu pointer stored
in intel_svm struct to do cache invalidations, it may only flush the cache
on a single DMAR unit, for others, the cache invalidation is missed.

As intel_svm struct already has a device list, this patch just moves the
intel_iommu pointer to be a field of intel_svm_dev struct.

Fixes: 1c4f88b7f1f92 ("iommu/vt-d: Shared virtual address in scalable mode")
Cc: Lu Baolu <baolu.lu@linux.intel.com>
Cc: Jacob Pan <jacob.jun.pan@linux.intel.com>
Cc: Raj Ashok <ashok.raj@intel.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Reported-by: Guo Kaijie <Kaijie.Guo@intel.com>
Reported-by: Xin Zeng <xin.zeng@intel.com>
Signed-off-by: Guo Kaijie <Kaijie.Guo@intel.com>
Signed-off-by: Xin Zeng <xin.zeng@intel.com>
Signed-off-by: Liu Yi L <yi.l.liu@intel.com>
---
 drivers/iommu/intel/svm.c   | 9 +++++----
 include/linux/intel-iommu.h | 2 +-
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index 4fa248b98031..69566695d032 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -142,7 +142,7 @@ static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_d
 	}
 	desc.qw2 = 0;
 	desc.qw3 = 0;
-	qi_submit_sync(svm->iommu, &desc, 1, 0);
+	qi_submit_sync(sdev->iommu, &desc, 1, 0);
 
 	if (sdev->dev_iotlb) {
 		desc.qw0 = QI_DEV_EIOTLB_PASID(svm->pasid) |
@@ -166,7 +166,7 @@ static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_d
 		}
 		desc.qw2 = 0;
 		desc.qw3 = 0;
-		qi_submit_sync(svm->iommu, &desc, 1, 0);
+		qi_submit_sync(sdev->iommu, &desc, 1, 0);
 	}
 }
 
@@ -211,7 +211,7 @@ static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 	 */
 	rcu_read_lock();
 	list_for_each_entry_rcu(sdev, &svm->devs, list)
-		intel_pasid_tear_down_entry(svm->iommu, sdev->dev,
+		intel_pasid_tear_down_entry(sdev->iommu, sdev->dev,
 					    svm->pasid, true);
 	rcu_read_unlock();
 
@@ -363,6 +363,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
 	}
 	sdev->dev = dev;
 	sdev->sid = PCI_DEVID(info->bus, info->devfn);
+	sdev->iommu = iommu;
 
 	/* Only count users if device has aux domains */
 	if (iommu_dev_feature_enabled(dev, IOMMU_DEV_FEAT_AUX))
@@ -546,6 +547,7 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
 		goto out;
 	}
 	sdev->dev = dev;
+	sdev->iommu = iommu;
 
 	ret = intel_iommu_enable_pasid(iommu, dev);
 	if (ret) {
@@ -575,7 +577,6 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
 			kfree(sdev);
 			goto out;
 		}
-		svm->iommu = iommu;
 
 		if (pasid_max > intel_pasid_max_id)
 			pasid_max = intel_pasid_max_id;
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index d956987ed032..94522685a0d9 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -758,6 +758,7 @@ struct intel_svm_dev {
 	struct list_head list;
 	struct rcu_head rcu;
 	struct device *dev;
+	struct intel_iommu *iommu;
 	struct svm_dev_ops *ops;
 	struct iommu_sva sva;
 	u32 pasid;
@@ -771,7 +772,6 @@ struct intel_svm {
 	struct mmu_notifier notifier;
 	struct mm_struct *mm;
 
-	struct intel_iommu *iommu;
 	unsigned int flags;
 	u32 pasid;
 	int gpasid; /* In case that guest PASID is different from host PASID */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 1/3] iommu/vt-d: Move intel_iommu info from struct intel_svm to struct intel_svm_dev
@ 2020-12-29  3:25   ` Liu Yi L
  0 siblings, 0 replies; 26+ messages in thread
From: Liu Yi L @ 2020-12-29  3:25 UTC (permalink / raw)
  To: baolu.lu, joro, will
  Cc: kevin.tian, ashok.raj, Guo Kaijie, jun.j.tian, iommu,
	linux-kernel, yi.y.sun, David Woodhouse

Current struct intel_svm has a field to record the struct intel_iommu
pointer for a PASID bind. And struct intel_svm will be shared by all
the devices bind to the same process. The devices may be behind different
DMAR units. As the iommu driver code uses the intel_iommu pointer stored
in intel_svm struct to do cache invalidations, it may only flush the cache
on a single DMAR unit, for others, the cache invalidation is missed.

As intel_svm struct already has a device list, this patch just moves the
intel_iommu pointer to be a field of intel_svm_dev struct.

Fixes: 1c4f88b7f1f92 ("iommu/vt-d: Shared virtual address in scalable mode")
Cc: Lu Baolu <baolu.lu@linux.intel.com>
Cc: Jacob Pan <jacob.jun.pan@linux.intel.com>
Cc: Raj Ashok <ashok.raj@intel.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Reported-by: Guo Kaijie <Kaijie.Guo@intel.com>
Reported-by: Xin Zeng <xin.zeng@intel.com>
Signed-off-by: Guo Kaijie <Kaijie.Guo@intel.com>
Signed-off-by: Xin Zeng <xin.zeng@intel.com>
Signed-off-by: Liu Yi L <yi.l.liu@intel.com>
---
 drivers/iommu/intel/svm.c   | 9 +++++----
 include/linux/intel-iommu.h | 2 +-
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index 4fa248b98031..69566695d032 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -142,7 +142,7 @@ static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_d
 	}
 	desc.qw2 = 0;
 	desc.qw3 = 0;
-	qi_submit_sync(svm->iommu, &desc, 1, 0);
+	qi_submit_sync(sdev->iommu, &desc, 1, 0);
 
 	if (sdev->dev_iotlb) {
 		desc.qw0 = QI_DEV_EIOTLB_PASID(svm->pasid) |
@@ -166,7 +166,7 @@ static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_d
 		}
 		desc.qw2 = 0;
 		desc.qw3 = 0;
-		qi_submit_sync(svm->iommu, &desc, 1, 0);
+		qi_submit_sync(sdev->iommu, &desc, 1, 0);
 	}
 }
 
@@ -211,7 +211,7 @@ static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 	 */
 	rcu_read_lock();
 	list_for_each_entry_rcu(sdev, &svm->devs, list)
-		intel_pasid_tear_down_entry(svm->iommu, sdev->dev,
+		intel_pasid_tear_down_entry(sdev->iommu, sdev->dev,
 					    svm->pasid, true);
 	rcu_read_unlock();
 
@@ -363,6 +363,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
 	}
 	sdev->dev = dev;
 	sdev->sid = PCI_DEVID(info->bus, info->devfn);
+	sdev->iommu = iommu;
 
 	/* Only count users if device has aux domains */
 	if (iommu_dev_feature_enabled(dev, IOMMU_DEV_FEAT_AUX))
@@ -546,6 +547,7 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
 		goto out;
 	}
 	sdev->dev = dev;
+	sdev->iommu = iommu;
 
 	ret = intel_iommu_enable_pasid(iommu, dev);
 	if (ret) {
@@ -575,7 +577,6 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
 			kfree(sdev);
 			goto out;
 		}
-		svm->iommu = iommu;
 
 		if (pasid_max > intel_pasid_max_id)
 			pasid_max = intel_pasid_max_id;
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index d956987ed032..94522685a0d9 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -758,6 +758,7 @@ struct intel_svm_dev {
 	struct list_head list;
 	struct rcu_head rcu;
 	struct device *dev;
+	struct intel_iommu *iommu;
 	struct svm_dev_ops *ops;
 	struct iommu_sva sva;
 	u32 pasid;
@@ -771,7 +772,6 @@ struct intel_svm {
 	struct mmu_notifier notifier;
 	struct mm_struct *mm;
 
-	struct intel_iommu *iommu;
 	unsigned int flags;
 	u32 pasid;
 	int gpasid; /* In case that guest PASID is different from host PASID */
-- 
2.25.1

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

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 2/3] iommu/vt-d: Track device aux-attach with subdevice_domain_info
  2020-12-29  3:25 ` Liu Yi L
@ 2020-12-29  3:25   ` Liu Yi L
  -1 siblings, 0 replies; 26+ messages in thread
From: Liu Yi L @ 2020-12-29  3:25 UTC (permalink / raw)
  To: baolu.lu, joro, will
  Cc: kevin.tian, jacob.jun.pan, ashok.raj, yi.l.liu, jun.j.tian,
	yi.y.sun, iommu, linux-kernel, Xin Zeng

In the existing code, loop all devices attached to a domain does not
include sub-devices attached via iommu_aux_attach_device().

This was found by when I'm working on the belwo patch, There is no
device in the domain->devices list, thus unable to get the cap and
ecap of iommu unit. But this domain actually has subdevice which is
attached via aux-manner. But it is tracked by domain. This patch is
going to fix it.

https://lore.kernel.org/kvm/1599734733-6431-17-git-send-email-yi.l.liu@intel.com/

And 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.

Co-developed-by: Xin Zeng <xin.zeng@intel.com>
Signed-off-by: Xin Zeng <xin.zeng@intel.com>
Signed-off-by: Liu Yi L <yi.l.liu@intel.com>
---
 drivers/iommu/intel/iommu.c | 95 +++++++++++++++++++++++++++----------
 include/linux/intel-iommu.h | 16 +++++--
 2 files changed, 82 insertions(+), 29 deletions(-)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 788119c5b021..d7720a836268 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -1877,6 +1877,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;
 }
@@ -2547,7 +2548,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);
@@ -4475,33 +4476,61 @@ is_aux_domain(struct device *dev, struct iommu_domain *domain)
 			domain->type == IOMMU_DOMAIN_UNMANAGED;
 }
 
-static void auxiliary_link_device(struct dmar_domain *domain,
-				  struct device *dev)
+static inline struct subdev_domain_info *
+lookup_subdev_info(struct dmar_domain *domain, struct device *dev)
+{
+	struct subdev_domain_info *sinfo;
+
+	if (!list_empty(&domain->subdevices)) {
+		list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
+			if (sinfo->pdev == dev)
+				return sinfo;
+		}
+	}
+
+	return NULL;
+}
+
+static int auxiliary_link_device(struct dmar_domain *domain,
+				 struct device *dev)
 {
 	struct device_domain_info *info = get_domain_info(dev);
+	struct subdev_domain_info *sinfo = lookup_subdev_info(domain, dev);
 
 	assert_spin_locked(&device_domain_lock);
 	if (WARN_ON(!info))
-		return;
+		return -EINVAL;
+
+	if (!sinfo) {
+		sinfo = kzalloc(sizeof(*sinfo), GFP_ATOMIC);
+		sinfo->domain = domain;
+		sinfo->pdev = dev;
+		list_add(&sinfo->link_phys, &info->subdevices);
+		list_add(&sinfo->link_domain, &domain->subdevices);
+	}
 
-	domain->auxd_refcnt++;
-	list_add(&domain->auxd, &info->auxiliary_domains);
+	return ++sinfo->users;
 }
 
-static void auxiliary_unlink_device(struct dmar_domain *domain,
-				    struct device *dev)
+static int auxiliary_unlink_device(struct dmar_domain *domain,
+				   struct device *dev)
 {
 	struct device_domain_info *info = get_domain_info(dev);
+	struct subdev_domain_info *sinfo = lookup_subdev_info(domain, dev);
+	int ret;
 
 	assert_spin_locked(&device_domain_lock);
-	if (WARN_ON(!info))
-		return;
+	if (WARN_ON(!info || !sinfo || sinfo->users <= 0))
+		return -EINVAL;
 
-	list_del(&domain->auxd);
-	domain->auxd_refcnt--;
+	ret = --sinfo->users;
+	if (!ret) {
+		list_del(&sinfo->link_phys);
+		list_del(&sinfo->link_domain);
+		kfree(sinfo);
+	}
 
-	if (!domain->auxd_refcnt && domain->default_pasid > 0)
-		ioasid_put(domain->default_pasid);
+	return ret;
 }
 
 static int aux_domain_add_dev(struct dmar_domain *domain,
@@ -4530,6 +4559,19 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
 	}
 
 	spin_lock_irqsave(&device_domain_lock, flags);
+	ret = auxiliary_link_device(domain, dev);
+	if (ret <= 0)
+		goto link_failed;
+
+	/*
+	 * Subdevices from the same physical device can be attached to the
+	 * same domain. For such cases, only the first subdevice attachment
+	 * needs to go through the full steps in this function. So if ret >
+	 * 1, just goto out.
+	 */
+	if (ret > 1)
+		goto out;
+
 	/*
 	 * iommu->lock must be held to attach domain to iommu and setup the
 	 * pasid entry for second level translation.
@@ -4548,10 +4590,9 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
 						     domain->default_pasid);
 	if (ret)
 		goto table_failed;
-	spin_unlock(&iommu->lock);
-
-	auxiliary_link_device(domain, dev);
 
+	spin_unlock(&iommu->lock);
+out:
 	spin_unlock_irqrestore(&device_domain_lock, flags);
 
 	return 0;
@@ -4560,8 +4601,10 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
 	domain_detach_iommu(domain, iommu);
 attach_failed:
 	spin_unlock(&iommu->lock);
+	auxiliary_unlink_device(domain, dev);
+link_failed:
 	spin_unlock_irqrestore(&device_domain_lock, flags);
-	if (!domain->auxd_refcnt && domain->default_pasid > 0)
+	if (list_empty(&domain->subdevices) && domain->default_pasid > 0)
 		ioasid_put(domain->default_pasid);
 
 	return ret;
@@ -4581,14 +4624,18 @@ static void aux_domain_remove_dev(struct dmar_domain *domain,
 	info = get_domain_info(dev);
 	iommu = info->iommu;
 
-	auxiliary_unlink_device(domain, dev);
-
-	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, dev)) {
+		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 (list_empty(&domain->subdevices) && domain->default_pasid > 0)
+		ioasid_put(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..09c6a0bf3892 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -533,11 +533,10 @@ struct dmar_domain {
 					/* Domain ids per IOMMU. Use u16 since
 					 * domain ids are 16 bit wide according
 					 * to VT-d spec, section 9.3 */
-	unsigned int	auxd_refcnt;	/* Refcount of auxiliary attaching */
 
 	bool has_iotlb_device;
 	struct list_head devices;	/* all devices' list */
-	struct list_head auxd;		/* link to device's auxiliary list */
+	struct list_head subdevices;	/* all subdevices' list */
 	struct iova_domain iovad;	/* iova's that belong to this domain */
 
 	struct dma_pte	*pgd;		/* virtual address */
@@ -610,14 +609,21 @@ struct intel_iommu {
 	struct dmar_drhd_unit *drhd;
 };
 
+/* Per subdevice private data */
+struct subdev_domain_info {
+	struct list_head link_phys;	/* link to phys device siblings */
+	struct list_head link_domain;	/* link to domain siblings */
+	struct device *pdev;		/* physical device derived from */
+	struct dmar_domain *domain;	/* aux-domain */
+	int users;			/* user count */
+};
+
 /* PCI domain-device relationship */
 struct device_domain_info {
 	struct list_head link;	/* link to domain siblings */
 	struct list_head global; /* link to global list */
 	struct list_head table;	/* link to pasid table */
-	struct list_head auxiliary_domains; /* auxiliary domains
-					     * attached to this device
-					     */
+	struct list_head subdevices; /* subdevices sibling */
 	u32 segment;		/* PCI segment number */
 	u8 bus;			/* PCI bus number */
 	u8 devfn;		/* PCI devfn number */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 2/3] iommu/vt-d: Track device aux-attach with subdevice_domain_info
@ 2020-12-29  3:25   ` Liu Yi L
  0 siblings, 0 replies; 26+ messages in thread
From: Liu Yi L @ 2020-12-29  3:25 UTC (permalink / raw)
  To: baolu.lu, joro, will
  Cc: kevin.tian, ashok.raj, jun.j.tian, iommu, linux-kernel, yi.y.sun

In the existing code, loop all devices attached to a domain does not
include sub-devices attached via iommu_aux_attach_device().

This was found by when I'm working on the belwo patch, There is no
device in the domain->devices list, thus unable to get the cap and
ecap of iommu unit. But this domain actually has subdevice which is
attached via aux-manner. But it is tracked by domain. This patch is
going to fix it.

https://lore.kernel.org/kvm/1599734733-6431-17-git-send-email-yi.l.liu@intel.com/

And 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.

Co-developed-by: Xin Zeng <xin.zeng@intel.com>
Signed-off-by: Xin Zeng <xin.zeng@intel.com>
Signed-off-by: Liu Yi L <yi.l.liu@intel.com>
---
 drivers/iommu/intel/iommu.c | 95 +++++++++++++++++++++++++++----------
 include/linux/intel-iommu.h | 16 +++++--
 2 files changed, 82 insertions(+), 29 deletions(-)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 788119c5b021..d7720a836268 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -1877,6 +1877,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;
 }
@@ -2547,7 +2548,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);
@@ -4475,33 +4476,61 @@ is_aux_domain(struct device *dev, struct iommu_domain *domain)
 			domain->type == IOMMU_DOMAIN_UNMANAGED;
 }
 
-static void auxiliary_link_device(struct dmar_domain *domain,
-				  struct device *dev)
+static inline struct subdev_domain_info *
+lookup_subdev_info(struct dmar_domain *domain, struct device *dev)
+{
+	struct subdev_domain_info *sinfo;
+
+	if (!list_empty(&domain->subdevices)) {
+		list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
+			if (sinfo->pdev == dev)
+				return sinfo;
+		}
+	}
+
+	return NULL;
+}
+
+static int auxiliary_link_device(struct dmar_domain *domain,
+				 struct device *dev)
 {
 	struct device_domain_info *info = get_domain_info(dev);
+	struct subdev_domain_info *sinfo = lookup_subdev_info(domain, dev);
 
 	assert_spin_locked(&device_domain_lock);
 	if (WARN_ON(!info))
-		return;
+		return -EINVAL;
+
+	if (!sinfo) {
+		sinfo = kzalloc(sizeof(*sinfo), GFP_ATOMIC);
+		sinfo->domain = domain;
+		sinfo->pdev = dev;
+		list_add(&sinfo->link_phys, &info->subdevices);
+		list_add(&sinfo->link_domain, &domain->subdevices);
+	}
 
-	domain->auxd_refcnt++;
-	list_add(&domain->auxd, &info->auxiliary_domains);
+	return ++sinfo->users;
 }
 
-static void auxiliary_unlink_device(struct dmar_domain *domain,
-				    struct device *dev)
+static int auxiliary_unlink_device(struct dmar_domain *domain,
+				   struct device *dev)
 {
 	struct device_domain_info *info = get_domain_info(dev);
+	struct subdev_domain_info *sinfo = lookup_subdev_info(domain, dev);
+	int ret;
 
 	assert_spin_locked(&device_domain_lock);
-	if (WARN_ON(!info))
-		return;
+	if (WARN_ON(!info || !sinfo || sinfo->users <= 0))
+		return -EINVAL;
 
-	list_del(&domain->auxd);
-	domain->auxd_refcnt--;
+	ret = --sinfo->users;
+	if (!ret) {
+		list_del(&sinfo->link_phys);
+		list_del(&sinfo->link_domain);
+		kfree(sinfo);
+	}
 
-	if (!domain->auxd_refcnt && domain->default_pasid > 0)
-		ioasid_put(domain->default_pasid);
+	return ret;
 }
 
 static int aux_domain_add_dev(struct dmar_domain *domain,
@@ -4530,6 +4559,19 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
 	}
 
 	spin_lock_irqsave(&device_domain_lock, flags);
+	ret = auxiliary_link_device(domain, dev);
+	if (ret <= 0)
+		goto link_failed;
+
+	/*
+	 * Subdevices from the same physical device can be attached to the
+	 * same domain. For such cases, only the first subdevice attachment
+	 * needs to go through the full steps in this function. So if ret >
+	 * 1, just goto out.
+	 */
+	if (ret > 1)
+		goto out;
+
 	/*
 	 * iommu->lock must be held to attach domain to iommu and setup the
 	 * pasid entry for second level translation.
@@ -4548,10 +4590,9 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
 						     domain->default_pasid);
 	if (ret)
 		goto table_failed;
-	spin_unlock(&iommu->lock);
-
-	auxiliary_link_device(domain, dev);
 
+	spin_unlock(&iommu->lock);
+out:
 	spin_unlock_irqrestore(&device_domain_lock, flags);
 
 	return 0;
@@ -4560,8 +4601,10 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
 	domain_detach_iommu(domain, iommu);
 attach_failed:
 	spin_unlock(&iommu->lock);
+	auxiliary_unlink_device(domain, dev);
+link_failed:
 	spin_unlock_irqrestore(&device_domain_lock, flags);
-	if (!domain->auxd_refcnt && domain->default_pasid > 0)
+	if (list_empty(&domain->subdevices) && domain->default_pasid > 0)
 		ioasid_put(domain->default_pasid);
 
 	return ret;
@@ -4581,14 +4624,18 @@ static void aux_domain_remove_dev(struct dmar_domain *domain,
 	info = get_domain_info(dev);
 	iommu = info->iommu;
 
-	auxiliary_unlink_device(domain, dev);
-
-	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, dev)) {
+		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 (list_empty(&domain->subdevices) && domain->default_pasid > 0)
+		ioasid_put(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..09c6a0bf3892 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -533,11 +533,10 @@ struct dmar_domain {
 					/* Domain ids per IOMMU. Use u16 since
 					 * domain ids are 16 bit wide according
 					 * to VT-d spec, section 9.3 */
-	unsigned int	auxd_refcnt;	/* Refcount of auxiliary attaching */
 
 	bool has_iotlb_device;
 	struct list_head devices;	/* all devices' list */
-	struct list_head auxd;		/* link to device's auxiliary list */
+	struct list_head subdevices;	/* all subdevices' list */
 	struct iova_domain iovad;	/* iova's that belong to this domain */
 
 	struct dma_pte	*pgd;		/* virtual address */
@@ -610,14 +609,21 @@ struct intel_iommu {
 	struct dmar_drhd_unit *drhd;
 };
 
+/* Per subdevice private data */
+struct subdev_domain_info {
+	struct list_head link_phys;	/* link to phys device siblings */
+	struct list_head link_domain;	/* link to domain siblings */
+	struct device *pdev;		/* physical device derived from */
+	struct dmar_domain *domain;	/* aux-domain */
+	int users;			/* user count */
+};
+
 /* PCI domain-device relationship */
 struct device_domain_info {
 	struct list_head link;	/* link to domain siblings */
 	struct list_head global; /* link to global list */
 	struct list_head table;	/* link to pasid table */
-	struct list_head auxiliary_domains; /* auxiliary domains
-					     * attached to this device
-					     */
+	struct list_head subdevices; /* subdevices sibling */
 	u32 segment;		/* PCI segment number */
 	u8 bus;			/* PCI bus number */
 	u8 devfn;		/* PCI devfn number */
-- 
2.25.1

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

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices
  2020-12-29  3:25 ` Liu Yi L
@ 2020-12-29  3:25   ` Liu Yi L
  -1 siblings, 0 replies; 26+ messages in thread
From: Liu Yi L @ 2020-12-29  3:25 UTC (permalink / raw)
  To: baolu.lu, joro, will
  Cc: kevin.tian, jacob.jun.pan, ashok.raj, yi.l.liu, jun.j.tian,
	yi.y.sun, iommu, linux-kernel

iommu_flush_dev_iotlb() is called to invalidate caches on device. It only
loops the devices which are full-attached to the domain. For sub-devices,
this is ineffective. This results in invalid caching entries left on the
device. Fix it by adding loop for subdevices as well. Also, the domain->
has_iotlb_device needs to be updated when attaching to subdevices.

Fixes: 67b8e02b5e761 ("iommu/vt-d: Aux-domain specific domain attach/detach")
Signed-off-by: Liu Yi L <yi.l.liu@intel.com>
---
 drivers/iommu/intel/iommu.c | 53 ++++++++++++++++++++++++++-----------
 1 file changed, 37 insertions(+), 16 deletions(-)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index d7720a836268..d48a60b61ba6 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -719,6 +719,8 @@ static int domain_update_device_node(struct dmar_domain *domain)
 	return nid;
 }
 
+static void domain_update_iotlb(struct dmar_domain *domain);
+
 /* Some capabilities may be different across iommus */
 static void domain_update_iommu_cap(struct dmar_domain *domain)
 {
@@ -744,6 +746,8 @@ static void domain_update_iommu_cap(struct dmar_domain *domain)
 		domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw - 1);
 	else
 		domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw);
+
+	domain_update_iotlb(domain);
 }
 
 struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
@@ -1464,17 +1468,22 @@ static void domain_update_iotlb(struct dmar_domain *domain)
 
 	assert_spin_locked(&device_domain_lock);
 
-	list_for_each_entry(info, &domain->devices, link) {
-		struct pci_dev *pdev;
-
-		if (!info->dev || !dev_is_pci(info->dev))
-			continue;
-
-		pdev = to_pci_dev(info->dev);
-		if (pdev->ats_enabled) {
+	list_for_each_entry(info, &domain->devices, link)
+		if (info && info->ats_enabled) {
 			has_iotlb_device = true;
 			break;
 		}
+
+	if (!has_iotlb_device) {
+		struct subdev_domain_info *sinfo;
+
+		list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
+			info = get_domain_info(sinfo->pdev);
+			if (info && info->ats_enabled) {
+				has_iotlb_device = true;
+				break;
+			}
+		}
 	}
 
 	domain->has_iotlb_device = has_iotlb_device;
@@ -1555,25 +1564,37 @@ static void iommu_disable_dev_iotlb(struct device_domain_info *info)
 #endif
 }
 
+static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
+				    u64 addr, unsigned int mask)
+{
+	u16 sid, qdep;
+
+	if (!info || !info->ats_enabled)
+		return;
+
+	sid = info->bus << 8 | info->devfn;
+	qdep = info->ats_qdep;
+	qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
+			   qdep, addr, mask);
+}
+
 static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
 				  u64 addr, unsigned mask)
 {
-	u16 sid, qdep;
 	unsigned long flags;
 	struct device_domain_info *info;
+	struct subdev_domain_info *sinfo;
 
 	if (!domain->has_iotlb_device)
 		return;
 
 	spin_lock_irqsave(&device_domain_lock, flags);
-	list_for_each_entry(info, &domain->devices, link) {
-		if (!info->ats_enabled)
-			continue;
+	list_for_each_entry(info, &domain->devices, link)
+		__iommu_flush_dev_iotlb(info, addr, mask);
 
-		sid = info->bus << 8 | info->devfn;
-		qdep = info->ats_qdep;
-		qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
-				qdep, addr, mask);
+	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
+		__iommu_flush_dev_iotlb(get_domain_info(sinfo->pdev),
+					addr, mask);
 	}
 	spin_unlock_irqrestore(&device_domain_lock, flags);
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices
@ 2020-12-29  3:25   ` Liu Yi L
  0 siblings, 0 replies; 26+ messages in thread
From: Liu Yi L @ 2020-12-29  3:25 UTC (permalink / raw)
  To: baolu.lu, joro, will
  Cc: kevin.tian, ashok.raj, jun.j.tian, iommu, linux-kernel, yi.y.sun

iommu_flush_dev_iotlb() is called to invalidate caches on device. It only
loops the devices which are full-attached to the domain. For sub-devices,
this is ineffective. This results in invalid caching entries left on the
device. Fix it by adding loop for subdevices as well. Also, the domain->
has_iotlb_device needs to be updated when attaching to subdevices.

Fixes: 67b8e02b5e761 ("iommu/vt-d: Aux-domain specific domain attach/detach")
Signed-off-by: Liu Yi L <yi.l.liu@intel.com>
---
 drivers/iommu/intel/iommu.c | 53 ++++++++++++++++++++++++++-----------
 1 file changed, 37 insertions(+), 16 deletions(-)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index d7720a836268..d48a60b61ba6 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -719,6 +719,8 @@ static int domain_update_device_node(struct dmar_domain *domain)
 	return nid;
 }
 
+static void domain_update_iotlb(struct dmar_domain *domain);
+
 /* Some capabilities may be different across iommus */
 static void domain_update_iommu_cap(struct dmar_domain *domain)
 {
@@ -744,6 +746,8 @@ static void domain_update_iommu_cap(struct dmar_domain *domain)
 		domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw - 1);
 	else
 		domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw);
+
+	domain_update_iotlb(domain);
 }
 
 struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
@@ -1464,17 +1468,22 @@ static void domain_update_iotlb(struct dmar_domain *domain)
 
 	assert_spin_locked(&device_domain_lock);
 
-	list_for_each_entry(info, &domain->devices, link) {
-		struct pci_dev *pdev;
-
-		if (!info->dev || !dev_is_pci(info->dev))
-			continue;
-
-		pdev = to_pci_dev(info->dev);
-		if (pdev->ats_enabled) {
+	list_for_each_entry(info, &domain->devices, link)
+		if (info && info->ats_enabled) {
 			has_iotlb_device = true;
 			break;
 		}
+
+	if (!has_iotlb_device) {
+		struct subdev_domain_info *sinfo;
+
+		list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
+			info = get_domain_info(sinfo->pdev);
+			if (info && info->ats_enabled) {
+				has_iotlb_device = true;
+				break;
+			}
+		}
 	}
 
 	domain->has_iotlb_device = has_iotlb_device;
@@ -1555,25 +1564,37 @@ static void iommu_disable_dev_iotlb(struct device_domain_info *info)
 #endif
 }
 
+static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
+				    u64 addr, unsigned int mask)
+{
+	u16 sid, qdep;
+
+	if (!info || !info->ats_enabled)
+		return;
+
+	sid = info->bus << 8 | info->devfn;
+	qdep = info->ats_qdep;
+	qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
+			   qdep, addr, mask);
+}
+
 static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
 				  u64 addr, unsigned mask)
 {
-	u16 sid, qdep;
 	unsigned long flags;
 	struct device_domain_info *info;
+	struct subdev_domain_info *sinfo;
 
 	if (!domain->has_iotlb_device)
 		return;
 
 	spin_lock_irqsave(&device_domain_lock, flags);
-	list_for_each_entry(info, &domain->devices, link) {
-		if (!info->ats_enabled)
-			continue;
+	list_for_each_entry(info, &domain->devices, link)
+		__iommu_flush_dev_iotlb(info, addr, mask);
 
-		sid = info->bus << 8 | info->devfn;
-		qdep = info->ats_qdep;
-		qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
-				qdep, addr, mask);
+	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
+		__iommu_flush_dev_iotlb(get_domain_info(sinfo->pdev),
+					addr, mask);
 	}
 	spin_unlock_irqrestore(&device_domain_lock, flags);
 }
-- 
2.25.1

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

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 1/3] iommu/vt-d: Move intel_iommu info from struct intel_svm to struct intel_svm_dev
  2020-12-29  3:25   ` Liu Yi L
@ 2020-12-29  8:34     ` Lu Baolu
  -1 siblings, 0 replies; 26+ messages in thread
From: Lu Baolu @ 2020-12-29  8:34 UTC (permalink / raw)
  To: Liu Yi L, joro, will
  Cc: baolu.lu, kevin.tian, jacob.jun.pan, ashok.raj, jun.j.tian,
	yi.y.sun, iommu, linux-kernel, David Woodhouse, Guo Kaijie,
	Xin Zeng

Hi Yi,

On 2020/12/29 11:25, Liu Yi L wrote:
> Current struct intel_svm has a field to record the struct intel_iommu
> pointer for a PASID bind. And struct intel_svm will be shared by all
> the devices bind to the same process. The devices may be behind different
> DMAR units. As the iommu driver code uses the intel_iommu pointer stored
> in intel_svm struct to do cache invalidations, it may only flush the cache
> on a single DMAR unit, for others, the cache invalidation is missed.
> 
> As intel_svm struct already has a device list, this patch just moves the
> intel_iommu pointer to be a field of intel_svm_dev struct.
> 
> Fixes: 1c4f88b7f1f92 ("iommu/vt-d: Shared virtual address in scalable mode")
> Cc: Lu Baolu <baolu.lu@linux.intel.com>
> Cc: Jacob Pan <jacob.jun.pan@linux.intel.com>
> Cc: Raj Ashok <ashok.raj@intel.com>
> Cc: David Woodhouse <dwmw2@infradead.org>
> Reported-by: Guo Kaijie <Kaijie.Guo@intel.com>
> Reported-by: Xin Zeng <xin.zeng@intel.com>
> Signed-off-by: Guo Kaijie <Kaijie.Guo@intel.com>
> Signed-off-by: Xin Zeng <xin.zeng@intel.com>
> Signed-off-by: Liu Yi L <yi.l.liu@intel.com>

This fix looks good to me. Thanks!

Cc: stable@vger.kernel.org # v5.0+
Acked-by: Lu Baolu <baolu.lu@linux.intel.com>

Best regards,
baolu

> ---
>   drivers/iommu/intel/svm.c   | 9 +++++----
>   include/linux/intel-iommu.h | 2 +-
>   2 files changed, 6 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
> index 4fa248b98031..69566695d032 100644
> --- a/drivers/iommu/intel/svm.c
> +++ b/drivers/iommu/intel/svm.c
> @@ -142,7 +142,7 @@ static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_d
>   	}
>   	desc.qw2 = 0;
>   	desc.qw3 = 0;
> -	qi_submit_sync(svm->iommu, &desc, 1, 0);
> +	qi_submit_sync(sdev->iommu, &desc, 1, 0);
>   
>   	if (sdev->dev_iotlb) {
>   		desc.qw0 = QI_DEV_EIOTLB_PASID(svm->pasid) |
> @@ -166,7 +166,7 @@ static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_d
>   		}
>   		desc.qw2 = 0;
>   		desc.qw3 = 0;
> -		qi_submit_sync(svm->iommu, &desc, 1, 0);
> +		qi_submit_sync(sdev->iommu, &desc, 1, 0);
>   	}
>   }
>   
> @@ -211,7 +211,7 @@ static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
>   	 */
>   	rcu_read_lock();
>   	list_for_each_entry_rcu(sdev, &svm->devs, list)
> -		intel_pasid_tear_down_entry(svm->iommu, sdev->dev,
> +		intel_pasid_tear_down_entry(sdev->iommu, sdev->dev,
>   					    svm->pasid, true);
>   	rcu_read_unlock();
>   
> @@ -363,6 +363,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
>   	}
>   	sdev->dev = dev;
>   	sdev->sid = PCI_DEVID(info->bus, info->devfn);
> +	sdev->iommu = iommu;
>   
>   	/* Only count users if device has aux domains */
>   	if (iommu_dev_feature_enabled(dev, IOMMU_DEV_FEAT_AUX))
> @@ -546,6 +547,7 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
>   		goto out;
>   	}
>   	sdev->dev = dev;
> +	sdev->iommu = iommu;
>   
>   	ret = intel_iommu_enable_pasid(iommu, dev);
>   	if (ret) {
> @@ -575,7 +577,6 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
>   			kfree(sdev);
>   			goto out;
>   		}
> -		svm->iommu = iommu;
>   
>   		if (pasid_max > intel_pasid_max_id)
>   			pasid_max = intel_pasid_max_id;
> diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
> index d956987ed032..94522685a0d9 100644
> --- a/include/linux/intel-iommu.h
> +++ b/include/linux/intel-iommu.h
> @@ -758,6 +758,7 @@ struct intel_svm_dev {
>   	struct list_head list;
>   	struct rcu_head rcu;
>   	struct device *dev;
> +	struct intel_iommu *iommu;
>   	struct svm_dev_ops *ops;
>   	struct iommu_sva sva;
>   	u32 pasid;
> @@ -771,7 +772,6 @@ struct intel_svm {
>   	struct mmu_notifier notifier;
>   	struct mm_struct *mm;
>   
> -	struct intel_iommu *iommu;
>   	unsigned int flags;
>   	u32 pasid;
>   	int gpasid; /* In case that guest PASID is different from host PASID */
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 1/3] iommu/vt-d: Move intel_iommu info from struct intel_svm to struct intel_svm_dev
@ 2020-12-29  8:34     ` Lu Baolu
  0 siblings, 0 replies; 26+ messages in thread
From: Lu Baolu @ 2020-12-29  8:34 UTC (permalink / raw)
  To: Liu Yi L, joro, will
  Cc: kevin.tian, ashok.raj, jun.j.tian, iommu, linux-kernel, yi.y.sun,
	Guo Kaijie, David Woodhouse

Hi Yi,

On 2020/12/29 11:25, Liu Yi L wrote:
> Current struct intel_svm has a field to record the struct intel_iommu
> pointer for a PASID bind. And struct intel_svm will be shared by all
> the devices bind to the same process. The devices may be behind different
> DMAR units. As the iommu driver code uses the intel_iommu pointer stored
> in intel_svm struct to do cache invalidations, it may only flush the cache
> on a single DMAR unit, for others, the cache invalidation is missed.
> 
> As intel_svm struct already has a device list, this patch just moves the
> intel_iommu pointer to be a field of intel_svm_dev struct.
> 
> Fixes: 1c4f88b7f1f92 ("iommu/vt-d: Shared virtual address in scalable mode")
> Cc: Lu Baolu <baolu.lu@linux.intel.com>
> Cc: Jacob Pan <jacob.jun.pan@linux.intel.com>
> Cc: Raj Ashok <ashok.raj@intel.com>
> Cc: David Woodhouse <dwmw2@infradead.org>
> Reported-by: Guo Kaijie <Kaijie.Guo@intel.com>
> Reported-by: Xin Zeng <xin.zeng@intel.com>
> Signed-off-by: Guo Kaijie <Kaijie.Guo@intel.com>
> Signed-off-by: Xin Zeng <xin.zeng@intel.com>
> Signed-off-by: Liu Yi L <yi.l.liu@intel.com>

This fix looks good to me. Thanks!

Cc: stable@vger.kernel.org # v5.0+
Acked-by: Lu Baolu <baolu.lu@linux.intel.com>

Best regards,
baolu

> ---
>   drivers/iommu/intel/svm.c   | 9 +++++----
>   include/linux/intel-iommu.h | 2 +-
>   2 files changed, 6 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
> index 4fa248b98031..69566695d032 100644
> --- a/drivers/iommu/intel/svm.c
> +++ b/drivers/iommu/intel/svm.c
> @@ -142,7 +142,7 @@ static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_d
>   	}
>   	desc.qw2 = 0;
>   	desc.qw3 = 0;
> -	qi_submit_sync(svm->iommu, &desc, 1, 0);
> +	qi_submit_sync(sdev->iommu, &desc, 1, 0);
>   
>   	if (sdev->dev_iotlb) {
>   		desc.qw0 = QI_DEV_EIOTLB_PASID(svm->pasid) |
> @@ -166,7 +166,7 @@ static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_d
>   		}
>   		desc.qw2 = 0;
>   		desc.qw3 = 0;
> -		qi_submit_sync(svm->iommu, &desc, 1, 0);
> +		qi_submit_sync(sdev->iommu, &desc, 1, 0);
>   	}
>   }
>   
> @@ -211,7 +211,7 @@ static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
>   	 */
>   	rcu_read_lock();
>   	list_for_each_entry_rcu(sdev, &svm->devs, list)
> -		intel_pasid_tear_down_entry(svm->iommu, sdev->dev,
> +		intel_pasid_tear_down_entry(sdev->iommu, sdev->dev,
>   					    svm->pasid, true);
>   	rcu_read_unlock();
>   
> @@ -363,6 +363,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
>   	}
>   	sdev->dev = dev;
>   	sdev->sid = PCI_DEVID(info->bus, info->devfn);
> +	sdev->iommu = iommu;
>   
>   	/* Only count users if device has aux domains */
>   	if (iommu_dev_feature_enabled(dev, IOMMU_DEV_FEAT_AUX))
> @@ -546,6 +547,7 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
>   		goto out;
>   	}
>   	sdev->dev = dev;
> +	sdev->iommu = iommu;
>   
>   	ret = intel_iommu_enable_pasid(iommu, dev);
>   	if (ret) {
> @@ -575,7 +577,6 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
>   			kfree(sdev);
>   			goto out;
>   		}
> -		svm->iommu = iommu;
>   
>   		if (pasid_max > intel_pasid_max_id)
>   			pasid_max = intel_pasid_max_id;
> diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
> index d956987ed032..94522685a0d9 100644
> --- a/include/linux/intel-iommu.h
> +++ b/include/linux/intel-iommu.h
> @@ -758,6 +758,7 @@ struct intel_svm_dev {
>   	struct list_head list;
>   	struct rcu_head rcu;
>   	struct device *dev;
> +	struct intel_iommu *iommu;
>   	struct svm_dev_ops *ops;
>   	struct iommu_sva sva;
>   	u32 pasid;
> @@ -771,7 +772,6 @@ struct intel_svm {
>   	struct mmu_notifier notifier;
>   	struct mm_struct *mm;
>   
> -	struct intel_iommu *iommu;
>   	unsigned int flags;
>   	u32 pasid;
>   	int gpasid; /* In case that guest PASID is different from host PASID */
> 
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 2/3] iommu/vt-d: Track device aux-attach with subdevice_domain_info
  2020-12-29  3:25   ` Liu Yi L
@ 2020-12-29  8:38     ` Lu Baolu
  -1 siblings, 0 replies; 26+ messages in thread
From: Lu Baolu @ 2020-12-29  8:38 UTC (permalink / raw)
  To: Liu Yi L, joro, will
  Cc: baolu.lu, kevin.tian, jacob.jun.pan, ashok.raj, jun.j.tian,
	yi.y.sun, iommu, linux-kernel, Xin Zeng

Hi Yi,

On 2020/12/29 11:25, Liu Yi L wrote:
> In the existing code, loop all devices attached to a domain does not
> include sub-devices attached via iommu_aux_attach_device().
> 
> This was found by when I'm working on the belwo patch, There is no
                                             ^^^^^
below

> device in the domain->devices list, thus unable to get the cap and
> ecap of iommu unit. But this domain actually has subdevice which is
> attached via aux-manner. But it is tracked by domain. This patch is
> going to fix it.
> 
> https://lore.kernel.org/kvm/1599734733-6431-17-git-send-email-yi.l.liu@intel.com/
> 
> And 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.
> 
> Co-developed-by: Xin Zeng <xin.zeng@intel.com>
> Signed-off-by: Xin Zeng <xin.zeng@intel.com>
> Signed-off-by: Liu Yi L <yi.l.liu@intel.com>

Others look good to me.

Fixes: 67b8e02b5e761 ("iommu/vt-d: Aux-domain specific domain 
attach/detach")
Acked-by: Lu Baolu <baolu.lu@linux.intel.com>

Best regards,
baolu

> ---
>   drivers/iommu/intel/iommu.c | 95 +++++++++++++++++++++++++++----------
>   include/linux/intel-iommu.h | 16 +++++--
>   2 files changed, 82 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index 788119c5b021..d7720a836268 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -1877,6 +1877,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;
>   }
> @@ -2547,7 +2548,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);
> @@ -4475,33 +4476,61 @@ is_aux_domain(struct device *dev, struct iommu_domain *domain)
>   			domain->type == IOMMU_DOMAIN_UNMANAGED;
>   }
>   
> -static void auxiliary_link_device(struct dmar_domain *domain,
> -				  struct device *dev)
> +static inline struct subdev_domain_info *
> +lookup_subdev_info(struct dmar_domain *domain, struct device *dev)
> +{
> +	struct subdev_domain_info *sinfo;
> +
> +	if (!list_empty(&domain->subdevices)) {
> +		list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> +			if (sinfo->pdev == dev)
> +				return sinfo;
> +		}
> +	}
> +
> +	return NULL;
> +}
> +
> +static int auxiliary_link_device(struct dmar_domain *domain,
> +				 struct device *dev)
>   {
>   	struct device_domain_info *info = get_domain_info(dev);
> +	struct subdev_domain_info *sinfo = lookup_subdev_info(domain, dev);
>   
>   	assert_spin_locked(&device_domain_lock);
>   	if (WARN_ON(!info))
> -		return;
> +		return -EINVAL;
> +
> +	if (!sinfo) {
> +		sinfo = kzalloc(sizeof(*sinfo), GFP_ATOMIC);
> +		sinfo->domain = domain;
> +		sinfo->pdev = dev;
> +		list_add(&sinfo->link_phys, &info->subdevices);
> +		list_add(&sinfo->link_domain, &domain->subdevices);
> +	}
>   
> -	domain->auxd_refcnt++;
> -	list_add(&domain->auxd, &info->auxiliary_domains);
> +	return ++sinfo->users;
>   }
>   
> -static void auxiliary_unlink_device(struct dmar_domain *domain,
> -				    struct device *dev)
> +static int auxiliary_unlink_device(struct dmar_domain *domain,
> +				   struct device *dev)
>   {
>   	struct device_domain_info *info = get_domain_info(dev);
> +	struct subdev_domain_info *sinfo = lookup_subdev_info(domain, dev);
> +	int ret;
>   
>   	assert_spin_locked(&device_domain_lock);
> -	if (WARN_ON(!info))
> -		return;
> +	if (WARN_ON(!info || !sinfo || sinfo->users <= 0))
> +		return -EINVAL;
>   
> -	list_del(&domain->auxd);
> -	domain->auxd_refcnt--;
> +	ret = --sinfo->users;
> +	if (!ret) {
> +		list_del(&sinfo->link_phys);
> +		list_del(&sinfo->link_domain);
> +		kfree(sinfo);
> +	}
>   
> -	if (!domain->auxd_refcnt && domain->default_pasid > 0)
> -		ioasid_put(domain->default_pasid);
> +	return ret;
>   }
>   
>   static int aux_domain_add_dev(struct dmar_domain *domain,
> @@ -4530,6 +4559,19 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
>   	}
>   
>   	spin_lock_irqsave(&device_domain_lock, flags);
> +	ret = auxiliary_link_device(domain, dev);
> +	if (ret <= 0)
> +		goto link_failed;
> +
> +	/*
> +	 * Subdevices from the same physical device can be attached to the
> +	 * same domain. For such cases, only the first subdevice attachment
> +	 * needs to go through the full steps in this function. So if ret >
> +	 * 1, just goto out.
> +	 */
> +	if (ret > 1)
> +		goto out;
> +
>   	/*
>   	 * iommu->lock must be held to attach domain to iommu and setup the
>   	 * pasid entry for second level translation.
> @@ -4548,10 +4590,9 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
>   						     domain->default_pasid);
>   	if (ret)
>   		goto table_failed;
> -	spin_unlock(&iommu->lock);
> -
> -	auxiliary_link_device(domain, dev);
>   
> +	spin_unlock(&iommu->lock);
> +out:
>   	spin_unlock_irqrestore(&device_domain_lock, flags);
>   
>   	return 0;
> @@ -4560,8 +4601,10 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
>   	domain_detach_iommu(domain, iommu);
>   attach_failed:
>   	spin_unlock(&iommu->lock);
> +	auxiliary_unlink_device(domain, dev);
> +link_failed:
>   	spin_unlock_irqrestore(&device_domain_lock, flags);
> -	if (!domain->auxd_refcnt && domain->default_pasid > 0)
> +	if (list_empty(&domain->subdevices) && domain->default_pasid > 0)
>   		ioasid_put(domain->default_pasid);
>   
>   	return ret;
> @@ -4581,14 +4624,18 @@ static void aux_domain_remove_dev(struct dmar_domain *domain,
>   	info = get_domain_info(dev);
>   	iommu = info->iommu;
>   
> -	auxiliary_unlink_device(domain, dev);
> -
> -	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, dev)) {
> +		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 (list_empty(&domain->subdevices) && domain->default_pasid > 0)
> +		ioasid_put(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..09c6a0bf3892 100644
> --- a/include/linux/intel-iommu.h
> +++ b/include/linux/intel-iommu.h
> @@ -533,11 +533,10 @@ struct dmar_domain {
>   					/* Domain ids per IOMMU. Use u16 since
>   					 * domain ids are 16 bit wide according
>   					 * to VT-d spec, section 9.3 */
> -	unsigned int	auxd_refcnt;	/* Refcount of auxiliary attaching */
>   
>   	bool has_iotlb_device;
>   	struct list_head devices;	/* all devices' list */
> -	struct list_head auxd;		/* link to device's auxiliary list */
> +	struct list_head subdevices;	/* all subdevices' list */
>   	struct iova_domain iovad;	/* iova's that belong to this domain */
>   
>   	struct dma_pte	*pgd;		/* virtual address */
> @@ -610,14 +609,21 @@ struct intel_iommu {
>   	struct dmar_drhd_unit *drhd;
>   };
>   
> +/* Per subdevice private data */
> +struct subdev_domain_info {
> +	struct list_head link_phys;	/* link to phys device siblings */
> +	struct list_head link_domain;	/* link to domain siblings */
> +	struct device *pdev;		/* physical device derived from */
> +	struct dmar_domain *domain;	/* aux-domain */
> +	int users;			/* user count */
> +};
> +
>   /* PCI domain-device relationship */
>   struct device_domain_info {
>   	struct list_head link;	/* link to domain siblings */
>   	struct list_head global; /* link to global list */
>   	struct list_head table;	/* link to pasid table */
> -	struct list_head auxiliary_domains; /* auxiliary domains
> -					     * attached to this device
> -					     */
> +	struct list_head subdevices; /* subdevices sibling */
>   	u32 segment;		/* PCI segment number */
>   	u8 bus;			/* PCI bus number */
>   	u8 devfn;		/* PCI devfn number */
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 2/3] iommu/vt-d: Track device aux-attach with subdevice_domain_info
@ 2020-12-29  8:38     ` Lu Baolu
  0 siblings, 0 replies; 26+ messages in thread
From: Lu Baolu @ 2020-12-29  8:38 UTC (permalink / raw)
  To: Liu Yi L, joro, will
  Cc: kevin.tian, ashok.raj, jun.j.tian, iommu, linux-kernel, yi.y.sun

Hi Yi,

On 2020/12/29 11:25, Liu Yi L wrote:
> In the existing code, loop all devices attached to a domain does not
> include sub-devices attached via iommu_aux_attach_device().
> 
> This was found by when I'm working on the belwo patch, There is no
                                             ^^^^^
below

> device in the domain->devices list, thus unable to get the cap and
> ecap of iommu unit. But this domain actually has subdevice which is
> attached via aux-manner. But it is tracked by domain. This patch is
> going to fix it.
> 
> https://lore.kernel.org/kvm/1599734733-6431-17-git-send-email-yi.l.liu@intel.com/
> 
> And 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.
> 
> Co-developed-by: Xin Zeng <xin.zeng@intel.com>
> Signed-off-by: Xin Zeng <xin.zeng@intel.com>
> Signed-off-by: Liu Yi L <yi.l.liu@intel.com>

Others look good to me.

Fixes: 67b8e02b5e761 ("iommu/vt-d: Aux-domain specific domain 
attach/detach")
Acked-by: Lu Baolu <baolu.lu@linux.intel.com>

Best regards,
baolu

> ---
>   drivers/iommu/intel/iommu.c | 95 +++++++++++++++++++++++++++----------
>   include/linux/intel-iommu.h | 16 +++++--
>   2 files changed, 82 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index 788119c5b021..d7720a836268 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -1877,6 +1877,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;
>   }
> @@ -2547,7 +2548,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);
> @@ -4475,33 +4476,61 @@ is_aux_domain(struct device *dev, struct iommu_domain *domain)
>   			domain->type == IOMMU_DOMAIN_UNMANAGED;
>   }
>   
> -static void auxiliary_link_device(struct dmar_domain *domain,
> -				  struct device *dev)
> +static inline struct subdev_domain_info *
> +lookup_subdev_info(struct dmar_domain *domain, struct device *dev)
> +{
> +	struct subdev_domain_info *sinfo;
> +
> +	if (!list_empty(&domain->subdevices)) {
> +		list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> +			if (sinfo->pdev == dev)
> +				return sinfo;
> +		}
> +	}
> +
> +	return NULL;
> +}
> +
> +static int auxiliary_link_device(struct dmar_domain *domain,
> +				 struct device *dev)
>   {
>   	struct device_domain_info *info = get_domain_info(dev);
> +	struct subdev_domain_info *sinfo = lookup_subdev_info(domain, dev);
>   
>   	assert_spin_locked(&device_domain_lock);
>   	if (WARN_ON(!info))
> -		return;
> +		return -EINVAL;
> +
> +	if (!sinfo) {
> +		sinfo = kzalloc(sizeof(*sinfo), GFP_ATOMIC);
> +		sinfo->domain = domain;
> +		sinfo->pdev = dev;
> +		list_add(&sinfo->link_phys, &info->subdevices);
> +		list_add(&sinfo->link_domain, &domain->subdevices);
> +	}
>   
> -	domain->auxd_refcnt++;
> -	list_add(&domain->auxd, &info->auxiliary_domains);
> +	return ++sinfo->users;
>   }
>   
> -static void auxiliary_unlink_device(struct dmar_domain *domain,
> -				    struct device *dev)
> +static int auxiliary_unlink_device(struct dmar_domain *domain,
> +				   struct device *dev)
>   {
>   	struct device_domain_info *info = get_domain_info(dev);
> +	struct subdev_domain_info *sinfo = lookup_subdev_info(domain, dev);
> +	int ret;
>   
>   	assert_spin_locked(&device_domain_lock);
> -	if (WARN_ON(!info))
> -		return;
> +	if (WARN_ON(!info || !sinfo || sinfo->users <= 0))
> +		return -EINVAL;
>   
> -	list_del(&domain->auxd);
> -	domain->auxd_refcnt--;
> +	ret = --sinfo->users;
> +	if (!ret) {
> +		list_del(&sinfo->link_phys);
> +		list_del(&sinfo->link_domain);
> +		kfree(sinfo);
> +	}
>   
> -	if (!domain->auxd_refcnt && domain->default_pasid > 0)
> -		ioasid_put(domain->default_pasid);
> +	return ret;
>   }
>   
>   static int aux_domain_add_dev(struct dmar_domain *domain,
> @@ -4530,6 +4559,19 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
>   	}
>   
>   	spin_lock_irqsave(&device_domain_lock, flags);
> +	ret = auxiliary_link_device(domain, dev);
> +	if (ret <= 0)
> +		goto link_failed;
> +
> +	/*
> +	 * Subdevices from the same physical device can be attached to the
> +	 * same domain. For such cases, only the first subdevice attachment
> +	 * needs to go through the full steps in this function. So if ret >
> +	 * 1, just goto out.
> +	 */
> +	if (ret > 1)
> +		goto out;
> +
>   	/*
>   	 * iommu->lock must be held to attach domain to iommu and setup the
>   	 * pasid entry for second level translation.
> @@ -4548,10 +4590,9 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
>   						     domain->default_pasid);
>   	if (ret)
>   		goto table_failed;
> -	spin_unlock(&iommu->lock);
> -
> -	auxiliary_link_device(domain, dev);
>   
> +	spin_unlock(&iommu->lock);
> +out:
>   	spin_unlock_irqrestore(&device_domain_lock, flags);
>   
>   	return 0;
> @@ -4560,8 +4601,10 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
>   	domain_detach_iommu(domain, iommu);
>   attach_failed:
>   	spin_unlock(&iommu->lock);
> +	auxiliary_unlink_device(domain, dev);
> +link_failed:
>   	spin_unlock_irqrestore(&device_domain_lock, flags);
> -	if (!domain->auxd_refcnt && domain->default_pasid > 0)
> +	if (list_empty(&domain->subdevices) && domain->default_pasid > 0)
>   		ioasid_put(domain->default_pasid);
>   
>   	return ret;
> @@ -4581,14 +4624,18 @@ static void aux_domain_remove_dev(struct dmar_domain *domain,
>   	info = get_domain_info(dev);
>   	iommu = info->iommu;
>   
> -	auxiliary_unlink_device(domain, dev);
> -
> -	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, dev)) {
> +		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 (list_empty(&domain->subdevices) && domain->default_pasid > 0)
> +		ioasid_put(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..09c6a0bf3892 100644
> --- a/include/linux/intel-iommu.h
> +++ b/include/linux/intel-iommu.h
> @@ -533,11 +533,10 @@ struct dmar_domain {
>   					/* Domain ids per IOMMU. Use u16 since
>   					 * domain ids are 16 bit wide according
>   					 * to VT-d spec, section 9.3 */
> -	unsigned int	auxd_refcnt;	/* Refcount of auxiliary attaching */
>   
>   	bool has_iotlb_device;
>   	struct list_head devices;	/* all devices' list */
> -	struct list_head auxd;		/* link to device's auxiliary list */
> +	struct list_head subdevices;	/* all subdevices' list */
>   	struct iova_domain iovad;	/* iova's that belong to this domain */
>   
>   	struct dma_pte	*pgd;		/* virtual address */
> @@ -610,14 +609,21 @@ struct intel_iommu {
>   	struct dmar_drhd_unit *drhd;
>   };
>   
> +/* Per subdevice private data */
> +struct subdev_domain_info {
> +	struct list_head link_phys;	/* link to phys device siblings */
> +	struct list_head link_domain;	/* link to domain siblings */
> +	struct device *pdev;		/* physical device derived from */
> +	struct dmar_domain *domain;	/* aux-domain */
> +	int users;			/* user count */
> +};
> +
>   /* PCI domain-device relationship */
>   struct device_domain_info {
>   	struct list_head link;	/* link to domain siblings */
>   	struct list_head global; /* link to global list */
>   	struct list_head table;	/* link to pasid table */
> -	struct list_head auxiliary_domains; /* auxiliary domains
> -					     * attached to this device
> -					     */
> +	struct list_head subdevices; /* subdevices sibling */
>   	u32 segment;		/* PCI segment number */
>   	u8 bus;			/* PCI bus number */
>   	u8 devfn;		/* PCI devfn number */
> 
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices
  2020-12-29  3:25   ` Liu Yi L
@ 2020-12-29  8:41     ` Lu Baolu
  -1 siblings, 0 replies; 26+ messages in thread
From: Lu Baolu @ 2020-12-29  8:41 UTC (permalink / raw)
  To: Liu Yi L, joro, will
  Cc: baolu.lu, kevin.tian, jacob.jun.pan, ashok.raj, jun.j.tian,
	yi.y.sun, iommu, linux-kernel

Hi Yi,

On 2020/12/29 11:25, Liu Yi L wrote:
> iommu_flush_dev_iotlb() is called to invalidate caches on device. It only
> loops the devices which are full-attached to the domain. For sub-devices,
> this is ineffective. This results in invalid caching entries left on the
> device. Fix it by adding loop for subdevices as well. Also, the domain->
> has_iotlb_device needs to be updated when attaching to subdevices.
> 
> Fixes: 67b8e02b5e761 ("iommu/vt-d: Aux-domain specific domain attach/detach")
> Signed-off-by: Liu Yi L <yi.l.liu@intel.com>
> ---
>   drivers/iommu/intel/iommu.c | 53 ++++++++++++++++++++++++++-----------
>   1 file changed, 37 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index d7720a836268..d48a60b61ba6 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -719,6 +719,8 @@ static int domain_update_device_node(struct dmar_domain *domain)
>   	return nid;
>   }
>   
> +static void domain_update_iotlb(struct dmar_domain *domain);
> +
>   /* Some capabilities may be different across iommus */
>   static void domain_update_iommu_cap(struct dmar_domain *domain)
>   {
> @@ -744,6 +746,8 @@ static void domain_update_iommu_cap(struct dmar_domain *domain)
>   		domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw - 1);
>   	else
>   		domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw);
> +
> +	domain_update_iotlb(domain);
>   }
>   
>   struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
> @@ -1464,17 +1468,22 @@ static void domain_update_iotlb(struct dmar_domain *domain)
>   
>   	assert_spin_locked(&device_domain_lock);
>   
> -	list_for_each_entry(info, &domain->devices, link) {
> -		struct pci_dev *pdev;
> -
> -		if (!info->dev || !dev_is_pci(info->dev))
> -			continue;
> -
> -		pdev = to_pci_dev(info->dev);
> -		if (pdev->ats_enabled) {
> +	list_for_each_entry(info, &domain->devices, link)
> +		if (info && info->ats_enabled) {
>   			has_iotlb_device = true;
>   			break;
>   		}
> +
> +	if (!has_iotlb_device) {
> +		struct subdev_domain_info *sinfo;
> +
> +		list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> +			info = get_domain_info(sinfo->pdev);
> +			if (info && info->ats_enabled) {
> +				has_iotlb_device = true;
> +				break;
> +			}
> +		}
>   	}
>   
>   	domain->has_iotlb_device = has_iotlb_device;
> @@ -1555,25 +1564,37 @@ static void iommu_disable_dev_iotlb(struct device_domain_info *info)
>   #endif
>   }
>   
> +static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
> +				    u64 addr, unsigned int mask)
> +{
> +	u16 sid, qdep;
> +
> +	if (!info || !info->ats_enabled)
> +		return;
> +
> +	sid = info->bus << 8 | info->devfn;
> +	qdep = info->ats_qdep;
> +	qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> +			   qdep, addr, mask);
> +}
> +
>   static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
>   				  u64 addr, unsigned mask)
>   {
> -	u16 sid, qdep;
>   	unsigned long flags;
>   	struct device_domain_info *info;
> +	struct subdev_domain_info *sinfo;
>   
>   	if (!domain->has_iotlb_device)
>   		return;
>   
>   	spin_lock_irqsave(&device_domain_lock, flags);
> -	list_for_each_entry(info, &domain->devices, link) {
> -		if (!info->ats_enabled)
> -			continue;
> +	list_for_each_entry(info, &domain->devices, link)
> +		__iommu_flush_dev_iotlb(info, addr, mask);
>   
> -		sid = info->bus << 8 | info->devfn;
> -		qdep = info->ats_qdep;
> -		qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> -				qdep, addr, mask);
> +	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> +		__iommu_flush_dev_iotlb(get_domain_info(sinfo->pdev),
> +					addr, mask);
>   	}

Nit:
	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
		info = get_domain_info(sinfo->pdev);
		__iommu_flush_dev_iotlb(info, addr, mask);
	}

Others look good to me.

Acked-by: Lu Baolu <baolu.lu@linux.intel.com>

Best regards,
baolu

>   	spin_unlock_irqrestore(&device_domain_lock, flags);
>   }
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices
@ 2020-12-29  8:41     ` Lu Baolu
  0 siblings, 0 replies; 26+ messages in thread
From: Lu Baolu @ 2020-12-29  8:41 UTC (permalink / raw)
  To: Liu Yi L, joro, will
  Cc: kevin.tian, ashok.raj, jun.j.tian, iommu, linux-kernel, yi.y.sun

Hi Yi,

On 2020/12/29 11:25, Liu Yi L wrote:
> iommu_flush_dev_iotlb() is called to invalidate caches on device. It only
> loops the devices which are full-attached to the domain. For sub-devices,
> this is ineffective. This results in invalid caching entries left on the
> device. Fix it by adding loop for subdevices as well. Also, the domain->
> has_iotlb_device needs to be updated when attaching to subdevices.
> 
> Fixes: 67b8e02b5e761 ("iommu/vt-d: Aux-domain specific domain attach/detach")
> Signed-off-by: Liu Yi L <yi.l.liu@intel.com>
> ---
>   drivers/iommu/intel/iommu.c | 53 ++++++++++++++++++++++++++-----------
>   1 file changed, 37 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index d7720a836268..d48a60b61ba6 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -719,6 +719,8 @@ static int domain_update_device_node(struct dmar_domain *domain)
>   	return nid;
>   }
>   
> +static void domain_update_iotlb(struct dmar_domain *domain);
> +
>   /* Some capabilities may be different across iommus */
>   static void domain_update_iommu_cap(struct dmar_domain *domain)
>   {
> @@ -744,6 +746,8 @@ static void domain_update_iommu_cap(struct dmar_domain *domain)
>   		domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw - 1);
>   	else
>   		domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw);
> +
> +	domain_update_iotlb(domain);
>   }
>   
>   struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
> @@ -1464,17 +1468,22 @@ static void domain_update_iotlb(struct dmar_domain *domain)
>   
>   	assert_spin_locked(&device_domain_lock);
>   
> -	list_for_each_entry(info, &domain->devices, link) {
> -		struct pci_dev *pdev;
> -
> -		if (!info->dev || !dev_is_pci(info->dev))
> -			continue;
> -
> -		pdev = to_pci_dev(info->dev);
> -		if (pdev->ats_enabled) {
> +	list_for_each_entry(info, &domain->devices, link)
> +		if (info && info->ats_enabled) {
>   			has_iotlb_device = true;
>   			break;
>   		}
> +
> +	if (!has_iotlb_device) {
> +		struct subdev_domain_info *sinfo;
> +
> +		list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> +			info = get_domain_info(sinfo->pdev);
> +			if (info && info->ats_enabled) {
> +				has_iotlb_device = true;
> +				break;
> +			}
> +		}
>   	}
>   
>   	domain->has_iotlb_device = has_iotlb_device;
> @@ -1555,25 +1564,37 @@ static void iommu_disable_dev_iotlb(struct device_domain_info *info)
>   #endif
>   }
>   
> +static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
> +				    u64 addr, unsigned int mask)
> +{
> +	u16 sid, qdep;
> +
> +	if (!info || !info->ats_enabled)
> +		return;
> +
> +	sid = info->bus << 8 | info->devfn;
> +	qdep = info->ats_qdep;
> +	qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> +			   qdep, addr, mask);
> +}
> +
>   static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
>   				  u64 addr, unsigned mask)
>   {
> -	u16 sid, qdep;
>   	unsigned long flags;
>   	struct device_domain_info *info;
> +	struct subdev_domain_info *sinfo;
>   
>   	if (!domain->has_iotlb_device)
>   		return;
>   
>   	spin_lock_irqsave(&device_domain_lock, flags);
> -	list_for_each_entry(info, &domain->devices, link) {
> -		if (!info->ats_enabled)
> -			continue;
> +	list_for_each_entry(info, &domain->devices, link)
> +		__iommu_flush_dev_iotlb(info, addr, mask);
>   
> -		sid = info->bus << 8 | info->devfn;
> -		qdep = info->ats_qdep;
> -		qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> -				qdep, addr, mask);
> +	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> +		__iommu_flush_dev_iotlb(get_domain_info(sinfo->pdev),
> +					addr, mask);
>   	}

Nit:
	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
		info = get_domain_info(sinfo->pdev);
		__iommu_flush_dev_iotlb(info, addr, mask);
	}

Others look good to me.

Acked-by: Lu Baolu <baolu.lu@linux.intel.com>

Best regards,
baolu

>   	spin_unlock_irqrestore(&device_domain_lock, flags);
>   }
> 
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices
  2020-12-29  8:41     ` Lu Baolu
@ 2021-01-05  5:50       ` Liu, Yi L
  -1 siblings, 0 replies; 26+ messages in thread
From: Liu, Yi L @ 2021-01-05  5:50 UTC (permalink / raw)
  To: Lu Baolu, joro, will
  Cc: Tian, Kevin, jacob.jun.pan, Raj, Ashok, Tian, Jun J, Sun, Yi Y,
	iommu, linux-kernel

Hi Baolu,

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Tuesday, December 29, 2020 4:42 PM
> 
> Hi Yi,
> 
> On 2020/12/29 11:25, Liu Yi L wrote:
> > iommu_flush_dev_iotlb() is called to invalidate caches on device. It only
> > loops the devices which are full-attached to the domain. For sub-devices,
> > this is ineffective. This results in invalid caching entries left on the
> > device. Fix it by adding loop for subdevices as well. Also, the domain->
> > has_iotlb_device needs to be updated when attaching to subdevices.
> >
> > Fixes: 67b8e02b5e761 ("iommu/vt-d: Aux-domain specific domain
> attach/detach")
> > Signed-off-by: Liu Yi L <yi.l.liu@intel.com>
> > ---
> >   drivers/iommu/intel/iommu.c | 53 ++++++++++++++++++++++++++---------
> --
> >   1 file changed, 37 insertions(+), 16 deletions(-)
> >
> > diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> > index d7720a836268..d48a60b61ba6 100644
> > --- a/drivers/iommu/intel/iommu.c
> > +++ b/drivers/iommu/intel/iommu.c
> > @@ -719,6 +719,8 @@ static int domain_update_device_node(struct
> dmar_domain *domain)
> >   	return nid;
> >   }
> >
> > +static void domain_update_iotlb(struct dmar_domain *domain);
> > +
> >   /* Some capabilities may be different across iommus */
> >   static void domain_update_iommu_cap(struct dmar_domain *domain)
> >   {
> > @@ -744,6 +746,8 @@ static void domain_update_iommu_cap(struct
> dmar_domain *domain)
> >   		domain->domain.geometry.aperture_end =
> __DOMAIN_MAX_ADDR(domain->gaw - 1);
> >   	else
> >   		domain->domain.geometry.aperture_end =
> __DOMAIN_MAX_ADDR(domain->gaw);
> > +
> > +	domain_update_iotlb(domain);
> >   }
> >
> >   struct context_entry *iommu_context_addr(struct intel_iommu *iommu,
> u8 bus,
> > @@ -1464,17 +1468,22 @@ static void domain_update_iotlb(struct
> dmar_domain *domain)
> >
> >   	assert_spin_locked(&device_domain_lock);
> >
> > -	list_for_each_entry(info, &domain->devices, link) {
> > -		struct pci_dev *pdev;
> > -
> > -		if (!info->dev || !dev_is_pci(info->dev))
> > -			continue;
> > -
> > -		pdev = to_pci_dev(info->dev);
> > -		if (pdev->ats_enabled) {
> > +	list_for_each_entry(info, &domain->devices, link)
> > +		if (info && info->ats_enabled) {
> >   			has_iotlb_device = true;
> >   			break;
> >   		}
> > +
> > +	if (!has_iotlb_device) {
> > +		struct subdev_domain_info *sinfo;
> > +
> > +		list_for_each_entry(sinfo, &domain->subdevices,
> link_domain) {
> > +			info = get_domain_info(sinfo->pdev);
> > +			if (info && info->ats_enabled) {
> > +				has_iotlb_device = true;
> > +				break;
> > +			}
> > +		}
> >   	}
> >
> >   	domain->has_iotlb_device = has_iotlb_device;
> > @@ -1555,25 +1564,37 @@ static void iommu_disable_dev_iotlb(struct
> device_domain_info *info)
> >   #endif
> >   }
> >
> > +static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
> > +				    u64 addr, unsigned int mask)
> > +{
> > +	u16 sid, qdep;
> > +
> > +	if (!info || !info->ats_enabled)
> > +		return;
> > +
> > +	sid = info->bus << 8 | info->devfn;
> > +	qdep = info->ats_qdep;
> > +	qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > +			   qdep, addr, mask);
> > +}
> > +
> >   static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
> >   				  u64 addr, unsigned mask)
> >   {
> > -	u16 sid, qdep;
> >   	unsigned long flags;
> >   	struct device_domain_info *info;
> > +	struct subdev_domain_info *sinfo;
> >
> >   	if (!domain->has_iotlb_device)
> >   		return;
> >
> >   	spin_lock_irqsave(&device_domain_lock, flags);
> > -	list_for_each_entry(info, &domain->devices, link) {
> > -		if (!info->ats_enabled)
> > -			continue;
> > +	list_for_each_entry(info, &domain->devices, link)
> > +		__iommu_flush_dev_iotlb(info, addr, mask);
> >
> > -		sid = info->bus << 8 | info->devfn;
> > -		qdep = info->ats_qdep;
> > -		qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > -				qdep, addr, mask);
> > +	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> > +		__iommu_flush_dev_iotlb(get_domain_info(sinfo->pdev),
> > +					addr, mask);
> >   	}
> 
> Nit:
> 	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> 		info = get_domain_info(sinfo->pdev);
> 		__iommu_flush_dev_iotlb(info, addr, mask);
> 	}

you are right. this should be better.

> Others look good to me.
>
> Acked-by: Lu Baolu <baolu.lu@linux.intel.com>
> 
> Best regards,
> baolu

Regards,
Yi Liu

> >   	spin_unlock_irqrestore(&device_domain_lock, flags);
> >   }
> >

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices
@ 2021-01-05  5:50       ` Liu, Yi L
  0 siblings, 0 replies; 26+ messages in thread
From: Liu, Yi L @ 2021-01-05  5:50 UTC (permalink / raw)
  To: Lu Baolu, joro, will
  Cc: Tian, Kevin, Raj, Ashok, Tian, Jun J, iommu, linux-kernel, Sun, Yi Y

Hi Baolu,

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Tuesday, December 29, 2020 4:42 PM
> 
> Hi Yi,
> 
> On 2020/12/29 11:25, Liu Yi L wrote:
> > iommu_flush_dev_iotlb() is called to invalidate caches on device. It only
> > loops the devices which are full-attached to the domain. For sub-devices,
> > this is ineffective. This results in invalid caching entries left on the
> > device. Fix it by adding loop for subdevices as well. Also, the domain->
> > has_iotlb_device needs to be updated when attaching to subdevices.
> >
> > Fixes: 67b8e02b5e761 ("iommu/vt-d: Aux-domain specific domain
> attach/detach")
> > Signed-off-by: Liu Yi L <yi.l.liu@intel.com>
> > ---
> >   drivers/iommu/intel/iommu.c | 53 ++++++++++++++++++++++++++---------
> --
> >   1 file changed, 37 insertions(+), 16 deletions(-)
> >
> > diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> > index d7720a836268..d48a60b61ba6 100644
> > --- a/drivers/iommu/intel/iommu.c
> > +++ b/drivers/iommu/intel/iommu.c
> > @@ -719,6 +719,8 @@ static int domain_update_device_node(struct
> dmar_domain *domain)
> >   	return nid;
> >   }
> >
> > +static void domain_update_iotlb(struct dmar_domain *domain);
> > +
> >   /* Some capabilities may be different across iommus */
> >   static void domain_update_iommu_cap(struct dmar_domain *domain)
> >   {
> > @@ -744,6 +746,8 @@ static void domain_update_iommu_cap(struct
> dmar_domain *domain)
> >   		domain->domain.geometry.aperture_end =
> __DOMAIN_MAX_ADDR(domain->gaw - 1);
> >   	else
> >   		domain->domain.geometry.aperture_end =
> __DOMAIN_MAX_ADDR(domain->gaw);
> > +
> > +	domain_update_iotlb(domain);
> >   }
> >
> >   struct context_entry *iommu_context_addr(struct intel_iommu *iommu,
> u8 bus,
> > @@ -1464,17 +1468,22 @@ static void domain_update_iotlb(struct
> dmar_domain *domain)
> >
> >   	assert_spin_locked(&device_domain_lock);
> >
> > -	list_for_each_entry(info, &domain->devices, link) {
> > -		struct pci_dev *pdev;
> > -
> > -		if (!info->dev || !dev_is_pci(info->dev))
> > -			continue;
> > -
> > -		pdev = to_pci_dev(info->dev);
> > -		if (pdev->ats_enabled) {
> > +	list_for_each_entry(info, &domain->devices, link)
> > +		if (info && info->ats_enabled) {
> >   			has_iotlb_device = true;
> >   			break;
> >   		}
> > +
> > +	if (!has_iotlb_device) {
> > +		struct subdev_domain_info *sinfo;
> > +
> > +		list_for_each_entry(sinfo, &domain->subdevices,
> link_domain) {
> > +			info = get_domain_info(sinfo->pdev);
> > +			if (info && info->ats_enabled) {
> > +				has_iotlb_device = true;
> > +				break;
> > +			}
> > +		}
> >   	}
> >
> >   	domain->has_iotlb_device = has_iotlb_device;
> > @@ -1555,25 +1564,37 @@ static void iommu_disable_dev_iotlb(struct
> device_domain_info *info)
> >   #endif
> >   }
> >
> > +static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
> > +				    u64 addr, unsigned int mask)
> > +{
> > +	u16 sid, qdep;
> > +
> > +	if (!info || !info->ats_enabled)
> > +		return;
> > +
> > +	sid = info->bus << 8 | info->devfn;
> > +	qdep = info->ats_qdep;
> > +	qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > +			   qdep, addr, mask);
> > +}
> > +
> >   static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
> >   				  u64 addr, unsigned mask)
> >   {
> > -	u16 sid, qdep;
> >   	unsigned long flags;
> >   	struct device_domain_info *info;
> > +	struct subdev_domain_info *sinfo;
> >
> >   	if (!domain->has_iotlb_device)
> >   		return;
> >
> >   	spin_lock_irqsave(&device_domain_lock, flags);
> > -	list_for_each_entry(info, &domain->devices, link) {
> > -		if (!info->ats_enabled)
> > -			continue;
> > +	list_for_each_entry(info, &domain->devices, link)
> > +		__iommu_flush_dev_iotlb(info, addr, mask);
> >
> > -		sid = info->bus << 8 | info->devfn;
> > -		qdep = info->ats_qdep;
> > -		qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > -				qdep, addr, mask);
> > +	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> > +		__iommu_flush_dev_iotlb(get_domain_info(sinfo->pdev),
> > +					addr, mask);
> >   	}
> 
> Nit:
> 	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> 		info = get_domain_info(sinfo->pdev);
> 		__iommu_flush_dev_iotlb(info, addr, mask);
> 	}

you are right. this should be better.

> Others look good to me.
>
> Acked-by: Lu Baolu <baolu.lu@linux.intel.com>
> 
> Best regards,
> baolu

Regards,
Yi Liu

> >   	spin_unlock_irqrestore(&device_domain_lock, flags);
> >   }
> >
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH v3 2/3] iommu/vt-d: Track device aux-attach with subdevice_domain_info
  2020-12-29  8:38     ` Lu Baolu
@ 2021-01-05  5:58       ` Liu, Yi L
  -1 siblings, 0 replies; 26+ messages in thread
From: Liu, Yi L @ 2021-01-05  5:58 UTC (permalink / raw)
  To: Lu Baolu, joro, will
  Cc: Tian, Kevin, jacob.jun.pan, Raj, Ashok, Tian, Jun J, Sun, Yi Y,
	iommu, linux-kernel, Zeng, Xin

Hi Baolu,

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Tuesday, December 29, 2020 4:38 PM
> 
> Hi Yi,
> 
> On 2020/12/29 11:25, Liu Yi L wrote:
> > In the existing code, loop all devices attached to a domain does not
> > include sub-devices attached via iommu_aux_attach_device().
> >
> > This was found by when I'm working on the belwo patch, There is no
>                                              ^^^^^
> below

nice catch. 😉

> > device in the domain->devices list, thus unable to get the cap and
> > ecap of iommu unit. But this domain actually has subdevice which is
> > attached via aux-manner. But it is tracked by domain. This patch is
> > going to fix it.
> >
> > https://lore.kernel.org/kvm/1599734733-6431-17-git-send-email-
> yi.l.liu@intel.com/
> >
> > And 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.
> >
> > Co-developed-by: Xin Zeng <xin.zeng@intel.com>
> > Signed-off-by: Xin Zeng <xin.zeng@intel.com>
> > Signed-off-by: Liu Yi L <yi.l.liu@intel.com>
> 
> Others look good to me.
> 
> Fixes: 67b8e02b5e761 ("iommu/vt-d: Aux-domain specific domain
> attach/detach")
> Acked-by: Lu Baolu <baolu.lu@linux.intel.com>

thanks,

Regards,
Yi Liu

> Best regards,
> baolu
> 
> > ---
> >   drivers/iommu/intel/iommu.c | 95 +++++++++++++++++++++++++++--------
> --
> >   include/linux/intel-iommu.h | 16 +++++--
> >   2 files changed, 82 insertions(+), 29 deletions(-)
> >
> > diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> > index 788119c5b021..d7720a836268 100644
> > --- a/drivers/iommu/intel/iommu.c
> > +++ b/drivers/iommu/intel/iommu.c
> > @@ -1877,6 +1877,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;
> >   }
> > @@ -2547,7 +2548,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);
> > @@ -4475,33 +4476,61 @@ is_aux_domain(struct device *dev, struct
> iommu_domain *domain)
> >   			domain->type == IOMMU_DOMAIN_UNMANAGED;
> >   }
> >
> > -static void auxiliary_link_device(struct dmar_domain *domain,
> > -				  struct device *dev)
> > +static inline struct subdev_domain_info *
> > +lookup_subdev_info(struct dmar_domain *domain, struct device *dev)
> > +{
> > +	struct subdev_domain_info *sinfo;
> > +
> > +	if (!list_empty(&domain->subdevices)) {
> > +		list_for_each_entry(sinfo, &domain->subdevices,
> link_domain) {
> > +			if (sinfo->pdev == dev)
> > +				return sinfo;
> > +		}
> > +	}
> > +
> > +	return NULL;
> > +}
> > +
> > +static int auxiliary_link_device(struct dmar_domain *domain,
> > +				 struct device *dev)
> >   {
> >   	struct device_domain_info *info = get_domain_info(dev);
> > +	struct subdev_domain_info *sinfo = lookup_subdev_info(domain,
> dev);
> >
> >   	assert_spin_locked(&device_domain_lock);
> >   	if (WARN_ON(!info))
> > -		return;
> > +		return -EINVAL;
> > +
> > +	if (!sinfo) {
> > +		sinfo = kzalloc(sizeof(*sinfo), GFP_ATOMIC);
> > +		sinfo->domain = domain;
> > +		sinfo->pdev = dev;
> > +		list_add(&sinfo->link_phys, &info->subdevices);
> > +		list_add(&sinfo->link_domain, &domain->subdevices);
> > +	}
> >
> > -	domain->auxd_refcnt++;
> > -	list_add(&domain->auxd, &info->auxiliary_domains);
> > +	return ++sinfo->users;
> >   }
> >
> > -static void auxiliary_unlink_device(struct dmar_domain *domain,
> > -				    struct device *dev)
> > +static int auxiliary_unlink_device(struct dmar_domain *domain,
> > +				   struct device *dev)
> >   {
> >   	struct device_domain_info *info = get_domain_info(dev);
> > +	struct subdev_domain_info *sinfo = lookup_subdev_info(domain,
> dev);
> > +	int ret;
> >
> >   	assert_spin_locked(&device_domain_lock);
> > -	if (WARN_ON(!info))
> > -		return;
> > +	if (WARN_ON(!info || !sinfo || sinfo->users <= 0))
> > +		return -EINVAL;
> >
> > -	list_del(&domain->auxd);
> > -	domain->auxd_refcnt--;
> > +	ret = --sinfo->users;
> > +	if (!ret) {
> > +		list_del(&sinfo->link_phys);
> > +		list_del(&sinfo->link_domain);
> > +		kfree(sinfo);
> > +	}
> >
> > -	if (!domain->auxd_refcnt && domain->default_pasid > 0)
> > -		ioasid_put(domain->default_pasid);
> > +	return ret;
> >   }
> >
> >   static int aux_domain_add_dev(struct dmar_domain *domain,
> > @@ -4530,6 +4559,19 @@ static int aux_domain_add_dev(struct
> dmar_domain *domain,
> >   	}
> >
> >   	spin_lock_irqsave(&device_domain_lock, flags);
> > +	ret = auxiliary_link_device(domain, dev);
> > +	if (ret <= 0)
> > +		goto link_failed;
> > +
> > +	/*
> > +	 * Subdevices from the same physical device can be attached to the
> > +	 * same domain. For such cases, only the first subdevice attachment
> > +	 * needs to go through the full steps in this function. So if ret >
> > +	 * 1, just goto out.
> > +	 */
> > +	if (ret > 1)
> > +		goto out;
> > +
> >   	/*
> >   	 * iommu->lock must be held to attach domain to iommu and setup
> the
> >   	 * pasid entry for second level translation.
> > @@ -4548,10 +4590,9 @@ static int aux_domain_add_dev(struct
> dmar_domain *domain,
> >   						     domain->default_pasid);
> >   	if (ret)
> >   		goto table_failed;
> > -	spin_unlock(&iommu->lock);
> > -
> > -	auxiliary_link_device(domain, dev);
> >
> > +	spin_unlock(&iommu->lock);
> > +out:
> >   	spin_unlock_irqrestore(&device_domain_lock, flags);
> >
> >   	return 0;
> > @@ -4560,8 +4601,10 @@ static int aux_domain_add_dev(struct
> dmar_domain *domain,
> >   	domain_detach_iommu(domain, iommu);
> >   attach_failed:
> >   	spin_unlock(&iommu->lock);
> > +	auxiliary_unlink_device(domain, dev);
> > +link_failed:
> >   	spin_unlock_irqrestore(&device_domain_lock, flags);
> > -	if (!domain->auxd_refcnt && domain->default_pasid > 0)
> > +	if (list_empty(&domain->subdevices) && domain->default_pasid > 0)
> >   		ioasid_put(domain->default_pasid);
> >
> >   	return ret;
> > @@ -4581,14 +4624,18 @@ static void aux_domain_remove_dev(struct
> dmar_domain *domain,
> >   	info = get_domain_info(dev);
> >   	iommu = info->iommu;
> >
> > -	auxiliary_unlink_device(domain, dev);
> > -
> > -	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, dev)) {
> > +		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 (list_empty(&domain->subdevices) && domain->default_pasid > 0)
> > +		ioasid_put(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..09c6a0bf3892 100644
> > --- a/include/linux/intel-iommu.h
> > +++ b/include/linux/intel-iommu.h
> > @@ -533,11 +533,10 @@ struct dmar_domain {
> >   					/* Domain ids per IOMMU. Use u16
> since
> >   					 * domain ids are 16 bit wide
> according
> >   					 * to VT-d spec, section 9.3 */
> > -	unsigned int	auxd_refcnt;	/* Refcount of auxiliary attaching */
> >
> >   	bool has_iotlb_device;
> >   	struct list_head devices;	/* all devices' list */
> > -	struct list_head auxd;		/* link to device's auxiliary list */
> > +	struct list_head subdevices;	/* all subdevices' list */
> >   	struct iova_domain iovad;	/* iova's that belong to this domain
> */
> >
> >   	struct dma_pte	*pgd;		/* virtual address */
> > @@ -610,14 +609,21 @@ struct intel_iommu {
> >   	struct dmar_drhd_unit *drhd;
> >   };
> >
> > +/* Per subdevice private data */
> > +struct subdev_domain_info {
> > +	struct list_head link_phys;	/* link to phys device siblings */
> > +	struct list_head link_domain;	/* link to domain siblings */
> > +	struct device *pdev;		/* physical device derived from */
> > +	struct dmar_domain *domain;	/* aux-domain */
> > +	int users;			/* user count */
> > +};
> > +
> >   /* PCI domain-device relationship */
> >   struct device_domain_info {
> >   	struct list_head link;	/* link to domain siblings */
> >   	struct list_head global; /* link to global list */
> >   	struct list_head table;	/* link to pasid table */
> > -	struct list_head auxiliary_domains; /* auxiliary domains
> > -					     * attached to this device
> > -					     */
> > +	struct list_head subdevices; /* subdevices sibling */
> >   	u32 segment;		/* PCI segment number */
> >   	u8 bus;			/* PCI bus number */
> >   	u8 devfn;		/* PCI devfn number */
> >

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH v3 2/3] iommu/vt-d: Track device aux-attach with subdevice_domain_info
@ 2021-01-05  5:58       ` Liu, Yi L
  0 siblings, 0 replies; 26+ messages in thread
From: Liu, Yi L @ 2021-01-05  5:58 UTC (permalink / raw)
  To: Lu Baolu, joro, will
  Cc: Tian, Kevin, Raj, Ashok, Tian, Jun J, iommu, linux-kernel, Sun, Yi Y

Hi Baolu,

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Tuesday, December 29, 2020 4:38 PM
> 
> Hi Yi,
> 
> On 2020/12/29 11:25, Liu Yi L wrote:
> > In the existing code, loop all devices attached to a domain does not
> > include sub-devices attached via iommu_aux_attach_device().
> >
> > This was found by when I'm working on the belwo patch, There is no
>                                              ^^^^^
> below

nice catch. 😉

> > device in the domain->devices list, thus unable to get the cap and
> > ecap of iommu unit. But this domain actually has subdevice which is
> > attached via aux-manner. But it is tracked by domain. This patch is
> > going to fix it.
> >
> > https://lore.kernel.org/kvm/1599734733-6431-17-git-send-email-
> yi.l.liu@intel.com/
> >
> > And 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.
> >
> > Co-developed-by: Xin Zeng <xin.zeng@intel.com>
> > Signed-off-by: Xin Zeng <xin.zeng@intel.com>
> > Signed-off-by: Liu Yi L <yi.l.liu@intel.com>
> 
> Others look good to me.
> 
> Fixes: 67b8e02b5e761 ("iommu/vt-d: Aux-domain specific domain
> attach/detach")
> Acked-by: Lu Baolu <baolu.lu@linux.intel.com>

thanks,

Regards,
Yi Liu

> Best regards,
> baolu
> 
> > ---
> >   drivers/iommu/intel/iommu.c | 95 +++++++++++++++++++++++++++--------
> --
> >   include/linux/intel-iommu.h | 16 +++++--
> >   2 files changed, 82 insertions(+), 29 deletions(-)
> >
> > diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> > index 788119c5b021..d7720a836268 100644
> > --- a/drivers/iommu/intel/iommu.c
> > +++ b/drivers/iommu/intel/iommu.c
> > @@ -1877,6 +1877,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;
> >   }
> > @@ -2547,7 +2548,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);
> > @@ -4475,33 +4476,61 @@ is_aux_domain(struct device *dev, struct
> iommu_domain *domain)
> >   			domain->type == IOMMU_DOMAIN_UNMANAGED;
> >   }
> >
> > -static void auxiliary_link_device(struct dmar_domain *domain,
> > -				  struct device *dev)
> > +static inline struct subdev_domain_info *
> > +lookup_subdev_info(struct dmar_domain *domain, struct device *dev)
> > +{
> > +	struct subdev_domain_info *sinfo;
> > +
> > +	if (!list_empty(&domain->subdevices)) {
> > +		list_for_each_entry(sinfo, &domain->subdevices,
> link_domain) {
> > +			if (sinfo->pdev == dev)
> > +				return sinfo;
> > +		}
> > +	}
> > +
> > +	return NULL;
> > +}
> > +
> > +static int auxiliary_link_device(struct dmar_domain *domain,
> > +				 struct device *dev)
> >   {
> >   	struct device_domain_info *info = get_domain_info(dev);
> > +	struct subdev_domain_info *sinfo = lookup_subdev_info(domain,
> dev);
> >
> >   	assert_spin_locked(&device_domain_lock);
> >   	if (WARN_ON(!info))
> > -		return;
> > +		return -EINVAL;
> > +
> > +	if (!sinfo) {
> > +		sinfo = kzalloc(sizeof(*sinfo), GFP_ATOMIC);
> > +		sinfo->domain = domain;
> > +		sinfo->pdev = dev;
> > +		list_add(&sinfo->link_phys, &info->subdevices);
> > +		list_add(&sinfo->link_domain, &domain->subdevices);
> > +	}
> >
> > -	domain->auxd_refcnt++;
> > -	list_add(&domain->auxd, &info->auxiliary_domains);
> > +	return ++sinfo->users;
> >   }
> >
> > -static void auxiliary_unlink_device(struct dmar_domain *domain,
> > -				    struct device *dev)
> > +static int auxiliary_unlink_device(struct dmar_domain *domain,
> > +				   struct device *dev)
> >   {
> >   	struct device_domain_info *info = get_domain_info(dev);
> > +	struct subdev_domain_info *sinfo = lookup_subdev_info(domain,
> dev);
> > +	int ret;
> >
> >   	assert_spin_locked(&device_domain_lock);
> > -	if (WARN_ON(!info))
> > -		return;
> > +	if (WARN_ON(!info || !sinfo || sinfo->users <= 0))
> > +		return -EINVAL;
> >
> > -	list_del(&domain->auxd);
> > -	domain->auxd_refcnt--;
> > +	ret = --sinfo->users;
> > +	if (!ret) {
> > +		list_del(&sinfo->link_phys);
> > +		list_del(&sinfo->link_domain);
> > +		kfree(sinfo);
> > +	}
> >
> > -	if (!domain->auxd_refcnt && domain->default_pasid > 0)
> > -		ioasid_put(domain->default_pasid);
> > +	return ret;
> >   }
> >
> >   static int aux_domain_add_dev(struct dmar_domain *domain,
> > @@ -4530,6 +4559,19 @@ static int aux_domain_add_dev(struct
> dmar_domain *domain,
> >   	}
> >
> >   	spin_lock_irqsave(&device_domain_lock, flags);
> > +	ret = auxiliary_link_device(domain, dev);
> > +	if (ret <= 0)
> > +		goto link_failed;
> > +
> > +	/*
> > +	 * Subdevices from the same physical device can be attached to the
> > +	 * same domain. For such cases, only the first subdevice attachment
> > +	 * needs to go through the full steps in this function. So if ret >
> > +	 * 1, just goto out.
> > +	 */
> > +	if (ret > 1)
> > +		goto out;
> > +
> >   	/*
> >   	 * iommu->lock must be held to attach domain to iommu and setup
> the
> >   	 * pasid entry for second level translation.
> > @@ -4548,10 +4590,9 @@ static int aux_domain_add_dev(struct
> dmar_domain *domain,
> >   						     domain->default_pasid);
> >   	if (ret)
> >   		goto table_failed;
> > -	spin_unlock(&iommu->lock);
> > -
> > -	auxiliary_link_device(domain, dev);
> >
> > +	spin_unlock(&iommu->lock);
> > +out:
> >   	spin_unlock_irqrestore(&device_domain_lock, flags);
> >
> >   	return 0;
> > @@ -4560,8 +4601,10 @@ static int aux_domain_add_dev(struct
> dmar_domain *domain,
> >   	domain_detach_iommu(domain, iommu);
> >   attach_failed:
> >   	spin_unlock(&iommu->lock);
> > +	auxiliary_unlink_device(domain, dev);
> > +link_failed:
> >   	spin_unlock_irqrestore(&device_domain_lock, flags);
> > -	if (!domain->auxd_refcnt && domain->default_pasid > 0)
> > +	if (list_empty(&domain->subdevices) && domain->default_pasid > 0)
> >   		ioasid_put(domain->default_pasid);
> >
> >   	return ret;
> > @@ -4581,14 +4624,18 @@ static void aux_domain_remove_dev(struct
> dmar_domain *domain,
> >   	info = get_domain_info(dev);
> >   	iommu = info->iommu;
> >
> > -	auxiliary_unlink_device(domain, dev);
> > -
> > -	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, dev)) {
> > +		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 (list_empty(&domain->subdevices) && domain->default_pasid > 0)
> > +		ioasid_put(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..09c6a0bf3892 100644
> > --- a/include/linux/intel-iommu.h
> > +++ b/include/linux/intel-iommu.h
> > @@ -533,11 +533,10 @@ struct dmar_domain {
> >   					/* Domain ids per IOMMU. Use u16
> since
> >   					 * domain ids are 16 bit wide
> according
> >   					 * to VT-d spec, section 9.3 */
> > -	unsigned int	auxd_refcnt;	/* Refcount of auxiliary attaching */
> >
> >   	bool has_iotlb_device;
> >   	struct list_head devices;	/* all devices' list */
> > -	struct list_head auxd;		/* link to device's auxiliary list */
> > +	struct list_head subdevices;	/* all subdevices' list */
> >   	struct iova_domain iovad;	/* iova's that belong to this domain
> */
> >
> >   	struct dma_pte	*pgd;		/* virtual address */
> > @@ -610,14 +609,21 @@ struct intel_iommu {
> >   	struct dmar_drhd_unit *drhd;
> >   };
> >
> > +/* Per subdevice private data */
> > +struct subdev_domain_info {
> > +	struct list_head link_phys;	/* link to phys device siblings */
> > +	struct list_head link_domain;	/* link to domain siblings */
> > +	struct device *pdev;		/* physical device derived from */
> > +	struct dmar_domain *domain;	/* aux-domain */
> > +	int users;			/* user count */
> > +};
> > +
> >   /* PCI domain-device relationship */
> >   struct device_domain_info {
> >   	struct list_head link;	/* link to domain siblings */
> >   	struct list_head global; /* link to global list */
> >   	struct list_head table;	/* link to pasid table */
> > -	struct list_head auxiliary_domains; /* auxiliary domains
> > -					     * attached to this device
> > -					     */
> > +	struct list_head subdevices; /* subdevices sibling */
> >   	u32 segment;		/* PCI segment number */
> >   	u8 bus;			/* PCI bus number */
> >   	u8 devfn;		/* PCI devfn number */
> >
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices
  2020-12-29  3:25   ` Liu Yi L
  (?)
@ 2021-01-05 12:14     ` Dan Carpenter
  -1 siblings, 0 replies; 26+ messages in thread
From: Dan Carpenter @ 2021-01-05 12:14 UTC (permalink / raw)
  To: kbuild, Liu Yi L, baolu.lu, joro, will
  Cc: kevin.tian, kbuild-all, lkp, jun.j.tian, iommu, yi.y.sun, ashok.raj

[-- Attachment #1: Type: text/plain, Size: 3729 bytes --]

Hi Liu,

url:    https://github.com/0day-ci/linux/commits/Liu-Yi-L/iommu-vt-d-Misc-fixes-on-scalable-mode/20201229-113203
base:    5c8fe583cce542aa0b84adc939ce85293de36e5e
config: i386-randconfig-m021-20201229 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>

New smatch warnings:
drivers/iommu/intel/iommu.c:1471 domain_update_iotlb() error: we previously assumed 'info' could be null (see line 1472)

Old smatch warnings:
drivers/iommu/intel/iommu.c:920 device_to_iommu() error: we previously assumed 'pdev' could be null (see line 893)
drivers/iommu/intel/iommu.c:3764 intel_iommu_add() warn: should '(1 << sp)' be a 64 bit type?

vim +/info +1471 drivers/iommu/intel/iommu.c

0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1464  static void domain_update_iotlb(struct dmar_domain *domain)
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1465  {
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1466  	struct device_domain_info *info;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1467  	bool has_iotlb_device = false;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1468  
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1469  	assert_spin_locked(&device_domain_lock);
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1470  
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29 @1471  	list_for_each_entry(info, &domain->devices, link)
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29 @1472  		if (info && info->ats_enabled) {
                                                                                            ^^^^
"info" is the list iterator so it can't ever be NULL.  Just delete the
NULL check.

1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1473  			has_iotlb_device = true;
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1474  			break;
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1475  		}
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1476  
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1477  	if (!has_iotlb_device) {
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1478  		struct subdev_domain_info *sinfo;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1479  
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1480  		list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1481  			info = get_domain_info(sinfo->pdev);
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1482  			if (info && info->ats_enabled) {
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1483  				has_iotlb_device = true;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1484  				break;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1485  			}
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1486  		}
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1487  	}
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1488  
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1489  	domain->has_iotlb_device = has_iotlb_device;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1490  }

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 35310 bytes --]

[-- Attachment #3: Type: text/plain, Size: 156 bytes --]

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

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices
@ 2021-01-05 12:14     ` Dan Carpenter
  0 siblings, 0 replies; 26+ messages in thread
From: Dan Carpenter @ 2021-01-05 12:14 UTC (permalink / raw)
  To: kbuild

[-- Attachment #1: Type: text/plain, Size: 3786 bytes --]

Hi Liu,

url:    https://github.com/0day-ci/linux/commits/Liu-Yi-L/iommu-vt-d-Misc-fixes-on-scalable-mode/20201229-113203
base:    5c8fe583cce542aa0b84adc939ce85293de36e5e
config: i386-randconfig-m021-20201229 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>

New smatch warnings:
drivers/iommu/intel/iommu.c:1471 domain_update_iotlb() error: we previously assumed 'info' could be null (see line 1472)

Old smatch warnings:
drivers/iommu/intel/iommu.c:920 device_to_iommu() error: we previously assumed 'pdev' could be null (see line 893)
drivers/iommu/intel/iommu.c:3764 intel_iommu_add() warn: should '(1 << sp)' be a 64 bit type?

vim +/info +1471 drivers/iommu/intel/iommu.c

0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1464  static void domain_update_iotlb(struct dmar_domain *domain)
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1465  {
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1466  	struct device_domain_info *info;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1467  	bool has_iotlb_device = false;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1468  
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1469  	assert_spin_locked(&device_domain_lock);
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1470  
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29 @1471  	list_for_each_entry(info, &domain->devices, link)
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29 @1472  		if (info && info->ats_enabled) {
                                                                                            ^^^^
"info" is the list iterator so it can't ever be NULL.  Just delete the
NULL check.

1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1473  			has_iotlb_device = true;
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1474  			break;
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1475  		}
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1476  
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1477  	if (!has_iotlb_device) {
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1478  		struct subdev_domain_info *sinfo;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1479  
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1480  		list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1481  			info = get_domain_info(sinfo->pdev);
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1482  			if (info && info->ats_enabled) {
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1483  				has_iotlb_device = true;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1484  				break;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1485  			}
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1486  		}
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1487  	}
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1488  
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1489  	domain->has_iotlb_device = has_iotlb_device;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1490  }

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 35310 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices
@ 2021-01-05 12:14     ` Dan Carpenter
  0 siblings, 0 replies; 26+ messages in thread
From: Dan Carpenter @ 2021-01-05 12:14 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 3786 bytes --]

Hi Liu,

url:    https://github.com/0day-ci/linux/commits/Liu-Yi-L/iommu-vt-d-Misc-fixes-on-scalable-mode/20201229-113203
base:    5c8fe583cce542aa0b84adc939ce85293de36e5e
config: i386-randconfig-m021-20201229 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>

New smatch warnings:
drivers/iommu/intel/iommu.c:1471 domain_update_iotlb() error: we previously assumed 'info' could be null (see line 1472)

Old smatch warnings:
drivers/iommu/intel/iommu.c:920 device_to_iommu() error: we previously assumed 'pdev' could be null (see line 893)
drivers/iommu/intel/iommu.c:3764 intel_iommu_add() warn: should '(1 << sp)' be a 64 bit type?

vim +/info +1471 drivers/iommu/intel/iommu.c

0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1464  static void domain_update_iotlb(struct dmar_domain *domain)
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1465  {
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1466  	struct device_domain_info *info;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1467  	bool has_iotlb_device = false;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1468  
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1469  	assert_spin_locked(&device_domain_lock);
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1470  
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29 @1471  	list_for_each_entry(info, &domain->devices, link)
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29 @1472  		if (info && info->ats_enabled) {
                                                                                            ^^^^
"info" is the list iterator so it can't ever be NULL.  Just delete the
NULL check.

1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1473  			has_iotlb_device = true;
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1474  			break;
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1475  		}
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1476  
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1477  	if (!has_iotlb_device) {
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1478  		struct subdev_domain_info *sinfo;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1479  
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1480  		list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1481  			info = get_domain_info(sinfo->pdev);
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1482  			if (info && info->ats_enabled) {
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1483  				has_iotlb_device = true;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1484  				break;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1485  			}
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1486  		}
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1487  	}
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1488  
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1489  	domain->has_iotlb_device = has_iotlb_device;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1490  }

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 35310 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices
  2021-01-05  5:50       ` Liu, Yi L
@ 2021-01-05 17:23         ` Will Deacon
  -1 siblings, 0 replies; 26+ messages in thread
From: Will Deacon @ 2021-01-05 17:23 UTC (permalink / raw)
  To: Liu, Yi L
  Cc: Lu Baolu, joro, Tian, Kevin, jacob.jun.pan, Raj, Ashok, Tian,
	Jun J, Sun, Yi Y, iommu, linux-kernel

On Tue, Jan 05, 2021 at 05:50:22AM +0000, Liu, Yi L wrote:
> > > +static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
> > > +				    u64 addr, unsigned int mask)
> > > +{
> > > +	u16 sid, qdep;
> > > +
> > > +	if (!info || !info->ats_enabled)
> > > +		return;
> > > +
> > > +	sid = info->bus << 8 | info->devfn;
> > > +	qdep = info->ats_qdep;
> > > +	qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > > +			   qdep, addr, mask);
> > > +}
> > > +
> > >   static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
> > >   				  u64 addr, unsigned mask)
> > >   {
> > > -	u16 sid, qdep;
> > >   	unsigned long flags;
> > >   	struct device_domain_info *info;
> > > +	struct subdev_domain_info *sinfo;
> > >
> > >   	if (!domain->has_iotlb_device)
> > >   		return;
> > >
> > >   	spin_lock_irqsave(&device_domain_lock, flags);
> > > -	list_for_each_entry(info, &domain->devices, link) {
> > > -		if (!info->ats_enabled)
> > > -			continue;
> > > +	list_for_each_entry(info, &domain->devices, link)
> > > +		__iommu_flush_dev_iotlb(info, addr, mask);
> > >
> > > -		sid = info->bus << 8 | info->devfn;
> > > -		qdep = info->ats_qdep;
> > > -		qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > > -				qdep, addr, mask);
> > > +	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> > > +		__iommu_flush_dev_iotlb(get_domain_info(sinfo->pdev),
> > > +					addr, mask);
> > >   	}
> > 
> > Nit:
> > 	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> > 		info = get_domain_info(sinfo->pdev);
> > 		__iommu_flush_dev_iotlb(info, addr, mask);
> > 	}
> 
> you are right. this should be better.

Please can you post a v4, with Lu's acks and the issue reported by Dan fixed
too?

Thanks,

Will

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices
@ 2021-01-05 17:23         ` Will Deacon
  0 siblings, 0 replies; 26+ messages in thread
From: Will Deacon @ 2021-01-05 17:23 UTC (permalink / raw)
  To: Liu, Yi L
  Cc: Tian, Kevin, Raj, Ashok, Tian, Jun J, iommu, linux-kernel, Sun, Yi Y

On Tue, Jan 05, 2021 at 05:50:22AM +0000, Liu, Yi L wrote:
> > > +static void __iommu_flush_dev_iotlb(struct device_domain_info *info,
> > > +				    u64 addr, unsigned int mask)
> > > +{
> > > +	u16 sid, qdep;
> > > +
> > > +	if (!info || !info->ats_enabled)
> > > +		return;
> > > +
> > > +	sid = info->bus << 8 | info->devfn;
> > > +	qdep = info->ats_qdep;
> > > +	qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > > +			   qdep, addr, mask);
> > > +}
> > > +
> > >   static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
> > >   				  u64 addr, unsigned mask)
> > >   {
> > > -	u16 sid, qdep;
> > >   	unsigned long flags;
> > >   	struct device_domain_info *info;
> > > +	struct subdev_domain_info *sinfo;
> > >
> > >   	if (!domain->has_iotlb_device)
> > >   		return;
> > >
> > >   	spin_lock_irqsave(&device_domain_lock, flags);
> > > -	list_for_each_entry(info, &domain->devices, link) {
> > > -		if (!info->ats_enabled)
> > > -			continue;
> > > +	list_for_each_entry(info, &domain->devices, link)
> > > +		__iommu_flush_dev_iotlb(info, addr, mask);
> > >
> > > -		sid = info->bus << 8 | info->devfn;
> > > -		qdep = info->ats_qdep;
> > > -		qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > > -				qdep, addr, mask);
> > > +	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> > > +		__iommu_flush_dev_iotlb(get_domain_info(sinfo->pdev),
> > > +					addr, mask);
> > >   	}
> > 
> > Nit:
> > 	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> > 		info = get_domain_info(sinfo->pdev);
> > 		__iommu_flush_dev_iotlb(info, addr, mask);
> > 	}
> 
> you are right. this should be better.

Please can you post a v4, with Lu's acks and the issue reported by Dan fixed
too?

Thanks,

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

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices
  2021-01-05 17:23         ` Will Deacon
@ 2021-01-07  5:22           ` Liu, Yi L
  -1 siblings, 0 replies; 26+ messages in thread
From: Liu, Yi L @ 2021-01-07  5:22 UTC (permalink / raw)
  To: Will Deacon
  Cc: Lu Baolu, joro, Tian, Kevin, jacob.jun.pan, Raj, Ashok, Tian,
	Jun J, Sun, Yi Y, iommu, linux-kernel

Hi Will,

> From: Will Deacon <will@kernel.org>
> Sent: Wednesday, January 6, 2021 1:24 AM
> 
> On Tue, Jan 05, 2021 at 05:50:22AM +0000, Liu, Yi L wrote:
> > > > +static void __iommu_flush_dev_iotlb(struct device_domain_info
> *info,
> > > > +				    u64 addr, unsigned int mask)
> > > > +{
> > > > +	u16 sid, qdep;
> > > > +
> > > > +	if (!info || !info->ats_enabled)
> > > > +		return;
> > > > +
> > > > +	sid = info->bus << 8 | info->devfn;
> > > > +	qdep = info->ats_qdep;
> > > > +	qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > > > +			   qdep, addr, mask);
> > > > +}
> > > > +
> > > >   static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
> > > >   				  u64 addr, unsigned mask)
> > > >   {
> > > > -	u16 sid, qdep;
> > > >   	unsigned long flags;
> > > >   	struct device_domain_info *info;
> > > > +	struct subdev_domain_info *sinfo;
> > > >
> > > >   	if (!domain->has_iotlb_device)
> > > >   		return;
> > > >
> > > >   	spin_lock_irqsave(&device_domain_lock, flags);
> > > > -	list_for_each_entry(info, &domain->devices, link) {
> > > > -		if (!info->ats_enabled)
> > > > -			continue;
> > > > +	list_for_each_entry(info, &domain->devices, link)
> > > > +		__iommu_flush_dev_iotlb(info, addr, mask);
> > > >
> > > > -		sid = info->bus << 8 | info->devfn;
> > > > -		qdep = info->ats_qdep;
> > > > -		qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > > > -				qdep, addr, mask);
> > > > +	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> > > > +		__iommu_flush_dev_iotlb(get_domain_info(sinfo->pdev),
> > > > +					addr, mask);
> > > >   	}
> > >
> > > Nit:
> > > 	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> > > 		info = get_domain_info(sinfo->pdev);
> > > 		__iommu_flush_dev_iotlb(info, addr, mask);
> > > 	}
> >
> > you are right. this should be better.
> 
> Please can you post a v4, with Lu's acks and the issue reported by Dan fixed
> too?

sure, will send out later.

Regards,
Yi Liu

> Thanks,
> 
> Will

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices
@ 2021-01-07  5:22           ` Liu, Yi L
  0 siblings, 0 replies; 26+ messages in thread
From: Liu, Yi L @ 2021-01-07  5:22 UTC (permalink / raw)
  To: Will Deacon
  Cc: Tian, Kevin, Raj, Ashok, Tian, Jun J, iommu, linux-kernel, Sun, Yi Y

Hi Will,

> From: Will Deacon <will@kernel.org>
> Sent: Wednesday, January 6, 2021 1:24 AM
> 
> On Tue, Jan 05, 2021 at 05:50:22AM +0000, Liu, Yi L wrote:
> > > > +static void __iommu_flush_dev_iotlb(struct device_domain_info
> *info,
> > > > +				    u64 addr, unsigned int mask)
> > > > +{
> > > > +	u16 sid, qdep;
> > > > +
> > > > +	if (!info || !info->ats_enabled)
> > > > +		return;
> > > > +
> > > > +	sid = info->bus << 8 | info->devfn;
> > > > +	qdep = info->ats_qdep;
> > > > +	qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > > > +			   qdep, addr, mask);
> > > > +}
> > > > +
> > > >   static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
> > > >   				  u64 addr, unsigned mask)
> > > >   {
> > > > -	u16 sid, qdep;
> > > >   	unsigned long flags;
> > > >   	struct device_domain_info *info;
> > > > +	struct subdev_domain_info *sinfo;
> > > >
> > > >   	if (!domain->has_iotlb_device)
> > > >   		return;
> > > >
> > > >   	spin_lock_irqsave(&device_domain_lock, flags);
> > > > -	list_for_each_entry(info, &domain->devices, link) {
> > > > -		if (!info->ats_enabled)
> > > > -			continue;
> > > > +	list_for_each_entry(info, &domain->devices, link)
> > > > +		__iommu_flush_dev_iotlb(info, addr, mask);
> > > >
> > > > -		sid = info->bus << 8 | info->devfn;
> > > > -		qdep = info->ats_qdep;
> > > > -		qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
> > > > -				qdep, addr, mask);
> > > > +	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> > > > +		__iommu_flush_dev_iotlb(get_domain_info(sinfo->pdev),
> > > > +					addr, mask);
> > > >   	}
> > >
> > > Nit:
> > > 	list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
> > > 		info = get_domain_info(sinfo->pdev);
> > > 		__iommu_flush_dev_iotlb(info, addr, mask);
> > > 	}
> >
> > you are right. this should be better.
> 
> Please can you post a v4, with Lu's acks and the issue reported by Dan fixed
> too?

sure, will send out later.

Regards,
Yi Liu

> Thanks,
> 
> Will
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices
@ 2020-12-29  8:42 kernel test robot
  0 siblings, 0 replies; 26+ messages in thread
From: kernel test robot @ 2020-12-29  8:42 UTC (permalink / raw)
  To: kbuild

[-- Attachment #1: Type: text/plain, Size: 4655 bytes --]

CC: kbuild-all(a)lists.01.org
In-Reply-To: <20201229032513.486395-4-yi.l.liu@intel.com>
References: <20201229032513.486395-4-yi.l.liu@intel.com>
TO: Liu Yi L <yi.l.liu@intel.com>
TO: baolu.lu(a)linux.intel.com
TO: joro(a)8bytes.org
TO: will(a)kernel.org
CC: kevin.tian(a)intel.com
CC: jacob.jun.pan(a)linux.intel.com
CC: ashok.raj(a)intel.com
CC: yi.l.liu(a)intel.com
CC: jun.j.tian(a)intel.com
CC: yi.y.sun(a)intel.com
CC: iommu(a)lists.linux-foundation.org

Hi Liu,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on v5.11-rc1]
[also build test WARNING on next-20201223]
[cannot apply to iommu/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Liu-Yi-L/iommu-vt-d-Misc-fixes-on-scalable-mode/20201229-113203
base:    5c8fe583cce542aa0b84adc939ce85293de36e5e
:::::: branch date: 5 hours ago
:::::: commit date: 5 hours ago
config: i386-randconfig-m021-20201229 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>

New smatch warnings:
drivers/iommu/intel/iommu.c:1471 domain_update_iotlb() error: we previously assumed 'info' could be null (see line 1472)

Old smatch warnings:
drivers/iommu/intel/iommu.c:920 device_to_iommu() error: we previously assumed 'pdev' could be null (see line 893)
drivers/iommu/intel/iommu.c:3764 intel_iommu_add() warn: should '(1 << sp)' be a 64 bit type?

vim +/info +1471 drivers/iommu/intel/iommu.c

93a23a7271dfb81 drivers/pci/intel-iommu.c   Yu Zhao    2009-05-18  1463  
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1464  static void domain_update_iotlb(struct dmar_domain *domain)
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1465  {
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1466  	struct device_domain_info *info;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1467  	bool has_iotlb_device = false;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1468  
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1469  	assert_spin_locked(&device_domain_lock);
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1470  
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29 @1471  	list_for_each_entry(info, &domain->devices, link)
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29 @1472  		if (info && info->ats_enabled) {
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1473  			has_iotlb_device = true;
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1474  			break;
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1475  		}
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1476  
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1477  	if (!has_iotlb_device) {
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1478  		struct subdev_domain_info *sinfo;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1479  
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1480  		list_for_each_entry(sinfo, &domain->subdevices, link_domain) {
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1481  			info = get_domain_info(sinfo->pdev);
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1482  			if (info && info->ats_enabled) {
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1483  				has_iotlb_device = true;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1484  				break;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1485  			}
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1486  		}
1aaf68f8927fb5c drivers/iommu/intel/iommu.c Liu Yi L   2020-12-29  1487  	}
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1488  
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1489  	domain->has_iotlb_device = has_iotlb_device;
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1490  }
0824c5920b16fe1 drivers/iommu/intel-iommu.c Omer Peleg 2016-04-20  1491  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 35310 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2021-01-07  5:23 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-29  3:25 [PATCH v3 0/3] iommu/vt-d: Misc fixes on scalable mode Liu Yi L
2020-12-29  3:25 ` Liu Yi L
2020-12-29  3:25 ` [PATCH v3 1/3] iommu/vt-d: Move intel_iommu info from struct intel_svm to struct intel_svm_dev Liu Yi L
2020-12-29  3:25   ` Liu Yi L
2020-12-29  8:34   ` Lu Baolu
2020-12-29  8:34     ` Lu Baolu
2020-12-29  3:25 ` [PATCH v3 2/3] iommu/vt-d: Track device aux-attach with subdevice_domain_info Liu Yi L
2020-12-29  3:25   ` Liu Yi L
2020-12-29  8:38   ` Lu Baolu
2020-12-29  8:38     ` Lu Baolu
2021-01-05  5:58     ` Liu, Yi L
2021-01-05  5:58       ` Liu, Yi L
2020-12-29  3:25 ` [PATCH v3 3/3] iommu/vt-d: Fix ineffective devTLB invalidation for subdevices Liu Yi L
2020-12-29  3:25   ` Liu Yi L
2020-12-29  8:41   ` Lu Baolu
2020-12-29  8:41     ` Lu Baolu
2021-01-05  5:50     ` Liu, Yi L
2021-01-05  5:50       ` Liu, Yi L
2021-01-05 17:23       ` Will Deacon
2021-01-05 17:23         ` Will Deacon
2021-01-07  5:22         ` Liu, Yi L
2021-01-07  5:22           ` Liu, Yi L
2021-01-05 12:14   ` Dan Carpenter
2021-01-05 12:14     ` Dan Carpenter
2021-01-05 12:14     ` Dan Carpenter
2020-12-29  8:42 kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.