All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC 00/11] iommu: SVA and IOPF refactoring
@ 2022-03-20  6:40 ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel, Lu Baolu

Hi,

The former part of this series refactors the IOMMU SVA code by assigning
an SVA type of iommu_domain to a shared virtual address and replacing
sva_bind/unbind iommu ops with attach/detach_dev_pasid domain ops.

The latter part changes the existing I/O page fault handling framework
from only serving SVA to a generic one. Any driver or component could
handle the I/O page faults for its domain in its own way by installing
an I/O page fault handler.

This series overlaps with another series posted here [1]. For the
convenience of review, I included all relevant patches in this series.
We will solve the overlap problem later.

This series is also available on github here [2].

[1] https://lore.kernel.org/lkml/20220315050713.2000518-1-jacob.jun.pan@linux.intel.com/
[2] https://github.com/LuBaolu/intel-iommu/commits/iommu-sva-refactoring-v1

Please help review and suggest.

Best regards,
baolu

Lu Baolu (11):
  iommu: Add pasid_bits field in struct dev_iommu
  iommu: Add iommu_domain type for SVA
  iommu: Add attach/detach_dev_pasid domain ops
  iommu/vt-d: Add SVA domain support
  arm-smmu-v3/sva: Add SVA domain support
  iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  iommu: Remove SVA related callbacks from iommu ops
  iommu: Handle IO page faults directly
  iommu: Add iommu_get_domain_for_dev_pasid()
  iommu: Make IOPF handling framework generic
  iommu: Rename iommu-sva-lib.{c,h}

 include/linux/intel-iommu.h                   |   5 +-
 include/linux/iommu.h                         |  95 +++++---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  25 +-
 .../iommu/{iommu-sva-lib.h => iommu-sva.h}    |   0
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   |  96 ++++----
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  19 +-
 drivers/iommu/intel/iommu.c                   |  36 +--
 drivers/iommu/intel/svm.c                     |  85 +++----
 drivers/iommu/io-pgfault.c                    |  69 +-----
 drivers/iommu/iommu-sva-lib.c                 |  71 ------
 drivers/iommu/iommu-sva.c                     | 230 ++++++++++++++++++
 drivers/iommu/iommu.c                         | 175 ++++++-------
 drivers/iommu/Makefile                        |   2 +-
 13 files changed, 515 insertions(+), 393 deletions(-)
 rename drivers/iommu/{iommu-sva-lib.h => iommu-sva.h} (100%)
 delete mode 100644 drivers/iommu/iommu-sva-lib.c
 create mode 100644 drivers/iommu/iommu-sva.c

-- 
2.25.1


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

* [PATCH RFC 00/11] iommu: SVA and IOPF refactoring
@ 2022-03-20  6:40 ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Jacob jun Pan

Hi,

The former part of this series refactors the IOMMU SVA code by assigning
an SVA type of iommu_domain to a shared virtual address and replacing
sva_bind/unbind iommu ops with attach/detach_dev_pasid domain ops.

The latter part changes the existing I/O page fault handling framework
from only serving SVA to a generic one. Any driver or component could
handle the I/O page faults for its domain in its own way by installing
an I/O page fault handler.

This series overlaps with another series posted here [1]. For the
convenience of review, I included all relevant patches in this series.
We will solve the overlap problem later.

This series is also available on github here [2].

[1] https://lore.kernel.org/lkml/20220315050713.2000518-1-jacob.jun.pan@linux.intel.com/
[2] https://github.com/LuBaolu/intel-iommu/commits/iommu-sva-refactoring-v1

Please help review and suggest.

Best regards,
baolu

Lu Baolu (11):
  iommu: Add pasid_bits field in struct dev_iommu
  iommu: Add iommu_domain type for SVA
  iommu: Add attach/detach_dev_pasid domain ops
  iommu/vt-d: Add SVA domain support
  arm-smmu-v3/sva: Add SVA domain support
  iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  iommu: Remove SVA related callbacks from iommu ops
  iommu: Handle IO page faults directly
  iommu: Add iommu_get_domain_for_dev_pasid()
  iommu: Make IOPF handling framework generic
  iommu: Rename iommu-sva-lib.{c,h}

 include/linux/intel-iommu.h                   |   5 +-
 include/linux/iommu.h                         |  95 +++++---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  25 +-
 .../iommu/{iommu-sva-lib.h => iommu-sva.h}    |   0
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   |  96 ++++----
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  19 +-
 drivers/iommu/intel/iommu.c                   |  36 +--
 drivers/iommu/intel/svm.c                     |  85 +++----
 drivers/iommu/io-pgfault.c                    |  69 +-----
 drivers/iommu/iommu-sva-lib.c                 |  71 ------
 drivers/iommu/iommu-sva.c                     | 230 ++++++++++++++++++
 drivers/iommu/iommu.c                         | 175 ++++++-------
 drivers/iommu/Makefile                        |   2 +-
 13 files changed, 515 insertions(+), 393 deletions(-)
 rename drivers/iommu/{iommu-sva-lib.h => iommu-sva.h} (100%)
 delete mode 100644 drivers/iommu/iommu-sva-lib.c
 create mode 100644 drivers/iommu/iommu-sva.c

-- 
2.25.1

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

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

* [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu
  2022-03-20  6:40 ` Lu Baolu
@ 2022-03-20  6:40   ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel, Lu Baolu

Use this field to save the pasid/ssid bits that a device is able to
support with its IOMMU hardware. It is a generic attribute of a device
and lifting it into the per-device dev_iommu struct makes it possible
to allocate a PASID for device without calls into the IOMMU drivers.
Any iommu driver which suports PASID related features should set this
field before features are enabled on the devices.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h                       | 1 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 1 +
 drivers/iommu/intel/iommu.c                 | 5 ++++-
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 6ef2df258673..36f43af0af53 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -368,6 +368,7 @@ struct dev_iommu {
 	struct iommu_fwspec		*fwspec;
 	struct iommu_device		*iommu_dev;
 	void				*priv;
+	unsigned int			pasid_bits;
 };
 
 int iommu_device_register(struct iommu_device *iommu,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 627a3ed5ee8f..8e262210b5ad 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2812,6 +2812,7 @@ static int arm_smmu_dev_enable_feature(struct device *dev,
 		master->iopf_enabled = true;
 		return 0;
 	case IOMMU_DEV_FEAT_SVA:
+		dev->iommu->pasid_bits = master->ssid_bits;
 		return arm_smmu_master_enable_sva(master);
 	default:
 		return -EINVAL;
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 6f7485c44a4b..c1b91bce1530 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4587,8 +4587,11 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
 			if (pasid_supported(iommu)) {
 				int features = pci_pasid_features(pdev);
 
-				if (features >= 0)
+				if (features >= 0) {
 					info->pasid_supported = features | 1;
+					dev->iommu->pasid_bits =
+						fls(pci_max_pasids(pdev)) - 1;
+				}
 			}
 
 			if (info->ats_supported && ecap_prs(iommu->ecap) &&
-- 
2.25.1


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

* [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu
@ 2022-03-20  6:40   ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Jacob jun Pan

Use this field to save the pasid/ssid bits that a device is able to
support with its IOMMU hardware. It is a generic attribute of a device
and lifting it into the per-device dev_iommu struct makes it possible
to allocate a PASID for device without calls into the IOMMU drivers.
Any iommu driver which suports PASID related features should set this
field before features are enabled on the devices.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h                       | 1 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 1 +
 drivers/iommu/intel/iommu.c                 | 5 ++++-
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 6ef2df258673..36f43af0af53 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -368,6 +368,7 @@ struct dev_iommu {
 	struct iommu_fwspec		*fwspec;
 	struct iommu_device		*iommu_dev;
 	void				*priv;
+	unsigned int			pasid_bits;
 };
 
 int iommu_device_register(struct iommu_device *iommu,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 627a3ed5ee8f..8e262210b5ad 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2812,6 +2812,7 @@ static int arm_smmu_dev_enable_feature(struct device *dev,
 		master->iopf_enabled = true;
 		return 0;
 	case IOMMU_DEV_FEAT_SVA:
+		dev->iommu->pasid_bits = master->ssid_bits;
 		return arm_smmu_master_enable_sva(master);
 	default:
 		return -EINVAL;
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 6f7485c44a4b..c1b91bce1530 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4587,8 +4587,11 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
 			if (pasid_supported(iommu)) {
 				int features = pci_pasid_features(pdev);
 
-				if (features >= 0)
+				if (features >= 0) {
 					info->pasid_supported = features | 1;
+					dev->iommu->pasid_bits =
+						fls(pci_max_pasids(pdev)) - 1;
+				}
 			}
 
 			if (info->ats_supported && ecap_prs(iommu->ecap) &&
-- 
2.25.1

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

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

* [PATCH RFC 02/11] iommu: Add iommu_domain type for SVA
  2022-03-20  6:40 ` Lu Baolu
@ 2022-03-20  6:40   ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel, Lu Baolu

Add a new iommu domain type IOMMU_DOMAIN_SVA to represent an I/O page
table which is shared from CPU host VA. Add a sva_cookie field in the
iommu_domain structure to save the mm_struct which represent the CPU
memory page table.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 36f43af0af53..3e179b853380 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -64,6 +64,9 @@ struct iommu_domain_geometry {
 #define __IOMMU_DOMAIN_PT	(1U << 2)  /* Domain is identity mapped   */
 #define __IOMMU_DOMAIN_DMA_FQ	(1U << 3)  /* DMA-API uses flush queue    */
 
+#define __IOMMU_DOMAIN_SHARED	(1U << 4)  /* Page table shared from CPU  */
+#define __IOMMU_DOMAIN_HOST_VA	(1U << 5)  /* Host CPU virtual address */
+
 /*
  * This are the possible domain-types
  *
@@ -86,6 +89,8 @@ struct iommu_domain_geometry {
 #define IOMMU_DOMAIN_DMA_FQ	(__IOMMU_DOMAIN_PAGING |	\
 				 __IOMMU_DOMAIN_DMA_API |	\
 				 __IOMMU_DOMAIN_DMA_FQ)
+#define IOMMU_DOMAIN_SVA	(__IOMMU_DOMAIN_SHARED |	\
+				 __IOMMU_DOMAIN_HOST_VA)
 
 struct iommu_domain {
 	unsigned type;
@@ -95,6 +100,7 @@ struct iommu_domain {
 	void *handler_token;
 	struct iommu_domain_geometry geometry;
 	struct iommu_dma_cookie *iova_cookie;
+	struct mm_struct *sva_cookie;
 };
 
 static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
-- 
2.25.1


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

* [PATCH RFC 02/11] iommu: Add iommu_domain type for SVA
@ 2022-03-20  6:40   ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Jacob jun Pan

Add a new iommu domain type IOMMU_DOMAIN_SVA to represent an I/O page
table which is shared from CPU host VA. Add a sva_cookie field in the
iommu_domain structure to save the mm_struct which represent the CPU
memory page table.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 36f43af0af53..3e179b853380 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -64,6 +64,9 @@ struct iommu_domain_geometry {
 #define __IOMMU_DOMAIN_PT	(1U << 2)  /* Domain is identity mapped   */
 #define __IOMMU_DOMAIN_DMA_FQ	(1U << 3)  /* DMA-API uses flush queue    */
 
+#define __IOMMU_DOMAIN_SHARED	(1U << 4)  /* Page table shared from CPU  */
+#define __IOMMU_DOMAIN_HOST_VA	(1U << 5)  /* Host CPU virtual address */
+
 /*
  * This are the possible domain-types
  *
@@ -86,6 +89,8 @@ struct iommu_domain_geometry {
 #define IOMMU_DOMAIN_DMA_FQ	(__IOMMU_DOMAIN_PAGING |	\
 				 __IOMMU_DOMAIN_DMA_API |	\
 				 __IOMMU_DOMAIN_DMA_FQ)
+#define IOMMU_DOMAIN_SVA	(__IOMMU_DOMAIN_SHARED |	\
+				 __IOMMU_DOMAIN_HOST_VA)
 
 struct iommu_domain {
 	unsigned type;
@@ -95,6 +100,7 @@ struct iommu_domain {
 	void *handler_token;
 	struct iommu_domain_geometry geometry;
 	struct iommu_dma_cookie *iova_cookie;
+	struct mm_struct *sva_cookie;
 };
 
 static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
-- 
2.25.1

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

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

* [PATCH RFC 03/11] iommu: Add attach/detach_dev_pasid domain ops
  2022-03-20  6:40 ` Lu Baolu
@ 2022-03-20  6:40   ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel, Lu Baolu

Attaching an IOMMU domain to a PASID of a device is a generic operation
for modern IOMMU drivers which support PASID-granular DMA address
translation. Currently visible usage scenarios include (but not limited):

 - SVA
 - kernel DMA with PASID
 - hardware-assist mediated device

This adds a pair of common domain ops for this purpose and implements a
couple of wrapper helpers for in-kernel usage.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h | 22 ++++++++++++++++++++++
 drivers/iommu/iommu.c | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 3e179b853380..e51845b9a146 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -268,6 +268,8 @@ struct iommu_ops {
  * struct iommu_domain_ops - domain specific operations
  * @attach_dev: attach an iommu domain to a device
  * @detach_dev: detach an iommu domain from a device
+ * @attach_dev_pasid: attach an iommu domain to a pasid of device
+ * @detach_dev_pasid: detach an iommu domain from a pasid of device
  * @map: map a physically contiguous memory region to an iommu domain
  * @map_pages: map a physically contiguous set of pages of the same size to
  *             an iommu domain.
@@ -285,6 +287,10 @@ struct iommu_ops {
 struct iommu_domain_ops {
 	int (*attach_dev)(struct iommu_domain *domain, struct device *dev);
 	void (*detach_dev)(struct iommu_domain *domain, struct device *dev);
+	int (*attach_dev_pasid)(struct iommu_domain *domain,
+				struct device *dev, ioasid_t id);
+	void (*detach_dev_pasid)(struct iommu_domain *domain,
+				 struct device *dev, ioasid_t id);
 
 	int (*map)(struct iommu_domain *domain, unsigned long iova,
 		   phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
@@ -678,6 +684,11 @@ int iommu_group_claim_dma_owner(struct iommu_group *group, void *owner);
 void iommu_group_release_dma_owner(struct iommu_group *group);
 bool iommu_group_dma_owner_claimed(struct iommu_group *group);
 
+int iommu_attach_device_pasid(struct iommu_domain *domain,
+			      struct device *dev, ioasid_t pasid);
+void iommu_detach_device_pasid(struct iommu_domain *domain,
+			       struct device *dev, ioasid_t pasid);
+
 #else /* CONFIG_IOMMU_API */
 
 struct iommu_ops {};
@@ -1046,6 +1057,17 @@ static inline bool iommu_group_dma_owner_claimed(struct iommu_group *group)
 {
 	return false;
 }
+
+static inline int iommu_attach_device_pasid(struct iommu_domain *domain,
+					    struct device *dev, ioasid_t pasid)
+{
+	return -ENODEV;
+}
+
+static inline void iommu_detach_device_pasid(struct iommu_domain *domain,
+					     struct device *dev, ioasid_t pasid)
+{
+}
 #endif /* CONFIG_IOMMU_API */
 
 /**
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 0c42ece25854..78c71ee15f36 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -3167,3 +3167,44 @@ bool iommu_group_dma_owner_claimed(struct iommu_group *group)
 	return user;
 }
 EXPORT_SYMBOL_GPL(iommu_group_dma_owner_claimed);
+
+int iommu_attach_device_pasid(struct iommu_domain *domain,
+			      struct device *dev, ioasid_t pasid)
+{
+	struct iommu_group *group;
+	int ret = -EINVAL;
+
+	if (!domain->ops->attach_dev_pasid)
+		return -EINVAL;
+
+	group = iommu_group_get(dev);
+	if (!group)
+		return -ENODEV;
+
+	mutex_lock(&group->mutex);
+	if (iommu_group_device_count(group) != 1)
+		goto out_unlock;
+
+	ret = domain->ops->attach_dev_pasid(domain, dev, pasid);
+
+out_unlock:
+	mutex_unlock(&group->mutex);
+	iommu_group_put(group);
+
+	return ret;
+}
+
+void iommu_detach_device_pasid(struct iommu_domain *domain,
+			       struct device *dev, ioasid_t pasid)
+{
+	struct iommu_group *group;
+
+	group = iommu_group_get(dev);
+	if (WARN_ON(!group))
+		return;
+
+	mutex_lock(&group->mutex);
+	domain->ops->detach_dev_pasid(domain, dev, pasid);
+	mutex_unlock(&group->mutex);
+	iommu_group_put(group);
+}
-- 
2.25.1


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

* [PATCH RFC 03/11] iommu: Add attach/detach_dev_pasid domain ops
@ 2022-03-20  6:40   ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Jacob jun Pan

Attaching an IOMMU domain to a PASID of a device is a generic operation
for modern IOMMU drivers which support PASID-granular DMA address
translation. Currently visible usage scenarios include (but not limited):

 - SVA
 - kernel DMA with PASID
 - hardware-assist mediated device

This adds a pair of common domain ops for this purpose and implements a
couple of wrapper helpers for in-kernel usage.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h | 22 ++++++++++++++++++++++
 drivers/iommu/iommu.c | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 3e179b853380..e51845b9a146 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -268,6 +268,8 @@ struct iommu_ops {
  * struct iommu_domain_ops - domain specific operations
  * @attach_dev: attach an iommu domain to a device
  * @detach_dev: detach an iommu domain from a device
+ * @attach_dev_pasid: attach an iommu domain to a pasid of device
+ * @detach_dev_pasid: detach an iommu domain from a pasid of device
  * @map: map a physically contiguous memory region to an iommu domain
  * @map_pages: map a physically contiguous set of pages of the same size to
  *             an iommu domain.
@@ -285,6 +287,10 @@ struct iommu_ops {
 struct iommu_domain_ops {
 	int (*attach_dev)(struct iommu_domain *domain, struct device *dev);
 	void (*detach_dev)(struct iommu_domain *domain, struct device *dev);
+	int (*attach_dev_pasid)(struct iommu_domain *domain,
+				struct device *dev, ioasid_t id);
+	void (*detach_dev_pasid)(struct iommu_domain *domain,
+				 struct device *dev, ioasid_t id);
 
 	int (*map)(struct iommu_domain *domain, unsigned long iova,
 		   phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
@@ -678,6 +684,11 @@ int iommu_group_claim_dma_owner(struct iommu_group *group, void *owner);
 void iommu_group_release_dma_owner(struct iommu_group *group);
 bool iommu_group_dma_owner_claimed(struct iommu_group *group);
 
+int iommu_attach_device_pasid(struct iommu_domain *domain,
+			      struct device *dev, ioasid_t pasid);
+void iommu_detach_device_pasid(struct iommu_domain *domain,
+			       struct device *dev, ioasid_t pasid);
+
 #else /* CONFIG_IOMMU_API */
 
 struct iommu_ops {};
@@ -1046,6 +1057,17 @@ static inline bool iommu_group_dma_owner_claimed(struct iommu_group *group)
 {
 	return false;
 }
+
+static inline int iommu_attach_device_pasid(struct iommu_domain *domain,
+					    struct device *dev, ioasid_t pasid)
+{
+	return -ENODEV;
+}
+
+static inline void iommu_detach_device_pasid(struct iommu_domain *domain,
+					     struct device *dev, ioasid_t pasid)
+{
+}
 #endif /* CONFIG_IOMMU_API */
 
 /**
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 0c42ece25854..78c71ee15f36 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -3167,3 +3167,44 @@ bool iommu_group_dma_owner_claimed(struct iommu_group *group)
 	return user;
 }
 EXPORT_SYMBOL_GPL(iommu_group_dma_owner_claimed);
+
+int iommu_attach_device_pasid(struct iommu_domain *domain,
+			      struct device *dev, ioasid_t pasid)
+{
+	struct iommu_group *group;
+	int ret = -EINVAL;
+
+	if (!domain->ops->attach_dev_pasid)
+		return -EINVAL;
+
+	group = iommu_group_get(dev);
+	if (!group)
+		return -ENODEV;
+
+	mutex_lock(&group->mutex);
+	if (iommu_group_device_count(group) != 1)
+		goto out_unlock;
+
+	ret = domain->ops->attach_dev_pasid(domain, dev, pasid);
+
+out_unlock:
+	mutex_unlock(&group->mutex);
+	iommu_group_put(group);
+
+	return ret;
+}
+
+void iommu_detach_device_pasid(struct iommu_domain *domain,
+			       struct device *dev, ioasid_t pasid)
+{
+	struct iommu_group *group;
+
+	group = iommu_group_get(dev);
+	if (WARN_ON(!group))
+		return;
+
+	mutex_lock(&group->mutex);
+	domain->ops->detach_dev_pasid(domain, dev, pasid);
+	mutex_unlock(&group->mutex);
+	iommu_group_put(group);
+}
-- 
2.25.1

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

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

* [PATCH RFC 04/11] iommu/vt-d: Add SVA domain support
  2022-03-20  6:40 ` Lu Baolu
@ 2022-03-20  6:40   ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel, Lu Baolu

Add support for SVA domain allocation and provide an SVA-specific
iommu_domain_ops.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/intel-iommu.h |  1 +
 drivers/iommu/intel/iommu.c | 12 ++++++++++++
 drivers/iommu/intel/svm.c   | 34 ++++++++++++++++++++++++++++++++++
 3 files changed, 47 insertions(+)

diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 2f9891cb3d00..c14283137fb5 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -744,6 +744,7 @@ void intel_svm_unbind(struct iommu_sva *handle);
 u32 intel_svm_get_pasid(struct iommu_sva *handle);
 int intel_svm_page_response(struct device *dev, struct iommu_fault_event *evt,
 			    struct iommu_page_response *msg);
+extern const struct iommu_domain_ops intel_svm_domain_ops;
 
 struct intel_svm_dev {
 	struct list_head list;
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index c1b91bce1530..d55dca3eacf8 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4318,6 +4318,18 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
 		return domain;
 	case IOMMU_DOMAIN_IDENTITY:
 		return &si_domain->domain;
+#ifdef CONFIG_INTEL_IOMMU_SVM
+	case IOMMU_DOMAIN_SVA:
+		dmar_domain = alloc_domain(type);
+		if (!dmar_domain) {
+			pr_err("Can't allocate sva domain\n");
+			return NULL;
+		}
+		domain = &dmar_domain->domain;
+		domain->ops = &intel_svm_domain_ops;
+
+		return domain;
+#endif /* CONFIG_INTEL_IOMMU_SVM */
 	default:
 		return NULL;
 	}
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index ee5ecde5b318..b9f4dd7057d1 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -932,3 +932,37 @@ int intel_svm_page_response(struct device *dev,
 	mutex_unlock(&pasid_mutex);
 	return ret;
 }
+
+static int intel_svm_attach_dev_pasid(struct iommu_domain *domain,
+				      struct device *dev, ioasid_t pasid)
+{
+	struct device_domain_info *info = dev_iommu_priv_get(dev);
+	struct mm_struct *mm = domain->sva_cookie;
+	struct intel_iommu *iommu = info->iommu;
+	struct iommu_sva *sva;
+
+	mutex_lock(&pasid_mutex);
+	sva = intel_svm_bind_mm(iommu, dev, mm);
+	mutex_unlock(&pasid_mutex);
+
+	return IS_ERR_OR_NULL(sva);
+}
+
+static void intel_svm_detach_dev_pasid(struct iommu_domain *domain,
+				       struct device *dev, ioasid_t pasid)
+{
+	mutex_lock(&pasid_mutex);
+	intel_svm_unbind_mm(dev, pasid);
+	mutex_unlock(&pasid_mutex);
+}
+
+static void intel_svm_domain_free(struct iommu_domain *domain)
+{
+	kfree(domain);
+}
+
+const struct iommu_domain_ops intel_svm_domain_ops = {
+	.attach_dev_pasid	= intel_svm_attach_dev_pasid,
+	.detach_dev_pasid	= intel_svm_detach_dev_pasid,
+	.free			= intel_svm_domain_free,
+};
-- 
2.25.1


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

* [PATCH RFC 04/11] iommu/vt-d: Add SVA domain support
@ 2022-03-20  6:40   ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Jacob jun Pan

Add support for SVA domain allocation and provide an SVA-specific
iommu_domain_ops.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/intel-iommu.h |  1 +
 drivers/iommu/intel/iommu.c | 12 ++++++++++++
 drivers/iommu/intel/svm.c   | 34 ++++++++++++++++++++++++++++++++++
 3 files changed, 47 insertions(+)

diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 2f9891cb3d00..c14283137fb5 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -744,6 +744,7 @@ void intel_svm_unbind(struct iommu_sva *handle);
 u32 intel_svm_get_pasid(struct iommu_sva *handle);
 int intel_svm_page_response(struct device *dev, struct iommu_fault_event *evt,
 			    struct iommu_page_response *msg);
+extern const struct iommu_domain_ops intel_svm_domain_ops;
 
 struct intel_svm_dev {
 	struct list_head list;
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index c1b91bce1530..d55dca3eacf8 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4318,6 +4318,18 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
 		return domain;
 	case IOMMU_DOMAIN_IDENTITY:
 		return &si_domain->domain;
+#ifdef CONFIG_INTEL_IOMMU_SVM
+	case IOMMU_DOMAIN_SVA:
+		dmar_domain = alloc_domain(type);
+		if (!dmar_domain) {
+			pr_err("Can't allocate sva domain\n");
+			return NULL;
+		}
+		domain = &dmar_domain->domain;
+		domain->ops = &intel_svm_domain_ops;
+
+		return domain;
+#endif /* CONFIG_INTEL_IOMMU_SVM */
 	default:
 		return NULL;
 	}
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index ee5ecde5b318..b9f4dd7057d1 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -932,3 +932,37 @@ int intel_svm_page_response(struct device *dev,
 	mutex_unlock(&pasid_mutex);
 	return ret;
 }
+
+static int intel_svm_attach_dev_pasid(struct iommu_domain *domain,
+				      struct device *dev, ioasid_t pasid)
+{
+	struct device_domain_info *info = dev_iommu_priv_get(dev);
+	struct mm_struct *mm = domain->sva_cookie;
+	struct intel_iommu *iommu = info->iommu;
+	struct iommu_sva *sva;
+
+	mutex_lock(&pasid_mutex);
+	sva = intel_svm_bind_mm(iommu, dev, mm);
+	mutex_unlock(&pasid_mutex);
+
+	return IS_ERR_OR_NULL(sva);
+}
+
+static void intel_svm_detach_dev_pasid(struct iommu_domain *domain,
+				       struct device *dev, ioasid_t pasid)
+{
+	mutex_lock(&pasid_mutex);
+	intel_svm_unbind_mm(dev, pasid);
+	mutex_unlock(&pasid_mutex);
+}
+
+static void intel_svm_domain_free(struct iommu_domain *domain)
+{
+	kfree(domain);
+}
+
+const struct iommu_domain_ops intel_svm_domain_ops = {
+	.attach_dev_pasid	= intel_svm_attach_dev_pasid,
+	.detach_dev_pasid	= intel_svm_detach_dev_pasid,
+	.free			= intel_svm_domain_free,
+};
-- 
2.25.1

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

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

* [PATCH RFC 05/11] arm-smmu-v3/sva: Add SVA domain support
  2022-03-20  6:40 ` Lu Baolu
@ 2022-03-20  6:40   ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel, Lu Baolu

Add support for SVA domain allocation and provide an SVA-specific
iommu_domain_ops.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   | 14 ++++++
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   | 45 +++++++++++++++++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 13 +++++-
 3 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index cd48590ada30..7631c00fdcbd 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -759,6 +759,10 @@ struct iommu_sva *arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm,
 void arm_smmu_sva_unbind(struct iommu_sva *handle);
 u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle);
 void arm_smmu_sva_notifier_synchronize(void);
+int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
+				  struct device *dev, ioasid_t id);
+void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
+				   struct device *dev, ioasid_t id);
 #else /* CONFIG_ARM_SMMU_V3_SVA */
 static inline bool arm_smmu_sva_supported(struct arm_smmu_device *smmu)
 {
@@ -804,5 +808,15 @@ static inline u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle)
 }
 
 static inline void arm_smmu_sva_notifier_synchronize(void) {}
+
+static inline int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
+						struct device *dev, ioasid_t id)
+{
+	return -ENODEV;
+}
+
+static inline void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
+						 struct device *dev,
+						 ioasid_t id) {}
 #endif /* CONFIG_ARM_SMMU_V3_SVA */
 #endif /* _ARM_SMMU_V3_H */
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 22ddd05bbdcd..1e114b9dc17f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -534,3 +534,48 @@ void arm_smmu_sva_notifier_synchronize(void)
 	 */
 	mmu_notifier_synchronize();
 }
+
+int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
+				  struct device *dev, ioasid_t id)
+{
+	int ret = 0;
+	struct iommu_sva *handle;
+	struct mm_struct *mm = domain->sva_cookie;
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+
+	if (smmu_domain->stage != ARM_SMMU_DOMAIN_S1 ||
+	    domain->type != IOMMU_DOMAIN_SVA || !mm)
+		return -EINVAL;
+
+	mutex_lock(&sva_lock);
+	handle = __arm_smmu_sva_bind(dev, mm);
+	if (IS_ERR_OR_NULL(handle))
+		ret = PTR_ERR(handle);
+	mutex_unlock(&sva_lock);
+
+	return ret;
+}
+
+void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
+				   struct device *dev, ioasid_t id)
+{
+	struct arm_smmu_bond *bond = NULL, *t;
+	struct mm_struct *mm = domain->sva_cookie;
+	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+
+	mutex_lock(&sva_lock);
+	list_for_each_entry(t, &master->bonds, list) {
+		if (t->mm == mm) {
+			bond = t;
+			break;
+		}
+	}
+
+	if (!WARN_ON(!bond) && refcount_dec_and_test(&bond->refs)) {
+		list_del(&bond->list);
+		arm_smmu_mmu_notifier_put(bond->smmu_mn);
+		iommu_sva_free_pasid(bond->mm);
+		kfree(bond);
+	}
+	mutex_unlock(&sva_lock);
+}
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 8e262210b5ad..2e9d3cd30510 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -88,6 +88,8 @@ static struct arm_smmu_option_prop arm_smmu_options[] = {
 	{ 0, NULL},
 };
 
+static void arm_smmu_domain_free(struct iommu_domain *domain);
+
 static void parse_driver_options(struct arm_smmu_device *smmu)
 {
 	int i = 0;
@@ -1995,6 +1997,12 @@ static bool arm_smmu_capable(enum iommu_cap cap)
 	}
 }
 
+static const struct iommu_domain_ops arm_smmu_sva_domain_ops = {
+	.attach_dev_pasid	= arm_smmu_sva_attach_dev_pasid,
+	.detach_dev_pasid	= arm_smmu_sva_detach_dev_pasid,
+	.free			= arm_smmu_domain_free,
+};
+
 static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
 {
 	struct arm_smmu_domain *smmu_domain;
@@ -2002,7 +2010,8 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
 	if (type != IOMMU_DOMAIN_UNMANAGED &&
 	    type != IOMMU_DOMAIN_DMA &&
 	    type != IOMMU_DOMAIN_DMA_FQ &&
-	    type != IOMMU_DOMAIN_IDENTITY)
+	    type != IOMMU_DOMAIN_IDENTITY &&
+	    type != IOMMU_DOMAIN_SVA)
 		return NULL;
 
 	/*
@@ -2018,6 +2027,8 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
 	INIT_LIST_HEAD(&smmu_domain->devices);
 	spin_lock_init(&smmu_domain->devices_lock);
 	INIT_LIST_HEAD(&smmu_domain->mmu_notifiers);
+	if (type == IOMMU_DOMAIN_SVA)
+		smmu_domain->domain.ops = &arm_smmu_sva_domain_ops;
 
 	return &smmu_domain->domain;
 }
-- 
2.25.1


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

* [PATCH RFC 05/11] arm-smmu-v3/sva: Add SVA domain support
@ 2022-03-20  6:40   ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Jacob jun Pan

Add support for SVA domain allocation and provide an SVA-specific
iommu_domain_ops.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   | 14 ++++++
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   | 45 +++++++++++++++++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 13 +++++-
 3 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index cd48590ada30..7631c00fdcbd 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -759,6 +759,10 @@ struct iommu_sva *arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm,
 void arm_smmu_sva_unbind(struct iommu_sva *handle);
 u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle);
 void arm_smmu_sva_notifier_synchronize(void);
+int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
+				  struct device *dev, ioasid_t id);
+void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
+				   struct device *dev, ioasid_t id);
 #else /* CONFIG_ARM_SMMU_V3_SVA */
 static inline bool arm_smmu_sva_supported(struct arm_smmu_device *smmu)
 {
@@ -804,5 +808,15 @@ static inline u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle)
 }
 
 static inline void arm_smmu_sva_notifier_synchronize(void) {}
+
+static inline int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
+						struct device *dev, ioasid_t id)
+{
+	return -ENODEV;
+}
+
+static inline void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
+						 struct device *dev,
+						 ioasid_t id) {}
 #endif /* CONFIG_ARM_SMMU_V3_SVA */
 #endif /* _ARM_SMMU_V3_H */
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 22ddd05bbdcd..1e114b9dc17f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -534,3 +534,48 @@ void arm_smmu_sva_notifier_synchronize(void)
 	 */
 	mmu_notifier_synchronize();
 }
+
+int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
+				  struct device *dev, ioasid_t id)
+{
+	int ret = 0;
+	struct iommu_sva *handle;
+	struct mm_struct *mm = domain->sva_cookie;
+	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+
+	if (smmu_domain->stage != ARM_SMMU_DOMAIN_S1 ||
+	    domain->type != IOMMU_DOMAIN_SVA || !mm)
+		return -EINVAL;
+
+	mutex_lock(&sva_lock);
+	handle = __arm_smmu_sva_bind(dev, mm);
+	if (IS_ERR_OR_NULL(handle))
+		ret = PTR_ERR(handle);
+	mutex_unlock(&sva_lock);
+
+	return ret;
+}
+
+void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
+				   struct device *dev, ioasid_t id)
+{
+	struct arm_smmu_bond *bond = NULL, *t;
+	struct mm_struct *mm = domain->sva_cookie;
+	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+
+	mutex_lock(&sva_lock);
+	list_for_each_entry(t, &master->bonds, list) {
+		if (t->mm == mm) {
+			bond = t;
+			break;
+		}
+	}
+
+	if (!WARN_ON(!bond) && refcount_dec_and_test(&bond->refs)) {
+		list_del(&bond->list);
+		arm_smmu_mmu_notifier_put(bond->smmu_mn);
+		iommu_sva_free_pasid(bond->mm);
+		kfree(bond);
+	}
+	mutex_unlock(&sva_lock);
+}
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 8e262210b5ad..2e9d3cd30510 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -88,6 +88,8 @@ static struct arm_smmu_option_prop arm_smmu_options[] = {
 	{ 0, NULL},
 };
 
+static void arm_smmu_domain_free(struct iommu_domain *domain);
+
 static void parse_driver_options(struct arm_smmu_device *smmu)
 {
 	int i = 0;
@@ -1995,6 +1997,12 @@ static bool arm_smmu_capable(enum iommu_cap cap)
 	}
 }
 
+static const struct iommu_domain_ops arm_smmu_sva_domain_ops = {
+	.attach_dev_pasid	= arm_smmu_sva_attach_dev_pasid,
+	.detach_dev_pasid	= arm_smmu_sva_detach_dev_pasid,
+	.free			= arm_smmu_domain_free,
+};
+
 static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
 {
 	struct arm_smmu_domain *smmu_domain;
@@ -2002,7 +2010,8 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
 	if (type != IOMMU_DOMAIN_UNMANAGED &&
 	    type != IOMMU_DOMAIN_DMA &&
 	    type != IOMMU_DOMAIN_DMA_FQ &&
-	    type != IOMMU_DOMAIN_IDENTITY)
+	    type != IOMMU_DOMAIN_IDENTITY &&
+	    type != IOMMU_DOMAIN_SVA)
 		return NULL;
 
 	/*
@@ -2018,6 +2027,8 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
 	INIT_LIST_HEAD(&smmu_domain->devices);
 	spin_lock_init(&smmu_domain->devices_lock);
 	INIT_LIST_HEAD(&smmu_domain->mmu_notifiers);
+	if (type == IOMMU_DOMAIN_SVA)
+		smmu_domain->domain.ops = &arm_smmu_sva_domain_ops;
 
 	return &smmu_domain->domain;
 }
-- 
2.25.1

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

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

* [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  2022-03-20  6:40 ` Lu Baolu
@ 2022-03-20  6:40   ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Jacob jun Pan

The existing iommu SVA interfaces are implemented by calling the SVA
specific iommu ops provided by the IOMMU drivers. There's no need for
any SVA specific ops in iommu_ops vector anymore as we can achieve
this through the generic attach/detach_dev_pasid domain ops.

This refactors the IOMMU SVA interfaces implementation by using the
attach/detach_pasid_dev ops and align them with the concept of the
iommu domain. Put the new SVA code in the sva related file in order
to make it self-contained.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h         |  46 +++++++++-------
 drivers/iommu/iommu-sva-lib.c | 100 ++++++++++++++++++++++++++++++++++
 drivers/iommu/iommu.c         |  92 -------------------------------
 3 files changed, 125 insertions(+), 113 deletions(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index e51845b9a146..1c7db6a94022 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -629,6 +629,8 @@ struct iommu_fwspec {
  */
 struct iommu_sva {
 	struct device			*dev;
+	ioasid_t			pasid;
+	struct iommu_domain		*domain;
 };
 
 int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
@@ -671,12 +673,6 @@ int iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features f);
 int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features f);
 bool iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features f);
 
-struct iommu_sva *iommu_sva_bind_device(struct device *dev,
-					struct mm_struct *mm,
-					void *drvdata);
-void iommu_sva_unbind_device(struct iommu_sva *handle);
-u32 iommu_sva_get_pasid(struct iommu_sva *handle);
-
 int iommu_device_use_default_domain(struct device *dev);
 void iommu_device_unuse_default_domain(struct device *dev);
 
@@ -1014,21 +1010,6 @@ iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat)
 	return -ENODEV;
 }
 
-static inline struct iommu_sva *
-iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
-{
-	return NULL;
-}
-
-static inline void iommu_sva_unbind_device(struct iommu_sva *handle)
-{
-}
-
-static inline u32 iommu_sva_get_pasid(struct iommu_sva *handle)
-{
-	return IOMMU_PASID_INVALID;
-}
-
 static inline struct iommu_fwspec *dev_iommu_fwspec_get(struct device *dev)
 {
 	return NULL;
@@ -1070,6 +1051,29 @@ static inline void iommu_detach_device_pasid(struct iommu_domain *domain,
 }
 #endif /* CONFIG_IOMMU_API */
 
+#ifdef CONFIG_IOMMU_SVA
+struct iommu_sva *iommu_sva_bind_device(struct device *dev,
+					struct mm_struct *mm,
+					void *drvdata);
+void iommu_sva_unbind_device(struct iommu_sva *handle);
+u32 iommu_sva_get_pasid(struct iommu_sva *handle);
+#else /* CONFIG_IOMMU_SVA */
+static inline struct iommu_sva *
+iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
+{
+	return NULL;
+}
+
+static inline void iommu_sva_unbind_device(struct iommu_sva *handle)
+{
+}
+
+static inline u32 iommu_sva_get_pasid(struct iommu_sva *handle)
+{
+	return IOMMU_PASID_INVALID;
+}
+#endif /* CONFIG_IOMMU_SVA */
+
 /**
  * iommu_map_sgtable - Map the given buffer to the IOMMU domain
  * @domain:	The IOMMU domain to perform the mapping
diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
index 106506143896..47cf98e661ff 100644
--- a/drivers/iommu/iommu-sva-lib.c
+++ b/drivers/iommu/iommu-sva-lib.c
@@ -3,6 +3,8 @@
  * Helpers for IOMMU drivers implementing SVA
  */
 #include <linux/mutex.h>
+#include <linux/iommu.h>
+#include <linux/slab.h>
 #include <linux/sched/mm.h>
 
 #include "iommu-sva-lib.h"
@@ -69,3 +71,101 @@ struct mm_struct *iommu_sva_find(ioasid_t pasid)
 	return ioasid_find(&iommu_sva_pasid, pasid, __mmget_not_zero);
 }
 EXPORT_SYMBOL_GPL(iommu_sva_find);
+
+static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev)
+{
+	struct bus_type *bus = dev->bus;
+	struct iommu_domain *domain;
+
+	if (!bus || !bus->iommu_ops)
+		return NULL;
+
+	domain = bus->iommu_ops->domain_alloc(IOMMU_DOMAIN_SVA);
+	if (domain)
+		domain->type = IOMMU_DOMAIN_SVA;
+
+	return domain;
+}
+
+/**
+ * iommu_sva_bind_device() - Bind a process address space to a device
+ * @dev: the device
+ * @mm: the mm to bind, caller must hold a reference to it
+ * @drvdata: opaque data pointer to pass to bind callback
+ *
+ * Create a bond between device and address space, allowing the device to access
+ * the mm using the returned PASID. If a bond already exists between @device and
+ * @mm, it is returned and an additional reference is taken. Caller must call
+ * iommu_sva_unbind_device() to release each reference.
+ *
+ * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
+ * initialize the required SVA features.
+ *
+ * On error, returns an ERR_PTR value.
+ */
+struct iommu_sva *
+iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
+{
+	int ret = -EINVAL;
+	struct iommu_sva *handle;
+	struct iommu_domain *domain;
+
+	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+	if (!handle)
+		return ERR_PTR(-ENOMEM);
+
+	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits) - 1);
+	if (ret)
+		goto out;
+
+	domain = iommu_sva_domain_alloc(dev);
+	if (!domain) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	domain->sva_cookie = mm;
+
+	ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
+	if (ret)
+		goto out_free_domain;
+
+	handle->dev = dev;
+	handle->domain = domain;
+	handle->pasid = mm->pasid;
+
+	return handle;
+
+out_free_domain:
+	iommu_domain_free(domain);
+out:
+	kfree(handle);
+
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
+
+/**
+ * iommu_sva_unbind_device() - Remove a bond created with iommu_sva_bind_device
+ * @handle: the handle returned by iommu_sva_bind_device()
+ *
+ * Put reference to a bond between device and address space. The device should
+ * not be issuing any more transaction for this PASID. All outstanding page
+ * requests for this PASID must have been flushed to the IOMMU.
+ */
+void iommu_sva_unbind_device(struct iommu_sva *handle)
+{
+	struct device *dev = handle->dev;
+	struct iommu_domain *domain = handle->domain;
+	struct mm_struct *mm = domain->sva_cookie;
+
+	iommu_detach_device_pasid(domain, dev, mm->pasid);
+	iommu_domain_free(domain);
+	kfree(handle);
+}
+EXPORT_SYMBOL_GPL(iommu_sva_unbind_device);
+
+u32 iommu_sva_get_pasid(struct iommu_sva *handle)
+{
+	return handle->pasid;
+}
+EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 78c71ee15f36..c0966fc9b686 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2706,98 +2706,6 @@ bool iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features feat)
 }
 EXPORT_SYMBOL_GPL(iommu_dev_feature_enabled);
 
-/**
- * iommu_sva_bind_device() - Bind a process address space to a device
- * @dev: the device
- * @mm: the mm to bind, caller must hold a reference to it
- * @drvdata: opaque data pointer to pass to bind callback
- *
- * Create a bond between device and address space, allowing the device to access
- * the mm using the returned PASID. If a bond already exists between @device and
- * @mm, it is returned and an additional reference is taken. Caller must call
- * iommu_sva_unbind_device() to release each reference.
- *
- * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
- * initialize the required SVA features.
- *
- * On error, returns an ERR_PTR value.
- */
-struct iommu_sva *
-iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
-{
-	struct iommu_group *group;
-	struct iommu_sva *handle = ERR_PTR(-EINVAL);
-	const struct iommu_ops *ops = dev_iommu_ops(dev);
-
-	if (!ops->sva_bind)
-		return ERR_PTR(-ENODEV);
-
-	group = iommu_group_get(dev);
-	if (!group)
-		return ERR_PTR(-ENODEV);
-
-	/* Ensure device count and domain don't change while we're binding */
-	mutex_lock(&group->mutex);
-
-	/*
-	 * To keep things simple, SVA currently doesn't support IOMMU groups
-	 * with more than one device. Existing SVA-capable systems are not
-	 * affected by the problems that required IOMMU groups (lack of ACS
-	 * isolation, device ID aliasing and other hardware issues).
-	 */
-	if (iommu_group_device_count(group) != 1)
-		goto out_unlock;
-
-	handle = ops->sva_bind(dev, mm, drvdata);
-
-out_unlock:
-	mutex_unlock(&group->mutex);
-	iommu_group_put(group);
-
-	return handle;
-}
-EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
-
-/**
- * iommu_sva_unbind_device() - Remove a bond created with iommu_sva_bind_device
- * @handle: the handle returned by iommu_sva_bind_device()
- *
- * Put reference to a bond between device and address space. The device should
- * not be issuing any more transaction for this PASID. All outstanding page
- * requests for this PASID must have been flushed to the IOMMU.
- */
-void iommu_sva_unbind_device(struct iommu_sva *handle)
-{
-	struct iommu_group *group;
-	struct device *dev = handle->dev;
-	const struct iommu_ops *ops = dev_iommu_ops(dev);
-
-	if (!ops->sva_unbind)
-		return;
-
-	group = iommu_group_get(dev);
-	if (!group)
-		return;
-
-	mutex_lock(&group->mutex);
-	ops->sva_unbind(handle);
-	mutex_unlock(&group->mutex);
-
-	iommu_group_put(group);
-}
-EXPORT_SYMBOL_GPL(iommu_sva_unbind_device);
-
-u32 iommu_sva_get_pasid(struct iommu_sva *handle)
-{
-	const struct iommu_ops *ops = dev_iommu_ops(handle->dev);
-
-	if (!ops->sva_get_pasid)
-		return IOMMU_PASID_INVALID;
-
-	return ops->sva_get_pasid(handle);
-}
-EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
-
 /*
  * Changes the default domain of an iommu group that has *only* one device
  *
-- 
2.25.1

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

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

* [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
@ 2022-03-20  6:40   ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel, Lu Baolu

The existing iommu SVA interfaces are implemented by calling the SVA
specific iommu ops provided by the IOMMU drivers. There's no need for
any SVA specific ops in iommu_ops vector anymore as we can achieve
this through the generic attach/detach_dev_pasid domain ops.

This refactors the IOMMU SVA interfaces implementation by using the
attach/detach_pasid_dev ops and align them with the concept of the
iommu domain. Put the new SVA code in the sva related file in order
to make it self-contained.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h         |  46 +++++++++-------
 drivers/iommu/iommu-sva-lib.c | 100 ++++++++++++++++++++++++++++++++++
 drivers/iommu/iommu.c         |  92 -------------------------------
 3 files changed, 125 insertions(+), 113 deletions(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index e51845b9a146..1c7db6a94022 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -629,6 +629,8 @@ struct iommu_fwspec {
  */
 struct iommu_sva {
 	struct device			*dev;
+	ioasid_t			pasid;
+	struct iommu_domain		*domain;
 };
 
 int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
@@ -671,12 +673,6 @@ int iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features f);
 int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features f);
 bool iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features f);
 
-struct iommu_sva *iommu_sva_bind_device(struct device *dev,
-					struct mm_struct *mm,
-					void *drvdata);
-void iommu_sva_unbind_device(struct iommu_sva *handle);
-u32 iommu_sva_get_pasid(struct iommu_sva *handle);
-
 int iommu_device_use_default_domain(struct device *dev);
 void iommu_device_unuse_default_domain(struct device *dev);
 
@@ -1014,21 +1010,6 @@ iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat)
 	return -ENODEV;
 }
 
-static inline struct iommu_sva *
-iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
-{
-	return NULL;
-}
-
-static inline void iommu_sva_unbind_device(struct iommu_sva *handle)
-{
-}
-
-static inline u32 iommu_sva_get_pasid(struct iommu_sva *handle)
-{
-	return IOMMU_PASID_INVALID;
-}
-
 static inline struct iommu_fwspec *dev_iommu_fwspec_get(struct device *dev)
 {
 	return NULL;
@@ -1070,6 +1051,29 @@ static inline void iommu_detach_device_pasid(struct iommu_domain *domain,
 }
 #endif /* CONFIG_IOMMU_API */
 
+#ifdef CONFIG_IOMMU_SVA
+struct iommu_sva *iommu_sva_bind_device(struct device *dev,
+					struct mm_struct *mm,
+					void *drvdata);
+void iommu_sva_unbind_device(struct iommu_sva *handle);
+u32 iommu_sva_get_pasid(struct iommu_sva *handle);
+#else /* CONFIG_IOMMU_SVA */
+static inline struct iommu_sva *
+iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
+{
+	return NULL;
+}
+
+static inline void iommu_sva_unbind_device(struct iommu_sva *handle)
+{
+}
+
+static inline u32 iommu_sva_get_pasid(struct iommu_sva *handle)
+{
+	return IOMMU_PASID_INVALID;
+}
+#endif /* CONFIG_IOMMU_SVA */
+
 /**
  * iommu_map_sgtable - Map the given buffer to the IOMMU domain
  * @domain:	The IOMMU domain to perform the mapping
diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
index 106506143896..47cf98e661ff 100644
--- a/drivers/iommu/iommu-sva-lib.c
+++ b/drivers/iommu/iommu-sva-lib.c
@@ -3,6 +3,8 @@
  * Helpers for IOMMU drivers implementing SVA
  */
 #include <linux/mutex.h>
+#include <linux/iommu.h>
+#include <linux/slab.h>
 #include <linux/sched/mm.h>
 
 #include "iommu-sva-lib.h"
@@ -69,3 +71,101 @@ struct mm_struct *iommu_sva_find(ioasid_t pasid)
 	return ioasid_find(&iommu_sva_pasid, pasid, __mmget_not_zero);
 }
 EXPORT_SYMBOL_GPL(iommu_sva_find);
+
+static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev)
+{
+	struct bus_type *bus = dev->bus;
+	struct iommu_domain *domain;
+
+	if (!bus || !bus->iommu_ops)
+		return NULL;
+
+	domain = bus->iommu_ops->domain_alloc(IOMMU_DOMAIN_SVA);
+	if (domain)
+		domain->type = IOMMU_DOMAIN_SVA;
+
+	return domain;
+}
+
+/**
+ * iommu_sva_bind_device() - Bind a process address space to a device
+ * @dev: the device
+ * @mm: the mm to bind, caller must hold a reference to it
+ * @drvdata: opaque data pointer to pass to bind callback
+ *
+ * Create a bond between device and address space, allowing the device to access
+ * the mm using the returned PASID. If a bond already exists between @device and
+ * @mm, it is returned and an additional reference is taken. Caller must call
+ * iommu_sva_unbind_device() to release each reference.
+ *
+ * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
+ * initialize the required SVA features.
+ *
+ * On error, returns an ERR_PTR value.
+ */
+struct iommu_sva *
+iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
+{
+	int ret = -EINVAL;
+	struct iommu_sva *handle;
+	struct iommu_domain *domain;
+
+	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+	if (!handle)
+		return ERR_PTR(-ENOMEM);
+
+	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits) - 1);
+	if (ret)
+		goto out;
+
+	domain = iommu_sva_domain_alloc(dev);
+	if (!domain) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	domain->sva_cookie = mm;
+
+	ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
+	if (ret)
+		goto out_free_domain;
+
+	handle->dev = dev;
+	handle->domain = domain;
+	handle->pasid = mm->pasid;
+
+	return handle;
+
+out_free_domain:
+	iommu_domain_free(domain);
+out:
+	kfree(handle);
+
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
+
+/**
+ * iommu_sva_unbind_device() - Remove a bond created with iommu_sva_bind_device
+ * @handle: the handle returned by iommu_sva_bind_device()
+ *
+ * Put reference to a bond between device and address space. The device should
+ * not be issuing any more transaction for this PASID. All outstanding page
+ * requests for this PASID must have been flushed to the IOMMU.
+ */
+void iommu_sva_unbind_device(struct iommu_sva *handle)
+{
+	struct device *dev = handle->dev;
+	struct iommu_domain *domain = handle->domain;
+	struct mm_struct *mm = domain->sva_cookie;
+
+	iommu_detach_device_pasid(domain, dev, mm->pasid);
+	iommu_domain_free(domain);
+	kfree(handle);
+}
+EXPORT_SYMBOL_GPL(iommu_sva_unbind_device);
+
+u32 iommu_sva_get_pasid(struct iommu_sva *handle)
+{
+	return handle->pasid;
+}
+EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 78c71ee15f36..c0966fc9b686 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2706,98 +2706,6 @@ bool iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features feat)
 }
 EXPORT_SYMBOL_GPL(iommu_dev_feature_enabled);
 
-/**
- * iommu_sva_bind_device() - Bind a process address space to a device
- * @dev: the device
- * @mm: the mm to bind, caller must hold a reference to it
- * @drvdata: opaque data pointer to pass to bind callback
- *
- * Create a bond between device and address space, allowing the device to access
- * the mm using the returned PASID. If a bond already exists between @device and
- * @mm, it is returned and an additional reference is taken. Caller must call
- * iommu_sva_unbind_device() to release each reference.
- *
- * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
- * initialize the required SVA features.
- *
- * On error, returns an ERR_PTR value.
- */
-struct iommu_sva *
-iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
-{
-	struct iommu_group *group;
-	struct iommu_sva *handle = ERR_PTR(-EINVAL);
-	const struct iommu_ops *ops = dev_iommu_ops(dev);
-
-	if (!ops->sva_bind)
-		return ERR_PTR(-ENODEV);
-
-	group = iommu_group_get(dev);
-	if (!group)
-		return ERR_PTR(-ENODEV);
-
-	/* Ensure device count and domain don't change while we're binding */
-	mutex_lock(&group->mutex);
-
-	/*
-	 * To keep things simple, SVA currently doesn't support IOMMU groups
-	 * with more than one device. Existing SVA-capable systems are not
-	 * affected by the problems that required IOMMU groups (lack of ACS
-	 * isolation, device ID aliasing and other hardware issues).
-	 */
-	if (iommu_group_device_count(group) != 1)
-		goto out_unlock;
-
-	handle = ops->sva_bind(dev, mm, drvdata);
-
-out_unlock:
-	mutex_unlock(&group->mutex);
-	iommu_group_put(group);
-
-	return handle;
-}
-EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
-
-/**
- * iommu_sva_unbind_device() - Remove a bond created with iommu_sva_bind_device
- * @handle: the handle returned by iommu_sva_bind_device()
- *
- * Put reference to a bond between device and address space. The device should
- * not be issuing any more transaction for this PASID. All outstanding page
- * requests for this PASID must have been flushed to the IOMMU.
- */
-void iommu_sva_unbind_device(struct iommu_sva *handle)
-{
-	struct iommu_group *group;
-	struct device *dev = handle->dev;
-	const struct iommu_ops *ops = dev_iommu_ops(dev);
-
-	if (!ops->sva_unbind)
-		return;
-
-	group = iommu_group_get(dev);
-	if (!group)
-		return;
-
-	mutex_lock(&group->mutex);
-	ops->sva_unbind(handle);
-	mutex_unlock(&group->mutex);
-
-	iommu_group_put(group);
-}
-EXPORT_SYMBOL_GPL(iommu_sva_unbind_device);
-
-u32 iommu_sva_get_pasid(struct iommu_sva *handle)
-{
-	const struct iommu_ops *ops = dev_iommu_ops(handle->dev);
-
-	if (!ops->sva_get_pasid)
-		return IOMMU_PASID_INVALID;
-
-	return ops->sva_get_pasid(handle);
-}
-EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
-
 /*
  * Changes the default domain of an iommu group that has *only* one device
  *
-- 
2.25.1


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

* [PATCH RFC 07/11] iommu: Remove SVA related callbacks from iommu ops
  2022-03-20  6:40 ` Lu Baolu
@ 2022-03-20  6:40   ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Jacob jun Pan

These ops'es have been replaced with the dev_attach/detach_pasid domain
ops'es. There's no need for them anymore. Remove them to avoid dead
code.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/intel-iommu.h                   |  4 --
 include/linux/iommu.h                         |  8 ---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   | 17 -------
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   | 36 --------------
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  3 --
 drivers/iommu/intel/iommu.c                   |  3 --
 drivers/iommu/intel/svm.c                     | 49 -------------------
 7 files changed, 120 deletions(-)

diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index c14283137fb5..7ce12590ce0f 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -738,10 +738,6 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn);
 extern void intel_svm_check(struct intel_iommu *iommu);
 extern int intel_svm_enable_prq(struct intel_iommu *iommu);
 extern int intel_svm_finish_prq(struct intel_iommu *iommu);
-struct iommu_sva *intel_svm_bind(struct device *dev, struct mm_struct *mm,
-				 void *drvdata);
-void intel_svm_unbind(struct iommu_sva *handle);
-u32 intel_svm_get_pasid(struct iommu_sva *handle);
 int intel_svm_page_response(struct device *dev, struct iommu_fault_event *evt,
 			    struct iommu_page_response *msg);
 extern const struct iommu_domain_ops intel_svm_domain_ops;
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 1c7db6a94022..47c9aa5aa9c8 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -212,9 +212,6 @@ struct iommu_iotlb_gather {
  * @dev_has/enable/disable_feat: per device entries to check/enable/disable
  *                               iommu specific features.
  * @dev_feat_enabled: check enabled feature
- * @sva_bind: Bind process address space to device
- * @sva_unbind: Unbind process address space from device
- * @sva_get_pasid: Get PASID associated to a SVA handle
  * @page_response: handle page request response
  * @def_domain_type: device default domain type, return value:
  *		- IOMMU_DOMAIN_IDENTITY: must use an identity domain
@@ -248,11 +245,6 @@ struct iommu_ops {
 	int (*dev_enable_feat)(struct device *dev, enum iommu_dev_features f);
 	int (*dev_disable_feat)(struct device *dev, enum iommu_dev_features f);
 
-	struct iommu_sva *(*sva_bind)(struct device *dev, struct mm_struct *mm,
-				      void *drvdata);
-	void (*sva_unbind)(struct iommu_sva *handle);
-	u32 (*sva_get_pasid)(struct iommu_sva *handle);
-
 	int (*page_response)(struct device *dev,
 			     struct iommu_fault_event *evt,
 			     struct iommu_page_response *msg);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 7631c00fdcbd..2513309ec0db 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -754,10 +754,6 @@ bool arm_smmu_master_sva_enabled(struct arm_smmu_master *master);
 int arm_smmu_master_enable_sva(struct arm_smmu_master *master);
 int arm_smmu_master_disable_sva(struct arm_smmu_master *master);
 bool arm_smmu_master_iopf_supported(struct arm_smmu_master *master);
-struct iommu_sva *arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm,
-				    void *drvdata);
-void arm_smmu_sva_unbind(struct iommu_sva *handle);
-u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle);
 void arm_smmu_sva_notifier_synchronize(void);
 int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
 				  struct device *dev, ioasid_t id);
@@ -794,19 +790,6 @@ static inline bool arm_smmu_master_iopf_supported(struct arm_smmu_master *master
 	return false;
 }
 
-static inline struct iommu_sva *
-arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm, void *drvdata)
-{
-	return ERR_PTR(-ENODEV);
-}
-
-static inline void arm_smmu_sva_unbind(struct iommu_sva *handle) {}
-
-static inline u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle)
-{
-	return IOMMU_PASID_INVALID;
-}
-
 static inline void arm_smmu_sva_notifier_synchronize(void) {}
 
 static inline int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 1e114b9dc17f..3537a2291d7c 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -351,42 +351,6 @@ __arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm)
 	return ERR_PTR(ret);
 }
 
-struct iommu_sva *
-arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm, void *drvdata)
-{
-	struct iommu_sva *handle;
-	struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
-	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
-
-	if (smmu_domain->stage != ARM_SMMU_DOMAIN_S1)
-		return ERR_PTR(-EINVAL);
-
-	mutex_lock(&sva_lock);
-	handle = __arm_smmu_sva_bind(dev, mm);
-	mutex_unlock(&sva_lock);
-	return handle;
-}
-
-void arm_smmu_sva_unbind(struct iommu_sva *handle)
-{
-	struct arm_smmu_bond *bond = sva_to_bond(handle);
-
-	mutex_lock(&sva_lock);
-	if (refcount_dec_and_test(&bond->refs)) {
-		list_del(&bond->list);
-		arm_smmu_mmu_notifier_put(bond->smmu_mn);
-		kfree(bond);
-	}
-	mutex_unlock(&sva_lock);
-}
-
-u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle)
-{
-	struct arm_smmu_bond *bond = sva_to_bond(handle);
-
-	return bond->mm->pasid;
-}
-
 bool arm_smmu_sva_supported(struct arm_smmu_device *smmu)
 {
 	unsigned long reg, fld;
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 2e9d3cd30510..026b783d602f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2864,9 +2864,6 @@ static struct iommu_ops arm_smmu_ops = {
 	.dev_feat_enabled	= arm_smmu_dev_feature_enabled,
 	.dev_enable_feat	= arm_smmu_dev_enable_feature,
 	.dev_disable_feat	= arm_smmu_dev_disable_feature,
-	.sva_bind		= arm_smmu_sva_bind,
-	.sva_unbind		= arm_smmu_sva_unbind,
-	.sva_get_pasid		= arm_smmu_sva_get_pasid,
 	.page_response		= arm_smmu_page_response,
 	.pgsize_bitmap		= -1UL, /* Restricted during device attach */
 	.owner			= THIS_MODULE,
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index d55dca3eacf8..8781305b9a02 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4892,9 +4892,6 @@ const struct iommu_ops intel_iommu_ops = {
 	.def_domain_type	= device_def_domain_type,
 	.pgsize_bitmap		= SZ_4K,
 #ifdef CONFIG_INTEL_IOMMU_SVM
-	.sva_bind		= intel_svm_bind,
-	.sva_unbind		= intel_svm_unbind,
-	.sva_get_pasid		= intel_svm_get_pasid,
 	.page_response		= intel_svm_page_response,
 #endif
 	.default_domain_ops = &(const struct iommu_domain_ops) {
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index b9f4dd7057d1..7a43ed4c0a27 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -313,14 +313,6 @@ static int pasid_to_svm_sdev(struct device *dev, unsigned int pasid,
 	return 0;
 }
 
-static int intel_svm_alloc_pasid(struct device *dev, struct mm_struct *mm)
-{
-	ioasid_t max_pasid = dev_is_pci(dev) ?
-			pci_max_pasids(to_pci_dev(dev)) : intel_pasid_max_id;
-
-	return iommu_sva_alloc_pasid(mm, PASID_MIN, max_pasid - 1);
-}
-
 static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
 					   struct device *dev,
 					   struct mm_struct *mm)
@@ -810,47 +802,6 @@ static irqreturn_t prq_event_thread(int irq, void *d)
 	return IRQ_RETVAL(handled);
 }
 
-struct iommu_sva *intel_svm_bind(struct device *dev, struct mm_struct *mm, void *drvdata)
-{
-	struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL);
-	struct iommu_sva *sva;
-	int ret;
-
-	mutex_lock(&pasid_mutex);
-	ret = intel_svm_alloc_pasid(dev, mm);
-	if (ret) {
-		mutex_unlock(&pasid_mutex);
-		return ERR_PTR(ret);
-	}
-
-	sva = intel_svm_bind_mm(iommu, dev, mm);
-	mutex_unlock(&pasid_mutex);
-
-	return sva;
-}
-
-void intel_svm_unbind(struct iommu_sva *sva)
-{
-	struct intel_svm_dev *sdev = to_intel_svm_dev(sva);
-
-	mutex_lock(&pasid_mutex);
-	intel_svm_unbind_mm(sdev->dev, sdev->pasid);
-	mutex_unlock(&pasid_mutex);
-}
-
-u32 intel_svm_get_pasid(struct iommu_sva *sva)
-{
-	struct intel_svm_dev *sdev;
-	u32 pasid;
-
-	mutex_lock(&pasid_mutex);
-	sdev = to_intel_svm_dev(sva);
-	pasid = sdev->pasid;
-	mutex_unlock(&pasid_mutex);
-
-	return pasid;
-}
-
 int intel_svm_page_response(struct device *dev,
 			    struct iommu_fault_event *evt,
 			    struct iommu_page_response *msg)
-- 
2.25.1

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

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

* [PATCH RFC 07/11] iommu: Remove SVA related callbacks from iommu ops
@ 2022-03-20  6:40   ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel, Lu Baolu

These ops'es have been replaced with the dev_attach/detach_pasid domain
ops'es. There's no need for them anymore. Remove them to avoid dead
code.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/intel-iommu.h                   |  4 --
 include/linux/iommu.h                         |  8 ---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   | 17 -------
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   | 36 --------------
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  3 --
 drivers/iommu/intel/iommu.c                   |  3 --
 drivers/iommu/intel/svm.c                     | 49 -------------------
 7 files changed, 120 deletions(-)

diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index c14283137fb5..7ce12590ce0f 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -738,10 +738,6 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn);
 extern void intel_svm_check(struct intel_iommu *iommu);
 extern int intel_svm_enable_prq(struct intel_iommu *iommu);
 extern int intel_svm_finish_prq(struct intel_iommu *iommu);
-struct iommu_sva *intel_svm_bind(struct device *dev, struct mm_struct *mm,
-				 void *drvdata);
-void intel_svm_unbind(struct iommu_sva *handle);
-u32 intel_svm_get_pasid(struct iommu_sva *handle);
 int intel_svm_page_response(struct device *dev, struct iommu_fault_event *evt,
 			    struct iommu_page_response *msg);
 extern const struct iommu_domain_ops intel_svm_domain_ops;
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 1c7db6a94022..47c9aa5aa9c8 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -212,9 +212,6 @@ struct iommu_iotlb_gather {
  * @dev_has/enable/disable_feat: per device entries to check/enable/disable
  *                               iommu specific features.
  * @dev_feat_enabled: check enabled feature
- * @sva_bind: Bind process address space to device
- * @sva_unbind: Unbind process address space from device
- * @sva_get_pasid: Get PASID associated to a SVA handle
  * @page_response: handle page request response
  * @def_domain_type: device default domain type, return value:
  *		- IOMMU_DOMAIN_IDENTITY: must use an identity domain
@@ -248,11 +245,6 @@ struct iommu_ops {
 	int (*dev_enable_feat)(struct device *dev, enum iommu_dev_features f);
 	int (*dev_disable_feat)(struct device *dev, enum iommu_dev_features f);
 
-	struct iommu_sva *(*sva_bind)(struct device *dev, struct mm_struct *mm,
-				      void *drvdata);
-	void (*sva_unbind)(struct iommu_sva *handle);
-	u32 (*sva_get_pasid)(struct iommu_sva *handle);
-
 	int (*page_response)(struct device *dev,
 			     struct iommu_fault_event *evt,
 			     struct iommu_page_response *msg);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 7631c00fdcbd..2513309ec0db 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -754,10 +754,6 @@ bool arm_smmu_master_sva_enabled(struct arm_smmu_master *master);
 int arm_smmu_master_enable_sva(struct arm_smmu_master *master);
 int arm_smmu_master_disable_sva(struct arm_smmu_master *master);
 bool arm_smmu_master_iopf_supported(struct arm_smmu_master *master);
-struct iommu_sva *arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm,
-				    void *drvdata);
-void arm_smmu_sva_unbind(struct iommu_sva *handle);
-u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle);
 void arm_smmu_sva_notifier_synchronize(void);
 int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
 				  struct device *dev, ioasid_t id);
@@ -794,19 +790,6 @@ static inline bool arm_smmu_master_iopf_supported(struct arm_smmu_master *master
 	return false;
 }
 
-static inline struct iommu_sva *
-arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm, void *drvdata)
-{
-	return ERR_PTR(-ENODEV);
-}
-
-static inline void arm_smmu_sva_unbind(struct iommu_sva *handle) {}
-
-static inline u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle)
-{
-	return IOMMU_PASID_INVALID;
-}
-
 static inline void arm_smmu_sva_notifier_synchronize(void) {}
 
 static inline int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 1e114b9dc17f..3537a2291d7c 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -351,42 +351,6 @@ __arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm)
 	return ERR_PTR(ret);
 }
 
-struct iommu_sva *
-arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm, void *drvdata)
-{
-	struct iommu_sva *handle;
-	struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
-	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
-
-	if (smmu_domain->stage != ARM_SMMU_DOMAIN_S1)
-		return ERR_PTR(-EINVAL);
-
-	mutex_lock(&sva_lock);
-	handle = __arm_smmu_sva_bind(dev, mm);
-	mutex_unlock(&sva_lock);
-	return handle;
-}
-
-void arm_smmu_sva_unbind(struct iommu_sva *handle)
-{
-	struct arm_smmu_bond *bond = sva_to_bond(handle);
-
-	mutex_lock(&sva_lock);
-	if (refcount_dec_and_test(&bond->refs)) {
-		list_del(&bond->list);
-		arm_smmu_mmu_notifier_put(bond->smmu_mn);
-		kfree(bond);
-	}
-	mutex_unlock(&sva_lock);
-}
-
-u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle)
-{
-	struct arm_smmu_bond *bond = sva_to_bond(handle);
-
-	return bond->mm->pasid;
-}
-
 bool arm_smmu_sva_supported(struct arm_smmu_device *smmu)
 {
 	unsigned long reg, fld;
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 2e9d3cd30510..026b783d602f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2864,9 +2864,6 @@ static struct iommu_ops arm_smmu_ops = {
 	.dev_feat_enabled	= arm_smmu_dev_feature_enabled,
 	.dev_enable_feat	= arm_smmu_dev_enable_feature,
 	.dev_disable_feat	= arm_smmu_dev_disable_feature,
-	.sva_bind		= arm_smmu_sva_bind,
-	.sva_unbind		= arm_smmu_sva_unbind,
-	.sva_get_pasid		= arm_smmu_sva_get_pasid,
 	.page_response		= arm_smmu_page_response,
 	.pgsize_bitmap		= -1UL, /* Restricted during device attach */
 	.owner			= THIS_MODULE,
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index d55dca3eacf8..8781305b9a02 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4892,9 +4892,6 @@ const struct iommu_ops intel_iommu_ops = {
 	.def_domain_type	= device_def_domain_type,
 	.pgsize_bitmap		= SZ_4K,
 #ifdef CONFIG_INTEL_IOMMU_SVM
-	.sva_bind		= intel_svm_bind,
-	.sva_unbind		= intel_svm_unbind,
-	.sva_get_pasid		= intel_svm_get_pasid,
 	.page_response		= intel_svm_page_response,
 #endif
 	.default_domain_ops = &(const struct iommu_domain_ops) {
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index b9f4dd7057d1..7a43ed4c0a27 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -313,14 +313,6 @@ static int pasid_to_svm_sdev(struct device *dev, unsigned int pasid,
 	return 0;
 }
 
-static int intel_svm_alloc_pasid(struct device *dev, struct mm_struct *mm)
-{
-	ioasid_t max_pasid = dev_is_pci(dev) ?
-			pci_max_pasids(to_pci_dev(dev)) : intel_pasid_max_id;
-
-	return iommu_sva_alloc_pasid(mm, PASID_MIN, max_pasid - 1);
-}
-
 static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
 					   struct device *dev,
 					   struct mm_struct *mm)
@@ -810,47 +802,6 @@ static irqreturn_t prq_event_thread(int irq, void *d)
 	return IRQ_RETVAL(handled);
 }
 
-struct iommu_sva *intel_svm_bind(struct device *dev, struct mm_struct *mm, void *drvdata)
-{
-	struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL);
-	struct iommu_sva *sva;
-	int ret;
-
-	mutex_lock(&pasid_mutex);
-	ret = intel_svm_alloc_pasid(dev, mm);
-	if (ret) {
-		mutex_unlock(&pasid_mutex);
-		return ERR_PTR(ret);
-	}
-
-	sva = intel_svm_bind_mm(iommu, dev, mm);
-	mutex_unlock(&pasid_mutex);
-
-	return sva;
-}
-
-void intel_svm_unbind(struct iommu_sva *sva)
-{
-	struct intel_svm_dev *sdev = to_intel_svm_dev(sva);
-
-	mutex_lock(&pasid_mutex);
-	intel_svm_unbind_mm(sdev->dev, sdev->pasid);
-	mutex_unlock(&pasid_mutex);
-}
-
-u32 intel_svm_get_pasid(struct iommu_sva *sva)
-{
-	struct intel_svm_dev *sdev;
-	u32 pasid;
-
-	mutex_lock(&pasid_mutex);
-	sdev = to_intel_svm_dev(sva);
-	pasid = sdev->pasid;
-	mutex_unlock(&pasid_mutex);
-
-	return pasid;
-}
-
 int intel_svm_page_response(struct device *dev,
 			    struct iommu_fault_event *evt,
 			    struct iommu_page_response *msg)
-- 
2.25.1


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

* [PATCH RFC 08/11] iommu: Handle IO page faults directly
  2022-03-20  6:40 ` Lu Baolu
@ 2022-03-20  6:40   ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Jacob jun Pan

Directly call the IO page fault handler in iommu_report_device_fault()
unless the device driver registered its own page fault handler. There
is no need to explicitly register the fault handler in IOMMU drivers.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 13 +------------
 drivers/iommu/intel/iommu.c                     | 14 ++------------
 drivers/iommu/iommu.c                           | 11 ++++++++---
 3 files changed, 11 insertions(+), 27 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 3537a2291d7c..8497425f3c13 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -426,7 +426,6 @@ bool arm_smmu_master_sva_enabled(struct arm_smmu_master *master)
 
 static int arm_smmu_master_sva_enable_iopf(struct arm_smmu_master *master)
 {
-	int ret;
 	struct device *dev = master->dev;
 
 	/*
@@ -439,16 +438,7 @@ static int arm_smmu_master_sva_enable_iopf(struct arm_smmu_master *master)
 	if (!master->iopf_enabled)
 		return -EINVAL;
 
-	ret = iopf_queue_add_device(master->smmu->evtq.iopf, dev);
-	if (ret)
-		return ret;
-
-	ret = iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev);
-	if (ret) {
-		iopf_queue_remove_device(master->smmu->evtq.iopf, dev);
-		return ret;
-	}
-	return 0;
+	return iopf_queue_add_device(master->smmu->evtq.iopf, dev);
 }
 
 static void arm_smmu_master_sva_disable_iopf(struct arm_smmu_master *master)
@@ -458,7 +448,6 @@ static void arm_smmu_master_sva_disable_iopf(struct arm_smmu_master *master)
 	if (!master->iopf_enabled)
 		return;
 
-	iommu_unregister_device_fault_handler(dev);
 	iopf_queue_remove_device(master->smmu->evtq.iopf, dev);
 }
 
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 8781305b9a02..8f9cc66787c3 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4760,7 +4760,6 @@ static int intel_iommu_enable_sva(struct device *dev)
 {
 	struct device_domain_info *info = dev_iommu_priv_get(dev);
 	struct intel_iommu *iommu;
-	int ret;
 
 	if (!info || dmar_disabled)
 		return -EINVAL;
@@ -4778,24 +4777,15 @@ static int intel_iommu_enable_sva(struct device *dev)
 	if (!info->pasid_enabled || !info->pri_enabled || !info->ats_enabled)
 		return -EINVAL;
 
-	ret = iopf_queue_add_device(iommu->iopf_queue, dev);
-	if (!ret)
-		ret = iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev);
-
-	return ret;
+	return iopf_queue_add_device(iommu->iopf_queue, dev);
 }
 
 static int intel_iommu_disable_sva(struct device *dev)
 {
 	struct device_domain_info *info = dev_iommu_priv_get(dev);
 	struct intel_iommu *iommu = info->iommu;
-	int ret;
-
-	ret = iommu_unregister_device_fault_handler(dev);
-	if (!ret)
-		ret = iopf_queue_remove_device(iommu->iopf_queue, dev);
 
-	return ret;
+	return iopf_queue_remove_device(iommu->iopf_queue, dev);
 }
 
 static int intel_iommu_enable_iopf(struct device *dev)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index c0966fc9b686..4f90b71c6f6e 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -27,6 +27,8 @@
 #include <linux/cc_platform.h>
 #include <trace/events/iommu.h>
 
+#include "iommu-sva-lib.h"
+
 static struct kset *iommu_group_kset;
 static DEFINE_IDA(iommu_group_ida);
 
@@ -1177,10 +1179,9 @@ int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt)
 	if (!param || !evt)
 		return -EINVAL;
 
-	/* we only report device fault if there is a handler registered */
 	mutex_lock(&param->lock);
 	fparam = param->fault_param;
-	if (!fparam || !fparam->handler) {
+	if (!fparam) {
 		ret = -EINVAL;
 		goto done_unlock;
 	}
@@ -1198,7 +1199,11 @@ int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt)
 		mutex_unlock(&fparam->lock);
 	}
 
-	ret = fparam->handler(&evt->fault, fparam->data);
+	if (fparam->handler)
+		ret = fparam->handler(&evt->fault, fparam->data);
+	else
+		ret = iommu_queue_iopf(&evt->fault, fparam->data);
+
 	if (ret && evt_pending) {
 		mutex_lock(&fparam->lock);
 		list_del(&evt_pending->list);
-- 
2.25.1

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

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

* [PATCH RFC 08/11] iommu: Handle IO page faults directly
@ 2022-03-20  6:40   ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel, Lu Baolu

Directly call the IO page fault handler in iommu_report_device_fault()
unless the device driver registered its own page fault handler. There
is no need to explicitly register the fault handler in IOMMU drivers.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 13 +------------
 drivers/iommu/intel/iommu.c                     | 14 ++------------
 drivers/iommu/iommu.c                           | 11 ++++++++---
 3 files changed, 11 insertions(+), 27 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 3537a2291d7c..8497425f3c13 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -426,7 +426,6 @@ bool arm_smmu_master_sva_enabled(struct arm_smmu_master *master)
 
 static int arm_smmu_master_sva_enable_iopf(struct arm_smmu_master *master)
 {
-	int ret;
 	struct device *dev = master->dev;
 
 	/*
@@ -439,16 +438,7 @@ static int arm_smmu_master_sva_enable_iopf(struct arm_smmu_master *master)
 	if (!master->iopf_enabled)
 		return -EINVAL;
 
-	ret = iopf_queue_add_device(master->smmu->evtq.iopf, dev);
-	if (ret)
-		return ret;
-
-	ret = iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev);
-	if (ret) {
-		iopf_queue_remove_device(master->smmu->evtq.iopf, dev);
-		return ret;
-	}
-	return 0;
+	return iopf_queue_add_device(master->smmu->evtq.iopf, dev);
 }
 
 static void arm_smmu_master_sva_disable_iopf(struct arm_smmu_master *master)
@@ -458,7 +448,6 @@ static void arm_smmu_master_sva_disable_iopf(struct arm_smmu_master *master)
 	if (!master->iopf_enabled)
 		return;
 
-	iommu_unregister_device_fault_handler(dev);
 	iopf_queue_remove_device(master->smmu->evtq.iopf, dev);
 }
 
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 8781305b9a02..8f9cc66787c3 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4760,7 +4760,6 @@ static int intel_iommu_enable_sva(struct device *dev)
 {
 	struct device_domain_info *info = dev_iommu_priv_get(dev);
 	struct intel_iommu *iommu;
-	int ret;
 
 	if (!info || dmar_disabled)
 		return -EINVAL;
@@ -4778,24 +4777,15 @@ static int intel_iommu_enable_sva(struct device *dev)
 	if (!info->pasid_enabled || !info->pri_enabled || !info->ats_enabled)
 		return -EINVAL;
 
-	ret = iopf_queue_add_device(iommu->iopf_queue, dev);
-	if (!ret)
-		ret = iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev);
-
-	return ret;
+	return iopf_queue_add_device(iommu->iopf_queue, dev);
 }
 
 static int intel_iommu_disable_sva(struct device *dev)
 {
 	struct device_domain_info *info = dev_iommu_priv_get(dev);
 	struct intel_iommu *iommu = info->iommu;
-	int ret;
-
-	ret = iommu_unregister_device_fault_handler(dev);
-	if (!ret)
-		ret = iopf_queue_remove_device(iommu->iopf_queue, dev);
 
-	return ret;
+	return iopf_queue_remove_device(iommu->iopf_queue, dev);
 }
 
 static int intel_iommu_enable_iopf(struct device *dev)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index c0966fc9b686..4f90b71c6f6e 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -27,6 +27,8 @@
 #include <linux/cc_platform.h>
 #include <trace/events/iommu.h>
 
+#include "iommu-sva-lib.h"
+
 static struct kset *iommu_group_kset;
 static DEFINE_IDA(iommu_group_ida);
 
@@ -1177,10 +1179,9 @@ int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt)
 	if (!param || !evt)
 		return -EINVAL;
 
-	/* we only report device fault if there is a handler registered */
 	mutex_lock(&param->lock);
 	fparam = param->fault_param;
-	if (!fparam || !fparam->handler) {
+	if (!fparam) {
 		ret = -EINVAL;
 		goto done_unlock;
 	}
@@ -1198,7 +1199,11 @@ int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt)
 		mutex_unlock(&fparam->lock);
 	}
 
-	ret = fparam->handler(&evt->fault, fparam->data);
+	if (fparam->handler)
+		ret = fparam->handler(&evt->fault, fparam->data);
+	else
+		ret = iommu_queue_iopf(&evt->fault, fparam->data);
+
 	if (ret && evt_pending) {
 		mutex_lock(&fparam->lock);
 		list_del(&evt_pending->list);
-- 
2.25.1


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

* [PATCH RFC 09/11] iommu: Add iommu_get_domain_for_dev_pasid()
  2022-03-20  6:40 ` Lu Baolu
@ 2022-03-20  6:40   ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Jacob jun Pan

This adds a helper to retrieve the iommu_domain which has been attached to
a {device, pasid}. One usage scenario of this helper exists in the I/O page
fault handling framework, where {device, pasid} was reported by hardware,
and software needs to retrieve the attached domain for further routing.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h |  8 ++++++++
 drivers/iommu/iommu.c | 31 +++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 47c9aa5aa9c8..803e7b07605e 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -676,6 +676,8 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
 			      struct device *dev, ioasid_t pasid);
 void iommu_detach_device_pasid(struct iommu_domain *domain,
 			       struct device *dev, ioasid_t pasid);
+struct iommu_domain *
+iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid);
 
 #else /* CONFIG_IOMMU_API */
 
@@ -1041,6 +1043,12 @@ static inline void iommu_detach_device_pasid(struct iommu_domain *domain,
 					     struct device *dev, ioasid_t pasid)
 {
 }
+
+static inline struct iommu_domain *
+iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid)
+{
+	return NULL;
+}
 #endif /* CONFIG_IOMMU_API */
 
 #ifdef CONFIG_IOMMU_SVA
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 4f90b71c6f6e..508fdcabda5c 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -40,6 +40,7 @@ struct iommu_group {
 	struct kobject kobj;
 	struct kobject *devices_kobj;
 	struct list_head devices;
+	struct xarray pasid_array;
 	struct mutex mutex;
 	void *iommu_data;
 	void (*iommu_data_release)(void *iommu_data);
@@ -632,6 +633,7 @@ struct iommu_group *iommu_group_alloc(void)
 	mutex_init(&group->mutex);
 	INIT_LIST_HEAD(&group->devices);
 	INIT_LIST_HEAD(&group->entry);
+	xa_init(&group->pasid_array);
 
 	ret = ida_simple_get(&iommu_group_ida, 0, 0, GFP_KERNEL);
 	if (ret < 0) {
@@ -3086,6 +3088,7 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
 {
 	struct iommu_group *group;
 	int ret = -EINVAL;
+	void *curr;
 
 	if (!domain->ops->attach_dev_pasid)
 		return -EINVAL;
@@ -3098,7 +3101,16 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
 	if (iommu_group_device_count(group) != 1)
 		goto out_unlock;
 
+	xa_lock(&group->pasid_array);
+	curr = __xa_cmpxchg(&group->pasid_array, pasid, NULL,
+			    domain, GFP_KERNEL);
+	xa_unlock(&group->pasid_array);
+	if (curr)
+		goto out_unlock;
+
 	ret = domain->ops->attach_dev_pasid(domain, dev, pasid);
+	if (ret)
+		xa_erase(&group->pasid_array, pasid);
 
 out_unlock:
 	mutex_unlock(&group->mutex);
@@ -3118,6 +3130,25 @@ void iommu_detach_device_pasid(struct iommu_domain *domain,
 
 	mutex_lock(&group->mutex);
 	domain->ops->detach_dev_pasid(domain, dev, pasid);
+	xa_erase(&group->pasid_array, pasid);
+	mutex_unlock(&group->mutex);
+	iommu_group_put(group);
+}
+
+struct iommu_domain *
+iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid)
+{
+	struct iommu_domain *domain;
+	struct iommu_group *group;
+
+	group = iommu_group_get(dev);
+	if (!group)
+		return NULL;
+
+	mutex_lock(&group->mutex);
+	domain = xa_load(&group->pasid_array, pasid);
 	mutex_unlock(&group->mutex);
 	iommu_group_put(group);
+
+	return domain;
 }
-- 
2.25.1

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

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

* [PATCH RFC 09/11] iommu: Add iommu_get_domain_for_dev_pasid()
@ 2022-03-20  6:40   ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel, Lu Baolu

This adds a helper to retrieve the iommu_domain which has been attached to
a {device, pasid}. One usage scenario of this helper exists in the I/O page
fault handling framework, where {device, pasid} was reported by hardware,
and software needs to retrieve the attached domain for further routing.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h |  8 ++++++++
 drivers/iommu/iommu.c | 31 +++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 47c9aa5aa9c8..803e7b07605e 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -676,6 +676,8 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
 			      struct device *dev, ioasid_t pasid);
 void iommu_detach_device_pasid(struct iommu_domain *domain,
 			       struct device *dev, ioasid_t pasid);
+struct iommu_domain *
+iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid);
 
 #else /* CONFIG_IOMMU_API */
 
@@ -1041,6 +1043,12 @@ static inline void iommu_detach_device_pasid(struct iommu_domain *domain,
 					     struct device *dev, ioasid_t pasid)
 {
 }
+
+static inline struct iommu_domain *
+iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid)
+{
+	return NULL;
+}
 #endif /* CONFIG_IOMMU_API */
 
 #ifdef CONFIG_IOMMU_SVA
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 4f90b71c6f6e..508fdcabda5c 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -40,6 +40,7 @@ struct iommu_group {
 	struct kobject kobj;
 	struct kobject *devices_kobj;
 	struct list_head devices;
+	struct xarray pasid_array;
 	struct mutex mutex;
 	void *iommu_data;
 	void (*iommu_data_release)(void *iommu_data);
@@ -632,6 +633,7 @@ struct iommu_group *iommu_group_alloc(void)
 	mutex_init(&group->mutex);
 	INIT_LIST_HEAD(&group->devices);
 	INIT_LIST_HEAD(&group->entry);
+	xa_init(&group->pasid_array);
 
 	ret = ida_simple_get(&iommu_group_ida, 0, 0, GFP_KERNEL);
 	if (ret < 0) {
@@ -3086,6 +3088,7 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
 {
 	struct iommu_group *group;
 	int ret = -EINVAL;
+	void *curr;
 
 	if (!domain->ops->attach_dev_pasid)
 		return -EINVAL;
@@ -3098,7 +3101,16 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
 	if (iommu_group_device_count(group) != 1)
 		goto out_unlock;
 
+	xa_lock(&group->pasid_array);
+	curr = __xa_cmpxchg(&group->pasid_array, pasid, NULL,
+			    domain, GFP_KERNEL);
+	xa_unlock(&group->pasid_array);
+	if (curr)
+		goto out_unlock;
+
 	ret = domain->ops->attach_dev_pasid(domain, dev, pasid);
+	if (ret)
+		xa_erase(&group->pasid_array, pasid);
 
 out_unlock:
 	mutex_unlock(&group->mutex);
@@ -3118,6 +3130,25 @@ void iommu_detach_device_pasid(struct iommu_domain *domain,
 
 	mutex_lock(&group->mutex);
 	domain->ops->detach_dev_pasid(domain, dev, pasid);
+	xa_erase(&group->pasid_array, pasid);
+	mutex_unlock(&group->mutex);
+	iommu_group_put(group);
+}
+
+struct iommu_domain *
+iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid)
+{
+	struct iommu_domain *domain;
+	struct iommu_group *group;
+
+	group = iommu_group_get(dev);
+	if (!group)
+		return NULL;
+
+	mutex_lock(&group->mutex);
+	domain = xa_load(&group->pasid_array, pasid);
 	mutex_unlock(&group->mutex);
 	iommu_group_put(group);
+
+	return domain;
 }
-- 
2.25.1


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

* [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-20  6:40 ` Lu Baolu
@ 2022-03-20  6:40   ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Jacob jun Pan

The existing IOPF handling framework only handles the I/O page faults for
SVA. Ginven that we are able to link iommu domain with each I/O page fault,
we can now make the I/O page fault handling framework more general for
more types of page faults.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h         |  4 +++
 drivers/iommu/io-pgfault.c    | 67 ++++++-----------------------------
 drivers/iommu/iommu-sva-lib.c | 59 ++++++++++++++++++++++++++++++
 3 files changed, 73 insertions(+), 57 deletions(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 803e7b07605e..11c65a7bed88 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -50,6 +50,8 @@ struct iommu_dma_cookie;
 typedef int (*iommu_fault_handler_t)(struct iommu_domain *,
 			struct device *, unsigned long, int, void *);
 typedef int (*iommu_dev_fault_handler_t)(struct iommu_fault *, void *);
+typedef enum iommu_page_response_code (*iommu_domain_iopf_handler_t)
+			(struct iommu_fault *, void *);
 
 struct iommu_domain_geometry {
 	dma_addr_t aperture_start; /* First address that can be mapped    */
@@ -101,6 +103,8 @@ struct iommu_domain {
 	struct iommu_domain_geometry geometry;
 	struct iommu_dma_cookie *iova_cookie;
 	struct mm_struct *sva_cookie;
+	iommu_domain_iopf_handler_t fault_handler;
+	void *fault_data;
 };
 
 static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
index 1df8c1dcae77..dad0e40cd8d2 100644
--- a/drivers/iommu/io-pgfault.c
+++ b/drivers/iommu/io-pgfault.c
@@ -69,62 +69,6 @@ static int iopf_complete_group(struct device *dev, struct iopf_fault *iopf,
 	return iommu_page_response(dev, &resp);
 }
 
-static enum iommu_page_response_code
-iopf_handle_single(struct iopf_fault *iopf)
-{
-	vm_fault_t ret;
-	struct mm_struct *mm;
-	struct vm_area_struct *vma;
-	unsigned int access_flags = 0;
-	unsigned int fault_flags = FAULT_FLAG_REMOTE;
-	struct iommu_fault_page_request *prm = &iopf->fault.prm;
-	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
-
-	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
-		return status;
-
-	mm = iommu_sva_find(prm->pasid);
-	if (IS_ERR_OR_NULL(mm))
-		return status;
-
-	mmap_read_lock(mm);
-
-	vma = find_extend_vma(mm, prm->addr);
-	if (!vma)
-		/* Unmapped area */
-		goto out_put_mm;
-
-	if (prm->perm & IOMMU_FAULT_PERM_READ)
-		access_flags |= VM_READ;
-
-	if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
-		access_flags |= VM_WRITE;
-		fault_flags |= FAULT_FLAG_WRITE;
-	}
-
-	if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
-		access_flags |= VM_EXEC;
-		fault_flags |= FAULT_FLAG_INSTRUCTION;
-	}
-
-	if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
-		fault_flags |= FAULT_FLAG_USER;
-
-	if (access_flags & ~vma->vm_flags)
-		/* Access fault */
-		goto out_put_mm;
-
-	ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
-	status = ret & VM_FAULT_ERROR ? IOMMU_PAGE_RESP_INVALID :
-		IOMMU_PAGE_RESP_SUCCESS;
-
-out_put_mm:
-	mmap_read_unlock(mm);
-	mmput(mm);
-
-	return status;
-}
-
 static void iopf_handle_group(struct work_struct *work)
 {
 	struct iopf_group *group;
@@ -134,12 +78,21 @@ static void iopf_handle_group(struct work_struct *work)
 	group = container_of(work, struct iopf_group, work);
 
 	list_for_each_entry_safe(iopf, next, &group->faults, list) {
+		struct iommu_domain *domain;
+
+		domain = iommu_get_domain_for_dev_pasid(group->dev,
+							iopf->fault.prm.pasid);
+
+		if (!domain || !domain->fault_handler)
+			status = IOMMU_PAGE_RESP_INVALID;
+
 		/*
 		 * For the moment, errors are sticky: don't handle subsequent
 		 * faults in the group if there is an error.
 		 */
 		if (status == IOMMU_PAGE_RESP_SUCCESS)
-			status = iopf_handle_single(iopf);
+			status = domain->fault_handler(&iopf->fault,
+						       domain->fault_data);
 
 		if (!(iopf->fault.prm.flags &
 		      IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE))
diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
index 47cf98e661ff..01fa8096bd02 100644
--- a/drivers/iommu/iommu-sva-lib.c
+++ b/drivers/iommu/iommu-sva-lib.c
@@ -87,6 +87,63 @@ static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev)
 	return domain;
 }
 
+static enum iommu_page_response_code
+iommu_sva_handle_iopf(struct iommu_fault *fault, void *data)
+{
+	vm_fault_t ret;
+	struct mm_struct *mm;
+	struct vm_area_struct *vma;
+	unsigned int access_flags = 0;
+	struct iommu_domain *domain = data;
+	unsigned int fault_flags = FAULT_FLAG_REMOTE;
+	struct iommu_fault_page_request *prm = &fault->prm;
+	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
+
+	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
+		return status;
+
+	mm = domain->sva_cookie;
+	if (IS_ERR_OR_NULL(mm))
+		return status;
+
+	mmap_read_lock(mm);
+
+	vma = find_extend_vma(mm, prm->addr);
+	if (!vma)
+		/* Unmapped area */
+		goto out_put_mm;
+
+	if (prm->perm & IOMMU_FAULT_PERM_READ)
+		access_flags |= VM_READ;
+
+	if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
+		access_flags |= VM_WRITE;
+		fault_flags |= FAULT_FLAG_WRITE;
+	}
+
+	if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
+		access_flags |= VM_EXEC;
+		fault_flags |= FAULT_FLAG_INSTRUCTION;
+	}
+
+	if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
+		fault_flags |= FAULT_FLAG_USER;
+
+	if (access_flags & ~vma->vm_flags)
+		/* Access fault */
+		goto out_put_mm;
+
+	ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
+	status = ret & VM_FAULT_ERROR ? IOMMU_PAGE_RESP_INVALID :
+		IOMMU_PAGE_RESP_SUCCESS;
+
+out_put_mm:
+	mmap_read_unlock(mm);
+	mmput(mm);
+
+	return status;
+}
+
 /**
  * iommu_sva_bind_device() - Bind a process address space to a device
  * @dev: the device
@@ -124,6 +181,8 @@ iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
 		goto out;
 	}
 	domain->sva_cookie = mm;
+	domain->fault_handler = iommu_sva_handle_iopf;
+	domain->fault_data = domain;
 
 	ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
 	if (ret)
-- 
2.25.1

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

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

* [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-20  6:40   ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel, Lu Baolu

The existing IOPF handling framework only handles the I/O page faults for
SVA. Ginven that we are able to link iommu domain with each I/O page fault,
we can now make the I/O page fault handling framework more general for
more types of page faults.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h         |  4 +++
 drivers/iommu/io-pgfault.c    | 67 ++++++-----------------------------
 drivers/iommu/iommu-sva-lib.c | 59 ++++++++++++++++++++++++++++++
 3 files changed, 73 insertions(+), 57 deletions(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 803e7b07605e..11c65a7bed88 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -50,6 +50,8 @@ struct iommu_dma_cookie;
 typedef int (*iommu_fault_handler_t)(struct iommu_domain *,
 			struct device *, unsigned long, int, void *);
 typedef int (*iommu_dev_fault_handler_t)(struct iommu_fault *, void *);
+typedef enum iommu_page_response_code (*iommu_domain_iopf_handler_t)
+			(struct iommu_fault *, void *);
 
 struct iommu_domain_geometry {
 	dma_addr_t aperture_start; /* First address that can be mapped    */
@@ -101,6 +103,8 @@ struct iommu_domain {
 	struct iommu_domain_geometry geometry;
 	struct iommu_dma_cookie *iova_cookie;
 	struct mm_struct *sva_cookie;
+	iommu_domain_iopf_handler_t fault_handler;
+	void *fault_data;
 };
 
 static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
index 1df8c1dcae77..dad0e40cd8d2 100644
--- a/drivers/iommu/io-pgfault.c
+++ b/drivers/iommu/io-pgfault.c
@@ -69,62 +69,6 @@ static int iopf_complete_group(struct device *dev, struct iopf_fault *iopf,
 	return iommu_page_response(dev, &resp);
 }
 
-static enum iommu_page_response_code
-iopf_handle_single(struct iopf_fault *iopf)
-{
-	vm_fault_t ret;
-	struct mm_struct *mm;
-	struct vm_area_struct *vma;
-	unsigned int access_flags = 0;
-	unsigned int fault_flags = FAULT_FLAG_REMOTE;
-	struct iommu_fault_page_request *prm = &iopf->fault.prm;
-	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
-
-	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
-		return status;
-
-	mm = iommu_sva_find(prm->pasid);
-	if (IS_ERR_OR_NULL(mm))
-		return status;
-
-	mmap_read_lock(mm);
-
-	vma = find_extend_vma(mm, prm->addr);
-	if (!vma)
-		/* Unmapped area */
-		goto out_put_mm;
-
-	if (prm->perm & IOMMU_FAULT_PERM_READ)
-		access_flags |= VM_READ;
-
-	if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
-		access_flags |= VM_WRITE;
-		fault_flags |= FAULT_FLAG_WRITE;
-	}
-
-	if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
-		access_flags |= VM_EXEC;
-		fault_flags |= FAULT_FLAG_INSTRUCTION;
-	}
-
-	if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
-		fault_flags |= FAULT_FLAG_USER;
-
-	if (access_flags & ~vma->vm_flags)
-		/* Access fault */
-		goto out_put_mm;
-
-	ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
-	status = ret & VM_FAULT_ERROR ? IOMMU_PAGE_RESP_INVALID :
-		IOMMU_PAGE_RESP_SUCCESS;
-
-out_put_mm:
-	mmap_read_unlock(mm);
-	mmput(mm);
-
-	return status;
-}
-
 static void iopf_handle_group(struct work_struct *work)
 {
 	struct iopf_group *group;
@@ -134,12 +78,21 @@ static void iopf_handle_group(struct work_struct *work)
 	group = container_of(work, struct iopf_group, work);
 
 	list_for_each_entry_safe(iopf, next, &group->faults, list) {
+		struct iommu_domain *domain;
+
+		domain = iommu_get_domain_for_dev_pasid(group->dev,
+							iopf->fault.prm.pasid);
+
+		if (!domain || !domain->fault_handler)
+			status = IOMMU_PAGE_RESP_INVALID;
+
 		/*
 		 * For the moment, errors are sticky: don't handle subsequent
 		 * faults in the group if there is an error.
 		 */
 		if (status == IOMMU_PAGE_RESP_SUCCESS)
-			status = iopf_handle_single(iopf);
+			status = domain->fault_handler(&iopf->fault,
+						       domain->fault_data);
 
 		if (!(iopf->fault.prm.flags &
 		      IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE))
diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
index 47cf98e661ff..01fa8096bd02 100644
--- a/drivers/iommu/iommu-sva-lib.c
+++ b/drivers/iommu/iommu-sva-lib.c
@@ -87,6 +87,63 @@ static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev)
 	return domain;
 }
 
+static enum iommu_page_response_code
+iommu_sva_handle_iopf(struct iommu_fault *fault, void *data)
+{
+	vm_fault_t ret;
+	struct mm_struct *mm;
+	struct vm_area_struct *vma;
+	unsigned int access_flags = 0;
+	struct iommu_domain *domain = data;
+	unsigned int fault_flags = FAULT_FLAG_REMOTE;
+	struct iommu_fault_page_request *prm = &fault->prm;
+	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
+
+	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
+		return status;
+
+	mm = domain->sva_cookie;
+	if (IS_ERR_OR_NULL(mm))
+		return status;
+
+	mmap_read_lock(mm);
+
+	vma = find_extend_vma(mm, prm->addr);
+	if (!vma)
+		/* Unmapped area */
+		goto out_put_mm;
+
+	if (prm->perm & IOMMU_FAULT_PERM_READ)
+		access_flags |= VM_READ;
+
+	if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
+		access_flags |= VM_WRITE;
+		fault_flags |= FAULT_FLAG_WRITE;
+	}
+
+	if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
+		access_flags |= VM_EXEC;
+		fault_flags |= FAULT_FLAG_INSTRUCTION;
+	}
+
+	if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
+		fault_flags |= FAULT_FLAG_USER;
+
+	if (access_flags & ~vma->vm_flags)
+		/* Access fault */
+		goto out_put_mm;
+
+	ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
+	status = ret & VM_FAULT_ERROR ? IOMMU_PAGE_RESP_INVALID :
+		IOMMU_PAGE_RESP_SUCCESS;
+
+out_put_mm:
+	mmap_read_unlock(mm);
+	mmput(mm);
+
+	return status;
+}
+
 /**
  * iommu_sva_bind_device() - Bind a process address space to a device
  * @dev: the device
@@ -124,6 +181,8 @@ iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
 		goto out;
 	}
 	domain->sva_cookie = mm;
+	domain->fault_handler = iommu_sva_handle_iopf;
+	domain->fault_data = domain;
 
 	ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
 	if (ret)
-- 
2.25.1


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

* [PATCH RFC 11/11] iommu: Rename iommu-sva-lib.{c,h}
  2022-03-20  6:40 ` Lu Baolu
@ 2022-03-20  6:40   ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Jacob jun Pan

Rename iommu-sva-lib.c[h] to iommu-sva.c[h] as it contains all code
for SVA implementation in iommu core.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/iommu/{iommu-sva-lib.h => iommu-sva.h}  | 0
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 2 +-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c     | 2 +-
 drivers/iommu/intel/iommu.c                     | 2 +-
 drivers/iommu/intel/svm.c                       | 2 +-
 drivers/iommu/io-pgfault.c                      | 2 +-
 drivers/iommu/{iommu-sva-lib.c => iommu-sva.c}  | 2 +-
 drivers/iommu/iommu.c                           | 2 +-
 drivers/iommu/Makefile                          | 2 +-
 9 files changed, 8 insertions(+), 8 deletions(-)
 rename drivers/iommu/{iommu-sva-lib.h => iommu-sva.h} (100%)
 rename drivers/iommu/{iommu-sva-lib.c => iommu-sva.c} (99%)

diff --git a/drivers/iommu/iommu-sva-lib.h b/drivers/iommu/iommu-sva.h
similarity index 100%
rename from drivers/iommu/iommu-sva-lib.h
rename to drivers/iommu/iommu-sva.h
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 8497425f3c13..a6505a6619f8 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -9,7 +9,7 @@
 #include <linux/slab.h>
 
 #include "arm-smmu-v3.h"
-#include "../../iommu-sva-lib.h"
+#include "../../iommu-sva.h"
 #include "../../io-pgtable-arm.h"
 
 struct arm_smmu_mmu_notifier {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 026b783d602f..62de69a01456 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -31,7 +31,7 @@
 #include <linux/amba/bus.h>
 
 #include "arm-smmu-v3.h"
-#include "../../iommu-sva-lib.h"
+#include "../../iommu-sva.h"
 
 static bool disable_bypass = true;
 module_param(disable_bypass, bool, 0444);
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 8f9cc66787c3..0a46b3b923eb 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -27,7 +27,7 @@
 #include <linux/tboot.h>
 
 #include "../irq_remapping.h"
-#include "../iommu-sva-lib.h"
+#include "../iommu-sva.h"
 #include "pasid.h"
 #include "cap_audit.h"
 
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index 7a43ed4c0a27..4195ea9aad5f 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -25,7 +25,7 @@
 
 #include "pasid.h"
 #include "perf.h"
-#include "../iommu-sva-lib.h"
+#include "../iommu-sva.h"
 
 static irqreturn_t prq_event_thread(int irq, void *d);
 static void intel_svm_drain_prq(struct device *dev, u32 pasid);
diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
index dad0e40cd8d2..c162d9d2a5c9 100644
--- a/drivers/iommu/io-pgfault.c
+++ b/drivers/iommu/io-pgfault.c
@@ -11,7 +11,7 @@
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 
-#include "iommu-sva-lib.h"
+#include "iommu-sva.h"
 
 /**
  * struct iopf_queue - IO Page Fault queue
diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva.c
similarity index 99%
rename from drivers/iommu/iommu-sva-lib.c
rename to drivers/iommu/iommu-sva.c
index 01fa8096bd02..8b92ce4b0807 100644
--- a/drivers/iommu/iommu-sva-lib.c
+++ b/drivers/iommu/iommu-sva.c
@@ -7,7 +7,7 @@
 #include <linux/slab.h>
 #include <linux/sched/mm.h>
 
-#include "iommu-sva-lib.h"
+#include "iommu-sva.h"
 
 static DEFINE_MUTEX(iommu_sva_lock);
 static DECLARE_IOASID_SET(iommu_sva_pasid);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 508fdcabda5c..0b5f0eee3ca6 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -27,7 +27,7 @@
 #include <linux/cc_platform.h>
 #include <trace/events/iommu.h>
 
-#include "iommu-sva-lib.h"
+#include "iommu-sva.h"
 
 static struct kset *iommu_group_kset;
 static DEFINE_IDA(iommu_group_ida);
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 44475a9b3eea..c1763476162b 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -27,6 +27,6 @@ obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o
 obj-$(CONFIG_S390_IOMMU) += s390-iommu.o
 obj-$(CONFIG_HYPERV_IOMMU) += hyperv-iommu.o
 obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o
-obj-$(CONFIG_IOMMU_SVA) += iommu-sva-lib.o io-pgfault.o
+obj-$(CONFIG_IOMMU_SVA) += iommu-sva.o io-pgfault.o
 obj-$(CONFIG_SPRD_IOMMU) += sprd-iommu.o
 obj-$(CONFIG_APPLE_DART) += apple-dart.o
-- 
2.25.1

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

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

* [PATCH RFC 11/11] iommu: Rename iommu-sva-lib.{c,h}
@ 2022-03-20  6:40   ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-20  6:40 UTC (permalink / raw)
  To: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel, Lu Baolu

Rename iommu-sva-lib.c[h] to iommu-sva.c[h] as it contains all code
for SVA implementation in iommu core.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/iommu/{iommu-sva-lib.h => iommu-sva.h}  | 0
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 2 +-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c     | 2 +-
 drivers/iommu/intel/iommu.c                     | 2 +-
 drivers/iommu/intel/svm.c                       | 2 +-
 drivers/iommu/io-pgfault.c                      | 2 +-
 drivers/iommu/{iommu-sva-lib.c => iommu-sva.c}  | 2 +-
 drivers/iommu/iommu.c                           | 2 +-
 drivers/iommu/Makefile                          | 2 +-
 9 files changed, 8 insertions(+), 8 deletions(-)
 rename drivers/iommu/{iommu-sva-lib.h => iommu-sva.h} (100%)
 rename drivers/iommu/{iommu-sva-lib.c => iommu-sva.c} (99%)

diff --git a/drivers/iommu/iommu-sva-lib.h b/drivers/iommu/iommu-sva.h
similarity index 100%
rename from drivers/iommu/iommu-sva-lib.h
rename to drivers/iommu/iommu-sva.h
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 8497425f3c13..a6505a6619f8 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -9,7 +9,7 @@
 #include <linux/slab.h>
 
 #include "arm-smmu-v3.h"
-#include "../../iommu-sva-lib.h"
+#include "../../iommu-sva.h"
 #include "../../io-pgtable-arm.h"
 
 struct arm_smmu_mmu_notifier {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 026b783d602f..62de69a01456 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -31,7 +31,7 @@
 #include <linux/amba/bus.h>
 
 #include "arm-smmu-v3.h"
-#include "../../iommu-sva-lib.h"
+#include "../../iommu-sva.h"
 
 static bool disable_bypass = true;
 module_param(disable_bypass, bool, 0444);
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 8f9cc66787c3..0a46b3b923eb 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -27,7 +27,7 @@
 #include <linux/tboot.h>
 
 #include "../irq_remapping.h"
-#include "../iommu-sva-lib.h"
+#include "../iommu-sva.h"
 #include "pasid.h"
 #include "cap_audit.h"
 
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index 7a43ed4c0a27..4195ea9aad5f 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -25,7 +25,7 @@
 
 #include "pasid.h"
 #include "perf.h"
-#include "../iommu-sva-lib.h"
+#include "../iommu-sva.h"
 
 static irqreturn_t prq_event_thread(int irq, void *d);
 static void intel_svm_drain_prq(struct device *dev, u32 pasid);
diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
index dad0e40cd8d2..c162d9d2a5c9 100644
--- a/drivers/iommu/io-pgfault.c
+++ b/drivers/iommu/io-pgfault.c
@@ -11,7 +11,7 @@
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 
-#include "iommu-sva-lib.h"
+#include "iommu-sva.h"
 
 /**
  * struct iopf_queue - IO Page Fault queue
diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva.c
similarity index 99%
rename from drivers/iommu/iommu-sva-lib.c
rename to drivers/iommu/iommu-sva.c
index 01fa8096bd02..8b92ce4b0807 100644
--- a/drivers/iommu/iommu-sva-lib.c
+++ b/drivers/iommu/iommu-sva.c
@@ -7,7 +7,7 @@
 #include <linux/slab.h>
 #include <linux/sched/mm.h>
 
-#include "iommu-sva-lib.h"
+#include "iommu-sva.h"
 
 static DEFINE_MUTEX(iommu_sva_lock);
 static DECLARE_IOASID_SET(iommu_sva_pasid);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 508fdcabda5c..0b5f0eee3ca6 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -27,7 +27,7 @@
 #include <linux/cc_platform.h>
 #include <trace/events/iommu.h>
 
-#include "iommu-sva-lib.h"
+#include "iommu-sva.h"
 
 static struct kset *iommu_group_kset;
 static DEFINE_IDA(iommu_group_ida);
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 44475a9b3eea..c1763476162b 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -27,6 +27,6 @@ obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o
 obj-$(CONFIG_S390_IOMMU) += s390-iommu.o
 obj-$(CONFIG_HYPERV_IOMMU) += hyperv-iommu.o
 obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o
-obj-$(CONFIG_IOMMU_SVA) += iommu-sva-lib.o io-pgfault.o
+obj-$(CONFIG_IOMMU_SVA) += iommu-sva.o io-pgfault.o
 obj-$(CONFIG_SPRD_IOMMU) += sprd-iommu.o
 obj-$(CONFIG_APPLE_DART) += apple-dart.o
-- 
2.25.1


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

* RE: [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21  7:01     ` Tian, Kevin
  -1 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-21  7:01 UTC (permalink / raw)
  To: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Sunday, March 20, 2022 2:40 PM
> 
> Use this field to save the pasid/ssid bits that a device is able to
> support with its IOMMU hardware. It is a generic attribute of a device
> and lifting it into the per-device dev_iommu struct makes it possible
> to allocate a PASID for device without calls into the IOMMU drivers.
> Any iommu driver which suports PASID related features should set this
> field before features are enabled on the devices.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  include/linux/iommu.h                       | 1 +
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 1 +
>  drivers/iommu/intel/iommu.c                 | 5 ++++-
>  3 files changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 6ef2df258673..36f43af0af53 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -368,6 +368,7 @@ struct dev_iommu {
>  	struct iommu_fwspec		*fwspec;
>  	struct iommu_device		*iommu_dev;
>  	void				*priv;
> +	unsigned int			pasid_bits;
>  };
> 
>  int iommu_device_register(struct iommu_device *iommu,
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 627a3ed5ee8f..8e262210b5ad 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -2812,6 +2812,7 @@ static int arm_smmu_dev_enable_feature(struct
> device *dev,
>  		master->iopf_enabled = true;
>  		return 0;
>  	case IOMMU_DEV_FEAT_SVA:
> +		dev->iommu->pasid_bits = master->ssid_bits;
>  		return arm_smmu_master_enable_sva(master);
>  	default:
>  		return -EINVAL;
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index 6f7485c44a4b..c1b91bce1530 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -4587,8 +4587,11 @@ static struct iommu_device
> *intel_iommu_probe_device(struct device *dev)
>  			if (pasid_supported(iommu)) {
>  				int features = pci_pasid_features(pdev);
> 
> -				if (features >= 0)
> +				if (features >= 0) {
>  					info->pasid_supported = features | 1;
> +					dev->iommu->pasid_bits =
> +						fls(pci_max_pasids(pdev)) - 1;

Original intel_svm_alloc_pasid() covers both PCI and non-PCI devices:

	ioasid_t max_pasid = dev_is_pci(dev) ?
		pci_max_pasids(to_pci_dev(dev)) : intel_pasid_max_id;

though I'm not sure whether non-PCI SVA has been supported indeed, this
patch implies a functional change here.

> +				}
>  			}
> 
>  			if (info->ats_supported && ecap_prs(iommu->ecap)
> &&
> --
> 2.25.1


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

* RE: [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu
@ 2022-03-21  7:01     ` Tian, Kevin
  0 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-21  7:01 UTC (permalink / raw)
  To: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: iommu, Pan, Jacob jun, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Sunday, March 20, 2022 2:40 PM
> 
> Use this field to save the pasid/ssid bits that a device is able to
> support with its IOMMU hardware. It is a generic attribute of a device
> and lifting it into the per-device dev_iommu struct makes it possible
> to allocate a PASID for device without calls into the IOMMU drivers.
> Any iommu driver which suports PASID related features should set this
> field before features are enabled on the devices.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  include/linux/iommu.h                       | 1 +
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 1 +
>  drivers/iommu/intel/iommu.c                 | 5 ++++-
>  3 files changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 6ef2df258673..36f43af0af53 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -368,6 +368,7 @@ struct dev_iommu {
>  	struct iommu_fwspec		*fwspec;
>  	struct iommu_device		*iommu_dev;
>  	void				*priv;
> +	unsigned int			pasid_bits;
>  };
> 
>  int iommu_device_register(struct iommu_device *iommu,
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 627a3ed5ee8f..8e262210b5ad 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -2812,6 +2812,7 @@ static int arm_smmu_dev_enable_feature(struct
> device *dev,
>  		master->iopf_enabled = true;
>  		return 0;
>  	case IOMMU_DEV_FEAT_SVA:
> +		dev->iommu->pasid_bits = master->ssid_bits;
>  		return arm_smmu_master_enable_sva(master);
>  	default:
>  		return -EINVAL;
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index 6f7485c44a4b..c1b91bce1530 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -4587,8 +4587,11 @@ static struct iommu_device
> *intel_iommu_probe_device(struct device *dev)
>  			if (pasid_supported(iommu)) {
>  				int features = pci_pasid_features(pdev);
> 
> -				if (features >= 0)
> +				if (features >= 0) {
>  					info->pasid_supported = features | 1;
> +					dev->iommu->pasid_bits =
> +						fls(pci_max_pasids(pdev)) - 1;

Original intel_svm_alloc_pasid() covers both PCI and non-PCI devices:

	ioasid_t max_pasid = dev_is_pci(dev) ?
		pci_max_pasids(to_pci_dev(dev)) : intel_pasid_max_id;

though I'm not sure whether non-PCI SVA has been supported indeed, this
patch implies a functional change here.

> +				}
>  			}
> 
>  			if (info->ats_supported && ecap_prs(iommu->ecap)
> &&
> --
> 2.25.1

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

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

* RE: [PATCH RFC 02/11] iommu: Add iommu_domain type for SVA
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21  7:06     ` Tian, Kevin
  -1 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-21  7:06 UTC (permalink / raw)
  To: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Sunday, March 20, 2022 2:40 PM
> 
> Add a new iommu domain type IOMMU_DOMAIN_SVA to represent an I/O
> page
> table which is shared from CPU host VA. Add a sva_cookie field in the
> iommu_domain structure to save the mm_struct which represent the CPU
> memory page table.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  include/linux/iommu.h | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 36f43af0af53..3e179b853380 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -64,6 +64,9 @@ struct iommu_domain_geometry {
>  #define __IOMMU_DOMAIN_PT	(1U << 2)  /* Domain is identity
> mapped   */
>  #define __IOMMU_DOMAIN_DMA_FQ	(1U << 3)  /* DMA-API uses
> flush queue    */
> 
> +#define __IOMMU_DOMAIN_SHARED	(1U << 4)  /* Page table shared from
> CPU  */
> +#define __IOMMU_DOMAIN_HOST_VA	(1U << 5)  /* Host CPU virtual
> address */

suppose the SHARED bit will be also used for KVM page table sharing and
HOST_VA bit is to differentiate mm sharing from the latter?

> +
>  /*
>   * This are the possible domain-types
>   *
> @@ -86,6 +89,8 @@ struct iommu_domain_geometry {
>  #define IOMMU_DOMAIN_DMA_FQ	(__IOMMU_DOMAIN_PAGING |
> 	\
>  				 __IOMMU_DOMAIN_DMA_API |	\
>  				 __IOMMU_DOMAIN_DMA_FQ)
> +#define IOMMU_DOMAIN_SVA	(__IOMMU_DOMAIN_SHARED |
> 	\
> +				 __IOMMU_DOMAIN_HOST_VA)
> 
>  struct iommu_domain {
>  	unsigned type;
> @@ -95,6 +100,7 @@ struct iommu_domain {
>  	void *handler_token;
>  	struct iommu_domain_geometry geometry;
>  	struct iommu_dma_cookie *iova_cookie;
> +	struct mm_struct *sva_cookie;
>  };
> 
>  static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
> --
> 2.25.1


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

* RE: [PATCH RFC 02/11] iommu: Add iommu_domain type for SVA
@ 2022-03-21  7:06     ` Tian, Kevin
  0 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-21  7:06 UTC (permalink / raw)
  To: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: iommu, Pan, Jacob jun, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Sunday, March 20, 2022 2:40 PM
> 
> Add a new iommu domain type IOMMU_DOMAIN_SVA to represent an I/O
> page
> table which is shared from CPU host VA. Add a sva_cookie field in the
> iommu_domain structure to save the mm_struct which represent the CPU
> memory page table.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  include/linux/iommu.h | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 36f43af0af53..3e179b853380 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -64,6 +64,9 @@ struct iommu_domain_geometry {
>  #define __IOMMU_DOMAIN_PT	(1U << 2)  /* Domain is identity
> mapped   */
>  #define __IOMMU_DOMAIN_DMA_FQ	(1U << 3)  /* DMA-API uses
> flush queue    */
> 
> +#define __IOMMU_DOMAIN_SHARED	(1U << 4)  /* Page table shared from
> CPU  */
> +#define __IOMMU_DOMAIN_HOST_VA	(1U << 5)  /* Host CPU virtual
> address */

suppose the SHARED bit will be also used for KVM page table sharing and
HOST_VA bit is to differentiate mm sharing from the latter?

> +
>  /*
>   * This are the possible domain-types
>   *
> @@ -86,6 +89,8 @@ struct iommu_domain_geometry {
>  #define IOMMU_DOMAIN_DMA_FQ	(__IOMMU_DOMAIN_PAGING |
> 	\
>  				 __IOMMU_DOMAIN_DMA_API |	\
>  				 __IOMMU_DOMAIN_DMA_FQ)
> +#define IOMMU_DOMAIN_SVA	(__IOMMU_DOMAIN_SHARED |
> 	\
> +				 __IOMMU_DOMAIN_HOST_VA)
> 
>  struct iommu_domain {
>  	unsigned type;
> @@ -95,6 +100,7 @@ struct iommu_domain {
>  	void *handler_token;
>  	struct iommu_domain_geometry geometry;
>  	struct iommu_dma_cookie *iova_cookie;
> +	struct mm_struct *sva_cookie;
>  };
> 
>  static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
> --
> 2.25.1

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

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

* RE: [PATCH RFC 03/11] iommu: Add attach/detach_dev_pasid domain ops
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21  7:13     ` Tian, Kevin
  -1 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-21  7:13 UTC (permalink / raw)
  To: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Sunday, March 20, 2022 2:40 PM
> 
> Attaching an IOMMU domain to a PASID of a device is a generic operation
> for modern IOMMU drivers which support PASID-granular DMA address
> translation. Currently visible usage scenarios include (but not limited):
> 
>  - SVA
>  - kernel DMA with PASID
>  - hardware-assist mediated device
> 
> This adds a pair of common domain ops for this purpose and implements a
> couple of wrapper helpers for in-kernel usage.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  include/linux/iommu.h | 22 ++++++++++++++++++++++
>  drivers/iommu/iommu.c | 41
> +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 63 insertions(+)
> 
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 3e179b853380..e51845b9a146 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -268,6 +268,8 @@ struct iommu_ops {
>   * struct iommu_domain_ops - domain specific operations
>   * @attach_dev: attach an iommu domain to a device
>   * @detach_dev: detach an iommu domain from a device
> + * @attach_dev_pasid: attach an iommu domain to a pasid of device
> + * @detach_dev_pasid: detach an iommu domain from a pasid of device
>   * @map: map a physically contiguous memory region to an iommu domain
>   * @map_pages: map a physically contiguous set of pages of the same size
> to
>   *             an iommu domain.
> @@ -285,6 +287,10 @@ struct iommu_ops {
>  struct iommu_domain_ops {
>  	int (*attach_dev)(struct iommu_domain *domain, struct device *dev);
>  	void (*detach_dev)(struct iommu_domain *domain, struct device
> *dev);
> +	int (*attach_dev_pasid)(struct iommu_domain *domain,
> +				struct device *dev, ioasid_t id);
> +	void (*detach_dev_pasid)(struct iommu_domain *domain,
> +				 struct device *dev, ioasid_t id);
> 
>  	int (*map)(struct iommu_domain *domain, unsigned long iova,
>  		   phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
> @@ -678,6 +684,11 @@ int iommu_group_claim_dma_owner(struct
> iommu_group *group, void *owner);
>  void iommu_group_release_dma_owner(struct iommu_group *group);
>  bool iommu_group_dma_owner_claimed(struct iommu_group *group);
> 
> +int iommu_attach_device_pasid(struct iommu_domain *domain,
> +			      struct device *dev, ioasid_t pasid);
> +void iommu_detach_device_pasid(struct iommu_domain *domain,
> +			       struct device *dev, ioasid_t pasid);
> +
>  #else /* CONFIG_IOMMU_API */
> 
>  struct iommu_ops {};
> @@ -1046,6 +1057,17 @@ static inline bool
> iommu_group_dma_owner_claimed(struct iommu_group *group)
>  {
>  	return false;
>  }
> +
> +static inline int iommu_attach_device_pasid(struct iommu_domain
> *domain,
> +					    struct device *dev, ioasid_t pasid)
> +{
> +	return -ENODEV;
> +}
> +
> +static inline void iommu_detach_device_pasid(struct iommu_domain
> *domain,
> +					     struct device *dev, ioasid_t pasid)
> +{
> +}
>  #endif /* CONFIG_IOMMU_API */
> 
>  /**
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index 0c42ece25854..78c71ee15f36 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -3167,3 +3167,44 @@ bool iommu_group_dma_owner_claimed(struct
> iommu_group *group)
>  	return user;
>  }
>  EXPORT_SYMBOL_GPL(iommu_group_dma_owner_claimed);
> +
> +int iommu_attach_device_pasid(struct iommu_domain *domain,
> +			      struct device *dev, ioasid_t pasid)
> +{
> +	struct iommu_group *group;
> +	int ret = -EINVAL;
> +
> +	if (!domain->ops->attach_dev_pasid)
> +		return -EINVAL;
> +
> +	group = iommu_group_get(dev);
> +	if (!group)
> +		return -ENODEV;
> +
> +	mutex_lock(&group->mutex);
> +	if (iommu_group_device_count(group) != 1)
> +		goto out_unlock;

Need move the reason of above limitation from iommu_sva_bind_device()
to here:

	/*
	 * To keep things simple, SVA currently doesn't support IOMMU groups
	 * with more than one device. Existing SVA-capable systems are not
	 * affected by the problems that required IOMMU groups (lack of ACS
	 * isolation, device ID aliasing and other hardware issues).
	 */
	if (iommu_group_device_count(group) != 1)
		goto out_unlock;

btw I didn't see any safeguard on above assumption in device hotplug path
to a group which already has SVA enabled...

> +
> +	ret = domain->ops->attach_dev_pasid(domain, dev, pasid);
> +
> +out_unlock:
> +	mutex_unlock(&group->mutex);
> +	iommu_group_put(group);
> +
> +	return ret;
> +}
> +
> +void iommu_detach_device_pasid(struct iommu_domain *domain,
> +			       struct device *dev, ioasid_t pasid)
> +{
> +	struct iommu_group *group;
> +
> +	group = iommu_group_get(dev);
> +	if (WARN_ON(!group))
> +		return;
> +
> +	mutex_lock(&group->mutex);
> +	domain->ops->detach_dev_pasid(domain, dev, pasid);
> +	mutex_unlock(&group->mutex);
> +	iommu_group_put(group);
> +}
> --
> 2.25.1


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

* RE: [PATCH RFC 03/11] iommu: Add attach/detach_dev_pasid domain ops
@ 2022-03-21  7:13     ` Tian, Kevin
  0 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-21  7:13 UTC (permalink / raw)
  To: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: iommu, Pan, Jacob jun, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Sunday, March 20, 2022 2:40 PM
> 
> Attaching an IOMMU domain to a PASID of a device is a generic operation
> for modern IOMMU drivers which support PASID-granular DMA address
> translation. Currently visible usage scenarios include (but not limited):
> 
>  - SVA
>  - kernel DMA with PASID
>  - hardware-assist mediated device
> 
> This adds a pair of common domain ops for this purpose and implements a
> couple of wrapper helpers for in-kernel usage.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  include/linux/iommu.h | 22 ++++++++++++++++++++++
>  drivers/iommu/iommu.c | 41
> +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 63 insertions(+)
> 
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 3e179b853380..e51845b9a146 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -268,6 +268,8 @@ struct iommu_ops {
>   * struct iommu_domain_ops - domain specific operations
>   * @attach_dev: attach an iommu domain to a device
>   * @detach_dev: detach an iommu domain from a device
> + * @attach_dev_pasid: attach an iommu domain to a pasid of device
> + * @detach_dev_pasid: detach an iommu domain from a pasid of device
>   * @map: map a physically contiguous memory region to an iommu domain
>   * @map_pages: map a physically contiguous set of pages of the same size
> to
>   *             an iommu domain.
> @@ -285,6 +287,10 @@ struct iommu_ops {
>  struct iommu_domain_ops {
>  	int (*attach_dev)(struct iommu_domain *domain, struct device *dev);
>  	void (*detach_dev)(struct iommu_domain *domain, struct device
> *dev);
> +	int (*attach_dev_pasid)(struct iommu_domain *domain,
> +				struct device *dev, ioasid_t id);
> +	void (*detach_dev_pasid)(struct iommu_domain *domain,
> +				 struct device *dev, ioasid_t id);
> 
>  	int (*map)(struct iommu_domain *domain, unsigned long iova,
>  		   phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
> @@ -678,6 +684,11 @@ int iommu_group_claim_dma_owner(struct
> iommu_group *group, void *owner);
>  void iommu_group_release_dma_owner(struct iommu_group *group);
>  bool iommu_group_dma_owner_claimed(struct iommu_group *group);
> 
> +int iommu_attach_device_pasid(struct iommu_domain *domain,
> +			      struct device *dev, ioasid_t pasid);
> +void iommu_detach_device_pasid(struct iommu_domain *domain,
> +			       struct device *dev, ioasid_t pasid);
> +
>  #else /* CONFIG_IOMMU_API */
> 
>  struct iommu_ops {};
> @@ -1046,6 +1057,17 @@ static inline bool
> iommu_group_dma_owner_claimed(struct iommu_group *group)
>  {
>  	return false;
>  }
> +
> +static inline int iommu_attach_device_pasid(struct iommu_domain
> *domain,
> +					    struct device *dev, ioasid_t pasid)
> +{
> +	return -ENODEV;
> +}
> +
> +static inline void iommu_detach_device_pasid(struct iommu_domain
> *domain,
> +					     struct device *dev, ioasid_t pasid)
> +{
> +}
>  #endif /* CONFIG_IOMMU_API */
> 
>  /**
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index 0c42ece25854..78c71ee15f36 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -3167,3 +3167,44 @@ bool iommu_group_dma_owner_claimed(struct
> iommu_group *group)
>  	return user;
>  }
>  EXPORT_SYMBOL_GPL(iommu_group_dma_owner_claimed);
> +
> +int iommu_attach_device_pasid(struct iommu_domain *domain,
> +			      struct device *dev, ioasid_t pasid)
> +{
> +	struct iommu_group *group;
> +	int ret = -EINVAL;
> +
> +	if (!domain->ops->attach_dev_pasid)
> +		return -EINVAL;
> +
> +	group = iommu_group_get(dev);
> +	if (!group)
> +		return -ENODEV;
> +
> +	mutex_lock(&group->mutex);
> +	if (iommu_group_device_count(group) != 1)
> +		goto out_unlock;

Need move the reason of above limitation from iommu_sva_bind_device()
to here:

	/*
	 * To keep things simple, SVA currently doesn't support IOMMU groups
	 * with more than one device. Existing SVA-capable systems are not
	 * affected by the problems that required IOMMU groups (lack of ACS
	 * isolation, device ID aliasing and other hardware issues).
	 */
	if (iommu_group_device_count(group) != 1)
		goto out_unlock;

btw I didn't see any safeguard on above assumption in device hotplug path
to a group which already has SVA enabled...

> +
> +	ret = domain->ops->attach_dev_pasid(domain, dev, pasid);
> +
> +out_unlock:
> +	mutex_unlock(&group->mutex);
> +	iommu_group_put(group);
> +
> +	return ret;
> +}
> +
> +void iommu_detach_device_pasid(struct iommu_domain *domain,
> +			       struct device *dev, ioasid_t pasid)
> +{
> +	struct iommu_group *group;
> +
> +	group = iommu_group_get(dev);
> +	if (WARN_ON(!group))
> +		return;
> +
> +	mutex_lock(&group->mutex);
> +	domain->ops->detach_dev_pasid(domain, dev, pasid);
> +	mutex_unlock(&group->mutex);
> +	iommu_group_put(group);
> +}
> --
> 2.25.1

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

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

* RE: [PATCH RFC 04/11] iommu/vt-d: Add SVA domain support
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21  7:45     ` Tian, Kevin
  -1 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-21  7:45 UTC (permalink / raw)
  To: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Sunday, March 20, 2022 2:40 PM
> 
> Add support for SVA domain allocation and provide an SVA-specific
> iommu_domain_ops.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  include/linux/intel-iommu.h |  1 +
>  drivers/iommu/intel/iommu.c | 12 ++++++++++++
>  drivers/iommu/intel/svm.c   | 34 ++++++++++++++++++++++++++++++++++
>  3 files changed, 47 insertions(+)
> 
> diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
> index 2f9891cb3d00..c14283137fb5 100644
> --- a/include/linux/intel-iommu.h
> +++ b/include/linux/intel-iommu.h
> @@ -744,6 +744,7 @@ void intel_svm_unbind(struct iommu_sva *handle);
>  u32 intel_svm_get_pasid(struct iommu_sva *handle);
>  int intel_svm_page_response(struct device *dev, struct iommu_fault_event
> *evt,
>  			    struct iommu_page_response *msg);
> +extern const struct iommu_domain_ops intel_svm_domain_ops;
> 
>  struct intel_svm_dev {
>  	struct list_head list;
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index c1b91bce1530..d55dca3eacf8 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -4318,6 +4318,18 @@ static struct iommu_domain
> *intel_iommu_domain_alloc(unsigned type)
>  		return domain;
>  	case IOMMU_DOMAIN_IDENTITY:
>  		return &si_domain->domain;
> +#ifdef CONFIG_INTEL_IOMMU_SVM
> +	case IOMMU_DOMAIN_SVA:
> +		dmar_domain = alloc_domain(type);
> +		if (!dmar_domain) {
> +			pr_err("Can't allocate sva domain\n");
> +			return NULL;
> +		}
> +		domain = &dmar_domain->domain;
> +		domain->ops = &intel_svm_domain_ops;
> +
> +		return domain;
> +#endif /* CONFIG_INTEL_IOMMU_SVM */
>  	default:
>  		return NULL;
>  	}
> diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
> index ee5ecde5b318..b9f4dd7057d1 100644
> --- a/drivers/iommu/intel/svm.c
> +++ b/drivers/iommu/intel/svm.c
> @@ -932,3 +932,37 @@ int intel_svm_page_response(struct device *dev,
>  	mutex_unlock(&pasid_mutex);
>  	return ret;
>  }
> +
> +static int intel_svm_attach_dev_pasid(struct iommu_domain *domain,
> +				      struct device *dev, ioasid_t pasid)
> +{
> +	struct device_domain_info *info = dev_iommu_priv_get(dev);
> +	struct mm_struct *mm = domain->sva_cookie;
> +	struct intel_iommu *iommu = info->iommu;
> +	struct iommu_sva *sva;
> +
> +	mutex_lock(&pasid_mutex);
> +	sva = intel_svm_bind_mm(iommu, dev, mm);
> +	mutex_unlock(&pasid_mutex);
> +

I'm not sure whether this is the right implementation of this callback.
In last patch you said it will be used for multiple usages but here it
is fixed to mm binding. Also the pasid argument is not used at all
and instead it is retrieved from mm struct implicitly.

Basically SVA requires three steps:

1) alloc a SVA-type domain;
2) construct the domain to wrap mm;
3) attach the domain to a PASID;

If we aim .attach_dev_pasid to be generic it may suggest that 1) and 2)
should be done before .attach_dev_pasid then within this callback it
just deals with domain/pasid attach in a generic way.

> +	return IS_ERR_OR_NULL(sva);
> +}
> +
> +static void intel_svm_detach_dev_pasid(struct iommu_domain *domain,
> +				       struct device *dev, ioasid_t pasid)
> +{
> +	mutex_lock(&pasid_mutex);
> +	intel_svm_unbind_mm(dev, pasid);
> +	mutex_unlock(&pasid_mutex);
> +}
> +
> +static void intel_svm_domain_free(struct iommu_domain *domain)
> +{
> +	kfree(domain);
> +}
> +
> +const struct iommu_domain_ops intel_svm_domain_ops = {
> +	.attach_dev_pasid	= intel_svm_attach_dev_pasid,
> +	.detach_dev_pasid	= intel_svm_detach_dev_pasid,
> +	.free			= intel_svm_domain_free,
> +};
> --
> 2.25.1


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

* RE: [PATCH RFC 04/11] iommu/vt-d: Add SVA domain support
@ 2022-03-21  7:45     ` Tian, Kevin
  0 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-21  7:45 UTC (permalink / raw)
  To: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: iommu, Pan, Jacob jun, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Sunday, March 20, 2022 2:40 PM
> 
> Add support for SVA domain allocation and provide an SVA-specific
> iommu_domain_ops.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  include/linux/intel-iommu.h |  1 +
>  drivers/iommu/intel/iommu.c | 12 ++++++++++++
>  drivers/iommu/intel/svm.c   | 34 ++++++++++++++++++++++++++++++++++
>  3 files changed, 47 insertions(+)
> 
> diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
> index 2f9891cb3d00..c14283137fb5 100644
> --- a/include/linux/intel-iommu.h
> +++ b/include/linux/intel-iommu.h
> @@ -744,6 +744,7 @@ void intel_svm_unbind(struct iommu_sva *handle);
>  u32 intel_svm_get_pasid(struct iommu_sva *handle);
>  int intel_svm_page_response(struct device *dev, struct iommu_fault_event
> *evt,
>  			    struct iommu_page_response *msg);
> +extern const struct iommu_domain_ops intel_svm_domain_ops;
> 
>  struct intel_svm_dev {
>  	struct list_head list;
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index c1b91bce1530..d55dca3eacf8 100644
> --- a/drivers/iommu/intel/iommu.c
> +++ b/drivers/iommu/intel/iommu.c
> @@ -4318,6 +4318,18 @@ static struct iommu_domain
> *intel_iommu_domain_alloc(unsigned type)
>  		return domain;
>  	case IOMMU_DOMAIN_IDENTITY:
>  		return &si_domain->domain;
> +#ifdef CONFIG_INTEL_IOMMU_SVM
> +	case IOMMU_DOMAIN_SVA:
> +		dmar_domain = alloc_domain(type);
> +		if (!dmar_domain) {
> +			pr_err("Can't allocate sva domain\n");
> +			return NULL;
> +		}
> +		domain = &dmar_domain->domain;
> +		domain->ops = &intel_svm_domain_ops;
> +
> +		return domain;
> +#endif /* CONFIG_INTEL_IOMMU_SVM */
>  	default:
>  		return NULL;
>  	}
> diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
> index ee5ecde5b318..b9f4dd7057d1 100644
> --- a/drivers/iommu/intel/svm.c
> +++ b/drivers/iommu/intel/svm.c
> @@ -932,3 +932,37 @@ int intel_svm_page_response(struct device *dev,
>  	mutex_unlock(&pasid_mutex);
>  	return ret;
>  }
> +
> +static int intel_svm_attach_dev_pasid(struct iommu_domain *domain,
> +				      struct device *dev, ioasid_t pasid)
> +{
> +	struct device_domain_info *info = dev_iommu_priv_get(dev);
> +	struct mm_struct *mm = domain->sva_cookie;
> +	struct intel_iommu *iommu = info->iommu;
> +	struct iommu_sva *sva;
> +
> +	mutex_lock(&pasid_mutex);
> +	sva = intel_svm_bind_mm(iommu, dev, mm);
> +	mutex_unlock(&pasid_mutex);
> +

I'm not sure whether this is the right implementation of this callback.
In last patch you said it will be used for multiple usages but here it
is fixed to mm binding. Also the pasid argument is not used at all
and instead it is retrieved from mm struct implicitly.

Basically SVA requires three steps:

1) alloc a SVA-type domain;
2) construct the domain to wrap mm;
3) attach the domain to a PASID;

If we aim .attach_dev_pasid to be generic it may suggest that 1) and 2)
should be done before .attach_dev_pasid then within this callback it
just deals with domain/pasid attach in a generic way.

> +	return IS_ERR_OR_NULL(sva);
> +}
> +
> +static void intel_svm_detach_dev_pasid(struct iommu_domain *domain,
> +				       struct device *dev, ioasid_t pasid)
> +{
> +	mutex_lock(&pasid_mutex);
> +	intel_svm_unbind_mm(dev, pasid);
> +	mutex_unlock(&pasid_mutex);
> +}
> +
> +static void intel_svm_domain_free(struct iommu_domain *domain)
> +{
> +	kfree(domain);
> +}
> +
> +const struct iommu_domain_ops intel_svm_domain_ops = {
> +	.attach_dev_pasid	= intel_svm_attach_dev_pasid,
> +	.detach_dev_pasid	= intel_svm_detach_dev_pasid,
> +	.free			= intel_svm_domain_free,
> +};
> --
> 2.25.1

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

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

* RE: [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21  8:04     ` Tian, Kevin
  -1 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-21  8:04 UTC (permalink / raw)
  To: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Sunday, March 20, 2022 2:40 PM
> +struct iommu_sva *
> +iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void
> *drvdata)
> +{
> +	int ret = -EINVAL;
> +	struct iommu_sva *handle;
> +	struct iommu_domain *domain;
> +
> +	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
> +	if (!handle)
> +		return ERR_PTR(-ENOMEM);
> +
> +	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits)
> - 1);
> +	if (ret)
> +		goto out;
> +
> +	domain = iommu_sva_domain_alloc(dev);
> +	if (!domain) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +	domain->sva_cookie = mm;

one domain can be attached by multiple devices, so this should not be
a blind alloc.

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

* RE: [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
@ 2022-03-21  8:04     ` Tian, Kevin
  0 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-21  8:04 UTC (permalink / raw)
  To: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: iommu, Pan, Jacob jun, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Sunday, March 20, 2022 2:40 PM
> +struct iommu_sva *
> +iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void
> *drvdata)
> +{
> +	int ret = -EINVAL;
> +	struct iommu_sva *handle;
> +	struct iommu_domain *domain;
> +
> +	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
> +	if (!handle)
> +		return ERR_PTR(-ENOMEM);
> +
> +	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits)
> - 1);
> +	if (ret)
> +		goto out;
> +
> +	domain = iommu_sva_domain_alloc(dev);
> +	if (!domain) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +	domain->sva_cookie = mm;

one domain can be attached by multiple devices, so this should not be
a blind alloc.
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

* RE: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21  8:09     ` Tian, Kevin
  -1 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-21  8:09 UTC (permalink / raw)
  To: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Sunday, March 20, 2022 2:40 PM
> 
> The existing IOPF handling framework only handles the I/O page faults for
> SVA. Ginven that we are able to link iommu domain with each I/O page fault,
> we can now make the I/O page fault handling framework more general for
> more types of page faults.

"make ... generic" in subject line is kind of confusing. Reading this patch I
think you really meant changing from per-device fault handling to per-domain
fault handling. This is more accurate in concept since the fault is caused by
the domain page table. 😊


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

* RE: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-21  8:09     ` Tian, Kevin
  0 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-21  8:09 UTC (permalink / raw)
  To: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: iommu, Pan, Jacob jun, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Sunday, March 20, 2022 2:40 PM
> 
> The existing IOPF handling framework only handles the I/O page faults for
> SVA. Ginven that we are able to link iommu domain with each I/O page fault,
> we can now make the I/O page fault handling framework more general for
> more types of page faults.

"make ... generic" in subject line is kind of confusing. Reading this patch I
think you really meant changing from per-device fault handling to per-domain
fault handling. This is more accurate in concept since the fault is caused by
the domain page table. 😊

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

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

* Re: [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu
  2022-03-21  7:01     ` Tian, Kevin
@ 2022-03-21 10:22       ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-21 10:22 UTC (permalink / raw)
  To: Tian, Kevin, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Raj, Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: baolu.lu, Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

On 2022/3/21 15:01, Tian, Kevin wrote:
>> From: Lu Baolu<baolu.lu@linux.intel.com>
>> Sent: Sunday, March 20, 2022 2:40 PM
>>
>> Use this field to save the pasid/ssid bits that a device is able to
>> support with its IOMMU hardware. It is a generic attribute of a device
>> and lifting it into the per-device dev_iommu struct makes it possible
>> to allocate a PASID for device without calls into the IOMMU drivers.
>> Any iommu driver which suports PASID related features should set this
>> field before features are enabled on the devices.
>>
>> Signed-off-by: Lu Baolu<baolu.lu@linux.intel.com>
>> ---
>>   include/linux/iommu.h                       | 1 +
>>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 1 +
>>   drivers/iommu/intel/iommu.c                 | 5 ++++-
>>   3 files changed, 6 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
>> index 6ef2df258673..36f43af0af53 100644
>> --- a/include/linux/iommu.h
>> +++ b/include/linux/iommu.h
>> @@ -368,6 +368,7 @@ struct dev_iommu {
>>   	struct iommu_fwspec		*fwspec;
>>   	struct iommu_device		*iommu_dev;
>>   	void				*priv;
>> +	unsigned int			pasid_bits;
>>   };
>>
>>   int iommu_device_register(struct iommu_device *iommu,
>> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> index 627a3ed5ee8f..8e262210b5ad 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> @@ -2812,6 +2812,7 @@ static int arm_smmu_dev_enable_feature(struct
>> device *dev,
>>   		master->iopf_enabled = true;
>>   		return 0;
>>   	case IOMMU_DEV_FEAT_SVA:
>> +		dev->iommu->pasid_bits = master->ssid_bits;
>>   		return arm_smmu_master_enable_sva(master);
>>   	default:
>>   		return -EINVAL;
>> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
>> index 6f7485c44a4b..c1b91bce1530 100644
>> --- a/drivers/iommu/intel/iommu.c
>> +++ b/drivers/iommu/intel/iommu.c
>> @@ -4587,8 +4587,11 @@ static struct iommu_device
>> *intel_iommu_probe_device(struct device *dev)
>>   			if (pasid_supported(iommu)) {
>>   				int features = pci_pasid_features(pdev);
>>
>> -				if (features >= 0)
>> +				if (features >= 0) {
>>   					info->pasid_supported = features | 1;
>> +					dev->iommu->pasid_bits =
>> +						fls(pci_max_pasids(pdev)) - 1;
> Original intel_svm_alloc_pasid() covers both PCI and non-PCI devices:
> 
> 	ioasid_t max_pasid = dev_is_pci(dev) ?
> 		pci_max_pasids(to_pci_dev(dev)) : intel_pasid_max_id;
> 
> though I'm not sure whether non-PCI SVA has been supported indeed, this
> patch implies a functional change here.
> 

The info->pasid_supported is only set for PCI devices. So the status is
that non-PCI SVA hasn't been supported. No functional change here from
this point of view.

Best regards,
baolu

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

* Re: [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu
@ 2022-03-21 10:22       ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-21 10:22 UTC (permalink / raw)
  To: Tian, Kevin, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Raj, Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Pan, Jacob jun

On 2022/3/21 15:01, Tian, Kevin wrote:
>> From: Lu Baolu<baolu.lu@linux.intel.com>
>> Sent: Sunday, March 20, 2022 2:40 PM
>>
>> Use this field to save the pasid/ssid bits that a device is able to
>> support with its IOMMU hardware. It is a generic attribute of a device
>> and lifting it into the per-device dev_iommu struct makes it possible
>> to allocate a PASID for device without calls into the IOMMU drivers.
>> Any iommu driver which suports PASID related features should set this
>> field before features are enabled on the devices.
>>
>> Signed-off-by: Lu Baolu<baolu.lu@linux.intel.com>
>> ---
>>   include/linux/iommu.h                       | 1 +
>>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 1 +
>>   drivers/iommu/intel/iommu.c                 | 5 ++++-
>>   3 files changed, 6 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
>> index 6ef2df258673..36f43af0af53 100644
>> --- a/include/linux/iommu.h
>> +++ b/include/linux/iommu.h
>> @@ -368,6 +368,7 @@ struct dev_iommu {
>>   	struct iommu_fwspec		*fwspec;
>>   	struct iommu_device		*iommu_dev;
>>   	void				*priv;
>> +	unsigned int			pasid_bits;
>>   };
>>
>>   int iommu_device_register(struct iommu_device *iommu,
>> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> index 627a3ed5ee8f..8e262210b5ad 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> @@ -2812,6 +2812,7 @@ static int arm_smmu_dev_enable_feature(struct
>> device *dev,
>>   		master->iopf_enabled = true;
>>   		return 0;
>>   	case IOMMU_DEV_FEAT_SVA:
>> +		dev->iommu->pasid_bits = master->ssid_bits;
>>   		return arm_smmu_master_enable_sva(master);
>>   	default:
>>   		return -EINVAL;
>> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
>> index 6f7485c44a4b..c1b91bce1530 100644
>> --- a/drivers/iommu/intel/iommu.c
>> +++ b/drivers/iommu/intel/iommu.c
>> @@ -4587,8 +4587,11 @@ static struct iommu_device
>> *intel_iommu_probe_device(struct device *dev)
>>   			if (pasid_supported(iommu)) {
>>   				int features = pci_pasid_features(pdev);
>>
>> -				if (features >= 0)
>> +				if (features >= 0) {
>>   					info->pasid_supported = features | 1;
>> +					dev->iommu->pasid_bits =
>> +						fls(pci_max_pasids(pdev)) - 1;
> Original intel_svm_alloc_pasid() covers both PCI and non-PCI devices:
> 
> 	ioasid_t max_pasid = dev_is_pci(dev) ?
> 		pci_max_pasids(to_pci_dev(dev)) : intel_pasid_max_id;
> 
> though I'm not sure whether non-PCI SVA has been supported indeed, this
> patch implies a functional change here.
> 

The info->pasid_supported is only set for PCI devices. So the status is
that non-PCI SVA hasn't been supported. No functional change here from
this point of view.

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

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

* Re: [PATCH RFC 02/11] iommu: Add iommu_domain type for SVA
  2022-03-21  7:06     ` Tian, Kevin
@ 2022-03-21 10:23       ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-21 10:23 UTC (permalink / raw)
  To: Tian, Kevin, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Raj, Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: baolu.lu, Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

On 2022/3/21 15:06, Tian, Kevin wrote:
>> From: Lu Baolu<baolu.lu@linux.intel.com>
>> Sent: Sunday, March 20, 2022 2:40 PM
>>
>> Add a new iommu domain type IOMMU_DOMAIN_SVA to represent an I/O
>> page
>> table which is shared from CPU host VA. Add a sva_cookie field in the
>> iommu_domain structure to save the mm_struct which represent the CPU
>> memory page table.
>>
>> Signed-off-by: Lu Baolu<baolu.lu@linux.intel.com>
>> ---
>>   include/linux/iommu.h | 6 ++++++
>>   1 file changed, 6 insertions(+)
>>
>> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
>> index 36f43af0af53..3e179b853380 100644
>> --- a/include/linux/iommu.h
>> +++ b/include/linux/iommu.h
>> @@ -64,6 +64,9 @@ struct iommu_domain_geometry {
>>   #define __IOMMU_DOMAIN_PT	(1U << 2)  /* Domain is identity
>> mapped   */
>>   #define __IOMMU_DOMAIN_DMA_FQ	(1U << 3)  /* DMA-API uses
>> flush queue    */
>>
>> +#define __IOMMU_DOMAIN_SHARED	(1U << 4)  /* Page table shared from
>> CPU  */
>> +#define __IOMMU_DOMAIN_HOST_VA	(1U << 5)  /* Host CPU virtual
>> address */
> suppose the SHARED bit will be also used for KVM page table sharing and
> HOST_VA bit is to differentiate mm sharing from the latter?
> 

Yes, that's my intention.

Best regards,
baolu

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

* Re: [PATCH RFC 02/11] iommu: Add iommu_domain type for SVA
@ 2022-03-21 10:23       ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-21 10:23 UTC (permalink / raw)
  To: Tian, Kevin, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Raj, Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Pan, Jacob jun

On 2022/3/21 15:06, Tian, Kevin wrote:
>> From: Lu Baolu<baolu.lu@linux.intel.com>
>> Sent: Sunday, March 20, 2022 2:40 PM
>>
>> Add a new iommu domain type IOMMU_DOMAIN_SVA to represent an I/O
>> page
>> table which is shared from CPU host VA. Add a sva_cookie field in the
>> iommu_domain structure to save the mm_struct which represent the CPU
>> memory page table.
>>
>> Signed-off-by: Lu Baolu<baolu.lu@linux.intel.com>
>> ---
>>   include/linux/iommu.h | 6 ++++++
>>   1 file changed, 6 insertions(+)
>>
>> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
>> index 36f43af0af53..3e179b853380 100644
>> --- a/include/linux/iommu.h
>> +++ b/include/linux/iommu.h
>> @@ -64,6 +64,9 @@ struct iommu_domain_geometry {
>>   #define __IOMMU_DOMAIN_PT	(1U << 2)  /* Domain is identity
>> mapped   */
>>   #define __IOMMU_DOMAIN_DMA_FQ	(1U << 3)  /* DMA-API uses
>> flush queue    */
>>
>> +#define __IOMMU_DOMAIN_SHARED	(1U << 4)  /* Page table shared from
>> CPU  */
>> +#define __IOMMU_DOMAIN_HOST_VA	(1U << 5)  /* Host CPU virtual
>> address */
> suppose the SHARED bit will be also used for KVM page table sharing and
> HOST_VA bit is to differentiate mm sharing from the latter?
> 

Yes, that's my intention.

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

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

* Re: [PATCH RFC 03/11] iommu: Add attach/detach_dev_pasid domain ops
  2022-03-21  7:13     ` Tian, Kevin
@ 2022-03-21 10:27       ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-21 10:27 UTC (permalink / raw)
  To: Tian, Kevin, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Raj, Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: baolu.lu, Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

On 2022/3/21 15:13, Tian, Kevin wrote:
>> From: Lu Baolu<baolu.lu@linux.intel.com>
>> Sent: Sunday, March 20, 2022 2:40 PM
>>
>> Attaching an IOMMU domain to a PASID of a device is a generic operation
>> for modern IOMMU drivers which support PASID-granular DMA address
>> translation. Currently visible usage scenarios include (but not limited):
>>
>>   - SVA
>>   - kernel DMA with PASID
>>   - hardware-assist mediated device
>>
>> This adds a pair of common domain ops for this purpose and implements a
>> couple of wrapper helpers for in-kernel usage.
>>
>> Signed-off-by: Lu Baolu<baolu.lu@linux.intel.com>
>> ---
>>   include/linux/iommu.h | 22 ++++++++++++++++++++++
>>   drivers/iommu/iommu.c | 41
>> +++++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 63 insertions(+)
>>
>> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
>> index 3e179b853380..e51845b9a146 100644
>> --- a/include/linux/iommu.h
>> +++ b/include/linux/iommu.h
>> @@ -268,6 +268,8 @@ struct iommu_ops {
>>    * struct iommu_domain_ops - domain specific operations
>>    * @attach_dev: attach an iommu domain to a device
>>    * @detach_dev: detach an iommu domain from a device
>> + * @attach_dev_pasid: attach an iommu domain to a pasid of device
>> + * @detach_dev_pasid: detach an iommu domain from a pasid of device
>>    * @map: map a physically contiguous memory region to an iommu domain
>>    * @map_pages: map a physically contiguous set of pages of the same size
>> to
>>    *             an iommu domain.
>> @@ -285,6 +287,10 @@ struct iommu_ops {
>>   struct iommu_domain_ops {
>>   	int (*attach_dev)(struct iommu_domain *domain, struct device *dev);
>>   	void (*detach_dev)(struct iommu_domain *domain, struct device
>> *dev);
>> +	int (*attach_dev_pasid)(struct iommu_domain *domain,
>> +				struct device *dev, ioasid_t id);
>> +	void (*detach_dev_pasid)(struct iommu_domain *domain,
>> +				 struct device *dev, ioasid_t id);
>>
>>   	int (*map)(struct iommu_domain *domain, unsigned long iova,
>>   		   phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
>> @@ -678,6 +684,11 @@ int iommu_group_claim_dma_owner(struct
>> iommu_group *group, void *owner);
>>   void iommu_group_release_dma_owner(struct iommu_group *group);
>>   bool iommu_group_dma_owner_claimed(struct iommu_group *group);
>>
>> +int iommu_attach_device_pasid(struct iommu_domain *domain,
>> +			      struct device *dev, ioasid_t pasid);
>> +void iommu_detach_device_pasid(struct iommu_domain *domain,
>> +			       struct device *dev, ioasid_t pasid);
>> +
>>   #else /* CONFIG_IOMMU_API */
>>
>>   struct iommu_ops {};
>> @@ -1046,6 +1057,17 @@ static inline bool
>> iommu_group_dma_owner_claimed(struct iommu_group *group)
>>   {
>>   	return false;
>>   }
>> +
>> +static inline int iommu_attach_device_pasid(struct iommu_domain
>> *domain,
>> +					    struct device *dev, ioasid_t pasid)
>> +{
>> +	return -ENODEV;
>> +}
>> +
>> +static inline void iommu_detach_device_pasid(struct iommu_domain
>> *domain,
>> +					     struct device *dev, ioasid_t pasid)
>> +{
>> +}
>>   #endif /* CONFIG_IOMMU_API */
>>
>>   /**
>> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
>> index 0c42ece25854..78c71ee15f36 100644
>> --- a/drivers/iommu/iommu.c
>> +++ b/drivers/iommu/iommu.c
>> @@ -3167,3 +3167,44 @@ bool iommu_group_dma_owner_claimed(struct
>> iommu_group *group)
>>   	return user;
>>   }
>>   EXPORT_SYMBOL_GPL(iommu_group_dma_owner_claimed);
>> +
>> +int iommu_attach_device_pasid(struct iommu_domain *domain,
>> +			      struct device *dev, ioasid_t pasid)
>> +{
>> +	struct iommu_group *group;
>> +	int ret = -EINVAL;
>> +
>> +	if (!domain->ops->attach_dev_pasid)
>> +		return -EINVAL;
>> +
>> +	group = iommu_group_get(dev);
>> +	if (!group)
>> +		return -ENODEV;
>> +
>> +	mutex_lock(&group->mutex);
>> +	if (iommu_group_device_count(group) != 1)
>> +		goto out_unlock;
> Need move the reason of above limitation from iommu_sva_bind_device()
> to here:
> 
> 	/*
> 	 * To keep things simple, SVA currently doesn't support IOMMU groups
> 	 * with more than one device. Existing SVA-capable systems are not
> 	 * affected by the problems that required IOMMU groups (lack of ACS
> 	 * isolation, device ID aliasing and other hardware issues).
> 	 */
> 	if (iommu_group_device_count(group) != 1)
> 		goto out_unlock;

Yes. We need a comment around this code. But it's not only for SVA but
also for all pasid attachment feature. I need more inputs to judge
whether this limitation is reasonable.

> 
> btw I didn't see any safeguard on above assumption in device hotplug path
> to a group which already has SVA enabled...
> 

Agreed.

Best regards,
baolu

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

* Re: [PATCH RFC 03/11] iommu: Add attach/detach_dev_pasid domain ops
@ 2022-03-21 10:27       ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-21 10:27 UTC (permalink / raw)
  To: Tian, Kevin, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Raj, Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Pan, Jacob jun

On 2022/3/21 15:13, Tian, Kevin wrote:
>> From: Lu Baolu<baolu.lu@linux.intel.com>
>> Sent: Sunday, March 20, 2022 2:40 PM
>>
>> Attaching an IOMMU domain to a PASID of a device is a generic operation
>> for modern IOMMU drivers which support PASID-granular DMA address
>> translation. Currently visible usage scenarios include (but not limited):
>>
>>   - SVA
>>   - kernel DMA with PASID
>>   - hardware-assist mediated device
>>
>> This adds a pair of common domain ops for this purpose and implements a
>> couple of wrapper helpers for in-kernel usage.
>>
>> Signed-off-by: Lu Baolu<baolu.lu@linux.intel.com>
>> ---
>>   include/linux/iommu.h | 22 ++++++++++++++++++++++
>>   drivers/iommu/iommu.c | 41
>> +++++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 63 insertions(+)
>>
>> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
>> index 3e179b853380..e51845b9a146 100644
>> --- a/include/linux/iommu.h
>> +++ b/include/linux/iommu.h
>> @@ -268,6 +268,8 @@ struct iommu_ops {
>>    * struct iommu_domain_ops - domain specific operations
>>    * @attach_dev: attach an iommu domain to a device
>>    * @detach_dev: detach an iommu domain from a device
>> + * @attach_dev_pasid: attach an iommu domain to a pasid of device
>> + * @detach_dev_pasid: detach an iommu domain from a pasid of device
>>    * @map: map a physically contiguous memory region to an iommu domain
>>    * @map_pages: map a physically contiguous set of pages of the same size
>> to
>>    *             an iommu domain.
>> @@ -285,6 +287,10 @@ struct iommu_ops {
>>   struct iommu_domain_ops {
>>   	int (*attach_dev)(struct iommu_domain *domain, struct device *dev);
>>   	void (*detach_dev)(struct iommu_domain *domain, struct device
>> *dev);
>> +	int (*attach_dev_pasid)(struct iommu_domain *domain,
>> +				struct device *dev, ioasid_t id);
>> +	void (*detach_dev_pasid)(struct iommu_domain *domain,
>> +				 struct device *dev, ioasid_t id);
>>
>>   	int (*map)(struct iommu_domain *domain, unsigned long iova,
>>   		   phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
>> @@ -678,6 +684,11 @@ int iommu_group_claim_dma_owner(struct
>> iommu_group *group, void *owner);
>>   void iommu_group_release_dma_owner(struct iommu_group *group);
>>   bool iommu_group_dma_owner_claimed(struct iommu_group *group);
>>
>> +int iommu_attach_device_pasid(struct iommu_domain *domain,
>> +			      struct device *dev, ioasid_t pasid);
>> +void iommu_detach_device_pasid(struct iommu_domain *domain,
>> +			       struct device *dev, ioasid_t pasid);
>> +
>>   #else /* CONFIG_IOMMU_API */
>>
>>   struct iommu_ops {};
>> @@ -1046,6 +1057,17 @@ static inline bool
>> iommu_group_dma_owner_claimed(struct iommu_group *group)
>>   {
>>   	return false;
>>   }
>> +
>> +static inline int iommu_attach_device_pasid(struct iommu_domain
>> *domain,
>> +					    struct device *dev, ioasid_t pasid)
>> +{
>> +	return -ENODEV;
>> +}
>> +
>> +static inline void iommu_detach_device_pasid(struct iommu_domain
>> *domain,
>> +					     struct device *dev, ioasid_t pasid)
>> +{
>> +}
>>   #endif /* CONFIG_IOMMU_API */
>>
>>   /**
>> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
>> index 0c42ece25854..78c71ee15f36 100644
>> --- a/drivers/iommu/iommu.c
>> +++ b/drivers/iommu/iommu.c
>> @@ -3167,3 +3167,44 @@ bool iommu_group_dma_owner_claimed(struct
>> iommu_group *group)
>>   	return user;
>>   }
>>   EXPORT_SYMBOL_GPL(iommu_group_dma_owner_claimed);
>> +
>> +int iommu_attach_device_pasid(struct iommu_domain *domain,
>> +			      struct device *dev, ioasid_t pasid)
>> +{
>> +	struct iommu_group *group;
>> +	int ret = -EINVAL;
>> +
>> +	if (!domain->ops->attach_dev_pasid)
>> +		return -EINVAL;
>> +
>> +	group = iommu_group_get(dev);
>> +	if (!group)
>> +		return -ENODEV;
>> +
>> +	mutex_lock(&group->mutex);
>> +	if (iommu_group_device_count(group) != 1)
>> +		goto out_unlock;
> Need move the reason of above limitation from iommu_sva_bind_device()
> to here:
> 
> 	/*
> 	 * To keep things simple, SVA currently doesn't support IOMMU groups
> 	 * with more than one device. Existing SVA-capable systems are not
> 	 * affected by the problems that required IOMMU groups (lack of ACS
> 	 * isolation, device ID aliasing and other hardware issues).
> 	 */
> 	if (iommu_group_device_count(group) != 1)
> 		goto out_unlock;

Yes. We need a comment around this code. But it's not only for SVA but
also for all pasid attachment feature. I need more inputs to judge
whether this limitation is reasonable.

> 
> btw I didn't see any safeguard on above assumption in device hotplug path
> to a group which already has SVA enabled...
> 

Agreed.

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

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

* Re: [PATCH RFC 04/11] iommu/vt-d: Add SVA domain support
  2022-03-21  7:45     ` Tian, Kevin
@ 2022-03-21 10:37       ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-21 10:37 UTC (permalink / raw)
  To: Tian, Kevin, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Raj, Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: baolu.lu, Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

On 2022/3/21 15:45, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Sunday, March 20, 2022 2:40 PM
>>
>> Add support for SVA domain allocation and provide an SVA-specific
>> iommu_domain_ops.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>> ---
>>   include/linux/intel-iommu.h |  1 +
>>   drivers/iommu/intel/iommu.c | 12 ++++++++++++
>>   drivers/iommu/intel/svm.c   | 34 ++++++++++++++++++++++++++++++++++
>>   3 files changed, 47 insertions(+)
>>
>> diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
>> index 2f9891cb3d00..c14283137fb5 100644
>> --- a/include/linux/intel-iommu.h
>> +++ b/include/linux/intel-iommu.h
>> @@ -744,6 +744,7 @@ void intel_svm_unbind(struct iommu_sva *handle);
>>   u32 intel_svm_get_pasid(struct iommu_sva *handle);
>>   int intel_svm_page_response(struct device *dev, struct iommu_fault_event
>> *evt,
>>   			    struct iommu_page_response *msg);
>> +extern const struct iommu_domain_ops intel_svm_domain_ops;
>>
>>   struct intel_svm_dev {
>>   	struct list_head list;
>> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
>> index c1b91bce1530..d55dca3eacf8 100644
>> --- a/drivers/iommu/intel/iommu.c
>> +++ b/drivers/iommu/intel/iommu.c
>> @@ -4318,6 +4318,18 @@ static struct iommu_domain
>> *intel_iommu_domain_alloc(unsigned type)
>>   		return domain;
>>   	case IOMMU_DOMAIN_IDENTITY:
>>   		return &si_domain->domain;
>> +#ifdef CONFIG_INTEL_IOMMU_SVM
>> +	case IOMMU_DOMAIN_SVA:
>> +		dmar_domain = alloc_domain(type);
>> +		if (!dmar_domain) {
>> +			pr_err("Can't allocate sva domain\n");
>> +			return NULL;
>> +		}
>> +		domain = &dmar_domain->domain;
>> +		domain->ops = &intel_svm_domain_ops;
>> +
>> +		return domain;
>> +#endif /* CONFIG_INTEL_IOMMU_SVM */
>>   	default:
>>   		return NULL;
>>   	}
>> diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
>> index ee5ecde5b318..b9f4dd7057d1 100644
>> --- a/drivers/iommu/intel/svm.c
>> +++ b/drivers/iommu/intel/svm.c
>> @@ -932,3 +932,37 @@ int intel_svm_page_response(struct device *dev,
>>   	mutex_unlock(&pasid_mutex);
>>   	return ret;
>>   }
>> +
>> +static int intel_svm_attach_dev_pasid(struct iommu_domain *domain,
>> +				      struct device *dev, ioasid_t pasid)
>> +{
>> +	struct device_domain_info *info = dev_iommu_priv_get(dev);
>> +	struct mm_struct *mm = domain->sva_cookie;
>> +	struct intel_iommu *iommu = info->iommu;
>> +	struct iommu_sva *sva;
>> +
>> +	mutex_lock(&pasid_mutex);
>> +	sva = intel_svm_bind_mm(iommu, dev, mm);
>> +	mutex_unlock(&pasid_mutex);
>> +
> 
> I'm not sure whether this is the right implementation of this callback.
> In last patch you said it will be used for multiple usages but here it
> is fixed to mm binding.

It is for svm domain ops so it should be mm binding only. For other
usages, they should have different domain ops.

> Also the pasid argument is not used at all
> and instead it is retrieved from mm struct implicitly.

The pasid is not used here because it has already been stored in
mm->pasid. Since it's only for SVM domain, I think it's okay.

> 
> Basically SVA requires three steps:
> 
> 1) alloc a SVA-type domain;
> 2) construct the domain to wrap mm;
> 3) attach the domain to a PASID;
> 
> If we aim .attach_dev_pasid to be generic it may suggest that 1) and 2)
> should be done before .attach_dev_pasid then within this callback it
> just deals with domain/pasid attach in a generic way.

You are right. This code does have room for further cleanup. I would
like to put that in a separated series so that we could focus on the
generic SVA and IOPF refactoring.

> 
>> +	return IS_ERR_OR_NULL(sva);
>> +}
>> +
>> +static void intel_svm_detach_dev_pasid(struct iommu_domain *domain,
>> +				       struct device *dev, ioasid_t pasid)
>> +{
>> +	mutex_lock(&pasid_mutex);
>> +	intel_svm_unbind_mm(dev, pasid);
>> +	mutex_unlock(&pasid_mutex);
>> +}
>> +
>> +static void intel_svm_domain_free(struct iommu_domain *domain)
>> +{
>> +	kfree(domain);
>> +}
>> +
>> +const struct iommu_domain_ops intel_svm_domain_ops = {
>> +	.attach_dev_pasid	= intel_svm_attach_dev_pasid,
>> +	.detach_dev_pasid	= intel_svm_detach_dev_pasid,
>> +	.free			= intel_svm_domain_free,
>> +};
>> --
>> 2.25.1
> 

Best regards,
baolu

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

* Re: [PATCH RFC 04/11] iommu/vt-d: Add SVA domain support
@ 2022-03-21 10:37       ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-21 10:37 UTC (permalink / raw)
  To: Tian, Kevin, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Raj, Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Pan, Jacob jun

On 2022/3/21 15:45, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Sunday, March 20, 2022 2:40 PM
>>
>> Add support for SVA domain allocation and provide an SVA-specific
>> iommu_domain_ops.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>> ---
>>   include/linux/intel-iommu.h |  1 +
>>   drivers/iommu/intel/iommu.c | 12 ++++++++++++
>>   drivers/iommu/intel/svm.c   | 34 ++++++++++++++++++++++++++++++++++
>>   3 files changed, 47 insertions(+)
>>
>> diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
>> index 2f9891cb3d00..c14283137fb5 100644
>> --- a/include/linux/intel-iommu.h
>> +++ b/include/linux/intel-iommu.h
>> @@ -744,6 +744,7 @@ void intel_svm_unbind(struct iommu_sva *handle);
>>   u32 intel_svm_get_pasid(struct iommu_sva *handle);
>>   int intel_svm_page_response(struct device *dev, struct iommu_fault_event
>> *evt,
>>   			    struct iommu_page_response *msg);
>> +extern const struct iommu_domain_ops intel_svm_domain_ops;
>>
>>   struct intel_svm_dev {
>>   	struct list_head list;
>> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
>> index c1b91bce1530..d55dca3eacf8 100644
>> --- a/drivers/iommu/intel/iommu.c
>> +++ b/drivers/iommu/intel/iommu.c
>> @@ -4318,6 +4318,18 @@ static struct iommu_domain
>> *intel_iommu_domain_alloc(unsigned type)
>>   		return domain;
>>   	case IOMMU_DOMAIN_IDENTITY:
>>   		return &si_domain->domain;
>> +#ifdef CONFIG_INTEL_IOMMU_SVM
>> +	case IOMMU_DOMAIN_SVA:
>> +		dmar_domain = alloc_domain(type);
>> +		if (!dmar_domain) {
>> +			pr_err("Can't allocate sva domain\n");
>> +			return NULL;
>> +		}
>> +		domain = &dmar_domain->domain;
>> +		domain->ops = &intel_svm_domain_ops;
>> +
>> +		return domain;
>> +#endif /* CONFIG_INTEL_IOMMU_SVM */
>>   	default:
>>   		return NULL;
>>   	}
>> diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
>> index ee5ecde5b318..b9f4dd7057d1 100644
>> --- a/drivers/iommu/intel/svm.c
>> +++ b/drivers/iommu/intel/svm.c
>> @@ -932,3 +932,37 @@ int intel_svm_page_response(struct device *dev,
>>   	mutex_unlock(&pasid_mutex);
>>   	return ret;
>>   }
>> +
>> +static int intel_svm_attach_dev_pasid(struct iommu_domain *domain,
>> +				      struct device *dev, ioasid_t pasid)
>> +{
>> +	struct device_domain_info *info = dev_iommu_priv_get(dev);
>> +	struct mm_struct *mm = domain->sva_cookie;
>> +	struct intel_iommu *iommu = info->iommu;
>> +	struct iommu_sva *sva;
>> +
>> +	mutex_lock(&pasid_mutex);
>> +	sva = intel_svm_bind_mm(iommu, dev, mm);
>> +	mutex_unlock(&pasid_mutex);
>> +
> 
> I'm not sure whether this is the right implementation of this callback.
> In last patch you said it will be used for multiple usages but here it
> is fixed to mm binding.

It is for svm domain ops so it should be mm binding only. For other
usages, they should have different domain ops.

> Also the pasid argument is not used at all
> and instead it is retrieved from mm struct implicitly.

The pasid is not used here because it has already been stored in
mm->pasid. Since it's only for SVM domain, I think it's okay.

> 
> Basically SVA requires three steps:
> 
> 1) alloc a SVA-type domain;
> 2) construct the domain to wrap mm;
> 3) attach the domain to a PASID;
> 
> If we aim .attach_dev_pasid to be generic it may suggest that 1) and 2)
> should be done before .attach_dev_pasid then within this callback it
> just deals with domain/pasid attach in a generic way.

You are right. This code does have room for further cleanup. I would
like to put that in a separated series so that we could focus on the
generic SVA and IOPF refactoring.

> 
>> +	return IS_ERR_OR_NULL(sva);
>> +}
>> +
>> +static void intel_svm_detach_dev_pasid(struct iommu_domain *domain,
>> +				       struct device *dev, ioasid_t pasid)
>> +{
>> +	mutex_lock(&pasid_mutex);
>> +	intel_svm_unbind_mm(dev, pasid);
>> +	mutex_unlock(&pasid_mutex);
>> +}
>> +
>> +static void intel_svm_domain_free(struct iommu_domain *domain)
>> +{
>> +	kfree(domain);
>> +}
>> +
>> +const struct iommu_domain_ops intel_svm_domain_ops = {
>> +	.attach_dev_pasid	= intel_svm_attach_dev_pasid,
>> +	.detach_dev_pasid	= intel_svm_detach_dev_pasid,
>> +	.free			= intel_svm_domain_free,
>> +};
>> --
>> 2.25.1
> 

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

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

* Re: [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  2022-03-21  8:04     ` Tian, Kevin
@ 2022-03-21 11:01       ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-21 11:01 UTC (permalink / raw)
  To: Tian, Kevin, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Raj, Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Pan, Jacob jun

On 2022/3/21 16:04, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Sunday, March 20, 2022 2:40 PM
>> +struct iommu_sva *
>> +iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void
>> *drvdata)
>> +{
>> +	int ret = -EINVAL;
>> +	struct iommu_sva *handle;
>> +	struct iommu_domain *domain;
>> +
>> +	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
>> +	if (!handle)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits)
>> - 1);
>> +	if (ret)
>> +		goto out;
>> +
>> +	domain = iommu_sva_domain_alloc(dev);
>> +	if (!domain) {
>> +		ret = -ENOMEM;
>> +		goto out;
>> +	}
>> +	domain->sva_cookie = mm;
> 
> one domain can be attached by multiple devices, so this should not be
> a blind alloc.

Indeed. Perhaps we could associate the SVA domain with the mm->pasid and
add a user counter inside the domain.

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

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

* Re: [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
@ 2022-03-21 11:01       ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-21 11:01 UTC (permalink / raw)
  To: Tian, Kevin, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Raj, Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: baolu.lu, Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

On 2022/3/21 16:04, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Sunday, March 20, 2022 2:40 PM
>> +struct iommu_sva *
>> +iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void
>> *drvdata)
>> +{
>> +	int ret = -EINVAL;
>> +	struct iommu_sva *handle;
>> +	struct iommu_domain *domain;
>> +
>> +	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
>> +	if (!handle)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits)
>> - 1);
>> +	if (ret)
>> +		goto out;
>> +
>> +	domain = iommu_sva_domain_alloc(dev);
>> +	if (!domain) {
>> +		ret = -ENOMEM;
>> +		goto out;
>> +	}
>> +	domain->sva_cookie = mm;
> 
> one domain can be attached by multiple devices, so this should not be
> a blind alloc.

Indeed. Perhaps we could associate the SVA domain with the mm->pasid and
add a user counter inside the domain.

Best regards,
baolu

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

* Re: [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21 11:22     ` Jean-Philippe Brucker
  -1 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-21 11:22 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker,
	Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel

Hi Baolu,

On Sun, Mar 20, 2022 at 02:40:20PM +0800, Lu Baolu wrote:
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 627a3ed5ee8f..8e262210b5ad 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -2812,6 +2812,7 @@ static int arm_smmu_dev_enable_feature(struct device *dev,
>  		master->iopf_enabled = true;
>  		return 0;
>  	case IOMMU_DEV_FEAT_SVA:
> +		dev->iommu->pasid_bits = master->ssid_bits;

This would be better in arm_smmu_probe_device()

Thanks,
Jean

>  		return arm_smmu_master_enable_sva(master);
>  	default:
>  		return -EINVAL;

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

* Re: [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu
@ 2022-03-21 11:22     ` Jean-Philippe Brucker
  0 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-21 11:22 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Kevin Tian, Ashok Raj, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Jason Gunthorpe, Will Deacon

Hi Baolu,

On Sun, Mar 20, 2022 at 02:40:20PM +0800, Lu Baolu wrote:
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 627a3ed5ee8f..8e262210b5ad 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -2812,6 +2812,7 @@ static int arm_smmu_dev_enable_feature(struct device *dev,
>  		master->iopf_enabled = true;
>  		return 0;
>  	case IOMMU_DEV_FEAT_SVA:
> +		dev->iommu->pasid_bits = master->ssid_bits;

This would be better in arm_smmu_probe_device()

Thanks,
Jean

>  		return arm_smmu_master_enable_sva(master);
>  	default:
>  		return -EINVAL;
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

* Re: [PATCH RFC 05/11] arm-smmu-v3/sva: Add SVA domain support
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21 11:31     ` Jean-Philippe Brucker
  -1 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-21 11:31 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker,
	Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On Sun, Mar 20, 2022 at 02:40:24PM +0800, Lu Baolu wrote:
> Add support for SVA domain allocation and provide an SVA-specific
> iommu_domain_ops.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   | 14 ++++++
>  .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   | 45 +++++++++++++++++++
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 13 +++++-
>  3 files changed, 71 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> index cd48590ada30..7631c00fdcbd 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> @@ -759,6 +759,10 @@ struct iommu_sva *arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm,
>  void arm_smmu_sva_unbind(struct iommu_sva *handle);
>  u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle);
>  void arm_smmu_sva_notifier_synchronize(void);
> +int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
> +				  struct device *dev, ioasid_t id);
> +void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
> +				   struct device *dev, ioasid_t id);
>  #else /* CONFIG_ARM_SMMU_V3_SVA */
>  static inline bool arm_smmu_sva_supported(struct arm_smmu_device *smmu)
>  {
> @@ -804,5 +808,15 @@ static inline u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle)
>  }
>  
>  static inline void arm_smmu_sva_notifier_synchronize(void) {}
> +
> +static inline int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
> +						struct device *dev, ioasid_t id)
> +{
> +	return -ENODEV;
> +}
> +
> +static inline void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
> +						 struct device *dev,
> +						 ioasid_t id) {}
>  #endif /* CONFIG_ARM_SMMU_V3_SVA */
>  #endif /* _ARM_SMMU_V3_H */
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> index 22ddd05bbdcd..1e114b9dc17f 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> @@ -534,3 +534,48 @@ void arm_smmu_sva_notifier_synchronize(void)
>  	 */
>  	mmu_notifier_synchronize();
>  }
> +
> +int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
> +				  struct device *dev, ioasid_t id)
> +{
> +	int ret = 0;
> +	struct iommu_sva *handle;
> +	struct mm_struct *mm = domain->sva_cookie;
> +	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
> +
> +	if (smmu_domain->stage != ARM_SMMU_DOMAIN_S1 ||

This check is for the parent domain, iommu_get_domain_for_dev(dev)

> +	    domain->type != IOMMU_DOMAIN_SVA || !mm)
> +		return -EINVAL;
> +
> +	mutex_lock(&sva_lock);
> +	handle = __arm_smmu_sva_bind(dev, mm);
> +	if (IS_ERR_OR_NULL(handle))
> +		ret = PTR_ERR(handle);
> +	mutex_unlock(&sva_lock);
> +
> +	return ret;
> +}
> +
> +void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
> +				   struct device *dev, ioasid_t id)
> +{
> +	struct arm_smmu_bond *bond = NULL, *t;
> +	struct mm_struct *mm = domain->sva_cookie;
> +	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
> +
> +	mutex_lock(&sva_lock);
> +	list_for_each_entry(t, &master->bonds, list) {
> +		if (t->mm == mm) {
> +			bond = t;
> +			break;
> +		}
> +	}
> +
> +	if (!WARN_ON(!bond) && refcount_dec_and_test(&bond->refs)) {
> +		list_del(&bond->list);
> +		arm_smmu_mmu_notifier_put(bond->smmu_mn);
> +		iommu_sva_free_pasid(bond->mm);

Can be dropped since iommu.c does PASID allocation (also the one in
__arm_smmu_sva_bind() as a cleanup patch)

> +		kfree(bond);
> +	}
> +	mutex_unlock(&sva_lock);
> +}
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 8e262210b5ad..2e9d3cd30510 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -88,6 +88,8 @@ static struct arm_smmu_option_prop arm_smmu_options[] = {
>  	{ 0, NULL},
>  };
>  
> +static void arm_smmu_domain_free(struct iommu_domain *domain);
> +
>  static void parse_driver_options(struct arm_smmu_device *smmu)
>  {
>  	int i = 0;
> @@ -1995,6 +1997,12 @@ static bool arm_smmu_capable(enum iommu_cap cap)
>  	}
>  }
>  
> +static const struct iommu_domain_ops arm_smmu_sva_domain_ops = {
> +	.attach_dev_pasid	= arm_smmu_sva_attach_dev_pasid,
> +	.detach_dev_pasid	= arm_smmu_sva_detach_dev_pasid,
> +	.free			= arm_smmu_domain_free,
> +};
> +
>  static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>  {
>  	struct arm_smmu_domain *smmu_domain;
> @@ -2002,7 +2010,8 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>  	if (type != IOMMU_DOMAIN_UNMANAGED &&
>  	    type != IOMMU_DOMAIN_DMA &&
>  	    type != IOMMU_DOMAIN_DMA_FQ &&
> -	    type != IOMMU_DOMAIN_IDENTITY)
> +	    type != IOMMU_DOMAIN_IDENTITY &&
> +	    type != IOMMU_DOMAIN_SVA)
>  		return NULL;

We don't need to allocate an arm_smmu_domain, it likely won't have
anything in common with the SVA domain and it would be much clearer within
the SMMU driver if we use different structs for parent and child domains.
For now we could just return a naked struct iommu_domain. Sanity checks in
arm_smmu_attach_dev() would be good too, a SVA domain can't be attached as
a parent domain.

I this this works otherwise, but will need to test the series to see what
more is needed, when I find some time.

Thanks,
Jean

>  
>  	/*
> @@ -2018,6 +2027,8 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>  	INIT_LIST_HEAD(&smmu_domain->devices);
>  	spin_lock_init(&smmu_domain->devices_lock);
>  	INIT_LIST_HEAD(&smmu_domain->mmu_notifiers);
> +	if (type == IOMMU_DOMAIN_SVA)
> +		smmu_domain->domain.ops = &arm_smmu_sva_domain_ops;
>  
>  	return &smmu_domain->domain;
>  }
> -- 
> 2.25.1
> 

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

* Re: [PATCH RFC 05/11] arm-smmu-v3/sva: Add SVA domain support
@ 2022-03-21 11:31     ` Jean-Philippe Brucker
  0 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-21 11:31 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Kevin Tian, Ashok Raj, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Jason Gunthorpe, Will Deacon

On Sun, Mar 20, 2022 at 02:40:24PM +0800, Lu Baolu wrote:
> Add support for SVA domain allocation and provide an SVA-specific
> iommu_domain_ops.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   | 14 ++++++
>  .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   | 45 +++++++++++++++++++
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 13 +++++-
>  3 files changed, 71 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> index cd48590ada30..7631c00fdcbd 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> @@ -759,6 +759,10 @@ struct iommu_sva *arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm,
>  void arm_smmu_sva_unbind(struct iommu_sva *handle);
>  u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle);
>  void arm_smmu_sva_notifier_synchronize(void);
> +int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
> +				  struct device *dev, ioasid_t id);
> +void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
> +				   struct device *dev, ioasid_t id);
>  #else /* CONFIG_ARM_SMMU_V3_SVA */
>  static inline bool arm_smmu_sva_supported(struct arm_smmu_device *smmu)
>  {
> @@ -804,5 +808,15 @@ static inline u32 arm_smmu_sva_get_pasid(struct iommu_sva *handle)
>  }
>  
>  static inline void arm_smmu_sva_notifier_synchronize(void) {}
> +
> +static inline int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
> +						struct device *dev, ioasid_t id)
> +{
> +	return -ENODEV;
> +}
> +
> +static inline void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
> +						 struct device *dev,
> +						 ioasid_t id) {}
>  #endif /* CONFIG_ARM_SMMU_V3_SVA */
>  #endif /* _ARM_SMMU_V3_H */
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> index 22ddd05bbdcd..1e114b9dc17f 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> @@ -534,3 +534,48 @@ void arm_smmu_sva_notifier_synchronize(void)
>  	 */
>  	mmu_notifier_synchronize();
>  }
> +
> +int arm_smmu_sva_attach_dev_pasid(struct iommu_domain *domain,
> +				  struct device *dev, ioasid_t id)
> +{
> +	int ret = 0;
> +	struct iommu_sva *handle;
> +	struct mm_struct *mm = domain->sva_cookie;
> +	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
> +
> +	if (smmu_domain->stage != ARM_SMMU_DOMAIN_S1 ||

This check is for the parent domain, iommu_get_domain_for_dev(dev)

> +	    domain->type != IOMMU_DOMAIN_SVA || !mm)
> +		return -EINVAL;
> +
> +	mutex_lock(&sva_lock);
> +	handle = __arm_smmu_sva_bind(dev, mm);
> +	if (IS_ERR_OR_NULL(handle))
> +		ret = PTR_ERR(handle);
> +	mutex_unlock(&sva_lock);
> +
> +	return ret;
> +}
> +
> +void arm_smmu_sva_detach_dev_pasid(struct iommu_domain *domain,
> +				   struct device *dev, ioasid_t id)
> +{
> +	struct arm_smmu_bond *bond = NULL, *t;
> +	struct mm_struct *mm = domain->sva_cookie;
> +	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
> +
> +	mutex_lock(&sva_lock);
> +	list_for_each_entry(t, &master->bonds, list) {
> +		if (t->mm == mm) {
> +			bond = t;
> +			break;
> +		}
> +	}
> +
> +	if (!WARN_ON(!bond) && refcount_dec_and_test(&bond->refs)) {
> +		list_del(&bond->list);
> +		arm_smmu_mmu_notifier_put(bond->smmu_mn);
> +		iommu_sva_free_pasid(bond->mm);

Can be dropped since iommu.c does PASID allocation (also the one in
__arm_smmu_sva_bind() as a cleanup patch)

> +		kfree(bond);
> +	}
> +	mutex_unlock(&sva_lock);
> +}
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 8e262210b5ad..2e9d3cd30510 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -88,6 +88,8 @@ static struct arm_smmu_option_prop arm_smmu_options[] = {
>  	{ 0, NULL},
>  };
>  
> +static void arm_smmu_domain_free(struct iommu_domain *domain);
> +
>  static void parse_driver_options(struct arm_smmu_device *smmu)
>  {
>  	int i = 0;
> @@ -1995,6 +1997,12 @@ static bool arm_smmu_capable(enum iommu_cap cap)
>  	}
>  }
>  
> +static const struct iommu_domain_ops arm_smmu_sva_domain_ops = {
> +	.attach_dev_pasid	= arm_smmu_sva_attach_dev_pasid,
> +	.detach_dev_pasid	= arm_smmu_sva_detach_dev_pasid,
> +	.free			= arm_smmu_domain_free,
> +};
> +
>  static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>  {
>  	struct arm_smmu_domain *smmu_domain;
> @@ -2002,7 +2010,8 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>  	if (type != IOMMU_DOMAIN_UNMANAGED &&
>  	    type != IOMMU_DOMAIN_DMA &&
>  	    type != IOMMU_DOMAIN_DMA_FQ &&
> -	    type != IOMMU_DOMAIN_IDENTITY)
> +	    type != IOMMU_DOMAIN_IDENTITY &&
> +	    type != IOMMU_DOMAIN_SVA)
>  		return NULL;

We don't need to allocate an arm_smmu_domain, it likely won't have
anything in common with the SVA domain and it would be much clearer within
the SMMU driver if we use different structs for parent and child domains.
For now we could just return a naked struct iommu_domain. Sanity checks in
arm_smmu_attach_dev() would be good too, a SVA domain can't be attached as
a parent domain.

I this this works otherwise, but will need to test the series to see what
more is needed, when I find some time.

Thanks,
Jean

>  
>  	/*
> @@ -2018,6 +2027,8 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
>  	INIT_LIST_HEAD(&smmu_domain->devices);
>  	spin_lock_init(&smmu_domain->devices_lock);
>  	INIT_LIST_HEAD(&smmu_domain->mmu_notifiers);
> +	if (type == IOMMU_DOMAIN_SVA)
> +		smmu_domain->domain.ops = &arm_smmu_sva_domain_ops;
>  
>  	return &smmu_domain->domain;
>  }
> -- 
> 2.25.1
> 
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

* Re: [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21 11:33     ` Jean-Philippe Brucker
  -1 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-21 11:33 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker,
	Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On Sun, Mar 20, 2022 at 02:40:25PM +0800, Lu Baolu wrote:
> diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
> index 106506143896..47cf98e661ff 100644
> --- a/drivers/iommu/iommu-sva-lib.c
> +++ b/drivers/iommu/iommu-sva-lib.c
> @@ -3,6 +3,8 @@
>   * Helpers for IOMMU drivers implementing SVA
>   */
>  #include <linux/mutex.h>
> +#include <linux/iommu.h>
> +#include <linux/slab.h>
>  #include <linux/sched/mm.h>
>  
>  #include "iommu-sva-lib.h"
> @@ -69,3 +71,101 @@ struct mm_struct *iommu_sva_find(ioasid_t pasid)
>  	return ioasid_find(&iommu_sva_pasid, pasid, __mmget_not_zero);
>  }
>  EXPORT_SYMBOL_GPL(iommu_sva_find);
> +
> +static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev)
> +{
> +	struct bus_type *bus = dev->bus;
> +	struct iommu_domain *domain;
> +
> +	if (!bus || !bus->iommu_ops)
> +		return NULL;
> +
> +	domain = bus->iommu_ops->domain_alloc(IOMMU_DOMAIN_SVA);
> +	if (domain)
> +		domain->type = IOMMU_DOMAIN_SVA;
> +
> +	return domain;
> +}
> +
> +/**
> + * iommu_sva_bind_device() - Bind a process address space to a device
> + * @dev: the device
> + * @mm: the mm to bind, caller must hold a reference to it
> + * @drvdata: opaque data pointer to pass to bind callback
> + *
> + * Create a bond between device and address space, allowing the device to access
> + * the mm using the returned PASID. If a bond already exists between @device and
> + * @mm, it is returned and an additional reference is taken.

This is not true anymore, we return a different structure for each call.

> Caller must call
> + * iommu_sva_unbind_device() to release each reference.
> + *
> + * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
> + * initialize the required SVA features.
> + *
> + * On error, returns an ERR_PTR value.
> + */
> +struct iommu_sva *
> +iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
> +{
> +	int ret = -EINVAL;
> +	struct iommu_sva *handle;
> +	struct iommu_domain *domain;
> +
> +	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
> +	if (!handle)
> +		return ERR_PTR(-ENOMEM);
> +
> +	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits) - 1);
> +	if (ret)
> +		goto out;
> +
> +	domain = iommu_sva_domain_alloc(dev);
> +	if (!domain) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +	domain->sva_cookie = mm;
> +
> +	ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
> +	if (ret)
> +		goto out_free_domain;
> +
> +	handle->dev = dev;
> +	handle->domain = domain;
> +	handle->pasid = mm->pasid;
> +
> +	return handle;
> +
> +out_free_domain:
> +	iommu_domain_free(domain);
> +out:
> +	kfree(handle);
> +
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
> +
> +/**
> + * iommu_sva_unbind_device() - Remove a bond created with iommu_sva_bind_device
> + * @handle: the handle returned by iommu_sva_bind_device()
> + *
> + * Put reference to a bond between device and address space.

Same here. But I'd prefer keeping the old behavior so device drivers don't
have to keep track of {dev, mm} pairs themselves.

Thanks,
Jean

> The device should
> + * not be issuing any more transaction for this PASID. All outstanding page
> + * requests for this PASID must have been flushed to the IOMMU.
> + */
> +void iommu_sva_unbind_device(struct iommu_sva *handle)
> +{
> +	struct device *dev = handle->dev;
> +	struct iommu_domain *domain = handle->domain;
> +	struct mm_struct *mm = domain->sva_cookie;
> +
> +	iommu_detach_device_pasid(domain, dev, mm->pasid);
> +	iommu_domain_free(domain);
> +	kfree(handle);
> +}
> +EXPORT_SYMBOL_GPL(iommu_sva_unbind_device);
> +
> +u32 iommu_sva_get_pasid(struct iommu_sva *handle)
> +{
> +	return handle->pasid;
> +}
> +EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);

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

* Re: [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
@ 2022-03-21 11:33     ` Jean-Philippe Brucker
  0 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-21 11:33 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Kevin Tian, Ashok Raj, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Jason Gunthorpe, Will Deacon

On Sun, Mar 20, 2022 at 02:40:25PM +0800, Lu Baolu wrote:
> diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
> index 106506143896..47cf98e661ff 100644
> --- a/drivers/iommu/iommu-sva-lib.c
> +++ b/drivers/iommu/iommu-sva-lib.c
> @@ -3,6 +3,8 @@
>   * Helpers for IOMMU drivers implementing SVA
>   */
>  #include <linux/mutex.h>
> +#include <linux/iommu.h>
> +#include <linux/slab.h>
>  #include <linux/sched/mm.h>
>  
>  #include "iommu-sva-lib.h"
> @@ -69,3 +71,101 @@ struct mm_struct *iommu_sva_find(ioasid_t pasid)
>  	return ioasid_find(&iommu_sva_pasid, pasid, __mmget_not_zero);
>  }
>  EXPORT_SYMBOL_GPL(iommu_sva_find);
> +
> +static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev)
> +{
> +	struct bus_type *bus = dev->bus;
> +	struct iommu_domain *domain;
> +
> +	if (!bus || !bus->iommu_ops)
> +		return NULL;
> +
> +	domain = bus->iommu_ops->domain_alloc(IOMMU_DOMAIN_SVA);
> +	if (domain)
> +		domain->type = IOMMU_DOMAIN_SVA;
> +
> +	return domain;
> +}
> +
> +/**
> + * iommu_sva_bind_device() - Bind a process address space to a device
> + * @dev: the device
> + * @mm: the mm to bind, caller must hold a reference to it
> + * @drvdata: opaque data pointer to pass to bind callback
> + *
> + * Create a bond between device and address space, allowing the device to access
> + * the mm using the returned PASID. If a bond already exists between @device and
> + * @mm, it is returned and an additional reference is taken.

This is not true anymore, we return a different structure for each call.

> Caller must call
> + * iommu_sva_unbind_device() to release each reference.
> + *
> + * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
> + * initialize the required SVA features.
> + *
> + * On error, returns an ERR_PTR value.
> + */
> +struct iommu_sva *
> +iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
> +{
> +	int ret = -EINVAL;
> +	struct iommu_sva *handle;
> +	struct iommu_domain *domain;
> +
> +	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
> +	if (!handle)
> +		return ERR_PTR(-ENOMEM);
> +
> +	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits) - 1);
> +	if (ret)
> +		goto out;
> +
> +	domain = iommu_sva_domain_alloc(dev);
> +	if (!domain) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +	domain->sva_cookie = mm;
> +
> +	ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
> +	if (ret)
> +		goto out_free_domain;
> +
> +	handle->dev = dev;
> +	handle->domain = domain;
> +	handle->pasid = mm->pasid;
> +
> +	return handle;
> +
> +out_free_domain:
> +	iommu_domain_free(domain);
> +out:
> +	kfree(handle);
> +
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
> +
> +/**
> + * iommu_sva_unbind_device() - Remove a bond created with iommu_sva_bind_device
> + * @handle: the handle returned by iommu_sva_bind_device()
> + *
> + * Put reference to a bond between device and address space.

Same here. But I'd prefer keeping the old behavior so device drivers don't
have to keep track of {dev, mm} pairs themselves.

Thanks,
Jean

> The device should
> + * not be issuing any more transaction for this PASID. All outstanding page
> + * requests for this PASID must have been flushed to the IOMMU.
> + */
> +void iommu_sva_unbind_device(struct iommu_sva *handle)
> +{
> +	struct device *dev = handle->dev;
> +	struct iommu_domain *domain = handle->domain;
> +	struct mm_struct *mm = domain->sva_cookie;
> +
> +	iommu_detach_device_pasid(domain, dev, mm->pasid);
> +	iommu_domain_free(domain);
> +	kfree(handle);
> +}
> +EXPORT_SYMBOL_GPL(iommu_sva_unbind_device);
> +
> +u32 iommu_sva_get_pasid(struct iommu_sva *handle)
> +{
> +	return handle->pasid;
> +}
> +EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

* Re: [PATCH RFC 08/11] iommu: Handle IO page faults directly
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21 11:35     ` Jean-Philippe Brucker
  -1 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-21 11:35 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker,
	Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On Sun, Mar 20, 2022 at 02:40:27PM +0800, Lu Baolu wrote:
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index c0966fc9b686..4f90b71c6f6e 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -27,6 +27,8 @@
>  #include <linux/cc_platform.h>
>  #include <trace/events/iommu.h>
>  
> +#include "iommu-sva-lib.h"
> +
>  static struct kset *iommu_group_kset;
>  static DEFINE_IDA(iommu_group_ida);
>  
> @@ -1177,10 +1179,9 @@ int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt)
>  	if (!param || !evt)
>  		return -EINVAL;
>  
> -	/* we only report device fault if there is a handler registered */
>  	mutex_lock(&param->lock);
>  	fparam = param->fault_param;
> -	if (!fparam || !fparam->handler) {
> +	if (!fparam) {
>  		ret = -EINVAL;
>  		goto done_unlock;
>  	}
> @@ -1198,7 +1199,11 @@ int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt)
>  		mutex_unlock(&fparam->lock);
>  	}
>  
> -	ret = fparam->handler(&evt->fault, fparam->data);
> +	if (fparam->handler)
> +		ret = fparam->handler(&evt->fault, fparam->data);
> +	else
> +		ret = iommu_queue_iopf(&evt->fault, fparam->data);
> +

I like the change, but we'll need to consolidate this, because now if the
driver registers a fault handler it disables IOPF. We could instead
prevent registration if an IOPF param is present. We could also just merge
fparam->handler but eventually I'd like to make IOPF fall back to the
fault handler registered by device driver, in case of invalid page faults.
I have a couple patches for this but am still missing some bits.

Thanks,
Jean

>  	if (ret && evt_pending) {
>  		mutex_lock(&fparam->lock);
>  		list_del(&evt_pending->list);
> -- 
> 2.25.1
> 

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

* Re: [PATCH RFC 08/11] iommu: Handle IO page faults directly
@ 2022-03-21 11:35     ` Jean-Philippe Brucker
  0 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-21 11:35 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Kevin Tian, Ashok Raj, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Jason Gunthorpe, Will Deacon

On Sun, Mar 20, 2022 at 02:40:27PM +0800, Lu Baolu wrote:
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index c0966fc9b686..4f90b71c6f6e 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -27,6 +27,8 @@
>  #include <linux/cc_platform.h>
>  #include <trace/events/iommu.h>
>  
> +#include "iommu-sva-lib.h"
> +
>  static struct kset *iommu_group_kset;
>  static DEFINE_IDA(iommu_group_ida);
>  
> @@ -1177,10 +1179,9 @@ int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt)
>  	if (!param || !evt)
>  		return -EINVAL;
>  
> -	/* we only report device fault if there is a handler registered */
>  	mutex_lock(&param->lock);
>  	fparam = param->fault_param;
> -	if (!fparam || !fparam->handler) {
> +	if (!fparam) {
>  		ret = -EINVAL;
>  		goto done_unlock;
>  	}
> @@ -1198,7 +1199,11 @@ int iommu_report_device_fault(struct device *dev, struct iommu_fault_event *evt)
>  		mutex_unlock(&fparam->lock);
>  	}
>  
> -	ret = fparam->handler(&evt->fault, fparam->data);
> +	if (fparam->handler)
> +		ret = fparam->handler(&evt->fault, fparam->data);
> +	else
> +		ret = iommu_queue_iopf(&evt->fault, fparam->data);
> +

I like the change, but we'll need to consolidate this, because now if the
driver registers a fault handler it disables IOPF. We could instead
prevent registration if an IOPF param is present. We could also just merge
fparam->handler but eventually I'd like to make IOPF fall back to the
fault handler registered by device driver, in case of invalid page faults.
I have a couple patches for this but am still missing some bits.

Thanks,
Jean

>  	if (ret && evt_pending) {
>  		mutex_lock(&fparam->lock);
>  		list_del(&evt_pending->list);
> -- 
> 2.25.1
> 
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21 11:39     ` Jean-Philippe Brucker
  -1 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-21 11:39 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Kevin Tian,
	Ashok Raj, Will Deacon, Robin Murphy, Jean-Philippe Brucker,
	Eric Auger, Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On Sun, Mar 20, 2022 at 02:40:29PM +0800, Lu Baolu wrote:
> The existing IOPF handling framework only handles the I/O page faults for
> SVA. Ginven that we are able to link iommu domain with each I/O page fault,
> we can now make the I/O page fault handling framework more general for
> more types of page faults.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  include/linux/iommu.h         |  4 +++
>  drivers/iommu/io-pgfault.c    | 67 ++++++-----------------------------
>  drivers/iommu/iommu-sva-lib.c | 59 ++++++++++++++++++++++++++++++
>  3 files changed, 73 insertions(+), 57 deletions(-)
> 
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 803e7b07605e..11c65a7bed88 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -50,6 +50,8 @@ struct iommu_dma_cookie;
>  typedef int (*iommu_fault_handler_t)(struct iommu_domain *,
>  			struct device *, unsigned long, int, void *);
>  typedef int (*iommu_dev_fault_handler_t)(struct iommu_fault *, void *);
> +typedef enum iommu_page_response_code (*iommu_domain_iopf_handler_t)
> +			(struct iommu_fault *, void *);
>  
>  struct iommu_domain_geometry {
>  	dma_addr_t aperture_start; /* First address that can be mapped    */
> @@ -101,6 +103,8 @@ struct iommu_domain {
>  	struct iommu_domain_geometry geometry;
>  	struct iommu_dma_cookie *iova_cookie;
>  	struct mm_struct *sva_cookie;
> +	iommu_domain_iopf_handler_t fault_handler;
> +	void *fault_data;
>  };
>  
>  static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
> diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
> index 1df8c1dcae77..dad0e40cd8d2 100644
> --- a/drivers/iommu/io-pgfault.c
> +++ b/drivers/iommu/io-pgfault.c
> @@ -69,62 +69,6 @@ static int iopf_complete_group(struct device *dev, struct iopf_fault *iopf,
>  	return iommu_page_response(dev, &resp);
>  }
>  
> -static enum iommu_page_response_code
> -iopf_handle_single(struct iopf_fault *iopf)
> -{
> -	vm_fault_t ret;
> -	struct mm_struct *mm;
> -	struct vm_area_struct *vma;
> -	unsigned int access_flags = 0;
> -	unsigned int fault_flags = FAULT_FLAG_REMOTE;
> -	struct iommu_fault_page_request *prm = &iopf->fault.prm;
> -	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
> -
> -	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
> -		return status;
> -
> -	mm = iommu_sva_find(prm->pasid);
> -	if (IS_ERR_OR_NULL(mm))
> -		return status;
> -
> -	mmap_read_lock(mm);
> -
> -	vma = find_extend_vma(mm, prm->addr);
> -	if (!vma)
> -		/* Unmapped area */
> -		goto out_put_mm;
> -
> -	if (prm->perm & IOMMU_FAULT_PERM_READ)
> -		access_flags |= VM_READ;
> -
> -	if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
> -		access_flags |= VM_WRITE;
> -		fault_flags |= FAULT_FLAG_WRITE;
> -	}
> -
> -	if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
> -		access_flags |= VM_EXEC;
> -		fault_flags |= FAULT_FLAG_INSTRUCTION;
> -	}
> -
> -	if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
> -		fault_flags |= FAULT_FLAG_USER;
> -
> -	if (access_flags & ~vma->vm_flags)
> -		/* Access fault */
> -		goto out_put_mm;
> -
> -	ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
> -	status = ret & VM_FAULT_ERROR ? IOMMU_PAGE_RESP_INVALID :
> -		IOMMU_PAGE_RESP_SUCCESS;
> -
> -out_put_mm:
> -	mmap_read_unlock(mm);
> -	mmput(mm);
> -
> -	return status;
> -}
> -
>  static void iopf_handle_group(struct work_struct *work)
>  {
>  	struct iopf_group *group;
> @@ -134,12 +78,21 @@ static void iopf_handle_group(struct work_struct *work)
>  	group = container_of(work, struct iopf_group, work);
>  
>  	list_for_each_entry_safe(iopf, next, &group->faults, list) {
> +		struct iommu_domain *domain;
> +
> +		domain = iommu_get_domain_for_dev_pasid(group->dev,
> +							iopf->fault.prm.pasid);

Do we have a guarantee that the domain is not freed while we handle the
fault?  We could prevent unbind() while there are pending faults on this
bond. But a refcount on SVA domains could defer freeing, and would also
help with keeping the semantics where bind() returns a single refcounted
bond for any {dev, mm}.

Given that this path is full of circular locking pitfalls, and to keep the
fault handler efficient (well, at least not make it worse), we should
probably keep a getter like iommu_sva_find() that does not require
locking.

> +
> +		if (!domain || !domain->fault_handler)
> +			status = IOMMU_PAGE_RESP_INVALID;
> +
>  		/*
>  		 * For the moment, errors are sticky: don't handle subsequent
>  		 * faults in the group if there is an error.
>  		 */
>  		if (status == IOMMU_PAGE_RESP_SUCCESS)
> -			status = iopf_handle_single(iopf);
> +			status = domain->fault_handler(&iopf->fault,
> +						       domain->fault_data);

If we make this a direct call and only use a light getter for the
PASID->mm lookup we don't need to look at the domain at all. Or are you
planning to add external fault handlers?

>  
>  		if (!(iopf->fault.prm.flags &
>  		      IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE))
> diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
> index 47cf98e661ff..01fa8096bd02 100644
> --- a/drivers/iommu/iommu-sva-lib.c
> +++ b/drivers/iommu/iommu-sva-lib.c
> @@ -87,6 +87,63 @@ static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev)
>  	return domain;
>  }
>  
> +static enum iommu_page_response_code
> +iommu_sva_handle_iopf(struct iommu_fault *fault, void *data)
> +{
> +	vm_fault_t ret;
> +	struct mm_struct *mm;
> +	struct vm_area_struct *vma;
> +	unsigned int access_flags = 0;
> +	struct iommu_domain *domain = data;
> +	unsigned int fault_flags = FAULT_FLAG_REMOTE;
> +	struct iommu_fault_page_request *prm = &fault->prm;
> +	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
> +
> +	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
> +		return status;
> +
> +	mm = domain->sva_cookie;
> +	if (IS_ERR_OR_NULL(mm))
> +		return status;
> +
> +	mmap_read_lock(mm);
> +
> +	vma = find_extend_vma(mm, prm->addr);
> +	if (!vma)
> +		/* Unmapped area */
> +		goto out_put_mm;
> +
> +	if (prm->perm & IOMMU_FAULT_PERM_READ)
> +		access_flags |= VM_READ;
> +
> +	if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
> +		access_flags |= VM_WRITE;
> +		fault_flags |= FAULT_FLAG_WRITE;
> +	}
> +
> +	if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
> +		access_flags |= VM_EXEC;
> +		fault_flags |= FAULT_FLAG_INSTRUCTION;
> +	}
> +
> +	if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
> +		fault_flags |= FAULT_FLAG_USER;
> +
> +	if (access_flags & ~vma->vm_flags)
> +		/* Access fault */
> +		goto out_put_mm;
> +
> +	ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
> +	status = ret & VM_FAULT_ERROR ? IOMMU_PAGE_RESP_INVALID :
> +		IOMMU_PAGE_RESP_SUCCESS;
> +
> +out_put_mm:
> +	mmap_read_unlock(mm);
> +	mmput(mm);

mmget_not_zero() is missing since iommu_sva_find() is gone. I'm guessing
we still need it in case the process dies

Thanks,
Jean

> +
> +	return status;
> +}
> +
>  /**
>   * iommu_sva_bind_device() - Bind a process address space to a device
>   * @dev: the device
> @@ -124,6 +181,8 @@ iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
>  		goto out;
>  	}
>  	domain->sva_cookie = mm;
> +	domain->fault_handler = iommu_sva_handle_iopf;
> +	domain->fault_data = domain;
>  
>  	ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
>  	if (ret)
> -- 
> 2.25.1
> 

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-21 11:39     ` Jean-Philippe Brucker
  0 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-21 11:39 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Kevin Tian, Ashok Raj, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Jason Gunthorpe, Will Deacon

On Sun, Mar 20, 2022 at 02:40:29PM +0800, Lu Baolu wrote:
> The existing IOPF handling framework only handles the I/O page faults for
> SVA. Ginven that we are able to link iommu domain with each I/O page fault,
> we can now make the I/O page fault handling framework more general for
> more types of page faults.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  include/linux/iommu.h         |  4 +++
>  drivers/iommu/io-pgfault.c    | 67 ++++++-----------------------------
>  drivers/iommu/iommu-sva-lib.c | 59 ++++++++++++++++++++++++++++++
>  3 files changed, 73 insertions(+), 57 deletions(-)
> 
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 803e7b07605e..11c65a7bed88 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -50,6 +50,8 @@ struct iommu_dma_cookie;
>  typedef int (*iommu_fault_handler_t)(struct iommu_domain *,
>  			struct device *, unsigned long, int, void *);
>  typedef int (*iommu_dev_fault_handler_t)(struct iommu_fault *, void *);
> +typedef enum iommu_page_response_code (*iommu_domain_iopf_handler_t)
> +			(struct iommu_fault *, void *);
>  
>  struct iommu_domain_geometry {
>  	dma_addr_t aperture_start; /* First address that can be mapped    */
> @@ -101,6 +103,8 @@ struct iommu_domain {
>  	struct iommu_domain_geometry geometry;
>  	struct iommu_dma_cookie *iova_cookie;
>  	struct mm_struct *sva_cookie;
> +	iommu_domain_iopf_handler_t fault_handler;
> +	void *fault_data;
>  };
>  
>  static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
> diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
> index 1df8c1dcae77..dad0e40cd8d2 100644
> --- a/drivers/iommu/io-pgfault.c
> +++ b/drivers/iommu/io-pgfault.c
> @@ -69,62 +69,6 @@ static int iopf_complete_group(struct device *dev, struct iopf_fault *iopf,
>  	return iommu_page_response(dev, &resp);
>  }
>  
> -static enum iommu_page_response_code
> -iopf_handle_single(struct iopf_fault *iopf)
> -{
> -	vm_fault_t ret;
> -	struct mm_struct *mm;
> -	struct vm_area_struct *vma;
> -	unsigned int access_flags = 0;
> -	unsigned int fault_flags = FAULT_FLAG_REMOTE;
> -	struct iommu_fault_page_request *prm = &iopf->fault.prm;
> -	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
> -
> -	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
> -		return status;
> -
> -	mm = iommu_sva_find(prm->pasid);
> -	if (IS_ERR_OR_NULL(mm))
> -		return status;
> -
> -	mmap_read_lock(mm);
> -
> -	vma = find_extend_vma(mm, prm->addr);
> -	if (!vma)
> -		/* Unmapped area */
> -		goto out_put_mm;
> -
> -	if (prm->perm & IOMMU_FAULT_PERM_READ)
> -		access_flags |= VM_READ;
> -
> -	if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
> -		access_flags |= VM_WRITE;
> -		fault_flags |= FAULT_FLAG_WRITE;
> -	}
> -
> -	if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
> -		access_flags |= VM_EXEC;
> -		fault_flags |= FAULT_FLAG_INSTRUCTION;
> -	}
> -
> -	if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
> -		fault_flags |= FAULT_FLAG_USER;
> -
> -	if (access_flags & ~vma->vm_flags)
> -		/* Access fault */
> -		goto out_put_mm;
> -
> -	ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
> -	status = ret & VM_FAULT_ERROR ? IOMMU_PAGE_RESP_INVALID :
> -		IOMMU_PAGE_RESP_SUCCESS;
> -
> -out_put_mm:
> -	mmap_read_unlock(mm);
> -	mmput(mm);
> -
> -	return status;
> -}
> -
>  static void iopf_handle_group(struct work_struct *work)
>  {
>  	struct iopf_group *group;
> @@ -134,12 +78,21 @@ static void iopf_handle_group(struct work_struct *work)
>  	group = container_of(work, struct iopf_group, work);
>  
>  	list_for_each_entry_safe(iopf, next, &group->faults, list) {
> +		struct iommu_domain *domain;
> +
> +		domain = iommu_get_domain_for_dev_pasid(group->dev,
> +							iopf->fault.prm.pasid);

Do we have a guarantee that the domain is not freed while we handle the
fault?  We could prevent unbind() while there are pending faults on this
bond. But a refcount on SVA domains could defer freeing, and would also
help with keeping the semantics where bind() returns a single refcounted
bond for any {dev, mm}.

Given that this path is full of circular locking pitfalls, and to keep the
fault handler efficient (well, at least not make it worse), we should
probably keep a getter like iommu_sva_find() that does not require
locking.

> +
> +		if (!domain || !domain->fault_handler)
> +			status = IOMMU_PAGE_RESP_INVALID;
> +
>  		/*
>  		 * For the moment, errors are sticky: don't handle subsequent
>  		 * faults in the group if there is an error.
>  		 */
>  		if (status == IOMMU_PAGE_RESP_SUCCESS)
> -			status = iopf_handle_single(iopf);
> +			status = domain->fault_handler(&iopf->fault,
> +						       domain->fault_data);

If we make this a direct call and only use a light getter for the
PASID->mm lookup we don't need to look at the domain at all. Or are you
planning to add external fault handlers?

>  
>  		if (!(iopf->fault.prm.flags &
>  		      IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE))
> diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
> index 47cf98e661ff..01fa8096bd02 100644
> --- a/drivers/iommu/iommu-sva-lib.c
> +++ b/drivers/iommu/iommu-sva-lib.c
> @@ -87,6 +87,63 @@ static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev)
>  	return domain;
>  }
>  
> +static enum iommu_page_response_code
> +iommu_sva_handle_iopf(struct iommu_fault *fault, void *data)
> +{
> +	vm_fault_t ret;
> +	struct mm_struct *mm;
> +	struct vm_area_struct *vma;
> +	unsigned int access_flags = 0;
> +	struct iommu_domain *domain = data;
> +	unsigned int fault_flags = FAULT_FLAG_REMOTE;
> +	struct iommu_fault_page_request *prm = &fault->prm;
> +	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
> +
> +	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
> +		return status;
> +
> +	mm = domain->sva_cookie;
> +	if (IS_ERR_OR_NULL(mm))
> +		return status;
> +
> +	mmap_read_lock(mm);
> +
> +	vma = find_extend_vma(mm, prm->addr);
> +	if (!vma)
> +		/* Unmapped area */
> +		goto out_put_mm;
> +
> +	if (prm->perm & IOMMU_FAULT_PERM_READ)
> +		access_flags |= VM_READ;
> +
> +	if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
> +		access_flags |= VM_WRITE;
> +		fault_flags |= FAULT_FLAG_WRITE;
> +	}
> +
> +	if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
> +		access_flags |= VM_EXEC;
> +		fault_flags |= FAULT_FLAG_INSTRUCTION;
> +	}
> +
> +	if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
> +		fault_flags |= FAULT_FLAG_USER;
> +
> +	if (access_flags & ~vma->vm_flags)
> +		/* Access fault */
> +		goto out_put_mm;
> +
> +	ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
> +	status = ret & VM_FAULT_ERROR ? IOMMU_PAGE_RESP_INVALID :
> +		IOMMU_PAGE_RESP_SUCCESS;
> +
> +out_put_mm:
> +	mmap_read_unlock(mm);
> +	mmput(mm);

mmget_not_zero() is missing since iommu_sva_find() is gone. I'm guessing
we still need it in case the process dies

Thanks,
Jean

> +
> +	return status;
> +}
> +
>  /**
>   * iommu_sva_bind_device() - Bind a process address space to a device
>   * @dev: the device
> @@ -124,6 +181,8 @@ iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
>  		goto out;
>  	}
>  	domain->sva_cookie = mm;
> +	domain->fault_handler = iommu_sva_handle_iopf;
> +	domain->fault_data = domain;
>  
>  	ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
>  	if (ret)
> -- 
> 2.25.1
> 
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-21  8:09     ` Tian, Kevin
@ 2022-03-21 11:42       ` Jean-Philippe Brucker
  -1 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-21 11:42 UTC (permalink / raw)
  To: Tian, Kevin
  Cc: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker,
	Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

Hi Kevin,

On Mon, Mar 21, 2022 at 08:09:36AM +0000, Tian, Kevin wrote:
> > From: Lu Baolu <baolu.lu@linux.intel.com>
> > Sent: Sunday, March 20, 2022 2:40 PM
> > 
> > The existing IOPF handling framework only handles the I/O page faults for
> > SVA. Ginven that we are able to link iommu domain with each I/O page fault,
> > we can now make the I/O page fault handling framework more general for
> > more types of page faults.
> 
> "make ... generic" in subject line is kind of confusing. Reading this patch I
> think you really meant changing from per-device fault handling to per-domain
> fault handling. This is more accurate in concept since the fault is caused by
> the domain page table. 😊

I tend to disagree with that last part. The fault is caused by a specific
device accessing shared page tables. We should keep that device
information throughout the fault handling, so that we can report it to the
driver when things go wrong. A process can have multiple threads bound to
different devices, they share the same mm so if the driver wanted to
signal a misbehaving thread, similarly to a SEGV on the CPU side, it would
need the device information to precisely report it to userspace.

Thanks,
Jean

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-21 11:42       ` Jean-Philippe Brucker
  0 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-21 11:42 UTC (permalink / raw)
  To: Tian, Kevin
  Cc: Raj, Ashok, Robin Murphy, linux-kernel, Christoph Hellwig,
	Jean-Philippe Brucker, iommu, Pan, Jacob jun, Jason Gunthorpe,
	Will Deacon

Hi Kevin,

On Mon, Mar 21, 2022 at 08:09:36AM +0000, Tian, Kevin wrote:
> > From: Lu Baolu <baolu.lu@linux.intel.com>
> > Sent: Sunday, March 20, 2022 2:40 PM
> > 
> > The existing IOPF handling framework only handles the I/O page faults for
> > SVA. Ginven that we are able to link iommu domain with each I/O page fault,
> > we can now make the I/O page fault handling framework more general for
> > more types of page faults.
> 
> "make ... generic" in subject line is kind of confusing. Reading this patch I
> think you really meant changing from per-device fault handling to per-domain
> fault handling. This is more accurate in concept since the fault is caused by
> the domain page table. 😊

I tend to disagree with that last part. The fault is caused by a specific
device accessing shared page tables. We should keep that device
information throughout the fault handling, so that we can report it to the
driver when things go wrong. A process can have multiple threads bound to
different devices, they share the same mm so if the driver wanted to
signal a misbehaving thread, similarly to a SEGV on the CPU side, it would
need the device information to precisely report it to userspace.

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

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

* Re: [PATCH RFC 02/11] iommu: Add iommu_domain type for SVA
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21 11:47     ` Jason Gunthorpe via iommu
  -1 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe @ 2022-03-21 11:47 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Joerg Roedel, Christoph Hellwig, Kevin Tian, Ashok Raj,
	Will Deacon, Robin Murphy, Jean-Philippe Brucker, Eric Auger,
	Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On Sun, Mar 20, 2022 at 02:40:21PM +0800, Lu Baolu wrote:
> Add a new iommu domain type IOMMU_DOMAIN_SVA to represent an I/O page
> table which is shared from CPU host VA. Add a sva_cookie field in the
> iommu_domain structure to save the mm_struct which represent the CPU
> memory page table.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>  include/linux/iommu.h | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 36f43af0af53..3e179b853380 100644
> +++ b/include/linux/iommu.h
> @@ -64,6 +64,9 @@ struct iommu_domain_geometry {
>  #define __IOMMU_DOMAIN_PT	(1U << 2)  /* Domain is identity mapped   */
>  #define __IOMMU_DOMAIN_DMA_FQ	(1U << 3)  /* DMA-API uses flush queue    */
>  
> +#define __IOMMU_DOMAIN_SHARED	(1U << 4)  /* Page table shared from CPU  */
> +#define __IOMMU_DOMAIN_HOST_VA	(1U << 5)  /* Host CPU virtual address */
> +
>  /*
>   * This are the possible domain-types
>   *
> @@ -86,6 +89,8 @@ struct iommu_domain_geometry {
>  #define IOMMU_DOMAIN_DMA_FQ	(__IOMMU_DOMAIN_PAGING |	\
>  				 __IOMMU_DOMAIN_DMA_API |	\
>  				 __IOMMU_DOMAIN_DMA_FQ)
> +#define IOMMU_DOMAIN_SVA	(__IOMMU_DOMAIN_SHARED |	\
> +				 __IOMMU_DOMAIN_HOST_VA)

Is there any use for this in the core code? I feel like flags should
only be created if the core code needs to test them in some way.

> @@ -95,6 +100,7 @@ struct iommu_domain {
>  	void *handler_token;
>  	struct iommu_domain_geometry geometry;
>  	struct iommu_dma_cookie *iova_cookie;
> +	struct mm_struct *sva_cookie;

Don't call a mm_struct a cookie please

And why do we need this in core code?

Jason

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

* Re: [PATCH RFC 02/11] iommu: Add iommu_domain type for SVA
@ 2022-03-21 11:47     ` Jason Gunthorpe via iommu
  0 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-03-21 11:47 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Kevin Tian, Ashok Raj, Will Deacon, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Robin Murphy

On Sun, Mar 20, 2022 at 02:40:21PM +0800, Lu Baolu wrote:
> Add a new iommu domain type IOMMU_DOMAIN_SVA to represent an I/O page
> table which is shared from CPU host VA. Add a sva_cookie field in the
> iommu_domain structure to save the mm_struct which represent the CPU
> memory page table.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>  include/linux/iommu.h | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index 36f43af0af53..3e179b853380 100644
> +++ b/include/linux/iommu.h
> @@ -64,6 +64,9 @@ struct iommu_domain_geometry {
>  #define __IOMMU_DOMAIN_PT	(1U << 2)  /* Domain is identity mapped   */
>  #define __IOMMU_DOMAIN_DMA_FQ	(1U << 3)  /* DMA-API uses flush queue    */
>  
> +#define __IOMMU_DOMAIN_SHARED	(1U << 4)  /* Page table shared from CPU  */
> +#define __IOMMU_DOMAIN_HOST_VA	(1U << 5)  /* Host CPU virtual address */
> +
>  /*
>   * This are the possible domain-types
>   *
> @@ -86,6 +89,8 @@ struct iommu_domain_geometry {
>  #define IOMMU_DOMAIN_DMA_FQ	(__IOMMU_DOMAIN_PAGING |	\
>  				 __IOMMU_DOMAIN_DMA_API |	\
>  				 __IOMMU_DOMAIN_DMA_FQ)
> +#define IOMMU_DOMAIN_SVA	(__IOMMU_DOMAIN_SHARED |	\
> +				 __IOMMU_DOMAIN_HOST_VA)

Is there any use for this in the core code? I feel like flags should
only be created if the core code needs to test them in some way.

> @@ -95,6 +100,7 @@ struct iommu_domain {
>  	void *handler_token;
>  	struct iommu_domain_geometry geometry;
>  	struct iommu_dma_cookie *iova_cookie;
> +	struct mm_struct *sva_cookie;

Don't call a mm_struct a cookie please

And why do we need this in core code?

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

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

* Re: [PATCH RFC 03/11] iommu: Add attach/detach_dev_pasid domain ops
  2022-03-21  7:13     ` Tian, Kevin
@ 2022-03-21 11:53       ` Jason Gunthorpe
  -1 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-03-21 11:53 UTC (permalink / raw)
  To: Tian, Kevin
  Cc: Raj, Ashok, Will Deacon, linux-kernel, Christoph Hellwig,
	Jean-Philippe Brucker, iommu, Pan, Jacob jun, Robin Murphy

On Mon, Mar 21, 2022 at 07:13:49AM +0000, Tian, Kevin wrote:

> 	/*
> 	 * To keep things simple, SVA currently doesn't support IOMMU groups
> 	 * with more than one device. Existing SVA-capable systems are not
> 	 * affected by the problems that required IOMMU groups (lack of ACS
> 	 * isolation, device ID aliasing and other hardware issues).
> 	 */
> 	if (iommu_group_device_count(group) != 1)
> 		goto out_unlock;
> 
> btw I didn't see any safeguard on above assumption in device hotplug path
> to a group which already has SVA enabled...

This is because using device_count is always wrong for these kinds of
tests.

The exclusion needs to be built up from the new owner mechanism. Once
the device is in SVA mode it is the same as having exclusive ownership
against any other probes()

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

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

* Re: [PATCH RFC 03/11] iommu: Add attach/detach_dev_pasid domain ops
@ 2022-03-21 11:53       ` Jason Gunthorpe
  0 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe @ 2022-03-21 11:53 UTC (permalink / raw)
  To: Tian, Kevin
  Cc: Lu Baolu, Joerg Roedel, Christoph Hellwig, Raj, Ashok,
	Will Deacon, Robin Murphy, Jean-Philippe Brucker, Eric Auger,
	Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

On Mon, Mar 21, 2022 at 07:13:49AM +0000, Tian, Kevin wrote:

> 	/*
> 	 * To keep things simple, SVA currently doesn't support IOMMU groups
> 	 * with more than one device. Existing SVA-capable systems are not
> 	 * affected by the problems that required IOMMU groups (lack of ACS
> 	 * isolation, device ID aliasing and other hardware issues).
> 	 */
> 	if (iommu_group_device_count(group) != 1)
> 		goto out_unlock;
> 
> btw I didn't see any safeguard on above assumption in device hotplug path
> to a group which already has SVA enabled...

This is because using device_count is always wrong for these kinds of
tests.

The exclusion needs to be built up from the new owner mechanism. Once
the device is in SVA mode it is the same as having exclusive ownership
against any other probes()

Jason

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

* Re: [PATCH RFC 04/11] iommu/vt-d: Add SVA domain support
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21 11:56     ` Jason Gunthorpe
  -1 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-03-21 11:56 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Kevin Tian, Ashok Raj, Will Deacon, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Robin Murphy

On Sun, Mar 20, 2022 at 02:40:23PM +0800, Lu Baolu wrote:
> Add support for SVA domain allocation and provide an SVA-specific
> iommu_domain_ops.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>  include/linux/intel-iommu.h |  1 +
>  drivers/iommu/intel/iommu.c | 12 ++++++++++++
>  drivers/iommu/intel/svm.c   | 34 ++++++++++++++++++++++++++++++++++
>  3 files changed, 47 insertions(+)
> 
> diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
> index 2f9891cb3d00..c14283137fb5 100644
> +++ b/include/linux/intel-iommu.h
> @@ -744,6 +744,7 @@ void intel_svm_unbind(struct iommu_sva *handle);
>  u32 intel_svm_get_pasid(struct iommu_sva *handle);
>  int intel_svm_page_response(struct device *dev, struct iommu_fault_event *evt,
>  			    struct iommu_page_response *msg);
> +extern const struct iommu_domain_ops intel_svm_domain_ops;
>  
>  struct intel_svm_dev {
>  	struct list_head list;
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index c1b91bce1530..d55dca3eacf8 100644
> +++ b/drivers/iommu/intel/iommu.c
> @@ -4318,6 +4318,18 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
>  		return domain;
>  	case IOMMU_DOMAIN_IDENTITY:
>  		return &si_domain->domain;
> +#ifdef CONFIG_INTEL_IOMMU_SVM
> +	case IOMMU_DOMAIN_SVA:
> +		dmar_domain = alloc_domain(type);
> +		if (!dmar_domain) {
> +			pr_err("Can't allocate sva domain\n");

Don't put random pr_err's/etc in drivers. At least try to use dev_err

> +			return NULL;
> +		}
> +		domain = &dmar_domain->domain;
> +		domain->ops = &intel_svm_domain_ops;
> +
> +		return domain;
> +#endif /* CONFIG_INTEL_IOMMU_SVM */
>  	default:
>  		return NULL;
>  	}
> diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
> index ee5ecde5b318..b9f4dd7057d1 100644
> +++ b/drivers/iommu/intel/svm.c
> @@ -932,3 +932,37 @@ int intel_svm_page_response(struct device *dev,
>  	mutex_unlock(&pasid_mutex);
>  	return ret;
>  }
> +
> +static int intel_svm_attach_dev_pasid(struct iommu_domain *domain,
> +				      struct device *dev, ioasid_t pasid)
> +{
> +	struct device_domain_info *info = dev_iommu_priv_get(dev);
> +	struct mm_struct *mm = domain->sva_cookie;
> +	struct intel_iommu *iommu = info->iommu;
> +	struct iommu_sva *sva;
> +
> +	mutex_lock(&pasid_mutex);
> +	sva = intel_svm_bind_mm(iommu, dev, mm);
> +	mutex_unlock(&pasid_mutex);
> +
> +	return IS_ERR_OR_NULL(sva);

Never use IS_ERR_OR_NULL(), fix whatever is wrong in intel_svm_bind_mm()
that it can return NULL on failure.

> +const struct iommu_domain_ops intel_svm_domain_ops = {
> +	.attach_dev_pasid	= intel_svm_attach_dev_pasid,
> +	.detach_dev_pasid	= intel_svm_detach_dev_pasid,

Lets have consistent language either this is called SVA or SVM but not
both.

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

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

* Re: [PATCH RFC 04/11] iommu/vt-d: Add SVA domain support
@ 2022-03-21 11:56     ` Jason Gunthorpe
  0 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe @ 2022-03-21 11:56 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Joerg Roedel, Christoph Hellwig, Kevin Tian, Ashok Raj,
	Will Deacon, Robin Murphy, Jean-Philippe Brucker, Eric Auger,
	Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On Sun, Mar 20, 2022 at 02:40:23PM +0800, Lu Baolu wrote:
> Add support for SVA domain allocation and provide an SVA-specific
> iommu_domain_ops.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>  include/linux/intel-iommu.h |  1 +
>  drivers/iommu/intel/iommu.c | 12 ++++++++++++
>  drivers/iommu/intel/svm.c   | 34 ++++++++++++++++++++++++++++++++++
>  3 files changed, 47 insertions(+)
> 
> diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
> index 2f9891cb3d00..c14283137fb5 100644
> +++ b/include/linux/intel-iommu.h
> @@ -744,6 +744,7 @@ void intel_svm_unbind(struct iommu_sva *handle);
>  u32 intel_svm_get_pasid(struct iommu_sva *handle);
>  int intel_svm_page_response(struct device *dev, struct iommu_fault_event *evt,
>  			    struct iommu_page_response *msg);
> +extern const struct iommu_domain_ops intel_svm_domain_ops;
>  
>  struct intel_svm_dev {
>  	struct list_head list;
> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
> index c1b91bce1530..d55dca3eacf8 100644
> +++ b/drivers/iommu/intel/iommu.c
> @@ -4318,6 +4318,18 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
>  		return domain;
>  	case IOMMU_DOMAIN_IDENTITY:
>  		return &si_domain->domain;
> +#ifdef CONFIG_INTEL_IOMMU_SVM
> +	case IOMMU_DOMAIN_SVA:
> +		dmar_domain = alloc_domain(type);
> +		if (!dmar_domain) {
> +			pr_err("Can't allocate sva domain\n");

Don't put random pr_err's/etc in drivers. At least try to use dev_err

> +			return NULL;
> +		}
> +		domain = &dmar_domain->domain;
> +		domain->ops = &intel_svm_domain_ops;
> +
> +		return domain;
> +#endif /* CONFIG_INTEL_IOMMU_SVM */
>  	default:
>  		return NULL;
>  	}
> diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
> index ee5ecde5b318..b9f4dd7057d1 100644
> +++ b/drivers/iommu/intel/svm.c
> @@ -932,3 +932,37 @@ int intel_svm_page_response(struct device *dev,
>  	mutex_unlock(&pasid_mutex);
>  	return ret;
>  }
> +
> +static int intel_svm_attach_dev_pasid(struct iommu_domain *domain,
> +				      struct device *dev, ioasid_t pasid)
> +{
> +	struct device_domain_info *info = dev_iommu_priv_get(dev);
> +	struct mm_struct *mm = domain->sva_cookie;
> +	struct intel_iommu *iommu = info->iommu;
> +	struct iommu_sva *sva;
> +
> +	mutex_lock(&pasid_mutex);
> +	sva = intel_svm_bind_mm(iommu, dev, mm);
> +	mutex_unlock(&pasid_mutex);
> +
> +	return IS_ERR_OR_NULL(sva);

Never use IS_ERR_OR_NULL(), fix whatever is wrong in intel_svm_bind_mm()
that it can return NULL on failure.

> +const struct iommu_domain_ops intel_svm_domain_ops = {
> +	.attach_dev_pasid	= intel_svm_attach_dev_pasid,
> +	.detach_dev_pasid	= intel_svm_detach_dev_pasid,

Lets have consistent language either this is called SVA or SVM but not
both.

Jason

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

* Re: [PATCH RFC 05/11] arm-smmu-v3/sva: Add SVA domain support
  2022-03-21 11:31     ` Jean-Philippe Brucker
@ 2022-03-21 11:58       ` Jason Gunthorpe via iommu
  -1 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe @ 2022-03-21 11:58 UTC (permalink / raw)
  To: Jean-Philippe Brucker
  Cc: Lu Baolu, Joerg Roedel, Christoph Hellwig, Kevin Tian, Ashok Raj,
	Will Deacon, Robin Murphy, Jean-Philippe Brucker, Eric Auger,
	Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On Mon, Mar 21, 2022 at 11:31:19AM +0000, Jean-Philippe Brucker wrote:
> For now we could just return a naked struct iommu_domain. Sanity checks in
> arm_smmu_attach_dev() would be good too, a SVA domain can't be attached as
> a parent domain.

Now that we have per-domain ops the 'standard' arm_smmu_attach_dev()
cannot be called on a SVA iommu_domain already.

Jason

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

* Re: [PATCH RFC 05/11] arm-smmu-v3/sva: Add SVA domain support
@ 2022-03-21 11:58       ` Jason Gunthorpe via iommu
  0 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-03-21 11:58 UTC (permalink / raw)
  To: Jean-Philippe Brucker
  Cc: Kevin Tian, Ashok Raj, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Will Deacon

On Mon, Mar 21, 2022 at 11:31:19AM +0000, Jean-Philippe Brucker wrote:
> For now we could just return a naked struct iommu_domain. Sanity checks in
> arm_smmu_attach_dev() would be good too, a SVA domain can't be attached as
> a parent domain.

Now that we have per-domain ops the 'standard' arm_smmu_attach_dev()
cannot be called on a SVA iommu_domain already.

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

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

* Re: [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  2022-03-21 11:01       ` Lu Baolu
@ 2022-03-21 12:03         ` Jason Gunthorpe via iommu
  -1 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe @ 2022-03-21 12:03 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Tian, Kevin, Joerg Roedel, Christoph Hellwig, Raj, Ashok,
	Will Deacon, Robin Murphy, Jean-Philippe Brucker, Eric Auger,
	Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

On Mon, Mar 21, 2022 at 07:01:45PM +0800, Lu Baolu wrote:

> > one domain can be attached by multiple devices, so this should not be
> > a blind alloc.
> 
> Indeed. Perhaps we could associate the SVA domain with the mm->pasid and
> add a user counter inside the domain.

This has the same problem as VFIO it needs to keep a list of
automatically created iommu domains in the mm_struct and try to re-use
them every time a device is bound.

Jason

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

* Re: [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
@ 2022-03-21 12:03         ` Jason Gunthorpe via iommu
  0 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-03-21 12:03 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Tian, Kevin, Raj, Ashok, Will Deacon, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Pan, Jacob jun,
	Robin Murphy

On Mon, Mar 21, 2022 at 07:01:45PM +0800, Lu Baolu wrote:

> > one domain can be attached by multiple devices, so this should not be
> > a blind alloc.
> 
> Indeed. Perhaps we could associate the SVA domain with the mm->pasid and
> add a user counter inside the domain.

This has the same problem as VFIO it needs to keep a list of
automatically created iommu domains in the mm_struct and try to re-use
them every time a device is bound.

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

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

* Re: [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21 12:05     ` Jason Gunthorpe via iommu
  -1 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe @ 2022-03-21 12:05 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Joerg Roedel, Christoph Hellwig, Kevin Tian, Ashok Raj,
	Will Deacon, Robin Murphy, Jean-Philippe Brucker, Eric Auger,
	Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On Sun, Mar 20, 2022 at 02:40:25PM +0800, Lu Baolu wrote:

> +/**
> + * iommu_sva_bind_device() - Bind a process address space to a device
> + * @dev: the device
> + * @mm: the mm to bind, caller must hold a reference to it
> + * @drvdata: opaque data pointer to pass to bind callback
> + *
> + * Create a bond between device and address space, allowing the device to access
> + * the mm using the returned PASID. If a bond already exists between @device and
> + * @mm, it is returned and an additional reference is taken. Caller must call
> + * iommu_sva_unbind_device() to release each reference.
> + *
> + * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
> + * initialize the required SVA features.
> + *
> + * On error, returns an ERR_PTR value.
> + */
> +struct iommu_sva *
> +iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)

The drvdata is never used

Jason

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

* Re: [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
@ 2022-03-21 12:05     ` Jason Gunthorpe via iommu
  0 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-03-21 12:05 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Kevin Tian, Ashok Raj, Will Deacon, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Robin Murphy

On Sun, Mar 20, 2022 at 02:40:25PM +0800, Lu Baolu wrote:

> +/**
> + * iommu_sva_bind_device() - Bind a process address space to a device
> + * @dev: the device
> + * @mm: the mm to bind, caller must hold a reference to it
> + * @drvdata: opaque data pointer to pass to bind callback
> + *
> + * Create a bond between device and address space, allowing the device to access
> + * the mm using the returned PASID. If a bond already exists between @device and
> + * @mm, it is returned and an additional reference is taken. Caller must call
> + * iommu_sva_unbind_device() to release each reference.
> + *
> + * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
> + * initialize the required SVA features.
> + *
> + * On error, returns an ERR_PTR value.
> + */
> +struct iommu_sva *
> +iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)

The drvdata is never used

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

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

* Re: [PATCH RFC 09/11] iommu: Add iommu_get_domain_for_dev_pasid()
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21 12:40     ` Jason Gunthorpe via iommu
  -1 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe @ 2022-03-21 12:40 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Joerg Roedel, Christoph Hellwig, Kevin Tian, Ashok Raj,
	Will Deacon, Robin Murphy, Jean-Philippe Brucker, Eric Auger,
	Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On Sun, Mar 20, 2022 at 02:40:28PM +0800, Lu Baolu wrote:
> @@ -3098,7 +3101,16 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
>  	if (iommu_group_device_count(group) != 1)
>  		goto out_unlock;
>  
> +	xa_lock(&group->pasid_array);
> +	curr = __xa_cmpxchg(&group->pasid_array, pasid, NULL,
> +			    domain, GFP_KERNEL);
> +	xa_unlock(&group->pasid_array);
> +	if (curr)

curr can be an xa_err that should be propogated.

> +		goto out_unlock;
> +
>  	ret = domain->ops->attach_dev_pasid(domain, dev, pasid);
> +	if (ret)
> +		xa_erase(&group->pasid_array, pasid);
>  
>  out_unlock:
>  	mutex_unlock(&group->mutex);
> @@ -3118,6 +3130,25 @@ void iommu_detach_device_pasid(struct iommu_domain *domain,
>  
>  	mutex_lock(&group->mutex);
>  	domain->ops->detach_dev_pasid(domain, dev, pasid);
> +	xa_erase(&group->pasid_array, pasid);
> +	mutex_unlock(&group->mutex);
> +	iommu_group_put(group);
> +}
> +
> +struct iommu_domain *
> +iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid)
> +{
> +	struct iommu_domain *domain;
> +	struct iommu_group *group;
> +
> +	group = iommu_group_get(dev);
> +	if (!group)
> +		return NULL;
> +
> +	mutex_lock(&group->mutex);
> +	domain = xa_load(&group->pasid_array, pasid);
>  	mutex_unlock(&group->mutex);
>  	iommu_group_put(group);

This whole API seems sketchy - what is the lifecycle of the returned
iommu_domain and what prevents it from being concurrently freed after
unlocking?

Jason

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

* Re: [PATCH RFC 09/11] iommu: Add iommu_get_domain_for_dev_pasid()
@ 2022-03-21 12:40     ` Jason Gunthorpe via iommu
  0 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-03-21 12:40 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Kevin Tian, Ashok Raj, Will Deacon, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Robin Murphy

On Sun, Mar 20, 2022 at 02:40:28PM +0800, Lu Baolu wrote:
> @@ -3098,7 +3101,16 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
>  	if (iommu_group_device_count(group) != 1)
>  		goto out_unlock;
>  
> +	xa_lock(&group->pasid_array);
> +	curr = __xa_cmpxchg(&group->pasid_array, pasid, NULL,
> +			    domain, GFP_KERNEL);
> +	xa_unlock(&group->pasid_array);
> +	if (curr)

curr can be an xa_err that should be propogated.

> +		goto out_unlock;
> +
>  	ret = domain->ops->attach_dev_pasid(domain, dev, pasid);
> +	if (ret)
> +		xa_erase(&group->pasid_array, pasid);
>  
>  out_unlock:
>  	mutex_unlock(&group->mutex);
> @@ -3118,6 +3130,25 @@ void iommu_detach_device_pasid(struct iommu_domain *domain,
>  
>  	mutex_lock(&group->mutex);
>  	domain->ops->detach_dev_pasid(domain, dev, pasid);
> +	xa_erase(&group->pasid_array, pasid);
> +	mutex_unlock(&group->mutex);
> +	iommu_group_put(group);
> +}
> +
> +struct iommu_domain *
> +iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid)
> +{
> +	struct iommu_domain *domain;
> +	struct iommu_group *group;
> +
> +	group = iommu_group_get(dev);
> +	if (!group)
> +		return NULL;
> +
> +	mutex_lock(&group->mutex);
> +	domain = xa_load(&group->pasid_array, pasid);
>  	mutex_unlock(&group->mutex);
>  	iommu_group_put(group);

This whole API seems sketchy - what is the lifecycle of the returned
iommu_domain and what prevents it from being concurrently freed after
unlocking?

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

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-21 11:42       ` Jean-Philippe Brucker
@ 2022-03-21 12:43         ` Jason Gunthorpe via iommu
  -1 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe @ 2022-03-21 12:43 UTC (permalink / raw)
  To: Jean-Philippe Brucker
  Cc: Tian, Kevin, Lu Baolu, Joerg Roedel, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker,
	Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

On Mon, Mar 21, 2022 at 11:42:16AM +0000, Jean-Philippe Brucker wrote:

> I tend to disagree with that last part. The fault is caused by a specific
> device accessing shared page tables. We should keep that device
> information throughout the fault handling, so that we can report it to the
> driver when things go wrong. 

SVA faults should never be reported to drivers??

> A process can have multiple threads bound to different devices, they
> share the same mm so if the driver wanted to signal a misbehaving
> thread, similarly to a SEGV on the CPU side, it would need the
> device information to precisely report it to userspace.

I'm not sure I understand this - we can't match DMAs to executing
CPUs. On fault we fail the DMA and let the process keep running or
SIGSEGV the whole thread group.

Jason

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-21 12:43         ` Jason Gunthorpe via iommu
  0 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-03-21 12:43 UTC (permalink / raw)
  To: Jean-Philippe Brucker
  Cc: Tian, Kevin, Raj, Ashok, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Pan, Jacob jun,
	Will Deacon

On Mon, Mar 21, 2022 at 11:42:16AM +0000, Jean-Philippe Brucker wrote:

> I tend to disagree with that last part. The fault is caused by a specific
> device accessing shared page tables. We should keep that device
> information throughout the fault handling, so that we can report it to the
> driver when things go wrong. 

SVA faults should never be reported to drivers??

> A process can have multiple threads bound to different devices, they
> share the same mm so if the driver wanted to signal a misbehaving
> thread, similarly to a SEGV on the CPU side, it would need the
> device information to precisely report it to userspace.

I'm not sure I understand this - we can't match DMAs to executing
CPUs. On fault we fail the DMA and let the process keep running or
SIGSEGV the whole thread group.

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

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-20  6:40   ` Lu Baolu
@ 2022-03-21 12:50     ` Jason Gunthorpe via iommu
  -1 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe @ 2022-03-21 12:50 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Joerg Roedel, Christoph Hellwig, Kevin Tian, Ashok Raj,
	Will Deacon, Robin Murphy, Jean-Philippe Brucker, Eric Auger,
	Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On Sun, Mar 20, 2022 at 02:40:29PM +0800, Lu Baolu wrote:

> +static enum iommu_page_response_code
> +iommu_sva_handle_iopf(struct iommu_fault *fault, void *data)
> +{
> +	vm_fault_t ret;
> +	struct mm_struct *mm;
> +	struct vm_area_struct *vma;
> +	unsigned int access_flags = 0;
> +	struct iommu_domain *domain = data;

Why is the iommu_domain not passed in as a fully typed object? I would
think data should some opaque value used by non-sva cases.

What is the lifetime model here anyhow?

> +	unsigned int fault_flags = FAULT_FLAG_REMOTE;
> +	struct iommu_fault_page_request *prm = &fault->prm;
> +	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
> +
> +	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
> +		return status;
> +
> +	mm = domain->sva_cookie;
> +	if (IS_ERR_OR_NULL(mm))

Do not use this function

Do not store err pointers in structs.

> +out_put_mm:
> +	mmap_read_unlock(mm);
> +	mmput(mm);

mm structs are weird, they have two refcounts.

The 'sva_cookie' should hold a mmgrab/mmdrop() refcount to keep the
pointer alive but to touch the mmap lock you have to upgrade it to a
refcount that prevents destruction using mmget_not_zero() just for
this short period.

Jason

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-21 12:50     ` Jason Gunthorpe via iommu
  0 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-03-21 12:50 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Kevin Tian, Ashok Raj, Will Deacon, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Robin Murphy

On Sun, Mar 20, 2022 at 02:40:29PM +0800, Lu Baolu wrote:

> +static enum iommu_page_response_code
> +iommu_sva_handle_iopf(struct iommu_fault *fault, void *data)
> +{
> +	vm_fault_t ret;
> +	struct mm_struct *mm;
> +	struct vm_area_struct *vma;
> +	unsigned int access_flags = 0;
> +	struct iommu_domain *domain = data;

Why is the iommu_domain not passed in as a fully typed object? I would
think data should some opaque value used by non-sva cases.

What is the lifetime model here anyhow?

> +	unsigned int fault_flags = FAULT_FLAG_REMOTE;
> +	struct iommu_fault_page_request *prm = &fault->prm;
> +	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
> +
> +	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
> +		return status;
> +
> +	mm = domain->sva_cookie;
> +	if (IS_ERR_OR_NULL(mm))

Do not use this function

Do not store err pointers in structs.

> +out_put_mm:
> +	mmap_read_unlock(mm);
> +	mmput(mm);

mm structs are weird, they have two refcounts.

The 'sva_cookie' should hold a mmgrab/mmdrop() refcount to keep the
pointer alive but to touch the mmap lock you have to upgrade it to a
refcount that prevents destruction using mmget_not_zero() just for
this short period.

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

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

* RE: [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu
  2022-03-21 10:22       ` Lu Baolu
@ 2022-03-22  0:26         ` Tian, Kevin
  -1 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-22  0:26 UTC (permalink / raw)
  To: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Monday, March 21, 2022 6:22 PM
> >> -				if (features >= 0)
> >> +				if (features >= 0) {
> >>   					info->pasid_supported = features | 1;
> >> +					dev->iommu->pasid_bits =
> >> +						fls(pci_max_pasids(pdev)) - 1;
> > Original intel_svm_alloc_pasid() covers both PCI and non-PCI devices:
> >
> > 	ioasid_t max_pasid = dev_is_pci(dev) ?
> > 		pci_max_pasids(to_pci_dev(dev)) : intel_pasid_max_id;
> >
> > though I'm not sure whether non-PCI SVA has been supported indeed, this
> > patch implies a functional change here.
> >
> 
> The info->pasid_supported is only set for PCI devices. So the status is
> that non-PCI SVA hasn't been supported. No functional change here from
> this point of view.
> 

Then this information should be included in the commit msg.

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

* RE: [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu
@ 2022-03-22  0:26         ` Tian, Kevin
  0 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-22  0:26 UTC (permalink / raw)
  To: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: iommu, Pan, Jacob jun, linux-kernel

> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Monday, March 21, 2022 6:22 PM
> >> -				if (features >= 0)
> >> +				if (features >= 0) {
> >>   					info->pasid_supported = features | 1;
> >> +					dev->iommu->pasid_bits =
> >> +						fls(pci_max_pasids(pdev)) - 1;
> > Original intel_svm_alloc_pasid() covers both PCI and non-PCI devices:
> >
> > 	ioasid_t max_pasid = dev_is_pci(dev) ?
> > 		pci_max_pasids(to_pci_dev(dev)) : intel_pasid_max_id;
> >
> > though I'm not sure whether non-PCI SVA has been supported indeed, this
> > patch implies a functional change here.
> >
> 
> The info->pasid_supported is only set for PCI devices. So the status is
> that non-PCI SVA hasn't been supported. No functional change here from
> this point of view.
> 

Then this information should be included in the commit msg.
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

* RE: [PATCH RFC 08/11] iommu: Handle IO page faults directly
  2022-03-21 11:35     ` Jean-Philippe Brucker
@ 2022-03-22  0:39       ` Tian, Kevin
  -1 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-22  0:39 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Lu Baolu
  Cc: Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj, Ashok,
	Will Deacon, Robin Murphy, Jean-Philippe Brucker, Eric Auger,
	Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

> From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> Sent: Monday, March 21, 2022 7:36 PM
> 
> On Sun, Mar 20, 2022 at 02:40:27PM +0800, Lu Baolu wrote:
> > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> > index c0966fc9b686..4f90b71c6f6e 100644
> > --- a/drivers/iommu/iommu.c
> > +++ b/drivers/iommu/iommu.c
> > @@ -27,6 +27,8 @@
> >  #include <linux/cc_platform.h>
> >  #include <trace/events/iommu.h>
> >
> > +#include "iommu-sva-lib.h"
> > +
> >  static struct kset *iommu_group_kset;
> >  static DEFINE_IDA(iommu_group_ida);
> >
> > @@ -1177,10 +1179,9 @@ int iommu_report_device_fault(struct device
> *dev, struct iommu_fault_event *evt)
> >  	if (!param || !evt)
> >  		return -EINVAL;
> >
> > -	/* we only report device fault if there is a handler registered */
> >  	mutex_lock(&param->lock);
> >  	fparam = param->fault_param;
> > -	if (!fparam || !fparam->handler) {
> > +	if (!fparam) {
> >  		ret = -EINVAL;
> >  		goto done_unlock;
> >  	}
> > @@ -1198,7 +1199,11 @@ int iommu_report_device_fault(struct device
> *dev, struct iommu_fault_event *evt)
> >  		mutex_unlock(&fparam->lock);
> >  	}
> >
> > -	ret = fparam->handler(&evt->fault, fparam->data);
> > +	if (fparam->handler)
> > +		ret = fparam->handler(&evt->fault, fparam->data);
> > +	else
> > +		ret = iommu_queue_iopf(&evt->fault, fparam->data);
> > +
> 
> I like the change, but we'll need to consolidate this, because now if the
> driver registers a fault handler it disables IOPF. We could instead
> prevent registration if an IOPF param is present. We could also just merge
> fparam->handler but eventually I'd like to make IOPF fall back to the
> fault handler registered by device driver, in case of invalid page faults.
> I have a couple patches for this but am still missing some bits.
> 

Probably we need two different fault reporting interfaces:

  iommu_report_device_fault()
  iommu_report_domain_fault()

iommu driver knows the type of faults and just calls individual API
accordingly. fallback is also managed by iommu driver if necessary.

Thanks
Kevin

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

* RE: [PATCH RFC 08/11] iommu: Handle IO page faults directly
@ 2022-03-22  0:39       ` Tian, Kevin
  0 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-22  0:39 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Lu Baolu
  Cc: Raj, Ashok, Will Deacon, linux-kernel, Christoph Hellwig,
	Jean-Philippe Brucker, iommu, Pan, Jacob jun, Jason Gunthorpe,
	Robin Murphy

> From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> Sent: Monday, March 21, 2022 7:36 PM
> 
> On Sun, Mar 20, 2022 at 02:40:27PM +0800, Lu Baolu wrote:
> > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> > index c0966fc9b686..4f90b71c6f6e 100644
> > --- a/drivers/iommu/iommu.c
> > +++ b/drivers/iommu/iommu.c
> > @@ -27,6 +27,8 @@
> >  #include <linux/cc_platform.h>
> >  #include <trace/events/iommu.h>
> >
> > +#include "iommu-sva-lib.h"
> > +
> >  static struct kset *iommu_group_kset;
> >  static DEFINE_IDA(iommu_group_ida);
> >
> > @@ -1177,10 +1179,9 @@ int iommu_report_device_fault(struct device
> *dev, struct iommu_fault_event *evt)
> >  	if (!param || !evt)
> >  		return -EINVAL;
> >
> > -	/* we only report device fault if there is a handler registered */
> >  	mutex_lock(&param->lock);
> >  	fparam = param->fault_param;
> > -	if (!fparam || !fparam->handler) {
> > +	if (!fparam) {
> >  		ret = -EINVAL;
> >  		goto done_unlock;
> >  	}
> > @@ -1198,7 +1199,11 @@ int iommu_report_device_fault(struct device
> *dev, struct iommu_fault_event *evt)
> >  		mutex_unlock(&fparam->lock);
> >  	}
> >
> > -	ret = fparam->handler(&evt->fault, fparam->data);
> > +	if (fparam->handler)
> > +		ret = fparam->handler(&evt->fault, fparam->data);
> > +	else
> > +		ret = iommu_queue_iopf(&evt->fault, fparam->data);
> > +
> 
> I like the change, but we'll need to consolidate this, because now if the
> driver registers a fault handler it disables IOPF. We could instead
> prevent registration if an IOPF param is present. We could also just merge
> fparam->handler but eventually I'd like to make IOPF fall back to the
> fault handler registered by device driver, in case of invalid page faults.
> I have a couple patches for this but am still missing some bits.
> 

Probably we need two different fault reporting interfaces:

  iommu_report_device_fault()
  iommu_report_domain_fault()

iommu driver knows the type of faults and just calls individual API
accordingly. fallback is also managed by iommu driver if necessary.

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

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

* Re: [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu
  2022-03-21 11:22     ` Jean-Philippe Brucker
@ 2022-03-22  0:45       ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  0:45 UTC (permalink / raw)
  To: Jean-Philippe Brucker
  Cc: baolu.lu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Kevin Tian, Ashok Raj, Will Deacon, Robin Murphy,
	Jean-Philippe Brucker, Eric Auger, Liu Yi L, Jacob jun Pan,
	iommu, linux-kernel

On 2022/3/21 19:22, Jean-Philippe Brucker wrote:
> Hi Baolu,
> 
> On Sun, Mar 20, 2022 at 02:40:20PM +0800, Lu Baolu wrote:
>> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> index 627a3ed5ee8f..8e262210b5ad 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> @@ -2812,6 +2812,7 @@ static int arm_smmu_dev_enable_feature(struct device *dev,
>>   		master->iopf_enabled = true;
>>   		return 0;
>>   	case IOMMU_DEV_FEAT_SVA:
>> +		dev->iommu->pasid_bits = master->ssid_bits;
> This would be better in arm_smmu_probe_device()

Sure.

Best regards,
baolu

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

* Re: [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu
@ 2022-03-22  0:45       ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  0:45 UTC (permalink / raw)
  To: Jean-Philippe Brucker
  Cc: Kevin Tian, Ashok Raj, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Jason Gunthorpe, Will Deacon

On 2022/3/21 19:22, Jean-Philippe Brucker wrote:
> Hi Baolu,
> 
> On Sun, Mar 20, 2022 at 02:40:20PM +0800, Lu Baolu wrote:
>> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> index 627a3ed5ee8f..8e262210b5ad 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> @@ -2812,6 +2812,7 @@ static int arm_smmu_dev_enable_feature(struct device *dev,
>>   		master->iopf_enabled = true;
>>   		return 0;
>>   	case IOMMU_DEV_FEAT_SVA:
>> +		dev->iommu->pasid_bits = master->ssid_bits;
> This would be better in arm_smmu_probe_device()

Sure.

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

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

* Re: [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu
  2022-03-22  0:26         ` Tian, Kevin
@ 2022-03-22  0:48           ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  0:48 UTC (permalink / raw)
  To: Tian, Kevin, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Raj, Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: baolu.lu, Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

On 2022/3/22 8:26, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Monday, March 21, 2022 6:22 PM
>>>> -				if (features >= 0)
>>>> +				if (features >= 0) {
>>>>    					info->pasid_supported = features | 1;
>>>> +					dev->iommu->pasid_bits =
>>>> +						fls(pci_max_pasids(pdev)) - 1;
>>> Original intel_svm_alloc_pasid() covers both PCI and non-PCI devices:
>>>
>>> 	ioasid_t max_pasid = dev_is_pci(dev) ?
>>> 		pci_max_pasids(to_pci_dev(dev)) : intel_pasid_max_id;
>>>
>>> though I'm not sure whether non-PCI SVA has been supported indeed, this
>>> patch implies a functional change here.
>>>
>>
>> The info->pasid_supported is only set for PCI devices. So the status is
>> that non-PCI SVA hasn't been supported. No functional change here from
>> this point of view.
>>
> 
> Then this information should be included in the commit msg.

Sure.

Best regards,
baolu

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

* Re: [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu
@ 2022-03-22  0:48           ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  0:48 UTC (permalink / raw)
  To: Tian, Kevin, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Raj, Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker
  Cc: linux-kernel, iommu, Pan, Jacob jun

On 2022/3/22 8:26, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Monday, March 21, 2022 6:22 PM
>>>> -				if (features >= 0)
>>>> +				if (features >= 0) {
>>>>    					info->pasid_supported = features | 1;
>>>> +					dev->iommu->pasid_bits =
>>>> +						fls(pci_max_pasids(pdev)) - 1;
>>> Original intel_svm_alloc_pasid() covers both PCI and non-PCI devices:
>>>
>>> 	ioasid_t max_pasid = dev_is_pci(dev) ?
>>> 		pci_max_pasids(to_pci_dev(dev)) : intel_pasid_max_id;
>>>
>>> though I'm not sure whether non-PCI SVA has been supported indeed, this
>>> patch implies a functional change here.
>>>
>>
>> The info->pasid_supported is only set for PCI devices. So the status is
>> that non-PCI SVA hasn't been supported. No functional change here from
>> this point of view.
>>
> 
> Then this information should be included in the commit msg.

Sure.

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

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

* Re: [PATCH RFC 02/11] iommu: Add iommu_domain type for SVA
  2022-03-21 11:47     ` Jason Gunthorpe via iommu
@ 2022-03-22  0:54       ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  0:54 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: baolu.lu, Joerg Roedel, Christoph Hellwig, Kevin Tian, Ashok Raj,
	Will Deacon, Robin Murphy, Jean-Philippe Brucker, Eric Auger,
	Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On 2022/3/21 19:47, Jason Gunthorpe wrote:
> On Sun, Mar 20, 2022 at 02:40:21PM +0800, Lu Baolu wrote:
>> Add a new iommu domain type IOMMU_DOMAIN_SVA to represent an I/O page
>> table which is shared from CPU host VA. Add a sva_cookie field in the
>> iommu_domain structure to save the mm_struct which represent the CPU
>> memory page table.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>>   include/linux/iommu.h | 6 ++++++
>>   1 file changed, 6 insertions(+)
>>
>> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
>> index 36f43af0af53..3e179b853380 100644
>> +++ b/include/linux/iommu.h
>> @@ -64,6 +64,9 @@ struct iommu_domain_geometry {
>>   #define __IOMMU_DOMAIN_PT	(1U << 2)  /* Domain is identity mapped   */
>>   #define __IOMMU_DOMAIN_DMA_FQ	(1U << 3)  /* DMA-API uses flush queue    */
>>   
>> +#define __IOMMU_DOMAIN_SHARED	(1U << 4)  /* Page table shared from CPU  */
>> +#define __IOMMU_DOMAIN_HOST_VA	(1U << 5)  /* Host CPU virtual address */
>> +
>>   /*
>>    * This are the possible domain-types
>>    *
>> @@ -86,6 +89,8 @@ struct iommu_domain_geometry {
>>   #define IOMMU_DOMAIN_DMA_FQ	(__IOMMU_DOMAIN_PAGING |	\
>>   				 __IOMMU_DOMAIN_DMA_API |	\
>>   				 __IOMMU_DOMAIN_DMA_FQ)
>> +#define IOMMU_DOMAIN_SVA	(__IOMMU_DOMAIN_SHARED |	\
>> +				 __IOMMU_DOMAIN_HOST_VA)
> 
> Is there any use for this in the core code? I feel like flags should
> only be created if the core code needs to test them in some way.

flags are some attributes of the domain and the combination of multiple
flags forms a domain type.

> 
>> @@ -95,6 +100,7 @@ struct iommu_domain {
>>   	void *handler_token;
>>   	struct iommu_domain_geometry geometry;
>>   	struct iommu_dma_cookie *iova_cookie;
>> +	struct mm_struct *sva_cookie;
> 
> Don't call a mm_struct a cookie please

Sure.

> 
> And why do we need this in core code?

Need to connect an SVA domain with mm.

Best regards,
baolu

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

* Re: [PATCH RFC 02/11] iommu: Add iommu_domain type for SVA
@ 2022-03-22  0:54       ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  0:54 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Kevin Tian, Ashok Raj, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Will Deacon

On 2022/3/21 19:47, Jason Gunthorpe wrote:
> On Sun, Mar 20, 2022 at 02:40:21PM +0800, Lu Baolu wrote:
>> Add a new iommu domain type IOMMU_DOMAIN_SVA to represent an I/O page
>> table which is shared from CPU host VA. Add a sva_cookie field in the
>> iommu_domain structure to save the mm_struct which represent the CPU
>> memory page table.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>>   include/linux/iommu.h | 6 ++++++
>>   1 file changed, 6 insertions(+)
>>
>> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
>> index 36f43af0af53..3e179b853380 100644
>> +++ b/include/linux/iommu.h
>> @@ -64,6 +64,9 @@ struct iommu_domain_geometry {
>>   #define __IOMMU_DOMAIN_PT	(1U << 2)  /* Domain is identity mapped   */
>>   #define __IOMMU_DOMAIN_DMA_FQ	(1U << 3)  /* DMA-API uses flush queue    */
>>   
>> +#define __IOMMU_DOMAIN_SHARED	(1U << 4)  /* Page table shared from CPU  */
>> +#define __IOMMU_DOMAIN_HOST_VA	(1U << 5)  /* Host CPU virtual address */
>> +
>>   /*
>>    * This are the possible domain-types
>>    *
>> @@ -86,6 +89,8 @@ struct iommu_domain_geometry {
>>   #define IOMMU_DOMAIN_DMA_FQ	(__IOMMU_DOMAIN_PAGING |	\
>>   				 __IOMMU_DOMAIN_DMA_API |	\
>>   				 __IOMMU_DOMAIN_DMA_FQ)
>> +#define IOMMU_DOMAIN_SVA	(__IOMMU_DOMAIN_SHARED |	\
>> +				 __IOMMU_DOMAIN_HOST_VA)
> 
> Is there any use for this in the core code? I feel like flags should
> only be created if the core code needs to test them in some way.

flags are some attributes of the domain and the combination of multiple
flags forms a domain type.

> 
>> @@ -95,6 +100,7 @@ struct iommu_domain {
>>   	void *handler_token;
>>   	struct iommu_domain_geometry geometry;
>>   	struct iommu_dma_cookie *iova_cookie;
>> +	struct mm_struct *sva_cookie;
> 
> Don't call a mm_struct a cookie please

Sure.

> 
> And why do we need this in core code?

Need to connect an SVA domain with mm.

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

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

* RE: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-21 11:42       ` Jean-Philippe Brucker
@ 2022-03-22  1:00         ` Tian, Kevin
  -1 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-22  1:00 UTC (permalink / raw)
  To: Jean-Philippe Brucker
  Cc: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker,
	Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

> From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> Sent: Monday, March 21, 2022 7:42 PM
> 
> Hi Kevin,
> 
> On Mon, Mar 21, 2022 at 08:09:36AM +0000, Tian, Kevin wrote:
> > > From: Lu Baolu <baolu.lu@linux.intel.com>
> > > Sent: Sunday, March 20, 2022 2:40 PM
> > >
> > > The existing IOPF handling framework only handles the I/O page faults for
> > > SVA. Ginven that we are able to link iommu domain with each I/O page
> fault,
> > > we can now make the I/O page fault handling framework more general
> for
> > > more types of page faults.
> >
> > "make ... generic" in subject line is kind of confusing. Reading this patch I
> > think you really meant changing from per-device fault handling to per-
> domain
> > fault handling. This is more accurate in concept since the fault is caused by
> > the domain page table. 😊
> 
> I tend to disagree with that last part. The fault is caused by a specific
> device accessing shared page tables. We should keep that device
> information throughout the fault handling, so that we can report it to the
> driver when things go wrong. A process can have multiple threads bound to
> different devices, they share the same mm so if the driver wanted to
> signal a misbehaving thread, similarly to a SEGV on the CPU side, it would
> need the device information to precisely report it to userspace.
> 

iommu driver can include the device information in the fault data. But
in concept the IOPF should be reported per domain.

and I agree with Jason that at most we can send SEGV to the entire thread
group since there is no way to associate a DMA back to a thread which 
initiates the DMA.

Thanks
Kevin



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

* RE: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-22  1:00         ` Tian, Kevin
  0 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-22  1:00 UTC (permalink / raw)
  To: Jean-Philippe Brucker
  Cc: Raj, Ashok, Robin Murphy, linux-kernel, Christoph Hellwig,
	Jean-Philippe Brucker, iommu, Pan,  Jacob jun, Jason Gunthorpe,
	Will Deacon

> From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> Sent: Monday, March 21, 2022 7:42 PM
> 
> Hi Kevin,
> 
> On Mon, Mar 21, 2022 at 08:09:36AM +0000, Tian, Kevin wrote:
> > > From: Lu Baolu <baolu.lu@linux.intel.com>
> > > Sent: Sunday, March 20, 2022 2:40 PM
> > >
> > > The existing IOPF handling framework only handles the I/O page faults for
> > > SVA. Ginven that we are able to link iommu domain with each I/O page
> fault,
> > > we can now make the I/O page fault handling framework more general
> for
> > > more types of page faults.
> >
> > "make ... generic" in subject line is kind of confusing. Reading this patch I
> > think you really meant changing from per-device fault handling to per-
> domain
> > fault handling. This is more accurate in concept since the fault is caused by
> > the domain page table. 😊
> 
> I tend to disagree with that last part. The fault is caused by a specific
> device accessing shared page tables. We should keep that device
> information throughout the fault handling, so that we can report it to the
> driver when things go wrong. A process can have multiple threads bound to
> different devices, they share the same mm so if the driver wanted to
> signal a misbehaving thread, similarly to a SEGV on the CPU side, it would
> need the device information to precisely report it to userspace.
> 

iommu driver can include the device information in the fault data. But
in concept the IOPF should be reported per domain.

and I agree with Jason that at most we can send SEGV to the entire thread
group since there is no way to associate a DMA back to a thread which 
initiates the DMA.

Thanks
Kevin


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

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

* Re: [PATCH RFC 04/11] iommu/vt-d: Add SVA domain support
  2022-03-21 11:56     ` Jason Gunthorpe
@ 2022-03-22  4:25       ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  4:25 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: baolu.lu, Joerg Roedel, Christoph Hellwig, Kevin Tian, Ashok Raj,
	Will Deacon, Robin Murphy, Jean-Philippe Brucker, Eric Auger,
	Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On 2022/3/21 19:56, Jason Gunthorpe wrote:
> On Sun, Mar 20, 2022 at 02:40:23PM +0800, Lu Baolu wrote:
>> Add support for SVA domain allocation and provide an SVA-specific
>> iommu_domain_ops.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>>   include/linux/intel-iommu.h |  1 +
>>   drivers/iommu/intel/iommu.c | 12 ++++++++++++
>>   drivers/iommu/intel/svm.c   | 34 ++++++++++++++++++++++++++++++++++
>>   3 files changed, 47 insertions(+)
>>
>> diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
>> index 2f9891cb3d00..c14283137fb5 100644
>> +++ b/include/linux/intel-iommu.h
>> @@ -744,6 +744,7 @@ void intel_svm_unbind(struct iommu_sva *handle);
>>   u32 intel_svm_get_pasid(struct iommu_sva *handle);
>>   int intel_svm_page_response(struct device *dev, struct iommu_fault_event *evt,
>>   			    struct iommu_page_response *msg);
>> +extern const struct iommu_domain_ops intel_svm_domain_ops;
>>   
>>   struct intel_svm_dev {
>>   	struct list_head list;
>> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
>> index c1b91bce1530..d55dca3eacf8 100644
>> +++ b/drivers/iommu/intel/iommu.c
>> @@ -4318,6 +4318,18 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
>>   		return domain;
>>   	case IOMMU_DOMAIN_IDENTITY:
>>   		return &si_domain->domain;
>> +#ifdef CONFIG_INTEL_IOMMU_SVM
>> +	case IOMMU_DOMAIN_SVA:
>> +		dmar_domain = alloc_domain(type);
>> +		if (!dmar_domain) {
>> +			pr_err("Can't allocate sva domain\n");
> 
> Don't put random pr_err's/etc in drivers. At least try to use dev_err
> 
>> +			return NULL;
>> +		}
>> +		domain = &dmar_domain->domain;
>> +		domain->ops = &intel_svm_domain_ops;
>> +
>> +		return domain;
>> +#endif /* CONFIG_INTEL_IOMMU_SVM */
>>   	default:
>>   		return NULL;
>>   	}
>> diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
>> index ee5ecde5b318..b9f4dd7057d1 100644
>> +++ b/drivers/iommu/intel/svm.c
>> @@ -932,3 +932,37 @@ int intel_svm_page_response(struct device *dev,
>>   	mutex_unlock(&pasid_mutex);
>>   	return ret;
>>   }
>> +
>> +static int intel_svm_attach_dev_pasid(struct iommu_domain *domain,
>> +				      struct device *dev, ioasid_t pasid)
>> +{
>> +	struct device_domain_info *info = dev_iommu_priv_get(dev);
>> +	struct mm_struct *mm = domain->sva_cookie;
>> +	struct intel_iommu *iommu = info->iommu;
>> +	struct iommu_sva *sva;
>> +
>> +	mutex_lock(&pasid_mutex);
>> +	sva = intel_svm_bind_mm(iommu, dev, mm);
>> +	mutex_unlock(&pasid_mutex);
>> +
>> +	return IS_ERR_OR_NULL(sva);
> 
> Never use IS_ERR_OR_NULL(), fix whatever is wrong in intel_svm_bind_mm()
> that it can return NULL on failure.
> 
>> +const struct iommu_domain_ops intel_svm_domain_ops = {
>> +	.attach_dev_pasid	= intel_svm_attach_dev_pasid,
>> +	.detach_dev_pasid	= intel_svm_detach_dev_pasid,
> 
> Lets have consistent language either this is called SVA or SVM but not
> both.

Thanks a lot for above comments. All make sense to me.

Best regards,
baolu

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

* Re: [PATCH RFC 04/11] iommu/vt-d: Add SVA domain support
@ 2022-03-22  4:25       ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  4:25 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Kevin Tian, Ashok Raj, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Will Deacon

On 2022/3/21 19:56, Jason Gunthorpe wrote:
> On Sun, Mar 20, 2022 at 02:40:23PM +0800, Lu Baolu wrote:
>> Add support for SVA domain allocation and provide an SVA-specific
>> iommu_domain_ops.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>>   include/linux/intel-iommu.h |  1 +
>>   drivers/iommu/intel/iommu.c | 12 ++++++++++++
>>   drivers/iommu/intel/svm.c   | 34 ++++++++++++++++++++++++++++++++++
>>   3 files changed, 47 insertions(+)
>>
>> diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
>> index 2f9891cb3d00..c14283137fb5 100644
>> +++ b/include/linux/intel-iommu.h
>> @@ -744,6 +744,7 @@ void intel_svm_unbind(struct iommu_sva *handle);
>>   u32 intel_svm_get_pasid(struct iommu_sva *handle);
>>   int intel_svm_page_response(struct device *dev, struct iommu_fault_event *evt,
>>   			    struct iommu_page_response *msg);
>> +extern const struct iommu_domain_ops intel_svm_domain_ops;
>>   
>>   struct intel_svm_dev {
>>   	struct list_head list;
>> diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
>> index c1b91bce1530..d55dca3eacf8 100644
>> +++ b/drivers/iommu/intel/iommu.c
>> @@ -4318,6 +4318,18 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
>>   		return domain;
>>   	case IOMMU_DOMAIN_IDENTITY:
>>   		return &si_domain->domain;
>> +#ifdef CONFIG_INTEL_IOMMU_SVM
>> +	case IOMMU_DOMAIN_SVA:
>> +		dmar_domain = alloc_domain(type);
>> +		if (!dmar_domain) {
>> +			pr_err("Can't allocate sva domain\n");
> 
> Don't put random pr_err's/etc in drivers. At least try to use dev_err
> 
>> +			return NULL;
>> +		}
>> +		domain = &dmar_domain->domain;
>> +		domain->ops = &intel_svm_domain_ops;
>> +
>> +		return domain;
>> +#endif /* CONFIG_INTEL_IOMMU_SVM */
>>   	default:
>>   		return NULL;
>>   	}
>> diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
>> index ee5ecde5b318..b9f4dd7057d1 100644
>> +++ b/drivers/iommu/intel/svm.c
>> @@ -932,3 +932,37 @@ int intel_svm_page_response(struct device *dev,
>>   	mutex_unlock(&pasid_mutex);
>>   	return ret;
>>   }
>> +
>> +static int intel_svm_attach_dev_pasid(struct iommu_domain *domain,
>> +				      struct device *dev, ioasid_t pasid)
>> +{
>> +	struct device_domain_info *info = dev_iommu_priv_get(dev);
>> +	struct mm_struct *mm = domain->sva_cookie;
>> +	struct intel_iommu *iommu = info->iommu;
>> +	struct iommu_sva *sva;
>> +
>> +	mutex_lock(&pasid_mutex);
>> +	sva = intel_svm_bind_mm(iommu, dev, mm);
>> +	mutex_unlock(&pasid_mutex);
>> +
>> +	return IS_ERR_OR_NULL(sva);
> 
> Never use IS_ERR_OR_NULL(), fix whatever is wrong in intel_svm_bind_mm()
> that it can return NULL on failure.
> 
>> +const struct iommu_domain_ops intel_svm_domain_ops = {
>> +	.attach_dev_pasid	= intel_svm_attach_dev_pasid,
>> +	.detach_dev_pasid	= intel_svm_detach_dev_pasid,
> 
> Lets have consistent language either this is called SVA or SVM but not
> both.

Thanks a lot for above comments. All make sense to me.

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

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

* Re: [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  2022-03-21 11:33     ` Jean-Philippe Brucker
@ 2022-03-22  4:29       ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  4:29 UTC (permalink / raw)
  To: Jean-Philippe Brucker
  Cc: baolu.lu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Kevin Tian, Ashok Raj, Will Deacon, Robin Murphy,
	Jean-Philippe Brucker, Eric Auger, Liu Yi L, Jacob jun Pan,
	iommu, linux-kernel

On 2022/3/21 19:33, Jean-Philippe Brucker wrote:
> On Sun, Mar 20, 2022 at 02:40:25PM +0800, Lu Baolu wrote:
>> diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
>> index 106506143896..47cf98e661ff 100644
>> --- a/drivers/iommu/iommu-sva-lib.c
>> +++ b/drivers/iommu/iommu-sva-lib.c
>> @@ -3,6 +3,8 @@
>>    * Helpers for IOMMU drivers implementing SVA
>>    */
>>   #include <linux/mutex.h>
>> +#include <linux/iommu.h>
>> +#include <linux/slab.h>
>>   #include <linux/sched/mm.h>
>>   
>>   #include "iommu-sva-lib.h"
>> @@ -69,3 +71,101 @@ struct mm_struct *iommu_sva_find(ioasid_t pasid)
>>   	return ioasid_find(&iommu_sva_pasid, pasid, __mmget_not_zero);
>>   }
>>   EXPORT_SYMBOL_GPL(iommu_sva_find);
>> +
>> +static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev)
>> +{
>> +	struct bus_type *bus = dev->bus;
>> +	struct iommu_domain *domain;
>> +
>> +	if (!bus || !bus->iommu_ops)
>> +		return NULL;
>> +
>> +	domain = bus->iommu_ops->domain_alloc(IOMMU_DOMAIN_SVA);
>> +	if (domain)
>> +		domain->type = IOMMU_DOMAIN_SVA;
>> +
>> +	return domain;
>> +}
>> +
>> +/**
>> + * iommu_sva_bind_device() - Bind a process address space to a device
>> + * @dev: the device
>> + * @mm: the mm to bind, caller must hold a reference to it
>> + * @drvdata: opaque data pointer to pass to bind callback
>> + *
>> + * Create a bond between device and address space, allowing the device to access
>> + * the mm using the returned PASID. If a bond already exists between @device and
>> + * @mm, it is returned and an additional reference is taken.
> This is not true anymore, we return a different structure for each call.
> 
>> Caller must call
>> + * iommu_sva_unbind_device() to release each reference.
>> + *
>> + * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
>> + * initialize the required SVA features.
>> + *
>> + * On error, returns an ERR_PTR value.
>> + */
>> +struct iommu_sva *
>> +iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
>> +{
>> +	int ret = -EINVAL;
>> +	struct iommu_sva *handle;
>> +	struct iommu_domain *domain;
>> +
>> +	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
>> +	if (!handle)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits) - 1);
>> +	if (ret)
>> +		goto out;
>> +
>> +	domain = iommu_sva_domain_alloc(dev);
>> +	if (!domain) {
>> +		ret = -ENOMEM;
>> +		goto out;
>> +	}
>> +	domain->sva_cookie = mm;
>> +
>> +	ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
>> +	if (ret)
>> +		goto out_free_domain;
>> +
>> +	handle->dev = dev;
>> +	handle->domain = domain;
>> +	handle->pasid = mm->pasid;
>> +
>> +	return handle;
>> +
>> +out_free_domain:
>> +	iommu_domain_free(domain);
>> +out:
>> +	kfree(handle);
>> +
>> +	return ERR_PTR(ret);
>> +}
>> +EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
>> +
>> +/**
>> + * iommu_sva_unbind_device() - Remove a bond created with iommu_sva_bind_device
>> + * @handle: the handle returned by iommu_sva_bind_device()
>> + *
>> + * Put reference to a bond between device and address space.
> Same here. But I'd prefer keeping the old behavior so device drivers don't
> have to keep track of {dev, mm} pairs themselves.

Okay. Thank you for pointing this out. Let me figure it out in the next
version.

Best regards,
baolu

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

* Re: [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
@ 2022-03-22  4:29       ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  4:29 UTC (permalink / raw)
  To: Jean-Philippe Brucker
  Cc: Kevin Tian, Ashok Raj, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Jason Gunthorpe, Will Deacon

On 2022/3/21 19:33, Jean-Philippe Brucker wrote:
> On Sun, Mar 20, 2022 at 02:40:25PM +0800, Lu Baolu wrote:
>> diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
>> index 106506143896..47cf98e661ff 100644
>> --- a/drivers/iommu/iommu-sva-lib.c
>> +++ b/drivers/iommu/iommu-sva-lib.c
>> @@ -3,6 +3,8 @@
>>    * Helpers for IOMMU drivers implementing SVA
>>    */
>>   #include <linux/mutex.h>
>> +#include <linux/iommu.h>
>> +#include <linux/slab.h>
>>   #include <linux/sched/mm.h>
>>   
>>   #include "iommu-sva-lib.h"
>> @@ -69,3 +71,101 @@ struct mm_struct *iommu_sva_find(ioasid_t pasid)
>>   	return ioasid_find(&iommu_sva_pasid, pasid, __mmget_not_zero);
>>   }
>>   EXPORT_SYMBOL_GPL(iommu_sva_find);
>> +
>> +static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev)
>> +{
>> +	struct bus_type *bus = dev->bus;
>> +	struct iommu_domain *domain;
>> +
>> +	if (!bus || !bus->iommu_ops)
>> +		return NULL;
>> +
>> +	domain = bus->iommu_ops->domain_alloc(IOMMU_DOMAIN_SVA);
>> +	if (domain)
>> +		domain->type = IOMMU_DOMAIN_SVA;
>> +
>> +	return domain;
>> +}
>> +
>> +/**
>> + * iommu_sva_bind_device() - Bind a process address space to a device
>> + * @dev: the device
>> + * @mm: the mm to bind, caller must hold a reference to it
>> + * @drvdata: opaque data pointer to pass to bind callback
>> + *
>> + * Create a bond between device and address space, allowing the device to access
>> + * the mm using the returned PASID. If a bond already exists between @device and
>> + * @mm, it is returned and an additional reference is taken.
> This is not true anymore, we return a different structure for each call.
> 
>> Caller must call
>> + * iommu_sva_unbind_device() to release each reference.
>> + *
>> + * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
>> + * initialize the required SVA features.
>> + *
>> + * On error, returns an ERR_PTR value.
>> + */
>> +struct iommu_sva *
>> +iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
>> +{
>> +	int ret = -EINVAL;
>> +	struct iommu_sva *handle;
>> +	struct iommu_domain *domain;
>> +
>> +	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
>> +	if (!handle)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits) - 1);
>> +	if (ret)
>> +		goto out;
>> +
>> +	domain = iommu_sva_domain_alloc(dev);
>> +	if (!domain) {
>> +		ret = -ENOMEM;
>> +		goto out;
>> +	}
>> +	domain->sva_cookie = mm;
>> +
>> +	ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
>> +	if (ret)
>> +		goto out_free_domain;
>> +
>> +	handle->dev = dev;
>> +	handle->domain = domain;
>> +	handle->pasid = mm->pasid;
>> +
>> +	return handle;
>> +
>> +out_free_domain:
>> +	iommu_domain_free(domain);
>> +out:
>> +	kfree(handle);
>> +
>> +	return ERR_PTR(ret);
>> +}
>> +EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
>> +
>> +/**
>> + * iommu_sva_unbind_device() - Remove a bond created with iommu_sva_bind_device
>> + * @handle: the handle returned by iommu_sva_bind_device()
>> + *
>> + * Put reference to a bond between device and address space.
> Same here. But I'd prefer keeping the old behavior so device drivers don't
> have to keep track of {dev, mm} pairs themselves.

Okay. Thank you for pointing this out. Let me figure it out in the next
version.

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

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

* Re: [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  2022-03-21 12:05     ` Jason Gunthorpe via iommu
@ 2022-03-22  4:31       ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  4:31 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: baolu.lu, Joerg Roedel, Christoph Hellwig, Kevin Tian, Ashok Raj,
	Will Deacon, Robin Murphy, Jean-Philippe Brucker, Eric Auger,
	Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On 2022/3/21 20:05, Jason Gunthorpe wrote:
> On Sun, Mar 20, 2022 at 02:40:25PM +0800, Lu Baolu wrote:
> 
>> +/**
>> + * iommu_sva_bind_device() - Bind a process address space to a device
>> + * @dev: the device
>> + * @mm: the mm to bind, caller must hold a reference to it
>> + * @drvdata: opaque data pointer to pass to bind callback
>> + *
>> + * Create a bond between device and address space, allowing the device to access
>> + * the mm using the returned PASID. If a bond already exists between @device and
>> + * @mm, it is returned and an additional reference is taken. Caller must call
>> + * iommu_sva_unbind_device() to release each reference.
>> + *
>> + * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
>> + * initialize the required SVA features.
>> + *
>> + * On error, returns an ERR_PTR value.
>> + */
>> +struct iommu_sva *
>> +iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
> The drvdata is never used

Yes. It is cleaned up in Jacob's series.

Best regards,
baolu

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

* Re: [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
@ 2022-03-22  4:31       ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  4:31 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Kevin Tian, Ashok Raj, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Will Deacon

On 2022/3/21 20:05, Jason Gunthorpe wrote:
> On Sun, Mar 20, 2022 at 02:40:25PM +0800, Lu Baolu wrote:
> 
>> +/**
>> + * iommu_sva_bind_device() - Bind a process address space to a device
>> + * @dev: the device
>> + * @mm: the mm to bind, caller must hold a reference to it
>> + * @drvdata: opaque data pointer to pass to bind callback
>> + *
>> + * Create a bond between device and address space, allowing the device to access
>> + * the mm using the returned PASID. If a bond already exists between @device and
>> + * @mm, it is returned and an additional reference is taken. Caller must call
>> + * iommu_sva_unbind_device() to release each reference.
>> + *
>> + * iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
>> + * initialize the required SVA features.
>> + *
>> + * On error, returns an ERR_PTR value.
>> + */
>> +struct iommu_sva *
>> +iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
> The drvdata is never used

Yes. It is cleaned up in Jacob's series.

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

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

* Re: [PATCH RFC 09/11] iommu: Add iommu_get_domain_for_dev_pasid()
  2022-03-21 12:40     ` Jason Gunthorpe via iommu
@ 2022-03-22  4:50       ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  4:50 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: baolu.lu, Joerg Roedel, Christoph Hellwig, Kevin Tian, Ashok Raj,
	Will Deacon, Robin Murphy, Jean-Philippe Brucker, Eric Auger,
	Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On 2022/3/21 20:40, Jason Gunthorpe wrote:
> On Sun, Mar 20, 2022 at 02:40:28PM +0800, Lu Baolu wrote:
>> @@ -3098,7 +3101,16 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
>>   	if (iommu_group_device_count(group) != 1)
>>   		goto out_unlock;
>>   
>> +	xa_lock(&group->pasid_array);
>> +	curr = __xa_cmpxchg(&group->pasid_array, pasid, NULL,
>> +			    domain, GFP_KERNEL);
>> +	xa_unlock(&group->pasid_array);
>> +	if (curr)
> 
> curr can be an xa_err that should be propogated.

Yes, should check xa_err().

> 
>> +		goto out_unlock;
>> +
>>   	ret = domain->ops->attach_dev_pasid(domain, dev, pasid);
>> +	if (ret)
>> +		xa_erase(&group->pasid_array, pasid);
>>   
>>   out_unlock:
>>   	mutex_unlock(&group->mutex);
>> @@ -3118,6 +3130,25 @@ void iommu_detach_device_pasid(struct iommu_domain *domain,
>>   
>>   	mutex_lock(&group->mutex);
>>   	domain->ops->detach_dev_pasid(domain, dev, pasid);
>> +	xa_erase(&group->pasid_array, pasid);
>> +	mutex_unlock(&group->mutex);
>> +	iommu_group_put(group);
>> +}
>> +
>> +struct iommu_domain *
>> +iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid)
>> +{
>> +	struct iommu_domain *domain;
>> +	struct iommu_group *group;
>> +
>> +	group = iommu_group_get(dev);
>> +	if (!group)
>> +		return NULL;
>> +
>> +	mutex_lock(&group->mutex);
>> +	domain = xa_load(&group->pasid_array, pasid);
>>   	mutex_unlock(&group->mutex);
>>   	iommu_group_put(group);
> 
> This whole API seems sketchy - what is the lifecycle of the returned
> iommu_domain and what prevents it from being concurrently freed after
> unlocking?

Agreed. The domain could be used in page fault handling thread, hence
need a mechanism to guarantee the concurrence.

Best regards,
baolu

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

* Re: [PATCH RFC 09/11] iommu: Add iommu_get_domain_for_dev_pasid()
@ 2022-03-22  4:50       ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  4:50 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Kevin Tian, Ashok Raj, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Will Deacon

On 2022/3/21 20:40, Jason Gunthorpe wrote:
> On Sun, Mar 20, 2022 at 02:40:28PM +0800, Lu Baolu wrote:
>> @@ -3098,7 +3101,16 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
>>   	if (iommu_group_device_count(group) != 1)
>>   		goto out_unlock;
>>   
>> +	xa_lock(&group->pasid_array);
>> +	curr = __xa_cmpxchg(&group->pasid_array, pasid, NULL,
>> +			    domain, GFP_KERNEL);
>> +	xa_unlock(&group->pasid_array);
>> +	if (curr)
> 
> curr can be an xa_err that should be propogated.

Yes, should check xa_err().

> 
>> +		goto out_unlock;
>> +
>>   	ret = domain->ops->attach_dev_pasid(domain, dev, pasid);
>> +	if (ret)
>> +		xa_erase(&group->pasid_array, pasid);
>>   
>>   out_unlock:
>>   	mutex_unlock(&group->mutex);
>> @@ -3118,6 +3130,25 @@ void iommu_detach_device_pasid(struct iommu_domain *domain,
>>   
>>   	mutex_lock(&group->mutex);
>>   	domain->ops->detach_dev_pasid(domain, dev, pasid);
>> +	xa_erase(&group->pasid_array, pasid);
>> +	mutex_unlock(&group->mutex);
>> +	iommu_group_put(group);
>> +}
>> +
>> +struct iommu_domain *
>> +iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid)
>> +{
>> +	struct iommu_domain *domain;
>> +	struct iommu_group *group;
>> +
>> +	group = iommu_group_get(dev);
>> +	if (!group)
>> +		return NULL;
>> +
>> +	mutex_lock(&group->mutex);
>> +	domain = xa_load(&group->pasid_array, pasid);
>>   	mutex_unlock(&group->mutex);
>>   	iommu_group_put(group);
> 
> This whole API seems sketchy - what is the lifecycle of the returned
> iommu_domain and what prevents it from being concurrently freed after
> unlocking?

Agreed. The domain could be used in page fault handling thread, hence
need a mechanism to guarantee the concurrence.

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

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-21 12:43         ` Jason Gunthorpe via iommu
@ 2022-03-22  5:03           ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  5:03 UTC (permalink / raw)
  To: Jason Gunthorpe, Jean-Philippe Brucker
  Cc: baolu.lu, Tian, Kevin, Joerg Roedel, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker,
	Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

On 2022/3/21 20:43, Jason Gunthorpe wrote:
> On Mon, Mar 21, 2022 at 11:42:16AM +0000, Jean-Philippe Brucker wrote:
> 
>> I tend to disagree with that last part. The fault is caused by a specific
>> device accessing shared page tables. We should keep that device
>> information throughout the fault handling, so that we can report it to the
>> driver when things go wrong.
> SVA faults should never be reported to drivers??
> 

When things go wrong, the corresponding response code will be responded
to the device through iommu_page_response(). The hardware should then
report the failure to the device driver and the device driver will
handle it in the device-specific way. There's no need to propagate the
I/O page faults to the device driver in any case. Do I understand it
right?

Best regards,
baolu

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-22  5:03           ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  5:03 UTC (permalink / raw)
  To: Jason Gunthorpe, Jean-Philippe Brucker
  Cc: Tian, Kevin, Raj, Ashok, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Pan, Jacob jun,
	Will Deacon

On 2022/3/21 20:43, Jason Gunthorpe wrote:
> On Mon, Mar 21, 2022 at 11:42:16AM +0000, Jean-Philippe Brucker wrote:
> 
>> I tend to disagree with that last part. The fault is caused by a specific
>> device accessing shared page tables. We should keep that device
>> information throughout the fault handling, so that we can report it to the
>> driver when things go wrong.
> SVA faults should never be reported to drivers??
> 

When things go wrong, the corresponding response code will be responded
to the device through iommu_page_response(). The hardware should then
report the failure to the device driver and the device driver will
handle it in the device-specific way. There's no need to propagate the
I/O page faults to the device driver in any case. Do I understand it
right?

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

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-21 11:39     ` Jean-Philippe Brucker
@ 2022-03-22  5:28       ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  5:28 UTC (permalink / raw)
  To: Jean-Philippe Brucker
  Cc: baolu.lu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig,
	Kevin Tian, Ashok Raj, Will Deacon, Robin Murphy,
	Jean-Philippe Brucker, Eric Auger, Liu Yi L, Jacob jun Pan,
	iommu, linux-kernel

On 2022/3/21 19:39, Jean-Philippe Brucker wrote:
> On Sun, Mar 20, 2022 at 02:40:29PM +0800, Lu Baolu wrote:
>> The existing IOPF handling framework only handles the I/O page faults for
>> SVA. Ginven that we are able to link iommu domain with each I/O page fault,
>> we can now make the I/O page fault handling framework more general for
>> more types of page faults.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>> ---
>>   include/linux/iommu.h         |  4 +++
>>   drivers/iommu/io-pgfault.c    | 67 ++++++-----------------------------
>>   drivers/iommu/iommu-sva-lib.c | 59 ++++++++++++++++++++++++++++++
>>   3 files changed, 73 insertions(+), 57 deletions(-)
>>
>> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
>> index 803e7b07605e..11c65a7bed88 100644
>> --- a/include/linux/iommu.h
>> +++ b/include/linux/iommu.h
>> @@ -50,6 +50,8 @@ struct iommu_dma_cookie;
>>   typedef int (*iommu_fault_handler_t)(struct iommu_domain *,
>>   			struct device *, unsigned long, int, void *);
>>   typedef int (*iommu_dev_fault_handler_t)(struct iommu_fault *, void *);
>> +typedef enum iommu_page_response_code (*iommu_domain_iopf_handler_t)
>> +			(struct iommu_fault *, void *);
>>   
>>   struct iommu_domain_geometry {
>>   	dma_addr_t aperture_start; /* First address that can be mapped    */
>> @@ -101,6 +103,8 @@ struct iommu_domain {
>>   	struct iommu_domain_geometry geometry;
>>   	struct iommu_dma_cookie *iova_cookie;
>>   	struct mm_struct *sva_cookie;
>> +	iommu_domain_iopf_handler_t fault_handler;
>> +	void *fault_data;
>>   };
>>   
>>   static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
>> diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
>> index 1df8c1dcae77..dad0e40cd8d2 100644
>> --- a/drivers/iommu/io-pgfault.c
>> +++ b/drivers/iommu/io-pgfault.c
>> @@ -69,62 +69,6 @@ static int iopf_complete_group(struct device *dev, struct iopf_fault *iopf,
>>   	return iommu_page_response(dev, &resp);
>>   }
>>   
>> -static enum iommu_page_response_code
>> -iopf_handle_single(struct iopf_fault *iopf)
>> -{
>> -	vm_fault_t ret;
>> -	struct mm_struct *mm;
>> -	struct vm_area_struct *vma;
>> -	unsigned int access_flags = 0;
>> -	unsigned int fault_flags = FAULT_FLAG_REMOTE;
>> -	struct iommu_fault_page_request *prm = &iopf->fault.prm;
>> -	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
>> -
>> -	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
>> -		return status;
>> -
>> -	mm = iommu_sva_find(prm->pasid);
>> -	if (IS_ERR_OR_NULL(mm))
>> -		return status;
>> -
>> -	mmap_read_lock(mm);
>> -
>> -	vma = find_extend_vma(mm, prm->addr);
>> -	if (!vma)
>> -		/* Unmapped area */
>> -		goto out_put_mm;
>> -
>> -	if (prm->perm & IOMMU_FAULT_PERM_READ)
>> -		access_flags |= VM_READ;
>> -
>> -	if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
>> -		access_flags |= VM_WRITE;
>> -		fault_flags |= FAULT_FLAG_WRITE;
>> -	}
>> -
>> -	if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
>> -		access_flags |= VM_EXEC;
>> -		fault_flags |= FAULT_FLAG_INSTRUCTION;
>> -	}
>> -
>> -	if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
>> -		fault_flags |= FAULT_FLAG_USER;
>> -
>> -	if (access_flags & ~vma->vm_flags)
>> -		/* Access fault */
>> -		goto out_put_mm;
>> -
>> -	ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
>> -	status = ret & VM_FAULT_ERROR ? IOMMU_PAGE_RESP_INVALID :
>> -		IOMMU_PAGE_RESP_SUCCESS;
>> -
>> -out_put_mm:
>> -	mmap_read_unlock(mm);
>> -	mmput(mm);
>> -
>> -	return status;
>> -}
>> -
>>   static void iopf_handle_group(struct work_struct *work)
>>   {
>>   	struct iopf_group *group;
>> @@ -134,12 +78,21 @@ static void iopf_handle_group(struct work_struct *work)
>>   	group = container_of(work, struct iopf_group, work);
>>   
>>   	list_for_each_entry_safe(iopf, next, &group->faults, list) {
>> +		struct iommu_domain *domain;
>> +
>> +		domain = iommu_get_domain_for_dev_pasid(group->dev,
>> +							iopf->fault.prm.pasid);
> 
> Do we have a guarantee that the domain is not freed while we handle the
> fault?  We could prevent unbind() while there are pending faults on this
> bond. But a refcount on SVA domains could defer freeing, and would also
> help with keeping the semantics where bind() returns a single refcounted
> bond for any {dev, mm}.
> 
> Given that this path is full of circular locking pitfalls, and to keep the
> fault handler efficient (well, at least not make it worse), we should
> probably keep a getter like iommu_sva_find() that does not require
> locking.

Agreed. We need a mechanism to ensure concurrency. I will look into it.

> 
>> +
>> +		if (!domain || !domain->fault_handler)
>> +			status = IOMMU_PAGE_RESP_INVALID;
>> +
>>   		/*
>>   		 * For the moment, errors are sticky: don't handle subsequent
>>   		 * faults in the group if there is an error.
>>   		 */
>>   		if (status == IOMMU_PAGE_RESP_SUCCESS)
>> -			status = iopf_handle_single(iopf);
>> +			status = domain->fault_handler(&iopf->fault,
>> +						       domain->fault_data);
> 
> If we make this a direct call and only use a light getter for the
> PASID->mm lookup we don't need to look at the domain at all. Or are you
> planning to add external fault handlers?

Yes. I'd like the I/O page fault handling framework to work for
external domains as well, for example, the I/O page faults for user
space page table should be routed to user space.

> 
>>   
>>   		if (!(iopf->fault.prm.flags &
>>   		      IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE))
>> diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
>> index 47cf98e661ff..01fa8096bd02 100644
>> --- a/drivers/iommu/iommu-sva-lib.c
>> +++ b/drivers/iommu/iommu-sva-lib.c
>> @@ -87,6 +87,63 @@ static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev)
>>   	return domain;
>>   }
>>   
>> +static enum iommu_page_response_code
>> +iommu_sva_handle_iopf(struct iommu_fault *fault, void *data)
>> +{
>> +	vm_fault_t ret;
>> +	struct mm_struct *mm;
>> +	struct vm_area_struct *vma;
>> +	unsigned int access_flags = 0;
>> +	struct iommu_domain *domain = data;
>> +	unsigned int fault_flags = FAULT_FLAG_REMOTE;
>> +	struct iommu_fault_page_request *prm = &fault->prm;
>> +	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
>> +
>> +	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
>> +		return status;
>> +
>> +	mm = domain->sva_cookie;
>> +	if (IS_ERR_OR_NULL(mm))
>> +		return status;
>> +
>> +	mmap_read_lock(mm);
>> +
>> +	vma = find_extend_vma(mm, prm->addr);
>> +	if (!vma)
>> +		/* Unmapped area */
>> +		goto out_put_mm;
>> +
>> +	if (prm->perm & IOMMU_FAULT_PERM_READ)
>> +		access_flags |= VM_READ;
>> +
>> +	if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
>> +		access_flags |= VM_WRITE;
>> +		fault_flags |= FAULT_FLAG_WRITE;
>> +	}
>> +
>> +	if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
>> +		access_flags |= VM_EXEC;
>> +		fault_flags |= FAULT_FLAG_INSTRUCTION;
>> +	}
>> +
>> +	if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
>> +		fault_flags |= FAULT_FLAG_USER;
>> +
>> +	if (access_flags & ~vma->vm_flags)
>> +		/* Access fault */
>> +		goto out_put_mm;
>> +
>> +	ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
>> +	status = ret & VM_FAULT_ERROR ? IOMMU_PAGE_RESP_INVALID :
>> +		IOMMU_PAGE_RESP_SUCCESS;
>> +
>> +out_put_mm:
>> +	mmap_read_unlock(mm);
>> +	mmput(mm);
> 
> mmget_not_zero() is missing since iommu_sva_find() is gone. I'm guessing
> we still need it in case the process dies

Agreed.

> 
> Thanks,
> Jean

Best regards,
baolu

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-22  5:28       ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  5:28 UTC (permalink / raw)
  To: Jean-Philippe Brucker
  Cc: Kevin Tian, Ashok Raj, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Jason Gunthorpe, Will Deacon

On 2022/3/21 19:39, Jean-Philippe Brucker wrote:
> On Sun, Mar 20, 2022 at 02:40:29PM +0800, Lu Baolu wrote:
>> The existing IOPF handling framework only handles the I/O page faults for
>> SVA. Ginven that we are able to link iommu domain with each I/O page fault,
>> we can now make the I/O page fault handling framework more general for
>> more types of page faults.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>> ---
>>   include/linux/iommu.h         |  4 +++
>>   drivers/iommu/io-pgfault.c    | 67 ++++++-----------------------------
>>   drivers/iommu/iommu-sva-lib.c | 59 ++++++++++++++++++++++++++++++
>>   3 files changed, 73 insertions(+), 57 deletions(-)
>>
>> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
>> index 803e7b07605e..11c65a7bed88 100644
>> --- a/include/linux/iommu.h
>> +++ b/include/linux/iommu.h
>> @@ -50,6 +50,8 @@ struct iommu_dma_cookie;
>>   typedef int (*iommu_fault_handler_t)(struct iommu_domain *,
>>   			struct device *, unsigned long, int, void *);
>>   typedef int (*iommu_dev_fault_handler_t)(struct iommu_fault *, void *);
>> +typedef enum iommu_page_response_code (*iommu_domain_iopf_handler_t)
>> +			(struct iommu_fault *, void *);
>>   
>>   struct iommu_domain_geometry {
>>   	dma_addr_t aperture_start; /* First address that can be mapped    */
>> @@ -101,6 +103,8 @@ struct iommu_domain {
>>   	struct iommu_domain_geometry geometry;
>>   	struct iommu_dma_cookie *iova_cookie;
>>   	struct mm_struct *sva_cookie;
>> +	iommu_domain_iopf_handler_t fault_handler;
>> +	void *fault_data;
>>   };
>>   
>>   static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
>> diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
>> index 1df8c1dcae77..dad0e40cd8d2 100644
>> --- a/drivers/iommu/io-pgfault.c
>> +++ b/drivers/iommu/io-pgfault.c
>> @@ -69,62 +69,6 @@ static int iopf_complete_group(struct device *dev, struct iopf_fault *iopf,
>>   	return iommu_page_response(dev, &resp);
>>   }
>>   
>> -static enum iommu_page_response_code
>> -iopf_handle_single(struct iopf_fault *iopf)
>> -{
>> -	vm_fault_t ret;
>> -	struct mm_struct *mm;
>> -	struct vm_area_struct *vma;
>> -	unsigned int access_flags = 0;
>> -	unsigned int fault_flags = FAULT_FLAG_REMOTE;
>> -	struct iommu_fault_page_request *prm = &iopf->fault.prm;
>> -	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
>> -
>> -	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
>> -		return status;
>> -
>> -	mm = iommu_sva_find(prm->pasid);
>> -	if (IS_ERR_OR_NULL(mm))
>> -		return status;
>> -
>> -	mmap_read_lock(mm);
>> -
>> -	vma = find_extend_vma(mm, prm->addr);
>> -	if (!vma)
>> -		/* Unmapped area */
>> -		goto out_put_mm;
>> -
>> -	if (prm->perm & IOMMU_FAULT_PERM_READ)
>> -		access_flags |= VM_READ;
>> -
>> -	if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
>> -		access_flags |= VM_WRITE;
>> -		fault_flags |= FAULT_FLAG_WRITE;
>> -	}
>> -
>> -	if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
>> -		access_flags |= VM_EXEC;
>> -		fault_flags |= FAULT_FLAG_INSTRUCTION;
>> -	}
>> -
>> -	if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
>> -		fault_flags |= FAULT_FLAG_USER;
>> -
>> -	if (access_flags & ~vma->vm_flags)
>> -		/* Access fault */
>> -		goto out_put_mm;
>> -
>> -	ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
>> -	status = ret & VM_FAULT_ERROR ? IOMMU_PAGE_RESP_INVALID :
>> -		IOMMU_PAGE_RESP_SUCCESS;
>> -
>> -out_put_mm:
>> -	mmap_read_unlock(mm);
>> -	mmput(mm);
>> -
>> -	return status;
>> -}
>> -
>>   static void iopf_handle_group(struct work_struct *work)
>>   {
>>   	struct iopf_group *group;
>> @@ -134,12 +78,21 @@ static void iopf_handle_group(struct work_struct *work)
>>   	group = container_of(work, struct iopf_group, work);
>>   
>>   	list_for_each_entry_safe(iopf, next, &group->faults, list) {
>> +		struct iommu_domain *domain;
>> +
>> +		domain = iommu_get_domain_for_dev_pasid(group->dev,
>> +							iopf->fault.prm.pasid);
> 
> Do we have a guarantee that the domain is not freed while we handle the
> fault?  We could prevent unbind() while there are pending faults on this
> bond. But a refcount on SVA domains could defer freeing, and would also
> help with keeping the semantics where bind() returns a single refcounted
> bond for any {dev, mm}.
> 
> Given that this path is full of circular locking pitfalls, and to keep the
> fault handler efficient (well, at least not make it worse), we should
> probably keep a getter like iommu_sva_find() that does not require
> locking.

Agreed. We need a mechanism to ensure concurrency. I will look into it.

> 
>> +
>> +		if (!domain || !domain->fault_handler)
>> +			status = IOMMU_PAGE_RESP_INVALID;
>> +
>>   		/*
>>   		 * For the moment, errors are sticky: don't handle subsequent
>>   		 * faults in the group if there is an error.
>>   		 */
>>   		if (status == IOMMU_PAGE_RESP_SUCCESS)
>> -			status = iopf_handle_single(iopf);
>> +			status = domain->fault_handler(&iopf->fault,
>> +						       domain->fault_data);
> 
> If we make this a direct call and only use a light getter for the
> PASID->mm lookup we don't need to look at the domain at all. Or are you
> planning to add external fault handlers?

Yes. I'd like the I/O page fault handling framework to work for
external domains as well, for example, the I/O page faults for user
space page table should be routed to user space.

> 
>>   
>>   		if (!(iopf->fault.prm.flags &
>>   		      IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE))
>> diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
>> index 47cf98e661ff..01fa8096bd02 100644
>> --- a/drivers/iommu/iommu-sva-lib.c
>> +++ b/drivers/iommu/iommu-sva-lib.c
>> @@ -87,6 +87,63 @@ static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev)
>>   	return domain;
>>   }
>>   
>> +static enum iommu_page_response_code
>> +iommu_sva_handle_iopf(struct iommu_fault *fault, void *data)
>> +{
>> +	vm_fault_t ret;
>> +	struct mm_struct *mm;
>> +	struct vm_area_struct *vma;
>> +	unsigned int access_flags = 0;
>> +	struct iommu_domain *domain = data;
>> +	unsigned int fault_flags = FAULT_FLAG_REMOTE;
>> +	struct iommu_fault_page_request *prm = &fault->prm;
>> +	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
>> +
>> +	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
>> +		return status;
>> +
>> +	mm = domain->sva_cookie;
>> +	if (IS_ERR_OR_NULL(mm))
>> +		return status;
>> +
>> +	mmap_read_lock(mm);
>> +
>> +	vma = find_extend_vma(mm, prm->addr);
>> +	if (!vma)
>> +		/* Unmapped area */
>> +		goto out_put_mm;
>> +
>> +	if (prm->perm & IOMMU_FAULT_PERM_READ)
>> +		access_flags |= VM_READ;
>> +
>> +	if (prm->perm & IOMMU_FAULT_PERM_WRITE) {
>> +		access_flags |= VM_WRITE;
>> +		fault_flags |= FAULT_FLAG_WRITE;
>> +	}
>> +
>> +	if (prm->perm & IOMMU_FAULT_PERM_EXEC) {
>> +		access_flags |= VM_EXEC;
>> +		fault_flags |= FAULT_FLAG_INSTRUCTION;
>> +	}
>> +
>> +	if (!(prm->perm & IOMMU_FAULT_PERM_PRIV))
>> +		fault_flags |= FAULT_FLAG_USER;
>> +
>> +	if (access_flags & ~vma->vm_flags)
>> +		/* Access fault */
>> +		goto out_put_mm;
>> +
>> +	ret = handle_mm_fault(vma, prm->addr, fault_flags, NULL);
>> +	status = ret & VM_FAULT_ERROR ? IOMMU_PAGE_RESP_INVALID :
>> +		IOMMU_PAGE_RESP_SUCCESS;
>> +
>> +out_put_mm:
>> +	mmap_read_unlock(mm);
>> +	mmput(mm);
> 
> mmget_not_zero() is missing since iommu_sva_find() is gone. I'm guessing
> we still need it in case the process dies

Agreed.

> 
> Thanks,
> Jean

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

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-21 12:50     ` Jason Gunthorpe via iommu
@ 2022-03-22  5:48       ` Lu Baolu
  -1 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  5:48 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: baolu.lu, Joerg Roedel, Christoph Hellwig, Kevin Tian, Ashok Raj,
	Will Deacon, Robin Murphy, Jean-Philippe Brucker, Eric Auger,
	Liu Yi L, Jacob jun Pan, iommu, linux-kernel

On 2022/3/21 20:50, Jason Gunthorpe wrote:
> On Sun, Mar 20, 2022 at 02:40:29PM +0800, Lu Baolu wrote:
> 
>> +static enum iommu_page_response_code
>> +iommu_sva_handle_iopf(struct iommu_fault *fault, void *data)
>> +{
>> +	vm_fault_t ret;
>> +	struct mm_struct *mm;
>> +	struct vm_area_struct *vma;
>> +	unsigned int access_flags = 0;
>> +	struct iommu_domain *domain = data;
> 
> Why is the iommu_domain not passed in as a fully typed object? I would
> think data should some opaque value used by non-sva cases.

The "data" is set together with the fault handler when the caller
installs a fault handler for an iommu domain. We will add a generic
interface to install fault handler for an iommu domain later when a real
non-sva case comes.

> 
> What is the lifetime model here anyhow?

I simply thought that the device driver should guarantee that there are
no pending faults after sva_unbind(). This is insufficient. I need to
rework this.

> 
>> +	unsigned int fault_flags = FAULT_FLAG_REMOTE;
>> +	struct iommu_fault_page_request *prm = &fault->prm;
>> +	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
>> +
>> +	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
>> +		return status;
>> +
>> +	mm = domain->sva_cookie;
>> +	if (IS_ERR_OR_NULL(mm))
> 
> Do not use this function
> 
> Do not store err pointers in structs.

Sure.

> 
>> +out_put_mm:
>> +	mmap_read_unlock(mm);
>> +	mmput(mm);
> 
> mm structs are weird, they have two refcounts.
> 
> The 'sva_cookie' should hold a mmgrab/mmdrop() refcount to keep the
> pointer alive but to touch the mmap lock you have to upgrade it to a
> refcount that prevents destruction using mmget_not_zero() just for
> this short period.

Yes. Will look into it.

Best regards,
baolu

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-22  5:48       ` Lu Baolu
  0 siblings, 0 replies; 112+ messages in thread
From: Lu Baolu @ 2022-03-22  5:48 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Kevin Tian, Ashok Raj, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Jacob jun Pan,
	Will Deacon

On 2022/3/21 20:50, Jason Gunthorpe wrote:
> On Sun, Mar 20, 2022 at 02:40:29PM +0800, Lu Baolu wrote:
> 
>> +static enum iommu_page_response_code
>> +iommu_sva_handle_iopf(struct iommu_fault *fault, void *data)
>> +{
>> +	vm_fault_t ret;
>> +	struct mm_struct *mm;
>> +	struct vm_area_struct *vma;
>> +	unsigned int access_flags = 0;
>> +	struct iommu_domain *domain = data;
> 
> Why is the iommu_domain not passed in as a fully typed object? I would
> think data should some opaque value used by non-sva cases.

The "data" is set together with the fault handler when the caller
installs a fault handler for an iommu domain. We will add a generic
interface to install fault handler for an iommu domain later when a real
non-sva case comes.

> 
> What is the lifetime model here anyhow?

I simply thought that the device driver should guarantee that there are
no pending faults after sva_unbind(). This is insufficient. I need to
rework this.

> 
>> +	unsigned int fault_flags = FAULT_FLAG_REMOTE;
>> +	struct iommu_fault_page_request *prm = &fault->prm;
>> +	enum iommu_page_response_code status = IOMMU_PAGE_RESP_INVALID;
>> +
>> +	if (!(prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID))
>> +		return status;
>> +
>> +	mm = domain->sva_cookie;
>> +	if (IS_ERR_OR_NULL(mm))
> 
> Do not use this function
> 
> Do not store err pointers in structs.

Sure.

> 
>> +out_put_mm:
>> +	mmap_read_unlock(mm);
>> +	mmput(mm);
> 
> mm structs are weird, they have two refcounts.
> 
> The 'sva_cookie' should hold a mmgrab/mmdrop() refcount to keep the
> pointer alive but to touch the mmap lock you have to upgrade it to a
> refcount that prevents destruction using mmget_not_zero() just for
> this short period.

Yes. Will look into it.

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

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-22  5:03           ` Lu Baolu
@ 2022-03-22 10:02             ` Jean-Philippe Brucker
  -1 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-22 10:02 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Jason Gunthorpe, Tian, Kevin, Joerg Roedel, Christoph Hellwig,
	Raj, Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker,
	Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

On Tue, Mar 22, 2022 at 01:03:14PM +0800, Lu Baolu wrote:
> On 2022/3/21 20:43, Jason Gunthorpe wrote:
> > On Mon, Mar 21, 2022 at 11:42:16AM +0000, Jean-Philippe Brucker wrote:
> > 
> > > I tend to disagree with that last part. The fault is caused by a specific
> > > device accessing shared page tables. We should keep that device
> > > information throughout the fault handling, so that we can report it to the
> > > driver when things go wrong.
> > SVA faults should never be reported to drivers??
> > 
> 
> When things go wrong, the corresponding response code will be responded
> to the device through iommu_page_response(). The hardware should then
> report the failure to the device driver and the device driver will
> handle it in the device-specific way. There's no need to propagate the
> I/O page faults to the device driver in any case. Do I understand it
> right?

In theory yes, but devices don't necessarily have the ability to report
precise errors, we may have more information.

Thanks,
Jean


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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-22 10:02             ` Jean-Philippe Brucker
  0 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-22 10:02 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Tian, Kevin, Raj, Ashok, Robin Murphy, linux-kernel,
	Christoph Hellwig, Jean-Philippe Brucker, iommu, Pan, Jacob jun,
	Jason Gunthorpe, Will Deacon

On Tue, Mar 22, 2022 at 01:03:14PM +0800, Lu Baolu wrote:
> On 2022/3/21 20:43, Jason Gunthorpe wrote:
> > On Mon, Mar 21, 2022 at 11:42:16AM +0000, Jean-Philippe Brucker wrote:
> > 
> > > I tend to disagree with that last part. The fault is caused by a specific
> > > device accessing shared page tables. We should keep that device
> > > information throughout the fault handling, so that we can report it to the
> > > driver when things go wrong.
> > SVA faults should never be reported to drivers??
> > 
> 
> When things go wrong, the corresponding response code will be responded
> to the device through iommu_page_response(). The hardware should then
> report the failure to the device driver and the device driver will
> handle it in the device-specific way. There's no need to propagate the
> I/O page faults to the device driver in any case. Do I understand it
> right?

In theory yes, but devices don't necessarily have the ability to report
precise errors, we may have more information.

Thanks,
Jean

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

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-22  1:00         ` Tian, Kevin
@ 2022-03-22 10:06           ` Jean-Philippe Brucker
  -1 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-22 10:06 UTC (permalink / raw)
  To: Tian, Kevin
  Cc: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker,
	Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

On Tue, Mar 22, 2022 at 01:00:08AM +0000, Tian, Kevin wrote:
> > From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> > Sent: Monday, March 21, 2022 7:42 PM
> > 
> > Hi Kevin,
> > 
> > On Mon, Mar 21, 2022 at 08:09:36AM +0000, Tian, Kevin wrote:
> > > > From: Lu Baolu <baolu.lu@linux.intel.com>
> > > > Sent: Sunday, March 20, 2022 2:40 PM
> > > >
> > > > The existing IOPF handling framework only handles the I/O page faults for
> > > > SVA. Ginven that we are able to link iommu domain with each I/O page
> > fault,
> > > > we can now make the I/O page fault handling framework more general
> > for
> > > > more types of page faults.
> > >
> > > "make ... generic" in subject line is kind of confusing. Reading this patch I
> > > think you really meant changing from per-device fault handling to per-
> > domain
> > > fault handling. This is more accurate in concept since the fault is caused by
> > > the domain page table. 😊
> > 
> > I tend to disagree with that last part. The fault is caused by a specific
> > device accessing shared page tables. We should keep that device
> > information throughout the fault handling, so that we can report it to the
> > driver when things go wrong. A process can have multiple threads bound to
> > different devices, they share the same mm so if the driver wanted to
> > signal a misbehaving thread, similarly to a SEGV on the CPU side, it would
> > need the device information to precisely report it to userspace.
> > 
> 
> iommu driver can include the device information in the fault data. But
> in concept the IOPF should be reported per domain.

So I don't remember where we left off on that topic, what about fault
injection into guests?  In that case device info is more than just
diagnostic, fault injection can't work without it. I think we talked about
passing a device cookie to userspace, just want to make sure.

> and I agree with Jason that at most we can send SEGV to the entire thread
> group since there is no way to associate a DMA back to a thread which 
> initiates the DMA.

The point is providing the most accurate information to the device driver
for diagnostics and debugging. A process opens multiple queues to
different devices, then if one of the queues issues invalid DMA, the
driver won't even know which queue is broken if you only report the target
mm and not the source dev. I don't think we gain anything from discarding
the device information from the fault path.

Thanks,
Jean

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-22 10:06           ` Jean-Philippe Brucker
  0 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-22 10:06 UTC (permalink / raw)
  To: Tian, Kevin
  Cc: Raj, Ashok, Robin Murphy, linux-kernel, Christoph Hellwig,
	Jean-Philippe Brucker, iommu, Pan, Jacob jun, Jason Gunthorpe,
	Will Deacon

On Tue, Mar 22, 2022 at 01:00:08AM +0000, Tian, Kevin wrote:
> > From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> > Sent: Monday, March 21, 2022 7:42 PM
> > 
> > Hi Kevin,
> > 
> > On Mon, Mar 21, 2022 at 08:09:36AM +0000, Tian, Kevin wrote:
> > > > From: Lu Baolu <baolu.lu@linux.intel.com>
> > > > Sent: Sunday, March 20, 2022 2:40 PM
> > > >
> > > > The existing IOPF handling framework only handles the I/O page faults for
> > > > SVA. Ginven that we are able to link iommu domain with each I/O page
> > fault,
> > > > we can now make the I/O page fault handling framework more general
> > for
> > > > more types of page faults.
> > >
> > > "make ... generic" in subject line is kind of confusing. Reading this patch I
> > > think you really meant changing from per-device fault handling to per-
> > domain
> > > fault handling. This is more accurate in concept since the fault is caused by
> > > the domain page table. 😊
> > 
> > I tend to disagree with that last part. The fault is caused by a specific
> > device accessing shared page tables. We should keep that device
> > information throughout the fault handling, so that we can report it to the
> > driver when things go wrong. A process can have multiple threads bound to
> > different devices, they share the same mm so if the driver wanted to
> > signal a misbehaving thread, similarly to a SEGV on the CPU side, it would
> > need the device information to precisely report it to userspace.
> > 
> 
> iommu driver can include the device information in the fault data. But
> in concept the IOPF should be reported per domain.

So I don't remember where we left off on that topic, what about fault
injection into guests?  In that case device info is more than just
diagnostic, fault injection can't work without it. I think we talked about
passing a device cookie to userspace, just want to make sure.

> and I agree with Jason that at most we can send SEGV to the entire thread
> group since there is no way to associate a DMA back to a thread which 
> initiates the DMA.

The point is providing the most accurate information to the device driver
for diagnostics and debugging. A process opens multiple queues to
different devices, then if one of the queues issues invalid DMA, the
driver won't even know which queue is broken if you only report the target
mm and not the source dev. I don't think we gain anything from discarding
the device information from the fault path.

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

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

* RE: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-22 10:06           ` Jean-Philippe Brucker
@ 2022-03-22 10:24             ` Tian, Kevin
  -1 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-22 10:24 UTC (permalink / raw)
  To: Jean-Philippe Brucker
  Cc: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker,
	Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

> From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> Sent: Tuesday, March 22, 2022 6:06 PM
> 
> On Tue, Mar 22, 2022 at 01:00:08AM +0000, Tian, Kevin wrote:
> > > From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> > > Sent: Monday, March 21, 2022 7:42 PM
> > >
> > > Hi Kevin,
> > >
> > > On Mon, Mar 21, 2022 at 08:09:36AM +0000, Tian, Kevin wrote:
> > > > > From: Lu Baolu <baolu.lu@linux.intel.com>
> > > > > Sent: Sunday, March 20, 2022 2:40 PM
> > > > >
> > > > > The existing IOPF handling framework only handles the I/O page faults
> for
> > > > > SVA. Ginven that we are able to link iommu domain with each I/O
> page
> > > fault,
> > > > > we can now make the I/O page fault handling framework more
> general
> > > for
> > > > > more types of page faults.
> > > >
> > > > "make ... generic" in subject line is kind of confusing. Reading this patch
> I
> > > > think you really meant changing from per-device fault handling to per-
> > > domain
> > > > fault handling. This is more accurate in concept since the fault is caused
> by
> > > > the domain page table. 😊
> > >
> > > I tend to disagree with that last part. The fault is caused by a specific
> > > device accessing shared page tables. We should keep that device
> > > information throughout the fault handling, so that we can report it to the
> > > driver when things go wrong. A process can have multiple threads bound
> to
> > > different devices, they share the same mm so if the driver wanted to
> > > signal a misbehaving thread, similarly to a SEGV on the CPU side, it would
> > > need the device information to precisely report it to userspace.
> > >
> >
> > iommu driver can include the device information in the fault data. But
> > in concept the IOPF should be reported per domain.
> 
> So I don't remember where we left off on that topic, what about fault
> injection into guests?  In that case device info is more than just
> diagnostic, fault injection can't work without it. I think we talked about
> passing a device cookie to userspace, just want to make sure.
> 
> > and I agree with Jason that at most we can send SEGV to the entire thread
> > group since there is no way to associate a DMA back to a thread which
> > initiates the DMA.
> 
> The point is providing the most accurate information to the device driver
> for diagnostics and debugging. A process opens multiple queues to
> different devices, then if one of the queues issues invalid DMA, the
> driver won't even know which queue is broken if you only report the target
> mm and not the source dev. I don't think we gain anything from discarding
> the device information from the fault path.
> 

In case I didn't make it clear, what I talked about is just about having iommu
core to report IOPF per domain handler vs. per device handler while this
design choice doesn't change what the fault data should include (device,
pasid, addr, etc.). i.e. it always includes all the information provided by the
iommu driver no matter how the fault is reported upwards.

e.g. with iommufd it is iommufd to register a IOPF handler per managed
domain and receive IOPF on those domains. If necessary, iommufd further
forwards to userspace including device cookie according to the fault data.

Thanks
Kevin

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

* RE: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-22 10:24             ` Tian, Kevin
  0 siblings, 0 replies; 112+ messages in thread
From: Tian, Kevin @ 2022-03-22 10:24 UTC (permalink / raw)
  To: Jean-Philippe Brucker
  Cc: Raj, Ashok, Robin Murphy, linux-kernel, Christoph Hellwig,
	Jean-Philippe Brucker, iommu, Pan,  Jacob jun, Jason Gunthorpe,
	Will Deacon

> From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> Sent: Tuesday, March 22, 2022 6:06 PM
> 
> On Tue, Mar 22, 2022 at 01:00:08AM +0000, Tian, Kevin wrote:
> > > From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> > > Sent: Monday, March 21, 2022 7:42 PM
> > >
> > > Hi Kevin,
> > >
> > > On Mon, Mar 21, 2022 at 08:09:36AM +0000, Tian, Kevin wrote:
> > > > > From: Lu Baolu <baolu.lu@linux.intel.com>
> > > > > Sent: Sunday, March 20, 2022 2:40 PM
> > > > >
> > > > > The existing IOPF handling framework only handles the I/O page faults
> for
> > > > > SVA. Ginven that we are able to link iommu domain with each I/O
> page
> > > fault,
> > > > > we can now make the I/O page fault handling framework more
> general
> > > for
> > > > > more types of page faults.
> > > >
> > > > "make ... generic" in subject line is kind of confusing. Reading this patch
> I
> > > > think you really meant changing from per-device fault handling to per-
> > > domain
> > > > fault handling. This is more accurate in concept since the fault is caused
> by
> > > > the domain page table. 😊
> > >
> > > I tend to disagree with that last part. The fault is caused by a specific
> > > device accessing shared page tables. We should keep that device
> > > information throughout the fault handling, so that we can report it to the
> > > driver when things go wrong. A process can have multiple threads bound
> to
> > > different devices, they share the same mm so if the driver wanted to
> > > signal a misbehaving thread, similarly to a SEGV on the CPU side, it would
> > > need the device information to precisely report it to userspace.
> > >
> >
> > iommu driver can include the device information in the fault data. But
> > in concept the IOPF should be reported per domain.
> 
> So I don't remember where we left off on that topic, what about fault
> injection into guests?  In that case device info is more than just
> diagnostic, fault injection can't work without it. I think we talked about
> passing a device cookie to userspace, just want to make sure.
> 
> > and I agree with Jason that at most we can send SEGV to the entire thread
> > group since there is no way to associate a DMA back to a thread which
> > initiates the DMA.
> 
> The point is providing the most accurate information to the device driver
> for diagnostics and debugging. A process opens multiple queues to
> different devices, then if one of the queues issues invalid DMA, the
> driver won't even know which queue is broken if you only report the target
> mm and not the source dev. I don't think we gain anything from discarding
> the device information from the fault path.
> 

In case I didn't make it clear, what I talked about is just about having iommu
core to report IOPF per domain handler vs. per device handler while this
design choice doesn't change what the fault data should include (device,
pasid, addr, etc.). i.e. it always includes all the information provided by the
iommu driver no matter how the fault is reported upwards.

e.g. with iommufd it is iommufd to register a IOPF handler per managed
domain and receive IOPF on those domains. If necessary, iommufd further
forwards to userspace including device cookie according to the fault data.

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

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-22 10:24             ` Tian, Kevin
@ 2022-03-22 10:50               ` Jean-Philippe Brucker
  -1 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-22 10:50 UTC (permalink / raw)
  To: Tian, Kevin
  Cc: Lu Baolu, Joerg Roedel, Jason Gunthorpe, Christoph Hellwig, Raj,
	Ashok, Will Deacon, Robin Murphy, Jean-Philippe Brucker,
	Eric Auger, Liu, Yi L, Pan, Jacob jun, iommu, linux-kernel

On Tue, Mar 22, 2022 at 10:24:26AM +0000, Tian, Kevin wrote:
> > From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> > Sent: Tuesday, March 22, 2022 6:06 PM
> > 
> > On Tue, Mar 22, 2022 at 01:00:08AM +0000, Tian, Kevin wrote:
> > > > From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> > > > Sent: Monday, March 21, 2022 7:42 PM
> > > >
> > > > Hi Kevin,
> > > >
> > > > On Mon, Mar 21, 2022 at 08:09:36AM +0000, Tian, Kevin wrote:
> > > > > > From: Lu Baolu <baolu.lu@linux.intel.com>
> > > > > > Sent: Sunday, March 20, 2022 2:40 PM
> > > > > >
> > > > > > The existing IOPF handling framework only handles the I/O page faults
> > for
> > > > > > SVA. Ginven that we are able to link iommu domain with each I/O
> > page
> > > > fault,
> > > > > > we can now make the I/O page fault handling framework more
> > general
> > > > for
> > > > > > more types of page faults.
> > > > >
> > > > > "make ... generic" in subject line is kind of confusing. Reading this patch
> > I
> > > > > think you really meant changing from per-device fault handling to per-
> > > > domain
> > > > > fault handling. This is more accurate in concept since the fault is caused
> > by
> > > > > the domain page table. 😊
> > > >
> > > > I tend to disagree with that last part. The fault is caused by a specific
> > > > device accessing shared page tables. We should keep that device
> > > > information throughout the fault handling, so that we can report it to the
> > > > driver when things go wrong. A process can have multiple threads bound
> > to
> > > > different devices, they share the same mm so if the driver wanted to
> > > > signal a misbehaving thread, similarly to a SEGV on the CPU side, it would
> > > > need the device information to precisely report it to userspace.
> > > >
> > >
> > > iommu driver can include the device information in the fault data. But
> > > in concept the IOPF should be reported per domain.
> > 
> > So I don't remember where we left off on that topic, what about fault
> > injection into guests?  In that case device info is more than just
> > diagnostic, fault injection can't work without it. I think we talked about
> > passing a device cookie to userspace, just want to make sure.
> > 
> > > and I agree with Jason that at most we can send SEGV to the entire thread
> > > group since there is no way to associate a DMA back to a thread which
> > > initiates the DMA.
> > 
> > The point is providing the most accurate information to the device driver
> > for diagnostics and debugging. A process opens multiple queues to
> > different devices, then if one of the queues issues invalid DMA, the
> > driver won't even know which queue is broken if you only report the target
> > mm and not the source dev. I don't think we gain anything from discarding
> > the device information from the fault path.
> > 
> 
> In case I didn't make it clear, what I talked about is just about having iommu
> core to report IOPF per domain handler vs. per device handler while this
> design choice doesn't change what the fault data should include (device,
> pasid, addr, etc.). i.e. it always includes all the information provided by the
> iommu driver no matter how the fault is reported upwards.

Right thanks, I misunderstood.

Thanks,
Jean

> 
> e.g. with iommufd it is iommufd to register a IOPF handler per managed
> domain and receive IOPF on those domains. If necessary, iommufd further
> forwards to userspace including device cookie according to the fault data.
> 
> Thanks
> Kevin

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-22 10:50               ` Jean-Philippe Brucker
  0 siblings, 0 replies; 112+ messages in thread
From: Jean-Philippe Brucker @ 2022-03-22 10:50 UTC (permalink / raw)
  To: Tian, Kevin
  Cc: Raj, Ashok, Robin Murphy, linux-kernel, Christoph Hellwig,
	Jean-Philippe Brucker, iommu, Pan, Jacob jun, Jason Gunthorpe,
	Will Deacon

On Tue, Mar 22, 2022 at 10:24:26AM +0000, Tian, Kevin wrote:
> > From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> > Sent: Tuesday, March 22, 2022 6:06 PM
> > 
> > On Tue, Mar 22, 2022 at 01:00:08AM +0000, Tian, Kevin wrote:
> > > > From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> > > > Sent: Monday, March 21, 2022 7:42 PM
> > > >
> > > > Hi Kevin,
> > > >
> > > > On Mon, Mar 21, 2022 at 08:09:36AM +0000, Tian, Kevin wrote:
> > > > > > From: Lu Baolu <baolu.lu@linux.intel.com>
> > > > > > Sent: Sunday, March 20, 2022 2:40 PM
> > > > > >
> > > > > > The existing IOPF handling framework only handles the I/O page faults
> > for
> > > > > > SVA. Ginven that we are able to link iommu domain with each I/O
> > page
> > > > fault,
> > > > > > we can now make the I/O page fault handling framework more
> > general
> > > > for
> > > > > > more types of page faults.
> > > > >
> > > > > "make ... generic" in subject line is kind of confusing. Reading this patch
> > I
> > > > > think you really meant changing from per-device fault handling to per-
> > > > domain
> > > > > fault handling. This is more accurate in concept since the fault is caused
> > by
> > > > > the domain page table. 😊
> > > >
> > > > I tend to disagree with that last part. The fault is caused by a specific
> > > > device accessing shared page tables. We should keep that device
> > > > information throughout the fault handling, so that we can report it to the
> > > > driver when things go wrong. A process can have multiple threads bound
> > to
> > > > different devices, they share the same mm so if the driver wanted to
> > > > signal a misbehaving thread, similarly to a SEGV on the CPU side, it would
> > > > need the device information to precisely report it to userspace.
> > > >
> > >
> > > iommu driver can include the device information in the fault data. But
> > > in concept the IOPF should be reported per domain.
> > 
> > So I don't remember where we left off on that topic, what about fault
> > injection into guests?  In that case device info is more than just
> > diagnostic, fault injection can't work without it. I think we talked about
> > passing a device cookie to userspace, just want to make sure.
> > 
> > > and I agree with Jason that at most we can send SEGV to the entire thread
> > > group since there is no way to associate a DMA back to a thread which
> > > initiates the DMA.
> > 
> > The point is providing the most accurate information to the device driver
> > for diagnostics and debugging. A process opens multiple queues to
> > different devices, then if one of the queues issues invalid DMA, the
> > driver won't even know which queue is broken if you only report the target
> > mm and not the source dev. I don't think we gain anything from discarding
> > the device information from the fault path.
> > 
> 
> In case I didn't make it clear, what I talked about is just about having iommu
> core to report IOPF per domain handler vs. per device handler while this
> design choice doesn't change what the fault data should include (device,
> pasid, addr, etc.). i.e. it always includes all the information provided by the
> iommu driver no matter how the fault is reported upwards.

Right thanks, I misunderstood.

Thanks,
Jean

> 
> e.g. with iommufd it is iommufd to register a IOPF handler per managed
> domain and receive IOPF on those domains. If necessary, iommufd further
> forwards to userspace including device cookie according to the fault data.
> 
> Thanks
> Kevin
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
  2022-03-22  5:03           ` Lu Baolu
@ 2022-03-22 12:15             ` Jason Gunthorpe via iommu
  -1 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe @ 2022-03-22 12:15 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Jean-Philippe Brucker, Tian, Kevin, Joerg Roedel,
	Christoph Hellwig, Raj, Ashok, Will Deacon, Robin Murphy,
	Jean-Philippe Brucker, Eric Auger, Liu, Yi L, Pan, Jacob jun,
	iommu, linux-kernel

On Tue, Mar 22, 2022 at 01:03:14PM +0800, Lu Baolu wrote:
> On 2022/3/21 20:43, Jason Gunthorpe wrote:
> > On Mon, Mar 21, 2022 at 11:42:16AM +0000, Jean-Philippe Brucker wrote:
> > 
> > > I tend to disagree with that last part. The fault is caused by a specific
> > > device accessing shared page tables. We should keep that device
> > > information throughout the fault handling, so that we can report it to the
> > > driver when things go wrong.
> > SVA faults should never be reported to drivers??
> > 
> 
> When things go wrong, the corresponding response code will be responded
> to the device through iommu_page_response(). The hardware should then
> report the failure to the device driver and the device driver will
> handle it in the device-specific way. There's no need to propagate the
> I/O page faults to the device driver in any case. Do I understand it
> right?

Something like that, I would expect fault failure to be similar to
accessing somethiing that is not in the iommu map. An Error TLP like
thing toward the device and whatever normal device-specific error
propagation happens.

SVA shouldn't require any special support in the using driver beyond
turing on PRI/ATS

Jason

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

* Re: [PATCH RFC 10/11] iommu: Make IOPF handling framework generic
@ 2022-03-22 12:15             ` Jason Gunthorpe via iommu
  0 siblings, 0 replies; 112+ messages in thread
From: Jason Gunthorpe via iommu @ 2022-03-22 12:15 UTC (permalink / raw)
  To: Lu Baolu
  Cc: Jean-Philippe Brucker, Tian, Kevin, Raj, Ashok, Robin Murphy,
	linux-kernel, Christoph Hellwig, Jean-Philippe Brucker, iommu,
	Pan, Jacob jun, Will Deacon

On Tue, Mar 22, 2022 at 01:03:14PM +0800, Lu Baolu wrote:
> On 2022/3/21 20:43, Jason Gunthorpe wrote:
> > On Mon, Mar 21, 2022 at 11:42:16AM +0000, Jean-Philippe Brucker wrote:
> > 
> > > I tend to disagree with that last part. The fault is caused by a specific
> > > device accessing shared page tables. We should keep that device
> > > information throughout the fault handling, so that we can report it to the
> > > driver when things go wrong.
> > SVA faults should never be reported to drivers??
> > 
> 
> When things go wrong, the corresponding response code will be responded
> to the device through iommu_page_response(). The hardware should then
> report the failure to the device driver and the device driver will
> handle it in the device-specific way. There's no need to propagate the
> I/O page faults to the device driver in any case. Do I understand it
> right?

Something like that, I would expect fault failure to be similar to
accessing somethiing that is not in the iommu map. An Error TLP like
thing toward the device and whatever normal device-specific error
propagation happens.

SVA shouldn't require any special support in the using driver beyond
turing on PRI/ATS

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

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

end of thread, other threads:[~2022-03-22 12:15 UTC | newest]

Thread overview: 112+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-20  6:40 [PATCH RFC 00/11] iommu: SVA and IOPF refactoring Lu Baolu
2022-03-20  6:40 ` Lu Baolu
2022-03-20  6:40 ` [PATCH RFC 01/11] iommu: Add pasid_bits field in struct dev_iommu Lu Baolu
2022-03-20  6:40   ` Lu Baolu
2022-03-21  7:01   ` Tian, Kevin
2022-03-21  7:01     ` Tian, Kevin
2022-03-21 10:22     ` Lu Baolu
2022-03-21 10:22       ` Lu Baolu
2022-03-22  0:26       ` Tian, Kevin
2022-03-22  0:26         ` Tian, Kevin
2022-03-22  0:48         ` Lu Baolu
2022-03-22  0:48           ` Lu Baolu
2022-03-21 11:22   ` Jean-Philippe Brucker
2022-03-21 11:22     ` Jean-Philippe Brucker
2022-03-22  0:45     ` Lu Baolu
2022-03-22  0:45       ` Lu Baolu
2022-03-20  6:40 ` [PATCH RFC 02/11] iommu: Add iommu_domain type for SVA Lu Baolu
2022-03-20  6:40   ` Lu Baolu
2022-03-21  7:06   ` Tian, Kevin
2022-03-21  7:06     ` Tian, Kevin
2022-03-21 10:23     ` Lu Baolu
2022-03-21 10:23       ` Lu Baolu
2022-03-21 11:47   ` Jason Gunthorpe
2022-03-21 11:47     ` Jason Gunthorpe via iommu
2022-03-22  0:54     ` Lu Baolu
2022-03-22  0:54       ` Lu Baolu
2022-03-20  6:40 ` [PATCH RFC 03/11] iommu: Add attach/detach_dev_pasid domain ops Lu Baolu
2022-03-20  6:40   ` Lu Baolu
2022-03-21  7:13   ` Tian, Kevin
2022-03-21  7:13     ` Tian, Kevin
2022-03-21 10:27     ` Lu Baolu
2022-03-21 10:27       ` Lu Baolu
2022-03-21 11:53     ` Jason Gunthorpe via iommu
2022-03-21 11:53       ` Jason Gunthorpe
2022-03-20  6:40 ` [PATCH RFC 04/11] iommu/vt-d: Add SVA domain support Lu Baolu
2022-03-20  6:40   ` Lu Baolu
2022-03-21  7:45   ` Tian, Kevin
2022-03-21  7:45     ` Tian, Kevin
2022-03-21 10:37     ` Lu Baolu
2022-03-21 10:37       ` Lu Baolu
2022-03-21 11:56   ` Jason Gunthorpe via iommu
2022-03-21 11:56     ` Jason Gunthorpe
2022-03-22  4:25     ` Lu Baolu
2022-03-22  4:25       ` Lu Baolu
2022-03-20  6:40 ` [PATCH RFC 05/11] arm-smmu-v3/sva: " Lu Baolu
2022-03-20  6:40   ` Lu Baolu
2022-03-21 11:31   ` Jean-Philippe Brucker
2022-03-21 11:31     ` Jean-Philippe Brucker
2022-03-21 11:58     ` Jason Gunthorpe
2022-03-21 11:58       ` Jason Gunthorpe via iommu
2022-03-20  6:40 ` [PATCH RFC 06/11] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces Lu Baolu
2022-03-20  6:40   ` Lu Baolu
2022-03-21  8:04   ` Tian, Kevin
2022-03-21  8:04     ` Tian, Kevin
2022-03-21 11:01     ` Lu Baolu
2022-03-21 11:01       ` Lu Baolu
2022-03-21 12:03       ` Jason Gunthorpe
2022-03-21 12:03         ` Jason Gunthorpe via iommu
2022-03-21 11:33   ` Jean-Philippe Brucker
2022-03-21 11:33     ` Jean-Philippe Brucker
2022-03-22  4:29     ` Lu Baolu
2022-03-22  4:29       ` Lu Baolu
2022-03-21 12:05   ` Jason Gunthorpe
2022-03-21 12:05     ` Jason Gunthorpe via iommu
2022-03-22  4:31     ` Lu Baolu
2022-03-22  4:31       ` Lu Baolu
2022-03-20  6:40 ` [PATCH RFC 07/11] iommu: Remove SVA related callbacks from iommu ops Lu Baolu
2022-03-20  6:40   ` Lu Baolu
2022-03-20  6:40 ` [PATCH RFC 08/11] iommu: Handle IO page faults directly Lu Baolu
2022-03-20  6:40   ` Lu Baolu
2022-03-21 11:35   ` Jean-Philippe Brucker
2022-03-21 11:35     ` Jean-Philippe Brucker
2022-03-22  0:39     ` Tian, Kevin
2022-03-22  0:39       ` Tian, Kevin
2022-03-20  6:40 ` [PATCH RFC 09/11] iommu: Add iommu_get_domain_for_dev_pasid() Lu Baolu
2022-03-20  6:40   ` Lu Baolu
2022-03-21 12:40   ` Jason Gunthorpe
2022-03-21 12:40     ` Jason Gunthorpe via iommu
2022-03-22  4:50     ` Lu Baolu
2022-03-22  4:50       ` Lu Baolu
2022-03-20  6:40 ` [PATCH RFC 10/11] iommu: Make IOPF handling framework generic Lu Baolu
2022-03-20  6:40   ` Lu Baolu
2022-03-21  8:09   ` Tian, Kevin
2022-03-21  8:09     ` Tian, Kevin
2022-03-21 11:42     ` Jean-Philippe Brucker
2022-03-21 11:42       ` Jean-Philippe Brucker
2022-03-21 12:43       ` Jason Gunthorpe
2022-03-21 12:43         ` Jason Gunthorpe via iommu
2022-03-22  5:03         ` Lu Baolu
2022-03-22  5:03           ` Lu Baolu
2022-03-22 10:02           ` Jean-Philippe Brucker
2022-03-22 10:02             ` Jean-Philippe Brucker
2022-03-22 12:15           ` Jason Gunthorpe
2022-03-22 12:15             ` Jason Gunthorpe via iommu
2022-03-22  1:00       ` Tian, Kevin
2022-03-22  1:00         ` Tian, Kevin
2022-03-22 10:06         ` Jean-Philippe Brucker
2022-03-22 10:06           ` Jean-Philippe Brucker
2022-03-22 10:24           ` Tian, Kevin
2022-03-22 10:24             ` Tian, Kevin
2022-03-22 10:50             ` Jean-Philippe Brucker
2022-03-22 10:50               ` Jean-Philippe Brucker
2022-03-21 11:39   ` Jean-Philippe Brucker
2022-03-21 11:39     ` Jean-Philippe Brucker
2022-03-22  5:28     ` Lu Baolu
2022-03-22  5:28       ` Lu Baolu
2022-03-21 12:50   ` Jason Gunthorpe
2022-03-21 12:50     ` Jason Gunthorpe via iommu
2022-03-22  5:48     ` Lu Baolu
2022-03-22  5:48       ` Lu Baolu
2022-03-20  6:40 ` [PATCH RFC 11/11] iommu: Rename iommu-sva-lib.{c,h} Lu Baolu
2022-03-20  6:40   ` Lu Baolu

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.