lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20231017032045.114868-7-tina.zhang@intel.com>
Date:   Tue, 17 Oct 2023 11:20:38 +0800
From:   Tina Zhang <tina.zhang@...el.com>
To:     iommu@...ts.linux.dev, linux-kernel@...r.kernel.org,
        kvm@...r.kernel.org
Cc:     David Woodhouse <dwmw2@...radead.org>,
        Lu Baolu <baolu.lu@...ux.intel.com>,
        Joerg Roedel <joro@...tes.org>, Jason Gunthorpe <jgg@...pe.ca>,
        Kevin Tian <kevin.tian@...el.com>,
        Tina Zhang <tina.zhang@...el.com>
Subject: [RFC PATCH 05/12] iommu/vt-d: Retire struct intel_svm_dev

The struct dev_pasid_info is used by IOMMU domain to keep pasid info of
attached device. For sva domain, there is another structure which keeps
info of attached device, named intel_svm_dev. Instead of using two structs
to keep attached device info separately, sva domain should use struct
dev_pasid to centralize info of attach device. To achieve this, rcu/sid/
qdep fields are moved from struct intel_svm_dev into struct
dev_pasid_info and then sva domain switches to use dev_pasid_info to
keep attached device info. In this way, struct intel_svm_dev gets retired.

Signed-off-by: Tina Zhang <tina.zhang@...el.com>
---
 drivers/iommu/intel/iommu.h | 11 +----
 drivers/iommu/intel/svm.c   | 94 ++++++++++++++++++-------------------
 2 files changed, 49 insertions(+), 56 deletions(-)

diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index 1e972e7edeca..bd7210980fb2 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -722,6 +722,8 @@ struct dev_pasid_info {
 	struct list_head link_domain;	/* link to domain siblings */
 	struct device *dev;
 	ioasid_t pasid;
+	struct rcu_head rcu;
+	u16 sid, qdep;
 };
 
 static inline void __iommu_flush_cache(
@@ -859,15 +861,6 @@ struct iommu_domain *intel_svm_domain_alloc(void);
 void intel_svm_remove_dev_pasid(struct device *dev, ioasid_t pasid);
 void intel_drain_pasid_prq(struct device *dev, u32 pasid);
 
-struct intel_svm_dev {
-	struct list_head list;
-	struct rcu_head rcu;
-	struct device *dev;
-	struct intel_iommu *iommu;
-	u16 did;
-	u16 sid, qdep;
-};
-
 struct intel_svm {
 	struct mmu_notifier notifier;
 	struct mm_struct *mm;
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index 03406395ac5b..e0373586811e 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -44,21 +44,21 @@ static void *pasid_private_find(ioasid_t pasid)
 	return xa_load(&pasid_private_array, pasid);
 }
 
-static struct intel_svm_dev *
-svm_lookup_device_by_dev(struct intel_svm *svm, struct device *dev)
+static struct dev_pasid_info *
+svm_lookup_dev_pasid_info_by_dev(struct intel_svm *svm, struct device *dev)
 {
-	struct intel_svm_dev *sdev = NULL, *t;
+	struct dev_pasid_info *dev_pasid = NULL, *t;
 
 	rcu_read_lock();
-	list_for_each_entry_rcu(t, &svm->devs, list) {
+	list_for_each_entry_rcu(t, &svm->devs, link_domain) {
 		if (t->dev == dev) {
-			sdev = t;
+			dev_pasid = t;
 			break;
 		}
 	}
 	rcu_read_unlock();
 
-	return sdev;
+	return dev_pasid;
 }
 
 int intel_svm_enable_prq(struct intel_iommu *iommu)
@@ -170,27 +170,28 @@ void intel_svm_check(struct intel_iommu *iommu)
 }
 
 static void __flush_svm_range_dev(struct intel_svm *svm,
-				  struct intel_svm_dev *sdev,
+				  struct dev_pasid_info *dev_pasid,
 				  unsigned long address,
 				  unsigned long pages, int ih)
 {
-	struct device_domain_info *info = dev_iommu_priv_get(sdev->dev);
+	struct device_domain_info *info = dev_iommu_priv_get(dev_pasid->dev);
+	struct intel_iommu *iommu = dev_to_intel_iommu(dev_pasid->dev);
 
 	if (WARN_ON(!pages))
 		return;
 
-	qi_flush_piotlb(sdev->iommu, sdev->did, svm->pasid, address, pages, ih);
+	qi_flush_piotlb(iommu, FLPT_DEFAULT_DID, svm->pasid, address, pages, ih);
 	if (info->ats_enabled) {
-		qi_flush_dev_iotlb_pasid(sdev->iommu, sdev->sid, info->pfsid,
-					 svm->pasid, sdev->qdep, address,
+		qi_flush_dev_iotlb_pasid(iommu, dev_pasid->sid, info->pfsid,
+					 svm->pasid, dev_pasid->qdep, address,
 					 order_base_2(pages));
 		quirk_extra_dev_tlb_flush(info, address, order_base_2(pages),
-					  svm->pasid, sdev->qdep);
+					  svm->pasid, dev_pasid->qdep);
 	}
 }
 
 static void intel_flush_svm_range_dev(struct intel_svm *svm,
-				      struct intel_svm_dev *sdev,
+				      struct dev_pasid_info *dev_pasid,
 				      unsigned long address,
 				      unsigned long pages, int ih)
 {
@@ -200,7 +201,7 @@ static void intel_flush_svm_range_dev(struct intel_svm *svm,
 	unsigned long end = ALIGN(address + (pages << VTD_PAGE_SHIFT), align);
 
 	while (start < end) {
-		__flush_svm_range_dev(svm, sdev, start, align >> VTD_PAGE_SHIFT, ih);
+		__flush_svm_range_dev(svm, dev_pasid, start, align >> VTD_PAGE_SHIFT, ih);
 		start += align;
 	}
 }
@@ -208,11 +209,11 @@ static void intel_flush_svm_range_dev(struct intel_svm *svm,
 static void intel_flush_svm_range(struct intel_svm *svm, unsigned long address,
 				unsigned long pages, int ih)
 {
-	struct intel_svm_dev *sdev;
+	struct dev_pasid_info *dev_pasid;
 
 	rcu_read_lock();
-	list_for_each_entry_rcu(sdev, &svm->devs, list)
-		intel_flush_svm_range_dev(svm, sdev, address, pages, ih);
+	list_for_each_entry_rcu(dev_pasid, &svm->devs, link_domain)
+		intel_flush_svm_range_dev(svm, dev_pasid, address, pages, ih);
 	rcu_read_unlock();
 }
 
@@ -230,7 +231,8 @@ static void intel_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
 static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 {
 	struct intel_svm *svm = container_of(mn, struct intel_svm, notifier);
-	struct intel_svm_dev *sdev;
+	struct dev_pasid_info *dev_pasid;
+	struct intel_iommu *iommu;
 
 	/* This might end up being called from exit_mmap(), *before* the page
 	 * tables are cleared. And __mmu_notifier_release() will delete us from
@@ -245,9 +247,11 @@ static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 	 * *has* to handle gracefully without affecting other processes.
 	 */
 	rcu_read_lock();
-	list_for_each_entry_rcu(sdev, &svm->devs, list)
-		intel_pasid_tear_down_entry(sdev->iommu, sdev->dev,
+	list_for_each_entry_rcu(dev_pasid, &svm->devs, link_domain) {
+		iommu = dev_to_intel_iommu(dev_pasid->dev);
+		intel_pasid_tear_down_entry(iommu, dev_pasid->dev,
 					    svm->pasid, true);
+	}
 	rcu_read_unlock();
 
 }
@@ -257,11 +261,11 @@ static const struct mmu_notifier_ops intel_mmuops = {
 	.arch_invalidate_secondary_tlbs = intel_arch_invalidate_secondary_tlbs,
 };
 
-static int pasid_to_svm_sdev(struct device *dev, unsigned int pasid,
+static int pasid_to_dev_pasid_info(struct device *dev, unsigned int pasid,
 			     struct intel_svm **rsvm,
-			     struct intel_svm_dev **rsdev)
+			     struct dev_pasid_info **rsdev_pasid_info)
 {
-	struct intel_svm_dev *sdev = NULL;
+	struct dev_pasid_info *dev_pasid = NULL;
 	struct intel_svm *svm;
 
 	if (pasid == IOMMU_PASID_INVALID || pasid >= PASID_MAX)
@@ -280,11 +284,11 @@ static int pasid_to_svm_sdev(struct device *dev, unsigned int pasid,
 	 */
 	if (WARN_ON(list_empty(&svm->devs)))
 		return -EINVAL;
-	sdev = svm_lookup_device_by_dev(svm, dev);
+	dev_pasid = svm_lookup_dev_pasid_info_by_dev(svm, dev);
 
 out:
 	*rsvm = svm;
-	*rsdev = sdev;
+	*rsdev_pasid_info = dev_pasid;
 
 	return 0;
 }
@@ -295,7 +299,7 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
 	struct device_domain_info *info = dev_iommu_priv_get(dev);
 	struct intel_iommu *iommu = info->iommu;
 	struct mm_struct *mm = domain->mm;
-	struct intel_svm_dev *sdev;
+	struct dev_pasid_info *dev_pasid;
 	struct intel_svm *svm;
 	unsigned long sflags;
 	int ret = 0;
@@ -325,20 +329,18 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
 		}
 	}
 
-	sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
-	if (!sdev) {
+	dev_pasid = kzalloc(sizeof(*dev_pasid), GFP_KERNEL);
+	if (!dev_pasid) {
 		ret = -ENOMEM;
 		goto free_svm;
 	}
 
-	sdev->dev = dev;
-	sdev->iommu = iommu;
-	sdev->did = FLPT_DEFAULT_DID;
-	sdev->sid = PCI_DEVID(info->bus, info->devfn);
+	dev_pasid->dev = dev;
+	dev_pasid->sid = PCI_DEVID(info->bus, info->devfn);
 	if (info->ats_enabled) {
-		sdev->qdep = info->ats_qdep;
-		if (sdev->qdep >= QI_DEV_EIOTLB_MAX_INVS)
-			sdev->qdep = 0;
+		dev_pasid->qdep = info->ats_qdep;
+		if (dev_pasid->qdep >= QI_DEV_EIOTLB_MAX_INVS)
+			dev_pasid->qdep = 0;
 	}
 
 	/* Setup the pasid table: */
@@ -346,14 +348,14 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
 	ret = intel_pasid_setup_first_level(iommu, dev, mm->pgd, pasid,
 					    FLPT_DEFAULT_DID, sflags);
 	if (ret)
-		goto free_sdev;
+		goto free_dev_pasid;
 
-	list_add_rcu(&sdev->list, &svm->devs);
+	list_add_rcu(&dev_pasid->link_domain, &svm->devs);
 
 	return 0;
 
-free_sdev:
-	kfree(sdev);
+free_dev_pasid:
+	kfree(dev_pasid);
 free_svm:
 	if (list_empty(&svm->devs)) {
 		mmu_notifier_unregister(&svm->notifier, mm);
@@ -366,26 +368,24 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
 
 void intel_svm_remove_dev_pasid(struct device *dev, u32 pasid)
 {
-	struct intel_svm_dev *sdev;
+	struct dev_pasid_info *dev_pasid;
 	struct intel_iommu *iommu;
 	struct intel_svm *svm;
-	struct mm_struct *mm;
 
 	iommu = device_to_iommu(dev, NULL, NULL);
 	if (!iommu)
 		return;
 
-	if (pasid_to_svm_sdev(dev, pasid, &svm, &sdev))
+	if (pasid_to_dev_pasid_info(dev, pasid, &svm, &dev_pasid))
 		return;
-	mm = svm->mm;
 
-	if (sdev) {
-		list_del_rcu(&sdev->list);
-		kfree_rcu(sdev, rcu);
+	if (dev_pasid) {
+		list_del_rcu(&dev_pasid->link_domain);
+		kfree_rcu(dev_pasid, rcu);
 
 		if (list_empty(&svm->devs)) {
 			if (svm->notifier.ops)
-				mmu_notifier_unregister(&svm->notifier, mm);
+				mmu_notifier_unregister(&svm->notifier, svm->mm);
 			pasid_private_remove(svm->pasid);
 			kfree(svm);
 		}
-- 
2.39.3

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ