All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC v3 00/12] iommu: SVA and IOPF refactoring
@ 2022-04-10 10:24 ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 folks,

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-v3

Please help review and suggest.

Best regards,
baolu

Change log:
v1:
 - https://lore.kernel.org/linux-iommu/20220320064030.2936936-1-baolu.lu@linux.intel.com/
 - Initial post.

v2:
 - https://lore.kernel.org/linux-iommu/20220329053800.3049561-1-baolu.lu@linux.intel.com/
 - Add sva domain life cycle management to avoid race between unbind and
   page fault handling.
 - Use a single domain for each mm.
 - Return a single sva handler for the same binding.
 - Add a new helper to meet singleton group requirement.
 - Rework the SVA domain allocation for arm smmu v3 driver and move the
   pasid_bit initialization to device probe.
 - Drop the patch "iommu: Handle IO page faults directly".
 - Add mmget_not_zero(mm) in SVA page fault handler.

v3:
 - Rework iommu_group_singleton_lockdown() by adding a flag to the group
   that positively indicates the group can never have more than one
   member, even after hot plug.
 - Abstract the data structs used for iommu sva in a separated patches to
   make it easier for review.
 - I still keep the RFC prefix in this series as above two significant
   changes need at least another round review to be finalized.
 - Several misc refinements.

Lu Baolu (12):
  iommu: Add pasid_bits field in struct dev_iommu
  iommu: Add a flag to indicate immutable singleton group
  iommu: Add attach/detach_dev_pasid domain ops
  iommu/sva: Basic data structures for SVA
  iommu/vt-d: Remove SVM_FLAG_SUPERVISOR_MODE support
  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: Prepare IOMMU domain for IOPF
  iommu: Per-domain I/O page fault handling
  iommu: Rename iommu-sva-lib.{c,h}

 include/linux/intel-iommu.h                   |   5 +-
 include/linux/iommu.h                         | 107 ++++--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  25 +-
 .../iommu/{iommu-sva-lib.h => iommu-sva.h}    |   8 +-
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   |  85 ++---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  28 +-
 drivers/iommu/intel/iommu.c                   |  20 +-
 drivers/iommu/intel/svm.c                     | 135 +++----
 drivers/iommu/io-pgfault.c                    |  71 +---
 drivers/iommu/iommu-sva-lib.c                 |  71 ----
 drivers/iommu/iommu-sva.c                     | 331 ++++++++++++++++++
 drivers/iommu/iommu.c                         | 239 +++++++------
 drivers/iommu/Makefile                        |   2 +-
 13 files changed, 706 insertions(+), 421 deletions(-)
 rename drivers/iommu/{iommu-sva-lib.h => iommu-sva.h} (88%)
 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] 64+ messages in thread

* [PATCH RFC v3 00/12] iommu: SVA and IOPF refactoring
@ 2022-04-10 10:24 ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 folks,

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-v3

Please help review and suggest.

Best regards,
baolu

Change log:
v1:
 - https://lore.kernel.org/linux-iommu/20220320064030.2936936-1-baolu.lu@linux.intel.com/
 - Initial post.

v2:
 - https://lore.kernel.org/linux-iommu/20220329053800.3049561-1-baolu.lu@linux.intel.com/
 - Add sva domain life cycle management to avoid race between unbind and
   page fault handling.
 - Use a single domain for each mm.
 - Return a single sva handler for the same binding.
 - Add a new helper to meet singleton group requirement.
 - Rework the SVA domain allocation for arm smmu v3 driver and move the
   pasid_bit initialization to device probe.
 - Drop the patch "iommu: Handle IO page faults directly".
 - Add mmget_not_zero(mm) in SVA page fault handler.

v3:
 - Rework iommu_group_singleton_lockdown() by adding a flag to the group
   that positively indicates the group can never have more than one
   member, even after hot plug.
 - Abstract the data structs used for iommu sva in a separated patches to
   make it easier for review.
 - I still keep the RFC prefix in this series as above two significant
   changes need at least another round review to be finalized.
 - Several misc refinements.

Lu Baolu (12):
  iommu: Add pasid_bits field in struct dev_iommu
  iommu: Add a flag to indicate immutable singleton group
  iommu: Add attach/detach_dev_pasid domain ops
  iommu/sva: Basic data structures for SVA
  iommu/vt-d: Remove SVM_FLAG_SUPERVISOR_MODE support
  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: Prepare IOMMU domain for IOPF
  iommu: Per-domain I/O page fault handling
  iommu: Rename iommu-sva-lib.{c,h}

 include/linux/intel-iommu.h                   |   5 +-
 include/linux/iommu.h                         | 107 ++++--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  25 +-
 .../iommu/{iommu-sva-lib.h => iommu-sva.h}    |   8 +-
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   |  85 ++---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  28 +-
 drivers/iommu/intel/iommu.c                   |  20 +-
 drivers/iommu/intel/svm.c                     | 135 +++----
 drivers/iommu/io-pgfault.c                    |  71 +---
 drivers/iommu/iommu-sva-lib.c                 |  71 ----
 drivers/iommu/iommu-sva.c                     | 331 ++++++++++++++++++
 drivers/iommu/iommu.c                         | 239 +++++++------
 drivers/iommu/Makefile                        |   2 +-
 13 files changed, 706 insertions(+), 421 deletions(-)
 rename drivers/iommu/{iommu-sva-lib.h => iommu-sva.h} (88%)
 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] 64+ messages in thread

* [PATCH RFC v3 01/12] iommu: Add pasid_bits field in struct dev_iommu
  2022-04-10 10:24 ` Lu Baolu
@ 2022-04-10 10:24   ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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.

For initialization of this field in the VT-d driver, the
info->pasid_supported is only set for PCI devices. So the status is
that non-PCI SVA hasn't been supported yet. Setting this field only for
PCI devices has no functional change.

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 | 2 ++
 drivers/iommu/intel/iommu.c                 | 5 ++++-
 3 files changed, 7 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..afc63fce6107 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2681,6 +2681,8 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
 	    smmu->features & ARM_SMMU_FEAT_STALL_FORCE)
 		master->stall_enabled = true;
 
+	dev->iommu->pasid_bits = master->ssid_bits;
+
 	return &smmu->iommu;
 
 err_free_master:
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index df5c62ecf942..ffad7f8f2d73 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4593,8 +4593,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] 64+ messages in thread

* [PATCH RFC v3 01/12] iommu: Add pasid_bits field in struct dev_iommu
@ 2022-04-10 10:24   ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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.

For initialization of this field in the VT-d driver, the
info->pasid_supported is only set for PCI devices. So the status is
that non-PCI SVA hasn't been supported yet. Setting this field only for
PCI devices has no functional change.

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 | 2 ++
 drivers/iommu/intel/iommu.c                 | 5 ++++-
 3 files changed, 7 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..afc63fce6107 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2681,6 +2681,8 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
 	    smmu->features & ARM_SMMU_FEAT_STALL_FORCE)
 		master->stall_enabled = true;
 
+	dev->iommu->pasid_bits = master->ssid_bits;
+
 	return &smmu->iommu;
 
 err_free_master:
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index df5c62ecf942..ffad7f8f2d73 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4593,8 +4593,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] 64+ messages in thread

* [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
  2022-04-10 10:24 ` Lu Baolu
@ 2022-04-10 10:24   ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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

Some features require that a single device must be immutably isolated,
even when hot plug is supported. For example, the SVA bind()/unbind()
interfaces require that the device exists in a singleton group. If we
have a singleton group that doesn't have ACS (or similar technologies)
and someone hotplugs in another device on a bridge, then our SVA is
completely broken and we get data corruption.

This adds a flag in the iommu_group struct to indicate an immutable
singleton group, and uses standard PCI bus topology, isolation features,
and DMA alias quirks to set the flag. If the device came from DT, assume
it is static and then the singleton attribute can know from the device
count in the group.

Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Suggested-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/iommu/iommu.c | 67 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 57 insertions(+), 10 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 0c42ece25854..56ffbf5fdc18 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -48,6 +48,7 @@ struct iommu_group {
 	struct list_head entry;
 	unsigned int owner_cnt;
 	void *owner;
+	bool immutable_singleton;
 };
 
 struct group_device {
@@ -74,6 +75,16 @@ static const char * const iommu_group_resv_type_string[] = {
 #define IOMMU_CMD_LINE_DMA_API		BIT(0)
 #define IOMMU_CMD_LINE_STRICT		BIT(1)
 
+/*
+ * To consider a PCI device isolated, we require ACS to support Source
+ * Validation, Request Redirection, Completer Redirection, and Upstream
+ * Forwarding.  This effectively means that devices cannot spoof their
+ * requester ID, requests and completions cannot be redirected, and all
+ * transactions are forwarded upstream, even as it passes through a
+ * bridge where the target device is downstream.
+ */
+#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
+
 static int iommu_alloc_default_domain(struct iommu_group *group,
 				      struct device *dev);
 static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
@@ -89,6 +100,7 @@ static int iommu_create_device_direct_mappings(struct iommu_group *group,
 static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
 static ssize_t iommu_group_store_type(struct iommu_group *group,
 				      const char *buf, size_t count);
+static int iommu_group_device_count(struct iommu_group *group);
 
 #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store)		\
 struct iommu_group_attribute iommu_group_attr_##_name =		\
@@ -844,6 +856,37 @@ static bool iommu_is_attach_deferred(struct device *dev)
 	return false;
 }
 
+static int has_pci_alias(struct pci_dev *pdev, u16 alias, void *opaque)
+{
+	return -EEXIST;
+}
+
+static bool pci_immutably_isolated(struct pci_dev *pdev)
+{
+	/* Skip the bridges. */
+	if (pci_is_bridge(pdev))
+		return false;
+
+	/*
+	 * The device could be considered to be fully isolated if
+	 * all devices on the path from the parent to the host-PCI
+	 * bridge are protected from peer-to-peer DMA by ACS.
+	 */
+	if (!pci_is_root_bus(pdev->bus) &&
+	    !pci_acs_path_enabled(pdev->bus->self, NULL, REQ_ACS_FLAGS))
+		return false;
+
+	/* Multi-function devices should have ACS enabled. */
+	if (pdev->multifunction && !pci_acs_enabled(pdev, REQ_ACS_FLAGS))
+		return false;
+
+	/* Filter out devices which has any alias device. */
+	if (pci_for_each_dma_alias(pdev, has_pci_alias, NULL))
+		return false;
+
+	return true;
+}
+
 /**
  * iommu_group_add_device - add a device to an iommu group
  * @group: the group into which to add the device (reference should be held)
@@ -898,6 +941,20 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev)
 	list_add_tail(&device->list, &group->devices);
 	if (group->domain  && !iommu_is_attach_deferred(dev))
 		ret = __iommu_attach_device(group->domain, dev);
+
+	/*
+	 * Use standard PCI bus topology, isolation features, and DMA
+	 * alias quirks to set the immutable singleton attribute. If
+	 * the device came from DT, assume it is static and then
+	 * singleton can know from the device count in the group.
+	 */
+	if (dev_is_pci(dev))
+		group->immutable_singleton =
+				pci_immutably_isolated(to_pci_dev(dev));
+	else if (is_of_node(dev_fwnode(dev)))
+		group->immutable_singleton =
+				(iommu_group_device_count(group) == 1);
+
 	mutex_unlock(&group->mutex);
 	if (ret)
 		goto err_put_group;
@@ -1290,16 +1347,6 @@ EXPORT_SYMBOL_GPL(iommu_group_id);
 static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev,
 					       unsigned long *devfns);
 
-/*
- * To consider a PCI device isolated, we require ACS to support Source
- * Validation, Request Redirection, Completer Redirection, and Upstream
- * Forwarding.  This effectively means that devices cannot spoof their
- * requester ID, requests and completions cannot be redirected, and all
- * transactions are forwarded upstream, even as it passes through a
- * bridge where the target device is downstream.
- */
-#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
-
 /*
  * For multifunction devices which are not isolated from each other, find
  * all the other non-isolated functions and look for existing groups.  For
-- 
2.25.1


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

* [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
@ 2022-04-10 10:24   ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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

Some features require that a single device must be immutably isolated,
even when hot plug is supported. For example, the SVA bind()/unbind()
interfaces require that the device exists in a singleton group. If we
have a singleton group that doesn't have ACS (or similar technologies)
and someone hotplugs in another device on a bridge, then our SVA is
completely broken and we get data corruption.

This adds a flag in the iommu_group struct to indicate an immutable
singleton group, and uses standard PCI bus topology, isolation features,
and DMA alias quirks to set the flag. If the device came from DT, assume
it is static and then the singleton attribute can know from the device
count in the group.

Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Suggested-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/iommu/iommu.c | 67 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 57 insertions(+), 10 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 0c42ece25854..56ffbf5fdc18 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -48,6 +48,7 @@ struct iommu_group {
 	struct list_head entry;
 	unsigned int owner_cnt;
 	void *owner;
+	bool immutable_singleton;
 };
 
 struct group_device {
@@ -74,6 +75,16 @@ static const char * const iommu_group_resv_type_string[] = {
 #define IOMMU_CMD_LINE_DMA_API		BIT(0)
 #define IOMMU_CMD_LINE_STRICT		BIT(1)
 
+/*
+ * To consider a PCI device isolated, we require ACS to support Source
+ * Validation, Request Redirection, Completer Redirection, and Upstream
+ * Forwarding.  This effectively means that devices cannot spoof their
+ * requester ID, requests and completions cannot be redirected, and all
+ * transactions are forwarded upstream, even as it passes through a
+ * bridge where the target device is downstream.
+ */
+#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
+
 static int iommu_alloc_default_domain(struct iommu_group *group,
 				      struct device *dev);
 static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
@@ -89,6 +100,7 @@ static int iommu_create_device_direct_mappings(struct iommu_group *group,
 static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
 static ssize_t iommu_group_store_type(struct iommu_group *group,
 				      const char *buf, size_t count);
+static int iommu_group_device_count(struct iommu_group *group);
 
 #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store)		\
 struct iommu_group_attribute iommu_group_attr_##_name =		\
@@ -844,6 +856,37 @@ static bool iommu_is_attach_deferred(struct device *dev)
 	return false;
 }
 
+static int has_pci_alias(struct pci_dev *pdev, u16 alias, void *opaque)
+{
+	return -EEXIST;
+}
+
+static bool pci_immutably_isolated(struct pci_dev *pdev)
+{
+	/* Skip the bridges. */
+	if (pci_is_bridge(pdev))
+		return false;
+
+	/*
+	 * The device could be considered to be fully isolated if
+	 * all devices on the path from the parent to the host-PCI
+	 * bridge are protected from peer-to-peer DMA by ACS.
+	 */
+	if (!pci_is_root_bus(pdev->bus) &&
+	    !pci_acs_path_enabled(pdev->bus->self, NULL, REQ_ACS_FLAGS))
+		return false;
+
+	/* Multi-function devices should have ACS enabled. */
+	if (pdev->multifunction && !pci_acs_enabled(pdev, REQ_ACS_FLAGS))
+		return false;
+
+	/* Filter out devices which has any alias device. */
+	if (pci_for_each_dma_alias(pdev, has_pci_alias, NULL))
+		return false;
+
+	return true;
+}
+
 /**
  * iommu_group_add_device - add a device to an iommu group
  * @group: the group into which to add the device (reference should be held)
@@ -898,6 +941,20 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev)
 	list_add_tail(&device->list, &group->devices);
 	if (group->domain  && !iommu_is_attach_deferred(dev))
 		ret = __iommu_attach_device(group->domain, dev);
+
+	/*
+	 * Use standard PCI bus topology, isolation features, and DMA
+	 * alias quirks to set the immutable singleton attribute. If
+	 * the device came from DT, assume it is static and then
+	 * singleton can know from the device count in the group.
+	 */
+	if (dev_is_pci(dev))
+		group->immutable_singleton =
+				pci_immutably_isolated(to_pci_dev(dev));
+	else if (is_of_node(dev_fwnode(dev)))
+		group->immutable_singleton =
+				(iommu_group_device_count(group) == 1);
+
 	mutex_unlock(&group->mutex);
 	if (ret)
 		goto err_put_group;
@@ -1290,16 +1347,6 @@ EXPORT_SYMBOL_GPL(iommu_group_id);
 static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev,
 					       unsigned long *devfns);
 
-/*
- * To consider a PCI device isolated, we require ACS to support Source
- * Validation, Request Redirection, Completer Redirection, and Upstream
- * Forwarding.  This effectively means that devices cannot spoof their
- * requester ID, requests and completions cannot be redirected, and all
- * transactions are forwarded upstream, even as it passes through a
- * bridge where the target device is downstream.
- */
-#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
-
 /*
  * For multifunction devices which are not isolated from each other, find
  * all the other non-isolated functions and look for existing groups.  For
-- 
2.25.1

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

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

* [PATCH RFC v3 03/12] iommu: Add attach/detach_dev_pasid domain ops
  2022-04-10 10:24 ` Lu Baolu
@ 2022-04-10 10:24   ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 (Shared Virtual Address)
 - kernel DMA with PASID
 - hardware-assist mediated device

This adds a pair of common domain ops for this purpose and adds helpers
to attach/detach a domain to/from a {device, PASID}.

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

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 36f43af0af53..fe7d9ee2bc2b 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -262,6 +262,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.
@@ -279,6 +281,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 pasid);
+	void (*detach_dev_pasid)(struct iommu_domain *domain,
+				 struct device *dev, ioasid_t pasid);
 
 	int (*map)(struct iommu_domain *domain, unsigned long iova,
 		   phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
@@ -672,6 +678,10 @@ 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 {};
@@ -1040,6 +1050,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 56ffbf5fdc18..63f880dd0c80 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -38,6 +38,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);
@@ -642,6 +643,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) {
@@ -3214,3 +3216,49 @@ 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;
+	void *curr;
+
+	if (!domain->ops->attach_dev_pasid)
+		return -EINVAL;
+
+	group = iommu_group_get(dev);
+	if (!group)
+		return -ENODEV;
+
+	mutex_lock(&group->mutex);
+	if (!group->immutable_singleton)
+		goto out_unlock;
+
+	curr = xa_cmpxchg(&group->pasid_array, pasid, NULL, domain, GFP_KERNEL);
+	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);
+	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 = iommu_group_get(dev);
+
+	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);
+}
-- 
2.25.1


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

* [PATCH RFC v3 03/12] iommu: Add attach/detach_dev_pasid domain ops
@ 2022-04-10 10:24   ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 (Shared Virtual Address)
 - kernel DMA with PASID
 - hardware-assist mediated device

This adds a pair of common domain ops for this purpose and adds helpers
to attach/detach a domain to/from a {device, PASID}.

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

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 36f43af0af53..fe7d9ee2bc2b 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -262,6 +262,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.
@@ -279,6 +281,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 pasid);
+	void (*detach_dev_pasid)(struct iommu_domain *domain,
+				 struct device *dev, ioasid_t pasid);
 
 	int (*map)(struct iommu_domain *domain, unsigned long iova,
 		   phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
@@ -672,6 +678,10 @@ 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 {};
@@ -1040,6 +1050,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 56ffbf5fdc18..63f880dd0c80 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -38,6 +38,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);
@@ -642,6 +643,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) {
@@ -3214,3 +3216,49 @@ 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;
+	void *curr;
+
+	if (!domain->ops->attach_dev_pasid)
+		return -EINVAL;
+
+	group = iommu_group_get(dev);
+	if (!group)
+		return -ENODEV;
+
+	mutex_lock(&group->mutex);
+	if (!group->immutable_singleton)
+		goto out_unlock;
+
+	curr = xa_cmpxchg(&group->pasid_array, pasid, NULL, domain, GFP_KERNEL);
+	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);
+	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 = iommu_group_get(dev);
+
+	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);
+}
-- 
2.25.1

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

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

* [PATCH RFC v3 04/12] iommu/sva: Basic data structures for SVA
  2022-04-10 10:24 ` Lu Baolu
@ 2022-04-10 10:24   ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 below data structures for SVA implementation in the IOMMU core:

- struct iommu_sva_ioas
  Represent the I/O address space shared with an application CPU address
  space. This structure has a 1:1 relationship with an mm_struct. It
  graps a "mm->mm_count" refcount during creation and drop it on release.

- struct iommu_domain (IOMMU_DOMAIN_SVA type)
  Represent a hardware pagetable that the IOMMU hardware could use for
  SVA translation. Multiple iommu domains could be bound with an SVA ioas
  and each graps a refcount from ioas in order to make sure ioas could
  only be freed after all domains have been unbound.

- struct iommu_sva
  Represent a bond relationship between an SVA ioas and an iommu domain.
  If a bond already exists, it's reused and a reference is taken.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h         | 14 +++++++++++++-
 drivers/iommu/iommu-sva-lib.h |  1 +
 drivers/iommu/iommu-sva-lib.c | 18 ++++++++++++++++++
 3 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index fe7d9ee2bc2b..14c3b2197b35 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -42,6 +42,7 @@ struct notifier_block;
 struct iommu_sva;
 struct iommu_fault_event;
 struct iommu_dma_cookie;
+struct iommu_sva_ioas;
 
 /* iommu fault flags */
 #define IOMMU_FAULT_READ	0x0
@@ -64,6 +65,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 +90,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 +101,7 @@ struct iommu_domain {
 	void *handler_token;
 	struct iommu_domain_geometry geometry;
 	struct iommu_dma_cookie *iova_cookie;
+	struct iommu_sva_ioas *sva_ioas;
 };
 
 static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
@@ -622,7 +629,12 @@ struct iommu_fwspec {
  * struct iommu_sva - handle to a device-mm bond
  */
 struct iommu_sva {
-	struct device			*dev;
+	struct device		*dev;
+	struct iommu_sva_ioas	*sva_ioas;
+	struct iommu_domain	*domain;
+	/* Link to sva ioas's bonds list */
+	struct list_head	node;
+	refcount_t		users;
 };
 
 int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
diff --git a/drivers/iommu/iommu-sva-lib.h b/drivers/iommu/iommu-sva-lib.h
index 8909ea1094e3..9c5e108e2c8a 100644
--- a/drivers/iommu/iommu-sva-lib.h
+++ b/drivers/iommu/iommu-sva-lib.h
@@ -10,6 +10,7 @@
 
 int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max);
 struct mm_struct *iommu_sva_find(ioasid_t pasid);
+struct mm_struct *iommu_sva_domain_mm(struct iommu_domain *domain);
 
 /* I/O Page fault */
 struct device;
diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
index 106506143896..d524a402be3b 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"
@@ -10,6 +12,22 @@
 static DEFINE_MUTEX(iommu_sva_lock);
 static DECLARE_IOASID_SET(iommu_sva_pasid);
 
+struct iommu_sva_ioas {
+	struct mm_struct *mm;
+	ioasid_t pasid;
+
+	/* Counter of domains attached to this ioas. */
+	refcount_t users;
+
+	/* All bindings are linked here. */
+	struct list_head bonds;
+};
+
+struct mm_struct *iommu_sva_domain_mm(struct iommu_domain *domain)
+{
+	return domain->sva_ioas->mm;
+}
+
 /**
  * iommu_sva_alloc_pasid - Allocate a PASID for the mm
  * @mm: the mm
-- 
2.25.1

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

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

* [PATCH RFC v3 04/12] iommu/sva: Basic data structures for SVA
@ 2022-04-10 10:24   ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 below data structures for SVA implementation in the IOMMU core:

- struct iommu_sva_ioas
  Represent the I/O address space shared with an application CPU address
  space. This structure has a 1:1 relationship with an mm_struct. It
  graps a "mm->mm_count" refcount during creation and drop it on release.

- struct iommu_domain (IOMMU_DOMAIN_SVA type)
  Represent a hardware pagetable that the IOMMU hardware could use for
  SVA translation. Multiple iommu domains could be bound with an SVA ioas
  and each graps a refcount from ioas in order to make sure ioas could
  only be freed after all domains have been unbound.

- struct iommu_sva
  Represent a bond relationship between an SVA ioas and an iommu domain.
  If a bond already exists, it's reused and a reference is taken.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h         | 14 +++++++++++++-
 drivers/iommu/iommu-sva-lib.h |  1 +
 drivers/iommu/iommu-sva-lib.c | 18 ++++++++++++++++++
 3 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index fe7d9ee2bc2b..14c3b2197b35 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -42,6 +42,7 @@ struct notifier_block;
 struct iommu_sva;
 struct iommu_fault_event;
 struct iommu_dma_cookie;
+struct iommu_sva_ioas;
 
 /* iommu fault flags */
 #define IOMMU_FAULT_READ	0x0
@@ -64,6 +65,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 +90,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 +101,7 @@ struct iommu_domain {
 	void *handler_token;
 	struct iommu_domain_geometry geometry;
 	struct iommu_dma_cookie *iova_cookie;
+	struct iommu_sva_ioas *sva_ioas;
 };
 
 static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
@@ -622,7 +629,12 @@ struct iommu_fwspec {
  * struct iommu_sva - handle to a device-mm bond
  */
 struct iommu_sva {
-	struct device			*dev;
+	struct device		*dev;
+	struct iommu_sva_ioas	*sva_ioas;
+	struct iommu_domain	*domain;
+	/* Link to sva ioas's bonds list */
+	struct list_head	node;
+	refcount_t		users;
 };
 
 int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
diff --git a/drivers/iommu/iommu-sva-lib.h b/drivers/iommu/iommu-sva-lib.h
index 8909ea1094e3..9c5e108e2c8a 100644
--- a/drivers/iommu/iommu-sva-lib.h
+++ b/drivers/iommu/iommu-sva-lib.h
@@ -10,6 +10,7 @@
 
 int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max);
 struct mm_struct *iommu_sva_find(ioasid_t pasid);
+struct mm_struct *iommu_sva_domain_mm(struct iommu_domain *domain);
 
 /* I/O Page fault */
 struct device;
diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
index 106506143896..d524a402be3b 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"
@@ -10,6 +12,22 @@
 static DEFINE_MUTEX(iommu_sva_lock);
 static DECLARE_IOASID_SET(iommu_sva_pasid);
 
+struct iommu_sva_ioas {
+	struct mm_struct *mm;
+	ioasid_t pasid;
+
+	/* Counter of domains attached to this ioas. */
+	refcount_t users;
+
+	/* All bindings are linked here. */
+	struct list_head bonds;
+};
+
+struct mm_struct *iommu_sva_domain_mm(struct iommu_domain *domain)
+{
+	return domain->sva_ioas->mm;
+}
+
 /**
  * iommu_sva_alloc_pasid - Allocate a PASID for the mm
  * @mm: the mm
-- 
2.25.1


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

* [PATCH RFC v3 05/12] iommu/vt-d: Remove SVM_FLAG_SUPERVISOR_MODE support
  2022-04-10 10:24 ` Lu Baolu
@ 2022-04-10 10:24   ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 current in-kernel supervisor PASID support is based on the SVA
machinery in SVA lib. The binding between a kernel PASID and kernel
mapping has many flaws. Remove SVM_FLAG_SUPERVISOR_MODE support.

Link: https://lore.kernel.org/linux-iommu/20210511194726.GP1002214@nvidia.com/
Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/iommu/intel/svm.c | 53 +++++++++------------------------------
 1 file changed, 12 insertions(+), 41 deletions(-)

diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index 23a38763c1d1..4c283a250541 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -313,8 +313,7 @@ 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,
-				 unsigned int flags)
+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;
@@ -324,8 +323,7 @@ static int intel_svm_alloc_pasid(struct device *dev, struct mm_struct *mm,
 
 static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
 					   struct device *dev,
-					   struct mm_struct *mm,
-					   unsigned int flags)
+					   struct mm_struct *mm)
 {
 	struct device_domain_info *info = dev_iommu_priv_get(dev);
 	unsigned long iflags, sflags;
@@ -341,22 +339,18 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
 
 		svm->pasid = mm->pasid;
 		svm->mm = mm;
-		svm->flags = flags;
 		INIT_LIST_HEAD_RCU(&svm->devs);
 
-		if (!(flags & SVM_FLAG_SUPERVISOR_MODE)) {
-			svm->notifier.ops = &intel_mmuops;
-			ret = mmu_notifier_register(&svm->notifier, mm);
-			if (ret) {
-				kfree(svm);
-				return ERR_PTR(ret);
-			}
+		svm->notifier.ops = &intel_mmuops;
+		ret = mmu_notifier_register(&svm->notifier, mm);
+		if (ret) {
+			kfree(svm);
+			return ERR_PTR(ret);
 		}
 
 		ret = pasid_private_add(svm->pasid, svm);
 		if (ret) {
-			if (svm->notifier.ops)
-				mmu_notifier_unregister(&svm->notifier, mm);
+			mmu_notifier_unregister(&svm->notifier, mm);
 			kfree(svm);
 			return ERR_PTR(ret);
 		}
@@ -391,9 +385,7 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
 	}
 
 	/* Setup the pasid table: */
-	sflags = (flags & SVM_FLAG_SUPERVISOR_MODE) ?
-			PASID_FLAG_SUPERVISOR_MODE : 0;
-	sflags |= cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;
+	sflags = cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;
 	spin_lock_irqsave(&iommu->lock, iflags);
 	ret = intel_pasid_setup_first_level(iommu, dev, mm->pgd, mm->pasid,
 					    FLPT_DEFAULT_DID, sflags);
@@ -410,8 +402,7 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
 	kfree(sdev);
 free_svm:
 	if (list_empty(&svm->devs)) {
-		if (svm->notifier.ops)
-			mmu_notifier_unregister(&svm->notifier, mm);
+		mmu_notifier_unregister(&svm->notifier, mm);
 		pasid_private_remove(mm->pasid);
 		kfree(svm);
 	}
@@ -817,37 +808,17 @@ static irqreturn_t prq_event_thread(int irq, void *d)
 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);
-	unsigned int flags = 0;
 	struct iommu_sva *sva;
 	int ret;
 
-	if (drvdata)
-		flags = *(unsigned int *)drvdata;
-
-	if (flags & SVM_FLAG_SUPERVISOR_MODE) {
-		if (!ecap_srs(iommu->ecap)) {
-			dev_err(dev, "%s: Supervisor PASID not supported\n",
-				iommu->name);
-			return ERR_PTR(-EOPNOTSUPP);
-		}
-
-		if (mm) {
-			dev_err(dev, "%s: Supervisor PASID with user provided mm\n",
-				iommu->name);
-			return ERR_PTR(-EINVAL);
-		}
-
-		mm = &init_mm;
-	}
-
 	mutex_lock(&pasid_mutex);
-	ret = intel_svm_alloc_pasid(dev, mm, flags);
+	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, flags);
+	sva = intel_svm_bind_mm(iommu, dev, mm);
 	mutex_unlock(&pasid_mutex);
 
 	return sva;
-- 
2.25.1

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

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

* [PATCH RFC v3 05/12] iommu/vt-d: Remove SVM_FLAG_SUPERVISOR_MODE support
@ 2022-04-10 10:24   ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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, Jacob Pan

The current in-kernel supervisor PASID support is based on the SVA
machinery in SVA lib. The binding between a kernel PASID and kernel
mapping has many flaws. Remove SVM_FLAG_SUPERVISOR_MODE support.

Link: https://lore.kernel.org/linux-iommu/20210511194726.GP1002214@nvidia.com/
Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/iommu/intel/svm.c | 53 +++++++++------------------------------
 1 file changed, 12 insertions(+), 41 deletions(-)

diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index 23a38763c1d1..4c283a250541 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -313,8 +313,7 @@ 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,
-				 unsigned int flags)
+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;
@@ -324,8 +323,7 @@ static int intel_svm_alloc_pasid(struct device *dev, struct mm_struct *mm,
 
 static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
 					   struct device *dev,
-					   struct mm_struct *mm,
-					   unsigned int flags)
+					   struct mm_struct *mm)
 {
 	struct device_domain_info *info = dev_iommu_priv_get(dev);
 	unsigned long iflags, sflags;
@@ -341,22 +339,18 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
 
 		svm->pasid = mm->pasid;
 		svm->mm = mm;
-		svm->flags = flags;
 		INIT_LIST_HEAD_RCU(&svm->devs);
 
-		if (!(flags & SVM_FLAG_SUPERVISOR_MODE)) {
-			svm->notifier.ops = &intel_mmuops;
-			ret = mmu_notifier_register(&svm->notifier, mm);
-			if (ret) {
-				kfree(svm);
-				return ERR_PTR(ret);
-			}
+		svm->notifier.ops = &intel_mmuops;
+		ret = mmu_notifier_register(&svm->notifier, mm);
+		if (ret) {
+			kfree(svm);
+			return ERR_PTR(ret);
 		}
 
 		ret = pasid_private_add(svm->pasid, svm);
 		if (ret) {
-			if (svm->notifier.ops)
-				mmu_notifier_unregister(&svm->notifier, mm);
+			mmu_notifier_unregister(&svm->notifier, mm);
 			kfree(svm);
 			return ERR_PTR(ret);
 		}
@@ -391,9 +385,7 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
 	}
 
 	/* Setup the pasid table: */
-	sflags = (flags & SVM_FLAG_SUPERVISOR_MODE) ?
-			PASID_FLAG_SUPERVISOR_MODE : 0;
-	sflags |= cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;
+	sflags = cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;
 	spin_lock_irqsave(&iommu->lock, iflags);
 	ret = intel_pasid_setup_first_level(iommu, dev, mm->pgd, mm->pasid,
 					    FLPT_DEFAULT_DID, sflags);
@@ -410,8 +402,7 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
 	kfree(sdev);
 free_svm:
 	if (list_empty(&svm->devs)) {
-		if (svm->notifier.ops)
-			mmu_notifier_unregister(&svm->notifier, mm);
+		mmu_notifier_unregister(&svm->notifier, mm);
 		pasid_private_remove(mm->pasid);
 		kfree(svm);
 	}
@@ -817,37 +808,17 @@ static irqreturn_t prq_event_thread(int irq, void *d)
 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);
-	unsigned int flags = 0;
 	struct iommu_sva *sva;
 	int ret;
 
-	if (drvdata)
-		flags = *(unsigned int *)drvdata;
-
-	if (flags & SVM_FLAG_SUPERVISOR_MODE) {
-		if (!ecap_srs(iommu->ecap)) {
-			dev_err(dev, "%s: Supervisor PASID not supported\n",
-				iommu->name);
-			return ERR_PTR(-EOPNOTSUPP);
-		}
-
-		if (mm) {
-			dev_err(dev, "%s: Supervisor PASID with user provided mm\n",
-				iommu->name);
-			return ERR_PTR(-EINVAL);
-		}
-
-		mm = &init_mm;
-	}
-
 	mutex_lock(&pasid_mutex);
-	ret = intel_svm_alloc_pasid(dev, mm, flags);
+	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, flags);
+	sva = intel_svm_bind_mm(iommu, dev, mm);
 	mutex_unlock(&pasid_mutex);
 
 	return sva;
-- 
2.25.1


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

* [PATCH RFC v3 06/12] iommu/vt-d: Add SVA domain support
  2022-04-10 10:24 ` Lu Baolu
@ 2022-04-10 10:24   ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 | 10 ++++++++++
 drivers/iommu/intel/svm.c   | 37 +++++++++++++++++++++++++++++++++++++
 3 files changed, 48 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 ffad7f8f2d73..9c2714ba04ff 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4324,6 +4324,16 @@ 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)
+			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 4c283a250541..251a3a65d77f 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -927,3 +927,40 @@ 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 = iommu_sva_domain_mm(domain);
+	struct intel_iommu *iommu = info->iommu;
+	struct iommu_sva *sva;
+	int ret = 0;
+
+	mutex_lock(&pasid_mutex);
+	sva = intel_svm_bind_mm(iommu, dev, mm);
+	if (IS_ERR(sva))
+		ret = PTR_ERR(sva);
+	mutex_unlock(&pasid_mutex);
+
+	return ret;
+}
+
+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(to_dmar_domain(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] 64+ messages in thread

* [PATCH RFC v3 06/12] iommu/vt-d: Add SVA domain support
@ 2022-04-10 10:24   ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 | 10 ++++++++++
 drivers/iommu/intel/svm.c   | 37 +++++++++++++++++++++++++++++++++++++
 3 files changed, 48 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 ffad7f8f2d73..9c2714ba04ff 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4324,6 +4324,16 @@ 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)
+			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 4c283a250541..251a3a65d77f 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -927,3 +927,40 @@ 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 = iommu_sva_domain_mm(domain);
+	struct intel_iommu *iommu = info->iommu;
+	struct iommu_sva *sva;
+	int ret = 0;
+
+	mutex_lock(&pasid_mutex);
+	sva = intel_svm_bind_mm(iommu, dev, mm);
+	if (IS_ERR(sva))
+		ret = PTR_ERR(sva);
+	mutex_unlock(&pasid_mutex);
+
+	return ret;
+}
+
+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(to_dmar_domain(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] 64+ messages in thread

* [PATCH RFC v3 07/12] arm-smmu-v3/sva: Add SVA domain support
  2022-04-10 10:24 ` Lu Baolu
@ 2022-04-10 10:24   ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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   | 42 +++++++++++++++++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 21 ++++++++++
 3 files changed, 77 insertions(+)

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..ce229820086d 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,45 @@ 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 = iommu_sva_domain_mm(domain);
+
+	if (domain->type != IOMMU_DOMAIN_SVA || !mm)
+		return -EINVAL;
+
+	mutex_lock(&sva_lock);
+	handle = __arm_smmu_sva_bind(dev, mm);
+	if (IS_ERR(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 = iommu_sva_domain_mm(domain);
+	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);
+		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 afc63fce6107..bd80de0bad98 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1995,10 +1995,31 @@ static bool arm_smmu_capable(enum iommu_cap cap)
 	}
 }
 
+static void arm_smmu_sva_domain_free(struct iommu_domain *domain)
+{
+	kfree(domain);
+}
+
+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_sva_domain_free,
+};
+
 static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
 {
 	struct arm_smmu_domain *smmu_domain;
 
+	if (type == IOMMU_DOMAIN_SVA) {
+		struct iommu_domain *domain;
+
+		domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+		if (domain)
+			domain->ops = &arm_smmu_sva_domain_ops;
+
+		return domain;
+	}
+
 	if (type != IOMMU_DOMAIN_UNMANAGED &&
 	    type != IOMMU_DOMAIN_DMA &&
 	    type != IOMMU_DOMAIN_DMA_FQ &&
-- 
2.25.1

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

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

* [PATCH RFC v3 07/12] arm-smmu-v3/sva: Add SVA domain support
@ 2022-04-10 10:24   ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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   | 42 +++++++++++++++++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   | 21 ++++++++++
 3 files changed, 77 insertions(+)

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..ce229820086d 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,45 @@ 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 = iommu_sva_domain_mm(domain);
+
+	if (domain->type != IOMMU_DOMAIN_SVA || !mm)
+		return -EINVAL;
+
+	mutex_lock(&sva_lock);
+	handle = __arm_smmu_sva_bind(dev, mm);
+	if (IS_ERR(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 = iommu_sva_domain_mm(domain);
+	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);
+		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 afc63fce6107..bd80de0bad98 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1995,10 +1995,31 @@ static bool arm_smmu_capable(enum iommu_cap cap)
 	}
 }
 
+static void arm_smmu_sva_domain_free(struct iommu_domain *domain)
+{
+	kfree(domain);
+}
+
+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_sva_domain_free,
+};
+
 static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
 {
 	struct arm_smmu_domain *smmu_domain;
 
+	if (type == IOMMU_DOMAIN_SVA) {
+		struct iommu_domain *domain;
+
+		domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+		if (domain)
+			domain->ops = &arm_smmu_sva_domain_ops;
+
+		return domain;
+	}
+
 	if (type != IOMMU_DOMAIN_UNMANAGED &&
 	    type != IOMMU_DOMAIN_DMA &&
 	    type != IOMMU_DOMAIN_DMA_FQ &&
-- 
2.25.1


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

* [PATCH RFC v3 08/12] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  2022-04-10 10:24 ` Lu Baolu
@ 2022-04-10 10:24   ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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         |  44 ++++----
 drivers/iommu/iommu-sva-lib.h |   5 +
 drivers/iommu/iommu-sva-lib.c | 196 ++++++++++++++++++++++++++++++++++
 drivers/iommu/iommu.c         |  95 +---------------
 4 files changed, 227 insertions(+), 113 deletions(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 14c3b2197b35..2a2d17431826 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -677,12 +677,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);
 
@@ -1019,21 +1013,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;
@@ -1075,6 +1054,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.h b/drivers/iommu/iommu-sva-lib.h
index 9c5e108e2c8a..724af2226581 100644
--- a/drivers/iommu/iommu-sva-lib.h
+++ b/drivers/iommu/iommu-sva-lib.h
@@ -27,6 +27,7 @@ int iopf_queue_flush_dev(struct device *dev);
 struct iopf_queue *iopf_queue_alloc(const char *name);
 void iopf_queue_free(struct iopf_queue *queue);
 int iopf_queue_discard_partial(struct iopf_queue *queue);
+void iommu_sva_ioas_put(struct iommu_sva_ioas *ioas);
 
 #else /* CONFIG_IOMMU_SVA */
 static inline int iommu_queue_iopf(struct iommu_fault *fault, void *cookie)
@@ -64,5 +65,9 @@ static inline int iopf_queue_discard_partial(struct iopf_queue *queue)
 {
 	return -ENODEV;
 }
+
+static inline void iommu_sva_ioas_put(struct iommu_sva_ioas *ioas)
+{
+}
 #endif /* CONFIG_IOMMU_SVA */
 #endif /* _IOMMU_SVA_LIB_H */
diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
index d524a402be3b..986759f501b1 100644
--- a/drivers/iommu/iommu-sva-lib.c
+++ b/drivers/iommu/iommu-sva-lib.c
@@ -11,6 +11,7 @@
 
 static DEFINE_MUTEX(iommu_sva_lock);
 static DECLARE_IOASID_SET(iommu_sva_pasid);
+static DEFINE_XARRAY_ALLOC(iommu_sva_ioas_array);
 
 struct iommu_sva_ioas {
 	struct mm_struct *mm;
@@ -87,3 +88,198 @@ 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);
+
+/*
+ * Get or put an ioas for a shared memory.
+ */
+static struct iommu_sva_ioas *iommu_sva_ioas_get(struct mm_struct *mm,
+						 ioasid_t pasid)
+{
+	struct iommu_sva_ioas *ioas;
+	void *curr;
+
+	ioas = xa_load(&iommu_sva_ioas_array, pasid);
+	if (ioas) {
+		if (WARN_ON(ioas->mm != mm))
+			return NULL;
+		refcount_inc(&ioas->users);
+		return ioas;
+	}
+
+	ioas = kzalloc(sizeof(*ioas), GFP_KERNEL);
+	if (!ioas)
+		return NULL;
+
+	ioas->mm = mm;
+	ioas->pasid = pasid;
+	refcount_set(&ioas->users, 1);
+	INIT_LIST_HEAD(&ioas->bonds);
+	curr = xa_store(&iommu_sva_ioas_array, pasid, ioas, GFP_KERNEL);
+	if (xa_err(curr)) {
+		kfree(ioas);
+		return NULL;
+	}
+
+	mmgrab(mm);
+
+	return ioas;
+}
+
+void iommu_sva_ioas_put(struct iommu_sva_ioas *ioas)
+{
+	if (!ioas)
+		return;
+
+	if (refcount_dec_and_test(&ioas->users)) {
+		WARN_ON(!list_empty(&ioas->bonds));
+		xa_erase(&iommu_sva_ioas_array, ioas->pasid);
+		mmdrop(ioas->mm);
+		kfree(ioas);
+	}
+}
+
+/*
+ * IOMMU SVA driver-oriented interfaces
+ */
+static struct iommu_domain *
+iommu_sva_alloc_domain(struct device *dev, struct iommu_sva_ioas *ioas)
+{
+	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)
+		return NULL;
+
+	/* The caller must hold a reference to ioas. */
+	domain->sva_ioas = ioas;
+	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;
+	struct iommu_sva_ioas *ioas;
+
+	/*
+	 * TODO: Remove the drvdata parameter after kernel PASID support is
+	 * enabled for the idxd driver.
+	 */
+	if (drvdata)
+		return ERR_PTR(-EOPNOTSUPP);
+
+	/* Allocate mm->pasid if necessary. */
+	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits) - 1);
+	if (ret)
+		return ERR_PTR(ret);
+
+	mutex_lock(&iommu_sva_lock);
+	ioas = iommu_sva_ioas_get(mm, mm->pasid);
+	if (!ioas) {
+		ret = -ENOMEM;
+		goto out_unlock;
+	}
+
+	/* Search for an existing bond. */
+	list_for_each_entry(handle, &ioas->bonds, node) {
+		if (handle->dev == dev) {
+			refcount_inc(&handle->users);
+			/* No new bond, drop the counter. */
+			iommu_sva_ioas_put(ioas);
+			goto out_success;
+		}
+	}
+
+	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+	if (!handle) {
+		ret = -ENOMEM;
+		goto out_put_ioas;
+	}
+
+	/* The reference to ioas will be kept until domain free. */
+	domain = iommu_sva_alloc_domain(dev, ioas);
+	if (!domain) {
+		ret = -ENODEV;
+		goto out_free_handle;
+	}
+
+	ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
+	if (ret)
+		goto out_free_domain;
+
+	handle->dev = dev;
+	handle->domain = domain;
+	handle->sva_ioas = ioas;
+	refcount_set(&handle->users, 1);
+	list_add_tail(&handle->node, &ioas->bonds);
+
+out_success:
+	mutex_unlock(&iommu_sva_lock);
+	return handle;
+
+out_free_domain:
+	domain->ops->free(domain);
+out_free_handle:
+	kfree(handle);
+out_put_ioas:
+	iommu_sva_ioas_put(ioas);
+out_unlock:
+	mutex_unlock(&iommu_sva_lock);
+	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 iommu_sva_ioas *ioas = handle->sva_ioas;
+
+	mutex_lock(&iommu_sva_lock);
+	if (refcount_dec_and_test(&handle->users)) {
+		list_del(&handle->node);
+		iommu_detach_device_pasid(domain, dev, ioas->pasid);
+		iommu_domain_free(domain);
+		kfree(handle);
+	}
+	mutex_unlock(&iommu_sva_lock);
+}
+EXPORT_SYMBOL_GPL(iommu_sva_unbind_device);
+
+u32 iommu_sva_get_pasid(struct iommu_sva *handle)
+{
+	return handle->sva_ioas->pasid;
+}
+EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 63f880dd0c80..1c4db9148608 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);
 
@@ -1952,6 +1954,7 @@ EXPORT_SYMBOL_GPL(iommu_domain_alloc);
 void iommu_domain_free(struct iommu_domain *domain)
 {
 	iommu_put_dma_cookie(domain);
+	iommu_sva_ioas_put(domain->sva_ioas);
 	domain->ops->free(domain);
 }
 EXPORT_SYMBOL_GPL(iommu_domain_free);
@@ -2755,98 +2758,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] 64+ messages in thread

* [PATCH RFC v3 08/12] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
@ 2022-04-10 10:24   ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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         |  44 ++++----
 drivers/iommu/iommu-sva-lib.h |   5 +
 drivers/iommu/iommu-sva-lib.c | 196 ++++++++++++++++++++++++++++++++++
 drivers/iommu/iommu.c         |  95 +---------------
 4 files changed, 227 insertions(+), 113 deletions(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 14c3b2197b35..2a2d17431826 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -677,12 +677,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);
 
@@ -1019,21 +1013,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;
@@ -1075,6 +1054,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.h b/drivers/iommu/iommu-sva-lib.h
index 9c5e108e2c8a..724af2226581 100644
--- a/drivers/iommu/iommu-sva-lib.h
+++ b/drivers/iommu/iommu-sva-lib.h
@@ -27,6 +27,7 @@ int iopf_queue_flush_dev(struct device *dev);
 struct iopf_queue *iopf_queue_alloc(const char *name);
 void iopf_queue_free(struct iopf_queue *queue);
 int iopf_queue_discard_partial(struct iopf_queue *queue);
+void iommu_sva_ioas_put(struct iommu_sva_ioas *ioas);
 
 #else /* CONFIG_IOMMU_SVA */
 static inline int iommu_queue_iopf(struct iommu_fault *fault, void *cookie)
@@ -64,5 +65,9 @@ static inline int iopf_queue_discard_partial(struct iopf_queue *queue)
 {
 	return -ENODEV;
 }
+
+static inline void iommu_sva_ioas_put(struct iommu_sva_ioas *ioas)
+{
+}
 #endif /* CONFIG_IOMMU_SVA */
 #endif /* _IOMMU_SVA_LIB_H */
diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
index d524a402be3b..986759f501b1 100644
--- a/drivers/iommu/iommu-sva-lib.c
+++ b/drivers/iommu/iommu-sva-lib.c
@@ -11,6 +11,7 @@
 
 static DEFINE_MUTEX(iommu_sva_lock);
 static DECLARE_IOASID_SET(iommu_sva_pasid);
+static DEFINE_XARRAY_ALLOC(iommu_sva_ioas_array);
 
 struct iommu_sva_ioas {
 	struct mm_struct *mm;
@@ -87,3 +88,198 @@ 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);
+
+/*
+ * Get or put an ioas for a shared memory.
+ */
+static struct iommu_sva_ioas *iommu_sva_ioas_get(struct mm_struct *mm,
+						 ioasid_t pasid)
+{
+	struct iommu_sva_ioas *ioas;
+	void *curr;
+
+	ioas = xa_load(&iommu_sva_ioas_array, pasid);
+	if (ioas) {
+		if (WARN_ON(ioas->mm != mm))
+			return NULL;
+		refcount_inc(&ioas->users);
+		return ioas;
+	}
+
+	ioas = kzalloc(sizeof(*ioas), GFP_KERNEL);
+	if (!ioas)
+		return NULL;
+
+	ioas->mm = mm;
+	ioas->pasid = pasid;
+	refcount_set(&ioas->users, 1);
+	INIT_LIST_HEAD(&ioas->bonds);
+	curr = xa_store(&iommu_sva_ioas_array, pasid, ioas, GFP_KERNEL);
+	if (xa_err(curr)) {
+		kfree(ioas);
+		return NULL;
+	}
+
+	mmgrab(mm);
+
+	return ioas;
+}
+
+void iommu_sva_ioas_put(struct iommu_sva_ioas *ioas)
+{
+	if (!ioas)
+		return;
+
+	if (refcount_dec_and_test(&ioas->users)) {
+		WARN_ON(!list_empty(&ioas->bonds));
+		xa_erase(&iommu_sva_ioas_array, ioas->pasid);
+		mmdrop(ioas->mm);
+		kfree(ioas);
+	}
+}
+
+/*
+ * IOMMU SVA driver-oriented interfaces
+ */
+static struct iommu_domain *
+iommu_sva_alloc_domain(struct device *dev, struct iommu_sva_ioas *ioas)
+{
+	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)
+		return NULL;
+
+	/* The caller must hold a reference to ioas. */
+	domain->sva_ioas = ioas;
+	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;
+	struct iommu_sva_ioas *ioas;
+
+	/*
+	 * TODO: Remove the drvdata parameter after kernel PASID support is
+	 * enabled for the idxd driver.
+	 */
+	if (drvdata)
+		return ERR_PTR(-EOPNOTSUPP);
+
+	/* Allocate mm->pasid if necessary. */
+	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits) - 1);
+	if (ret)
+		return ERR_PTR(ret);
+
+	mutex_lock(&iommu_sva_lock);
+	ioas = iommu_sva_ioas_get(mm, mm->pasid);
+	if (!ioas) {
+		ret = -ENOMEM;
+		goto out_unlock;
+	}
+
+	/* Search for an existing bond. */
+	list_for_each_entry(handle, &ioas->bonds, node) {
+		if (handle->dev == dev) {
+			refcount_inc(&handle->users);
+			/* No new bond, drop the counter. */
+			iommu_sva_ioas_put(ioas);
+			goto out_success;
+		}
+	}
+
+	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+	if (!handle) {
+		ret = -ENOMEM;
+		goto out_put_ioas;
+	}
+
+	/* The reference to ioas will be kept until domain free. */
+	domain = iommu_sva_alloc_domain(dev, ioas);
+	if (!domain) {
+		ret = -ENODEV;
+		goto out_free_handle;
+	}
+
+	ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
+	if (ret)
+		goto out_free_domain;
+
+	handle->dev = dev;
+	handle->domain = domain;
+	handle->sva_ioas = ioas;
+	refcount_set(&handle->users, 1);
+	list_add_tail(&handle->node, &ioas->bonds);
+
+out_success:
+	mutex_unlock(&iommu_sva_lock);
+	return handle;
+
+out_free_domain:
+	domain->ops->free(domain);
+out_free_handle:
+	kfree(handle);
+out_put_ioas:
+	iommu_sva_ioas_put(ioas);
+out_unlock:
+	mutex_unlock(&iommu_sva_lock);
+	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 iommu_sva_ioas *ioas = handle->sva_ioas;
+
+	mutex_lock(&iommu_sva_lock);
+	if (refcount_dec_and_test(&handle->users)) {
+		list_del(&handle->node);
+		iommu_detach_device_pasid(domain, dev, ioas->pasid);
+		iommu_domain_free(domain);
+		kfree(handle);
+	}
+	mutex_unlock(&iommu_sva_lock);
+}
+EXPORT_SYMBOL_GPL(iommu_sva_unbind_device);
+
+u32 iommu_sva_get_pasid(struct iommu_sva *handle)
+{
+	return handle->sva_ioas->pasid;
+}
+EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 63f880dd0c80..1c4db9148608 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);
 
@@ -1952,6 +1954,7 @@ EXPORT_SYMBOL_GPL(iommu_domain_alloc);
 void iommu_domain_free(struct iommu_domain *domain)
 {
 	iommu_put_dma_cookie(domain);
+	iommu_sva_ioas_put(domain->sva_ioas);
 	domain->ops->free(domain);
 }
 EXPORT_SYMBOL_GPL(iommu_domain_free);
@@ -2755,98 +2758,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] 64+ messages in thread

* [PATCH RFC v3 09/12] iommu: Remove SVA related callbacks from iommu ops
  2022-04-10 10:24 ` Lu Baolu
@ 2022-04-10 10:24   ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 -------
 drivers/iommu/iommu-sva-lib.h                 |  1 -
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   | 41 ----------------
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  3 --
 drivers/iommu/intel/iommu.c                   |  3 --
 drivers/iommu/intel/svm.c                     | 49 -------------------
 drivers/iommu/iommu-sva-lib.c                 |  4 +-
 9 files changed, 2 insertions(+), 128 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 2a2d17431826..57650b773f3f 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -213,9 +213,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
@@ -249,11 +246,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/iommu-sva-lib.h b/drivers/iommu/iommu-sva-lib.h
index 724af2226581..0f33472e5212 100644
--- a/drivers/iommu/iommu-sva-lib.h
+++ b/drivers/iommu/iommu-sva-lib.h
@@ -8,7 +8,6 @@
 #include <linux/ioasid.h>
 #include <linux/mm_types.h>
 
-int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max);
 struct mm_struct *iommu_sva_find(ioasid_t pasid);
 struct mm_struct *iommu_sva_domain_mm(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 ce229820086d..5591321f9e11 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
@@ -328,11 +328,6 @@ __arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm)
 	if (!bond)
 		return ERR_PTR(-ENOMEM);
 
-	/* Allocate a PASID for this mm if necessary */
-	ret = iommu_sva_alloc_pasid(mm, 1, (1U << master->ssid_bits) - 1);
-	if (ret)
-		goto err_free_bond;
-
 	bond->mm = mm;
 	bond->sva.dev = dev;
 	refcount_set(&bond->refs, 1);
@@ -351,42 +346,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 bd80de0bad98..543d3ef1c102 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2875,9 +2875,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 9c2714ba04ff..3164bd5a3572 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4896,9 +4896,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 251a3a65d77f..61155f1cb985 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)
@@ -805,47 +797,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)
diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
index 986759f501b1..8df39893726f 100644
--- a/drivers/iommu/iommu-sva-lib.c
+++ b/drivers/iommu/iommu-sva-lib.c
@@ -41,7 +41,8 @@ struct mm_struct *iommu_sva_domain_mm(struct iommu_domain *domain)
  *
  * Returns 0 on success and < 0 on error.
  */
-int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max)
+static int iommu_sva_alloc_pasid(struct mm_struct *mm,
+				 ioasid_t min, ioasid_t max)
 {
 	int ret = 0;
 	ioasid_t pasid;
@@ -67,7 +68,6 @@ int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max)
 	mutex_unlock(&iommu_sva_lock);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(iommu_sva_alloc_pasid);
 
 /* ioasid_find getter() requires a void * argument */
 static bool __mmget_not_zero(void *mm)
-- 
2.25.1


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

* [PATCH RFC v3 09/12] iommu: Remove SVA related callbacks from iommu ops
@ 2022-04-10 10:24   ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 -------
 drivers/iommu/iommu-sva-lib.h                 |  1 -
 .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c   | 41 ----------------
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  3 --
 drivers/iommu/intel/iommu.c                   |  3 --
 drivers/iommu/intel/svm.c                     | 49 -------------------
 drivers/iommu/iommu-sva-lib.c                 |  4 +-
 9 files changed, 2 insertions(+), 128 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 2a2d17431826..57650b773f3f 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -213,9 +213,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
@@ -249,11 +246,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/iommu-sva-lib.h b/drivers/iommu/iommu-sva-lib.h
index 724af2226581..0f33472e5212 100644
--- a/drivers/iommu/iommu-sva-lib.h
+++ b/drivers/iommu/iommu-sva-lib.h
@@ -8,7 +8,6 @@
 #include <linux/ioasid.h>
 #include <linux/mm_types.h>
 
-int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max);
 struct mm_struct *iommu_sva_find(ioasid_t pasid);
 struct mm_struct *iommu_sva_domain_mm(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 ce229820086d..5591321f9e11 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
@@ -328,11 +328,6 @@ __arm_smmu_sva_bind(struct device *dev, struct mm_struct *mm)
 	if (!bond)
 		return ERR_PTR(-ENOMEM);
 
-	/* Allocate a PASID for this mm if necessary */
-	ret = iommu_sva_alloc_pasid(mm, 1, (1U << master->ssid_bits) - 1);
-	if (ret)
-		goto err_free_bond;
-
 	bond->mm = mm;
 	bond->sva.dev = dev;
 	refcount_set(&bond->refs, 1);
@@ -351,42 +346,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 bd80de0bad98..543d3ef1c102 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2875,9 +2875,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 9c2714ba04ff..3164bd5a3572 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -4896,9 +4896,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 251a3a65d77f..61155f1cb985 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)
@@ -805,47 +797,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)
diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
index 986759f501b1..8df39893726f 100644
--- a/drivers/iommu/iommu-sva-lib.c
+++ b/drivers/iommu/iommu-sva-lib.c
@@ -41,7 +41,8 @@ struct mm_struct *iommu_sva_domain_mm(struct iommu_domain *domain)
  *
  * Returns 0 on success and < 0 on error.
  */
-int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max)
+static int iommu_sva_alloc_pasid(struct mm_struct *mm,
+				 ioasid_t min, ioasid_t max)
 {
 	int ret = 0;
 	ioasid_t pasid;
@@ -67,7 +68,6 @@ int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max)
 	mutex_unlock(&iommu_sva_lock);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(iommu_sva_alloc_pasid);
 
 /* ioasid_find getter() requires a void * argument */
 static bool __mmget_not_zero(void *mm)
-- 
2.25.1

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

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

* [PATCH RFC v3 10/12] iommu: Prepare IOMMU domain for IOPF
  2022-04-10 10:24 ` Lu Baolu
@ 2022-04-10 10:24   ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 some mechanisms around the iommu_domain so that the I/O page
fault handling framework could route a page fault to the domain and
call the fault handler from it.

It includes:

- A reference counter for the iommu domain. The page fault handler is
  a different context from the bind()/unbind() thread. A reference
  counter is added to struct iommu_domain so that the life cycle of
  the iommu_domain could be synced between different threads.

- A pointer to the page fault handler and its private data. The fault
  handler will be called with the private data as a parameter once a
  page fault is routed to the domain. Any kernel component which owns
  an iommu domain could install handler and its parameter so that the
  page fault could be further routed or handled.

This also prepares the SVA implementation to be the first consumer of
the per-domain page fault handling model.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h         | 19 ++++++++++
 drivers/iommu/iommu-sva-lib.c | 68 ++++++++++++++++++++++++++++++++++-
 drivers/iommu/iommu.c         | 29 +++++++++++++++
 3 files changed, 115 insertions(+), 1 deletion(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 57650b773f3f..e23ec718515d 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -51,6 +51,8 @@ struct iommu_sva_ioas;
 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    */
@@ -102,6 +104,9 @@ struct iommu_domain {
 	struct iommu_domain_geometry geometry;
 	struct iommu_dma_cookie *iova_cookie;
 	struct iommu_sva_ioas *sva_ioas;
+	iommu_domain_iopf_handler_t iopf_handler;
+	void *fault_data;
+	refcount_t async_users;
 };
 
 static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
@@ -680,6 +685,14 @@ 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_async(struct device *dev, ioasid_t pasid);
+
+static inline void iommu_domain_put_async(struct iommu_domain *domain)
+{
+	if (refcount_dec_and_test(&domain->async_users))
+		iommu_domain_free(domain);
+}
 #else /* CONFIG_IOMMU_API */
 
 struct iommu_ops {};
@@ -1044,6 +1057,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_async(struct device *dev, ioasid_t pasid)
+{
+	return NULL;
+}
 #endif /* CONFIG_IOMMU_API */
 
 #ifdef CONFIG_IOMMU_SVA
diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
index 8df39893726f..1206423acc12 100644
--- a/drivers/iommu/iommu-sva-lib.c
+++ b/drivers/iommu/iommu-sva-lib.c
@@ -138,6 +138,69 @@ void iommu_sva_ioas_put(struct iommu_sva_ioas *ioas)
 	}
 }
 
+/*
+ * I/O page fault handler for SVA
+ *
+ * Copied from io-pgfault.c with mmget_not_zero() added before
+ * mmap_read_lock().
+ */
+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 = iommu_sva_domain_mm(domain);
+	if (IS_ERR_OR_NULL(mm) || !mmget_not_zero(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 driver-oriented interfaces
  */
@@ -157,6 +220,9 @@ iommu_sva_alloc_domain(struct device *dev, struct iommu_sva_ioas *ioas)
 	/* The caller must hold a reference to ioas. */
 	domain->sva_ioas = ioas;
 	domain->type = IOMMU_DOMAIN_SVA;
+	domain->iopf_handler = iommu_sva_handle_iopf;
+	domain->fault_data = domain;
+	refcount_set(&domain->async_users, 1);
 
 	return domain;
 }
@@ -271,7 +337,7 @@ void iommu_sva_unbind_device(struct iommu_sva *handle)
 	if (refcount_dec_and_test(&handle->users)) {
 		list_del(&handle->node);
 		iommu_detach_device_pasid(domain, dev, ioas->pasid);
-		iommu_domain_free(domain);
+		iommu_domain_put_async(domain);
 		kfree(handle);
 	}
 	mutex_unlock(&iommu_sva_lock);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 1c4db9148608..ba9a687490c9 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -3173,3 +3173,32 @@ void iommu_detach_device_pasid(struct iommu_domain *domain,
 
 	iommu_group_put(group);
 }
+
+/*
+ * Get the attached domain for asynchronous usage, for example the I/O
+ * page fault handling framework. The caller get a reference counter
+ * of the domain automatically on a successful return and should put
+ * it with iommu_domain_put() after usage.
+ */
+struct iommu_domain *
+iommu_get_domain_for_dev_pasid_async(struct device *dev, ioasid_t pasid)
+{
+	struct iommu_domain *domain;
+	struct iommu_group *group;
+
+	if (!pasid_valid(pasid))
+		return NULL;
+
+	group = iommu_group_get(dev);
+	if (!group)
+		return NULL;
+
+	mutex_lock(&group->mutex);
+	domain = xa_load(&group->pasid_array, pasid);
+	if (domain)
+		refcount_inc(&domain->async_users);
+	mutex_unlock(&group->mutex);
+	iommu_group_put(group);
+
+	return domain;
+}
-- 
2.25.1


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

* [PATCH RFC v3 10/12] iommu: Prepare IOMMU domain for IOPF
@ 2022-04-10 10:24   ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 some mechanisms around the iommu_domain so that the I/O page
fault handling framework could route a page fault to the domain and
call the fault handler from it.

It includes:

- A reference counter for the iommu domain. The page fault handler is
  a different context from the bind()/unbind() thread. A reference
  counter is added to struct iommu_domain so that the life cycle of
  the iommu_domain could be synced between different threads.

- A pointer to the page fault handler and its private data. The fault
  handler will be called with the private data as a parameter once a
  page fault is routed to the domain. Any kernel component which owns
  an iommu domain could install handler and its parameter so that the
  page fault could be further routed or handled.

This also prepares the SVA implementation to be the first consumer of
the per-domain page fault handling model.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 include/linux/iommu.h         | 19 ++++++++++
 drivers/iommu/iommu-sva-lib.c | 68 ++++++++++++++++++++++++++++++++++-
 drivers/iommu/iommu.c         | 29 +++++++++++++++
 3 files changed, 115 insertions(+), 1 deletion(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 57650b773f3f..e23ec718515d 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -51,6 +51,8 @@ struct iommu_sva_ioas;
 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    */
@@ -102,6 +104,9 @@ struct iommu_domain {
 	struct iommu_domain_geometry geometry;
 	struct iommu_dma_cookie *iova_cookie;
 	struct iommu_sva_ioas *sva_ioas;
+	iommu_domain_iopf_handler_t iopf_handler;
+	void *fault_data;
+	refcount_t async_users;
 };
 
 static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
@@ -680,6 +685,14 @@ 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_async(struct device *dev, ioasid_t pasid);
+
+static inline void iommu_domain_put_async(struct iommu_domain *domain)
+{
+	if (refcount_dec_and_test(&domain->async_users))
+		iommu_domain_free(domain);
+}
 #else /* CONFIG_IOMMU_API */
 
 struct iommu_ops {};
@@ -1044,6 +1057,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_async(struct device *dev, ioasid_t pasid)
+{
+	return NULL;
+}
 #endif /* CONFIG_IOMMU_API */
 
 #ifdef CONFIG_IOMMU_SVA
diff --git a/drivers/iommu/iommu-sva-lib.c b/drivers/iommu/iommu-sva-lib.c
index 8df39893726f..1206423acc12 100644
--- a/drivers/iommu/iommu-sva-lib.c
+++ b/drivers/iommu/iommu-sva-lib.c
@@ -138,6 +138,69 @@ void iommu_sva_ioas_put(struct iommu_sva_ioas *ioas)
 	}
 }
 
+/*
+ * I/O page fault handler for SVA
+ *
+ * Copied from io-pgfault.c with mmget_not_zero() added before
+ * mmap_read_lock().
+ */
+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 = iommu_sva_domain_mm(domain);
+	if (IS_ERR_OR_NULL(mm) || !mmget_not_zero(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 driver-oriented interfaces
  */
@@ -157,6 +220,9 @@ iommu_sva_alloc_domain(struct device *dev, struct iommu_sva_ioas *ioas)
 	/* The caller must hold a reference to ioas. */
 	domain->sva_ioas = ioas;
 	domain->type = IOMMU_DOMAIN_SVA;
+	domain->iopf_handler = iommu_sva_handle_iopf;
+	domain->fault_data = domain;
+	refcount_set(&domain->async_users, 1);
 
 	return domain;
 }
@@ -271,7 +337,7 @@ void iommu_sva_unbind_device(struct iommu_sva *handle)
 	if (refcount_dec_and_test(&handle->users)) {
 		list_del(&handle->node);
 		iommu_detach_device_pasid(domain, dev, ioas->pasid);
-		iommu_domain_free(domain);
+		iommu_domain_put_async(domain);
 		kfree(handle);
 	}
 	mutex_unlock(&iommu_sva_lock);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 1c4db9148608..ba9a687490c9 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -3173,3 +3173,32 @@ void iommu_detach_device_pasid(struct iommu_domain *domain,
 
 	iommu_group_put(group);
 }
+
+/*
+ * Get the attached domain for asynchronous usage, for example the I/O
+ * page fault handling framework. The caller get a reference counter
+ * of the domain automatically on a successful return and should put
+ * it with iommu_domain_put() after usage.
+ */
+struct iommu_domain *
+iommu_get_domain_for_dev_pasid_async(struct device *dev, ioasid_t pasid)
+{
+	struct iommu_domain *domain;
+	struct iommu_group *group;
+
+	if (!pasid_valid(pasid))
+		return NULL;
+
+	group = iommu_group_get(dev);
+	if (!group)
+		return NULL;
+
+	mutex_lock(&group->mutex);
+	domain = xa_load(&group->pasid_array, pasid);
+	if (domain)
+		refcount_inc(&domain->async_users);
+	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] 64+ messages in thread

* [PATCH RFC v3 11/12] iommu: Per-domain I/O page fault handling
  2022-04-10 10:24 ` Lu Baolu
@ 2022-04-10 10:24   ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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

Tweak the I/O page fault handling framework to route the page faults to
the domain and call the page fault handler retrieved from the domain.
This makes the I/O page fault handling framework possible to serve more
usage scenarios as long as they have an IOMMU domain and install a page
fault handler in it. Some unused functions are also removed to avoid
dead code.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/iommu/iommu-sva-lib.h |  1 -
 drivers/iommu/io-pgfault.c    | 69 ++++++-----------------------------
 drivers/iommu/iommu-sva-lib.c | 20 ----------
 3 files changed, 12 insertions(+), 78 deletions(-)

diff --git a/drivers/iommu/iommu-sva-lib.h b/drivers/iommu/iommu-sva-lib.h
index 0f33472e5212..90d4bd3a61b1 100644
--- a/drivers/iommu/iommu-sva-lib.h
+++ b/drivers/iommu/iommu-sva-lib.h
@@ -8,7 +8,6 @@
 #include <linux/ioasid.h>
 #include <linux/mm_types.h>
 
-struct mm_struct *iommu_sva_find(ioasid_t pasid);
 struct mm_struct *iommu_sva_domain_mm(struct iommu_domain *domain);
 
 /* I/O Page fault */
diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
index 1df8c1dcae77..fc1b2bdeedf8 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,23 @@ 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_async(group->dev,
+				iopf->fault.prm.pasid);
+		if (!domain || !domain->iopf_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->iopf_handler(&iopf->fault,
+						      domain->fault_data);
+
+		if (domain)
+			iommu_domain_put_async(domain);
 
 		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 1206423acc12..4c9d89f375df 100644
--- a/drivers/iommu/iommu-sva-lib.c
+++ b/drivers/iommu/iommu-sva-lib.c
@@ -69,26 +69,6 @@ static int iommu_sva_alloc_pasid(struct mm_struct *mm,
 	return ret;
 }
 
-/* ioasid_find getter() requires a void * argument */
-static bool __mmget_not_zero(void *mm)
-{
-	return mmget_not_zero(mm);
-}
-
-/**
- * iommu_sva_find() - Find mm associated to the given PASID
- * @pasid: Process Address Space ID assigned to the mm
- *
- * On success a reference to the mm is taken, and must be released with mmput().
- *
- * Returns the mm corresponding to this PASID, or an error if not found.
- */
-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);
-
 /*
  * Get or put an ioas for a shared memory.
  */
-- 
2.25.1


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

* [PATCH RFC v3 11/12] iommu: Per-domain I/O page fault handling
@ 2022-04-10 10:24   ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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

Tweak the I/O page fault handling framework to route the page faults to
the domain and call the page fault handler retrieved from the domain.
This makes the I/O page fault handling framework possible to serve more
usage scenarios as long as they have an IOMMU domain and install a page
fault handler in it. Some unused functions are also removed to avoid
dead code.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/iommu/iommu-sva-lib.h |  1 -
 drivers/iommu/io-pgfault.c    | 69 ++++++-----------------------------
 drivers/iommu/iommu-sva-lib.c | 20 ----------
 3 files changed, 12 insertions(+), 78 deletions(-)

diff --git a/drivers/iommu/iommu-sva-lib.h b/drivers/iommu/iommu-sva-lib.h
index 0f33472e5212..90d4bd3a61b1 100644
--- a/drivers/iommu/iommu-sva-lib.h
+++ b/drivers/iommu/iommu-sva-lib.h
@@ -8,7 +8,6 @@
 #include <linux/ioasid.h>
 #include <linux/mm_types.h>
 
-struct mm_struct *iommu_sva_find(ioasid_t pasid);
 struct mm_struct *iommu_sva_domain_mm(struct iommu_domain *domain);
 
 /* I/O Page fault */
diff --git a/drivers/iommu/io-pgfault.c b/drivers/iommu/io-pgfault.c
index 1df8c1dcae77..fc1b2bdeedf8 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,23 @@ 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_async(group->dev,
+				iopf->fault.prm.pasid);
+		if (!domain || !domain->iopf_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->iopf_handler(&iopf->fault,
+						      domain->fault_data);
+
+		if (domain)
+			iommu_domain_put_async(domain);
 
 		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 1206423acc12..4c9d89f375df 100644
--- a/drivers/iommu/iommu-sva-lib.c
+++ b/drivers/iommu/iommu-sva-lib.c
@@ -69,26 +69,6 @@ static int iommu_sva_alloc_pasid(struct mm_struct *mm,
 	return ret;
 }
 
-/* ioasid_find getter() requires a void * argument */
-static bool __mmget_not_zero(void *mm)
-{
-	return mmget_not_zero(mm);
-}
-
-/**
- * iommu_sva_find() - Find mm associated to the given PASID
- * @pasid: Process Address Space ID assigned to the mm
- *
- * On success a reference to the mm is taken, and must be released with mmput().
- *
- * Returns the mm corresponding to this PASID, or an error if not found.
- */
-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);
-
 /*
  * Get or put an ioas for a shared memory.
  */
-- 
2.25.1

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

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

* [PATCH RFC v3 12/12] iommu: Rename iommu-sva-lib.{c,h}
  2022-04-10 10:24 ` Lu Baolu
@ 2022-04-10 10:24   ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 5591321f9e11..a13543aa9df4 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 543d3ef1c102..ca2bd17eec41 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 3164bd5a3572..d3dbef5b74a7 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 61155f1cb985..166d1af2bda4 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 fc1b2bdeedf8..d337165f3707 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 4c9d89f375df..c4e4684edc14 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 ba9a687490c9..ac7af02ee50a 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] 64+ messages in thread

* [PATCH RFC v3 12/12] iommu: Rename iommu-sva-lib.{c,h}
@ 2022-04-10 10:24   ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-10 10:24 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 5591321f9e11..a13543aa9df4 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 543d3ef1c102..ca2bd17eec41 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 3164bd5a3572..d3dbef5b74a7 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 61155f1cb985..166d1af2bda4 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 fc1b2bdeedf8..d337165f3707 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 4c9d89f375df..c4e4684edc14 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 ba9a687490c9..ac7af02ee50a 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] 64+ messages in thread

* RE: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
  2022-04-10 10:24   ` Lu Baolu
@ 2022-04-12  3:15     ` Tian, Kevin
  -1 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12  3:15 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, April 10, 2022 6:25 PM
> 
> Some features require that a single device must be immutably isolated,
> even when hot plug is supported. 

This reads confusing, as hotplug cannot be allowed in a singleton group.
What you actually meant suppose to be:

"Enabling certain device features require the device in a singleton iommu
group which is immutable in fabric i.e. not affected by hotplug"

> For example, the SVA bind()/unbind()
> interfaces require that the device exists in a singleton group. If we
> have a singleton group that doesn't have ACS (or similar technologies)
> and someone hotplugs in another device on a bridge, then our SVA is
> completely broken and we get data corruption.

this needs the background that PASID doesn't join PCI packet routing
thus the dma address (CPU VA) may hit a p2p range.

> 
> This adds a flag in the iommu_group struct to indicate an immutable
> singleton group, and uses standard PCI bus topology, isolation features,
> and DMA alias quirks to set the flag. If the device came from DT, assume
> it is static and then the singleton attribute can know from the device
> count in the group.

where does the assumption come from?

> 
> Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
> Suggested-by: Kevin Tian <kevin.tian@intel.com>
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  drivers/iommu/iommu.c | 67 ++++++++++++++++++++++++++++++++++++----
> ---
>  1 file changed, 57 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index 0c42ece25854..56ffbf5fdc18 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -48,6 +48,7 @@ struct iommu_group {
>  	struct list_head entry;
>  	unsigned int owner_cnt;
>  	void *owner;
> +	bool immutable_singleton;

Just call it 'singleton' with a comment to explain it must be immutable?

>  };
> 
>  struct group_device {
> @@ -74,6 +75,16 @@ static const char * const
> iommu_group_resv_type_string[] = {
>  #define IOMMU_CMD_LINE_DMA_API		BIT(0)
>  #define IOMMU_CMD_LINE_STRICT		BIT(1)
> 
> +/*
> + * To consider a PCI device isolated, we require ACS to support Source
> + * Validation, Request Redirection, Completer Redirection, and Upstream
> + * Forwarding.  This effectively means that devices cannot spoof their
> + * requester ID, requests and completions cannot be redirected, and all
> + * transactions are forwarded upstream, even as it passes through a
> + * bridge where the target device is downstream.
> + */
> +#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR |
> PCI_ACS_UF)
> +
>  static int iommu_alloc_default_domain(struct iommu_group *group,
>  				      struct device *dev);
>  static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
> @@ -89,6 +100,7 @@ static int
> iommu_create_device_direct_mappings(struct iommu_group *group,
>  static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
>  static ssize_t iommu_group_store_type(struct iommu_group *group,
>  				      const char *buf, size_t count);
> +static int iommu_group_device_count(struct iommu_group *group);
> 
>  #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store)
> 	\
>  struct iommu_group_attribute iommu_group_attr_##_name =		\
> @@ -844,6 +856,37 @@ static bool iommu_is_attach_deferred(struct device
> *dev)
>  	return false;
>  }
> 
> +static int has_pci_alias(struct pci_dev *pdev, u16 alias, void *opaque)
> +{
> +	return -EEXIST;
> +}
> +
> +static bool pci_immutably_isolated(struct pci_dev *pdev)
> +{
> +	/* Skip the bridges. */
> +	if (pci_is_bridge(pdev))
> +		return false;
> +
> +	/*
> +	 * The device could be considered to be fully isolated if
> +	 * all devices on the path from the parent to the host-PCI
> +	 * bridge are protected from peer-to-peer DMA by ACS.
> +	 */
> +	if (!pci_is_root_bus(pdev->bus) &&
> +	    !pci_acs_path_enabled(pdev->bus->self, NULL, REQ_ACS_FLAGS))
> +		return false;
> +
> +	/* Multi-function devices should have ACS enabled. */
> +	if (pdev->multifunction && !pci_acs_enabled(pdev, REQ_ACS_FLAGS))
> +		return false;

Looks my earlier comment was lost, i.e. you can just use
pci_acs_path_enabled(pdev) to cover above two checks.

> +
> +	/* Filter out devices which has any alias device. */
> +	if (pci_for_each_dma_alias(pdev, has_pci_alias, NULL))
> +		return false;
> +
> +	return true;
> +}
> +
>  /**
>   * iommu_group_add_device - add a device to an iommu group
>   * @group: the group into which to add the device (reference should be held)
> @@ -898,6 +941,20 @@ int iommu_group_add_device(struct iommu_group
> *group, struct device *dev)
>  	list_add_tail(&device->list, &group->devices);
>  	if (group->domain  && !iommu_is_attach_deferred(dev))
>  		ret = __iommu_attach_device(group->domain, dev);
> +
> +	/*
> +	 * Use standard PCI bus topology, isolation features, and DMA
> +	 * alias quirks to set the immutable singleton attribute. If
> +	 * the device came from DT, assume it is static and then
> +	 * singleton can know from the device count in the group.
> +	 */
> +	if (dev_is_pci(dev))
> +		group->immutable_singleton =
> +				pci_immutably_isolated(to_pci_dev(dev));
> +	else if (is_of_node(dev_fwnode(dev)))
> +		group->immutable_singleton =
> +				(iommu_group_device_count(group) == 1);
> +
>  	mutex_unlock(&group->mutex);
>  	if (ret)
>  		goto err_put_group;
> @@ -1290,16 +1347,6 @@ EXPORT_SYMBOL_GPL(iommu_group_id);
>  static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev,
>  					       unsigned long *devfns);
> 
> -/*
> - * To consider a PCI device isolated, we require ACS to support Source
> - * Validation, Request Redirection, Completer Redirection, and Upstream
> - * Forwarding.  This effectively means that devices cannot spoof their
> - * requester ID, requests and completions cannot be redirected, and all
> - * transactions are forwarded upstream, even as it passes through a
> - * bridge where the target device is downstream.
> - */
> -#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR |
> PCI_ACS_UF)
> -
>  /*
>   * For multifunction devices which are not isolated from each other, find
>   * all the other non-isolated functions and look for existing groups.  For
> --
> 2.25.1


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

* RE: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
@ 2022-04-12  3:15     ` Tian, Kevin
  0 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12  3:15 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, April 10, 2022 6:25 PM
> 
> Some features require that a single device must be immutably isolated,
> even when hot plug is supported. 

This reads confusing, as hotplug cannot be allowed in a singleton group.
What you actually meant suppose to be:

"Enabling certain device features require the device in a singleton iommu
group which is immutable in fabric i.e. not affected by hotplug"

> For example, the SVA bind()/unbind()
> interfaces require that the device exists in a singleton group. If we
> have a singleton group that doesn't have ACS (or similar technologies)
> and someone hotplugs in another device on a bridge, then our SVA is
> completely broken and we get data corruption.

this needs the background that PASID doesn't join PCI packet routing
thus the dma address (CPU VA) may hit a p2p range.

> 
> This adds a flag in the iommu_group struct to indicate an immutable
> singleton group, and uses standard PCI bus topology, isolation features,
> and DMA alias quirks to set the flag. If the device came from DT, assume
> it is static and then the singleton attribute can know from the device
> count in the group.

where does the assumption come from?

> 
> Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
> Suggested-by: Kevin Tian <kevin.tian@intel.com>
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  drivers/iommu/iommu.c | 67 ++++++++++++++++++++++++++++++++++++----
> ---
>  1 file changed, 57 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index 0c42ece25854..56ffbf5fdc18 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -48,6 +48,7 @@ struct iommu_group {
>  	struct list_head entry;
>  	unsigned int owner_cnt;
>  	void *owner;
> +	bool immutable_singleton;

Just call it 'singleton' with a comment to explain it must be immutable?

>  };
> 
>  struct group_device {
> @@ -74,6 +75,16 @@ static const char * const
> iommu_group_resv_type_string[] = {
>  #define IOMMU_CMD_LINE_DMA_API		BIT(0)
>  #define IOMMU_CMD_LINE_STRICT		BIT(1)
> 
> +/*
> + * To consider a PCI device isolated, we require ACS to support Source
> + * Validation, Request Redirection, Completer Redirection, and Upstream
> + * Forwarding.  This effectively means that devices cannot spoof their
> + * requester ID, requests and completions cannot be redirected, and all
> + * transactions are forwarded upstream, even as it passes through a
> + * bridge where the target device is downstream.
> + */
> +#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR |
> PCI_ACS_UF)
> +
>  static int iommu_alloc_default_domain(struct iommu_group *group,
>  				      struct device *dev);
>  static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
> @@ -89,6 +100,7 @@ static int
> iommu_create_device_direct_mappings(struct iommu_group *group,
>  static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
>  static ssize_t iommu_group_store_type(struct iommu_group *group,
>  				      const char *buf, size_t count);
> +static int iommu_group_device_count(struct iommu_group *group);
> 
>  #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store)
> 	\
>  struct iommu_group_attribute iommu_group_attr_##_name =		\
> @@ -844,6 +856,37 @@ static bool iommu_is_attach_deferred(struct device
> *dev)
>  	return false;
>  }
> 
> +static int has_pci_alias(struct pci_dev *pdev, u16 alias, void *opaque)
> +{
> +	return -EEXIST;
> +}
> +
> +static bool pci_immutably_isolated(struct pci_dev *pdev)
> +{
> +	/* Skip the bridges. */
> +	if (pci_is_bridge(pdev))
> +		return false;
> +
> +	/*
> +	 * The device could be considered to be fully isolated if
> +	 * all devices on the path from the parent to the host-PCI
> +	 * bridge are protected from peer-to-peer DMA by ACS.
> +	 */
> +	if (!pci_is_root_bus(pdev->bus) &&
> +	    !pci_acs_path_enabled(pdev->bus->self, NULL, REQ_ACS_FLAGS))
> +		return false;
> +
> +	/* Multi-function devices should have ACS enabled. */
> +	if (pdev->multifunction && !pci_acs_enabled(pdev, REQ_ACS_FLAGS))
> +		return false;

Looks my earlier comment was lost, i.e. you can just use
pci_acs_path_enabled(pdev) to cover above two checks.

> +
> +	/* Filter out devices which has any alias device. */
> +	if (pci_for_each_dma_alias(pdev, has_pci_alias, NULL))
> +		return false;
> +
> +	return true;
> +}
> +
>  /**
>   * iommu_group_add_device - add a device to an iommu group
>   * @group: the group into which to add the device (reference should be held)
> @@ -898,6 +941,20 @@ int iommu_group_add_device(struct iommu_group
> *group, struct device *dev)
>  	list_add_tail(&device->list, &group->devices);
>  	if (group->domain  && !iommu_is_attach_deferred(dev))
>  		ret = __iommu_attach_device(group->domain, dev);
> +
> +	/*
> +	 * Use standard PCI bus topology, isolation features, and DMA
> +	 * alias quirks to set the immutable singleton attribute. If
> +	 * the device came from DT, assume it is static and then
> +	 * singleton can know from the device count in the group.
> +	 */
> +	if (dev_is_pci(dev))
> +		group->immutable_singleton =
> +				pci_immutably_isolated(to_pci_dev(dev));
> +	else if (is_of_node(dev_fwnode(dev)))
> +		group->immutable_singleton =
> +				(iommu_group_device_count(group) == 1);
> +
>  	mutex_unlock(&group->mutex);
>  	if (ret)
>  		goto err_put_group;
> @@ -1290,16 +1347,6 @@ EXPORT_SYMBOL_GPL(iommu_group_id);
>  static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev,
>  					       unsigned long *devfns);
> 
> -/*
> - * To consider a PCI device isolated, we require ACS to support Source
> - * Validation, Request Redirection, Completer Redirection, and Upstream
> - * Forwarding.  This effectively means that devices cannot spoof their
> - * requester ID, requests and completions cannot be redirected, and all
> - * transactions are forwarded upstream, even as it passes through a
> - * bridge where the target device is downstream.
> - */
> -#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR |
> PCI_ACS_UF)
> -
>  /*
>   * For multifunction devices which are not isolated from each other, find
>   * all the other non-isolated functions and look for existing groups.  For
> --
> 2.25.1

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

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

* Re: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
  2022-04-12  3:15     ` Tian, Kevin
@ 2022-04-12  5:08       ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-12  5:08 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

Hi Kevin,

Thanks for your time.

On 2022/4/12 11:15, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Sunday, April 10, 2022 6:25 PM
>>
>> Some features require that a single device must be immutably isolated,
>> even when hot plug is supported.
> 
> This reads confusing, as hotplug cannot be allowed in a singleton group.
> What you actually meant suppose to be:
> 
> "Enabling certain device features require the device in a singleton iommu
> group which is immutable in fabric i.e. not affected by hotplug"

Yours is better. Thank you.

> 
>> For example, the SVA bind()/unbind()
>> interfaces require that the device exists in a singleton group. If we
>> have a singleton group that doesn't have ACS (or similar technologies)
>> and someone hotplugs in another device on a bridge, then our SVA is
>> completely broken and we get data corruption.
> 
> this needs the background that PASID doesn't join PCI packet routing
> thus the dma address (CPU VA) may hit a p2p range.

Sure.

> 
>>
>> This adds a flag in the iommu_group struct to indicate an immutable
>> singleton group, and uses standard PCI bus topology, isolation features,
>> and DMA alias quirks to set the flag. If the device came from DT, assume
>> it is static and then the singleton attribute can know from the device
>> count in the group.
> 
> where does the assumption come from?

Hotplug is the only factor that can dynamically affect the
characteristics of IOMMU group singleton as far as I can see. If a
device node was created from the DT, it could be treated as static,
hence we can judge the singleton in iommu probe phase during boot.

> 
>>
>> Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
>> Suggested-by: Kevin Tian <kevin.tian@intel.com>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>> ---
>>   drivers/iommu/iommu.c | 67 ++++++++++++++++++++++++++++++++++++----
>> ---
>>   1 file changed, 57 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
>> index 0c42ece25854..56ffbf5fdc18 100644
>> --- a/drivers/iommu/iommu.c
>> +++ b/drivers/iommu/iommu.c
>> @@ -48,6 +48,7 @@ struct iommu_group {
>>   	struct list_head entry;
>>   	unsigned int owner_cnt;
>>   	void *owner;
>> +	bool immutable_singleton;
> 
> Just call it 'singleton' with a comment to explain it must be immutable?

I was just trying to distinguish "singleton" and "immutable singleton".
A group is singleton if it only contains a single device in the device
list, while a group is immutable singleton only if the fabric doesn't
allow to change the state.

> 
>>   };
>>
>>   struct group_device {
>> @@ -74,6 +75,16 @@ static const char * const
>> iommu_group_resv_type_string[] = {
>>   #define IOMMU_CMD_LINE_DMA_API		BIT(0)
>>   #define IOMMU_CMD_LINE_STRICT		BIT(1)
>>
>> +/*
>> + * To consider a PCI device isolated, we require ACS to support Source
>> + * Validation, Request Redirection, Completer Redirection, and Upstream
>> + * Forwarding.  This effectively means that devices cannot spoof their
>> + * requester ID, requests and completions cannot be redirected, and all
>> + * transactions are forwarded upstream, even as it passes through a
>> + * bridge where the target device is downstream.
>> + */
>> +#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR |
>> PCI_ACS_UF)
>> +
>>   static int iommu_alloc_default_domain(struct iommu_group *group,
>>   				      struct device *dev);
>>   static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
>> @@ -89,6 +100,7 @@ static int
>> iommu_create_device_direct_mappings(struct iommu_group *group,
>>   static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
>>   static ssize_t iommu_group_store_type(struct iommu_group *group,
>>   				      const char *buf, size_t count);
>> +static int iommu_group_device_count(struct iommu_group *group);
>>
>>   #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store)
>> 	\
>>   struct iommu_group_attribute iommu_group_attr_##_name =		\
>> @@ -844,6 +856,37 @@ static bool iommu_is_attach_deferred(struct device
>> *dev)
>>   	return false;
>>   }
>>
>> +static int has_pci_alias(struct pci_dev *pdev, u16 alias, void *opaque)
>> +{
>> +	return -EEXIST;
>> +}
>> +
>> +static bool pci_immutably_isolated(struct pci_dev *pdev)
>> +{
>> +	/* Skip the bridges. */
>> +	if (pci_is_bridge(pdev))
>> +		return false;
>> +
>> +	/*
>> +	 * The device could be considered to be fully isolated if
>> +	 * all devices on the path from the parent to the host-PCI
>> +	 * bridge are protected from peer-to-peer DMA by ACS.
>> +	 */
>> +	if (!pci_is_root_bus(pdev->bus) &&
>> +	    !pci_acs_path_enabled(pdev->bus->self, NULL, REQ_ACS_FLAGS))
>> +		return false;
>> +
>> +	/* Multi-function devices should have ACS enabled. */
>> +	if (pdev->multifunction && !pci_acs_enabled(pdev, REQ_ACS_FLAGS))
>> +		return false;
> 
> Looks my earlier comment was lost, i.e. you can just use
> pci_acs_path_enabled(pdev) to cover above two checks.

If a device is directly connected to the root bridge and it is not an
MFD, do we still need ACS on it? The Intel idxd device seems to be such
a device. I had a quick check with lspci, it has no ACS support.

I probably missed anything.

> 
>> +
>> +	/* Filter out devices which has any alias device. */
>> +	if (pci_for_each_dma_alias(pdev, has_pci_alias, NULL))
>> +		return false;
>> +
>> +	return true;
>> +}
>> +
>>   /**
>>    * iommu_group_add_device - add a device to an iommu group
>>    * @group: the group into which to add the device (reference should be held)
>> @@ -898,6 +941,20 @@ int iommu_group_add_device(struct iommu_group
>> *group, struct device *dev)
>>   	list_add_tail(&device->list, &group->devices);
>>   	if (group->domain  && !iommu_is_attach_deferred(dev))
>>   		ret = __iommu_attach_device(group->domain, dev);
>> +
>> +	/*
>> +	 * Use standard PCI bus topology, isolation features, and DMA
>> +	 * alias quirks to set the immutable singleton attribute. If
>> +	 * the device came from DT, assume it is static and then
>> +	 * singleton can know from the device count in the group.
>> +	 */
>> +	if (dev_is_pci(dev))
>> +		group->immutable_singleton =
>> +				pci_immutably_isolated(to_pci_dev(dev));
>> +	else if (is_of_node(dev_fwnode(dev)))
>> +		group->immutable_singleton =
>> +				(iommu_group_device_count(group) == 1);
>> +
>>   	mutex_unlock(&group->mutex);
>>   	if (ret)
>>   		goto err_put_group;
>> @@ -1290,16 +1347,6 @@ EXPORT_SYMBOL_GPL(iommu_group_id);
>>   static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev,
>>   					       unsigned long *devfns);
>>
>> -/*
>> - * To consider a PCI device isolated, we require ACS to support Source
>> - * Validation, Request Redirection, Completer Redirection, and Upstream
>> - * Forwarding.  This effectively means that devices cannot spoof their
>> - * requester ID, requests and completions cannot be redirected, and all
>> - * transactions are forwarded upstream, even as it passes through a
>> - * bridge where the target device is downstream.
>> - */
>> -#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR |
>> PCI_ACS_UF)
>> -
>>   /*
>>    * For multifunction devices which are not isolated from each other, find
>>    * all the other non-isolated functions and look for existing groups.  For
>> --
>> 2.25.1
> 

Best regards,
baolu

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

* Re: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
@ 2022-04-12  5:08       ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-12  5:08 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

Hi Kevin,

Thanks for your time.

On 2022/4/12 11:15, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Sunday, April 10, 2022 6:25 PM
>>
>> Some features require that a single device must be immutably isolated,
>> even when hot plug is supported.
> 
> This reads confusing, as hotplug cannot be allowed in a singleton group.
> What you actually meant suppose to be:
> 
> "Enabling certain device features require the device in a singleton iommu
> group which is immutable in fabric i.e. not affected by hotplug"

Yours is better. Thank you.

> 
>> For example, the SVA bind()/unbind()
>> interfaces require that the device exists in a singleton group. If we
>> have a singleton group that doesn't have ACS (or similar technologies)
>> and someone hotplugs in another device on a bridge, then our SVA is
>> completely broken and we get data corruption.
> 
> this needs the background that PASID doesn't join PCI packet routing
> thus the dma address (CPU VA) may hit a p2p range.

Sure.

> 
>>
>> This adds a flag in the iommu_group struct to indicate an immutable
>> singleton group, and uses standard PCI bus topology, isolation features,
>> and DMA alias quirks to set the flag. If the device came from DT, assume
>> it is static and then the singleton attribute can know from the device
>> count in the group.
> 
> where does the assumption come from?

Hotplug is the only factor that can dynamically affect the
characteristics of IOMMU group singleton as far as I can see. If a
device node was created from the DT, it could be treated as static,
hence we can judge the singleton in iommu probe phase during boot.

> 
>>
>> Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
>> Suggested-by: Kevin Tian <kevin.tian@intel.com>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>> ---
>>   drivers/iommu/iommu.c | 67 ++++++++++++++++++++++++++++++++++++----
>> ---
>>   1 file changed, 57 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
>> index 0c42ece25854..56ffbf5fdc18 100644
>> --- a/drivers/iommu/iommu.c
>> +++ b/drivers/iommu/iommu.c
>> @@ -48,6 +48,7 @@ struct iommu_group {
>>   	struct list_head entry;
>>   	unsigned int owner_cnt;
>>   	void *owner;
>> +	bool immutable_singleton;
> 
> Just call it 'singleton' with a comment to explain it must be immutable?

I was just trying to distinguish "singleton" and "immutable singleton".
A group is singleton if it only contains a single device in the device
list, while a group is immutable singleton only if the fabric doesn't
allow to change the state.

> 
>>   };
>>
>>   struct group_device {
>> @@ -74,6 +75,16 @@ static const char * const
>> iommu_group_resv_type_string[] = {
>>   #define IOMMU_CMD_LINE_DMA_API		BIT(0)
>>   #define IOMMU_CMD_LINE_STRICT		BIT(1)
>>
>> +/*
>> + * To consider a PCI device isolated, we require ACS to support Source
>> + * Validation, Request Redirection, Completer Redirection, and Upstream
>> + * Forwarding.  This effectively means that devices cannot spoof their
>> + * requester ID, requests and completions cannot be redirected, and all
>> + * transactions are forwarded upstream, even as it passes through a
>> + * bridge where the target device is downstream.
>> + */
>> +#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR |
>> PCI_ACS_UF)
>> +
>>   static int iommu_alloc_default_domain(struct iommu_group *group,
>>   				      struct device *dev);
>>   static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
>> @@ -89,6 +100,7 @@ static int
>> iommu_create_device_direct_mappings(struct iommu_group *group,
>>   static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
>>   static ssize_t iommu_group_store_type(struct iommu_group *group,
>>   				      const char *buf, size_t count);
>> +static int iommu_group_device_count(struct iommu_group *group);
>>
>>   #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store)
>> 	\
>>   struct iommu_group_attribute iommu_group_attr_##_name =		\
>> @@ -844,6 +856,37 @@ static bool iommu_is_attach_deferred(struct device
>> *dev)
>>   	return false;
>>   }
>>
>> +static int has_pci_alias(struct pci_dev *pdev, u16 alias, void *opaque)
>> +{
>> +	return -EEXIST;
>> +}
>> +
>> +static bool pci_immutably_isolated(struct pci_dev *pdev)
>> +{
>> +	/* Skip the bridges. */
>> +	if (pci_is_bridge(pdev))
>> +		return false;
>> +
>> +	/*
>> +	 * The device could be considered to be fully isolated if
>> +	 * all devices on the path from the parent to the host-PCI
>> +	 * bridge are protected from peer-to-peer DMA by ACS.
>> +	 */
>> +	if (!pci_is_root_bus(pdev->bus) &&
>> +	    !pci_acs_path_enabled(pdev->bus->self, NULL, REQ_ACS_FLAGS))
>> +		return false;
>> +
>> +	/* Multi-function devices should have ACS enabled. */
>> +	if (pdev->multifunction && !pci_acs_enabled(pdev, REQ_ACS_FLAGS))
>> +		return false;
> 
> Looks my earlier comment was lost, i.e. you can just use
> pci_acs_path_enabled(pdev) to cover above two checks.

If a device is directly connected to the root bridge and it is not an
MFD, do we still need ACS on it? The Intel idxd device seems to be such
a device. I had a quick check with lspci, it has no ACS support.

I probably missed anything.

> 
>> +
>> +	/* Filter out devices which has any alias device. */
>> +	if (pci_for_each_dma_alias(pdev, has_pci_alias, NULL))
>> +		return false;
>> +
>> +	return true;
>> +}
>> +
>>   /**
>>    * iommu_group_add_device - add a device to an iommu group
>>    * @group: the group into which to add the device (reference should be held)
>> @@ -898,6 +941,20 @@ int iommu_group_add_device(struct iommu_group
>> *group, struct device *dev)
>>   	list_add_tail(&device->list, &group->devices);
>>   	if (group->domain  && !iommu_is_attach_deferred(dev))
>>   		ret = __iommu_attach_device(group->domain, dev);
>> +
>> +	/*
>> +	 * Use standard PCI bus topology, isolation features, and DMA
>> +	 * alias quirks to set the immutable singleton attribute. If
>> +	 * the device came from DT, assume it is static and then
>> +	 * singleton can know from the device count in the group.
>> +	 */
>> +	if (dev_is_pci(dev))
>> +		group->immutable_singleton =
>> +				pci_immutably_isolated(to_pci_dev(dev));
>> +	else if (is_of_node(dev_fwnode(dev)))
>> +		group->immutable_singleton =
>> +				(iommu_group_device_count(group) == 1);
>> +
>>   	mutex_unlock(&group->mutex);
>>   	if (ret)
>>   		goto err_put_group;
>> @@ -1290,16 +1347,6 @@ EXPORT_SYMBOL_GPL(iommu_group_id);
>>   static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev,
>>   					       unsigned long *devfns);
>>
>> -/*
>> - * To consider a PCI device isolated, we require ACS to support Source
>> - * Validation, Request Redirection, Completer Redirection, and Upstream
>> - * Forwarding.  This effectively means that devices cannot spoof their
>> - * requester ID, requests and completions cannot be redirected, and all
>> - * transactions are forwarded upstream, even as it passes through a
>> - * bridge where the target device is downstream.
>> - */
>> -#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR |
>> PCI_ACS_UF)
>> -
>>   /*
>>    * For multifunction devices which are not isolated from each other, find
>>    * all the other non-isolated functions and look for existing groups.  For
>> --
>> 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] 64+ messages in thread

* Re: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
  2022-04-12  5:08       ` Lu Baolu
@ 2022-04-12  6:34         ` Yi Liu
  -1 siblings, 0 replies; 64+ messages in thread
From: Yi Liu @ 2022-04-12  6:34 UTC (permalink / raw)
  To: Lu Baolu, Tian, Kevin, Joerg Roedel, Jason Gunthorpe,
	Christoph Hellwig, Raj, Ashok, Will Deacon, Robin Murphy,
	Jean-Philippe Brucker
  Cc: iommu, Pan, Jacob jun, linux-kernel

Hi Baolu,

On 2022/4/12 13:08, Lu Baolu wrote:
> Hi Kevin,
> 
> Thanks for your time.
> 
> On 2022/4/12 11:15, Tian, Kevin wrote:
>>> From: Lu Baolu <baolu.lu@linux.intel.com>
>>> Sent: Sunday, April 10, 2022 6:25 PM
>>>
>>> Some features require that a single device must be immutably isolated,
>>> even when hot plug is supported.
>>
>> This reads confusing, as hotplug cannot be allowed in a singleton group.
>> What you actually meant suppose to be:
>>
>> "Enabling certain device features require the device in a singleton iommu
>> group which is immutable in fabric i.e. not affected by hotplug"
> 
> Yours is better. Thank you.
> 
>>
>>> For example, the SVA bind()/unbind()
>>> interfaces require that the device exists in a singleton group. If we
>>> have a singleton group that doesn't have ACS (or similar technologies)
>>> and someone hotplugs in another device on a bridge, then our SVA is
>>> completely broken and we get data corruption.
>>
>> this needs the background that PASID doesn't join PCI packet routing
>> thus the dma address (CPU VA) may hit a p2p range.
> 
> Sure.
> 
>>
>>>
>>> This adds a flag in the iommu_group struct to indicate an immutable
>>> singleton group, and uses standard PCI bus topology, isolation features,
>>> and DMA alias quirks to set the flag. If the device came from DT, assume
>>> it is static and then the singleton attribute can know from the device
>>> count in the group.
>>
>> where does the assumption come from?
> 
> Hotplug is the only factor that can dynamically affect the
> characteristics of IOMMU group singleton as far as I can see. If a
> device node was created from the DT, it could be treated as static,
> hence we can judge the singleton in iommu probe phase during boot.

not sure if hotplug is the only factor. Is it possible that admin modifies
the ACS configuration on the bridge?

>>
>>>
>>> Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
>>> Suggested-by: Kevin Tian <kevin.tian@intel.com>
>>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>>> ---
>>>   drivers/iommu/iommu.c | 67 ++++++++++++++++++++++++++++++++++++----
>>> ---
>>>   1 file changed, 57 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
>>> index 0c42ece25854..56ffbf5fdc18 100644
>>> --- a/drivers/iommu/iommu.c
>>> +++ b/drivers/iommu/iommu.c
>>> @@ -48,6 +48,7 @@ struct iommu_group {
>>>       struct list_head entry;
>>>       unsigned int owner_cnt;
>>>       void *owner;
>>> +    bool immutable_singleton;
>>
>> Just call it 'singleton' with a comment to explain it must be immutable?
> 
> I was just trying to distinguish "singleton" and "immutable singleton".
> A group is singleton if it only contains a single device in the device
> list, while a group is immutable singleton only if the fabric doesn't
> allow to change the state.
> 
>>
>>>   };
>>>
>>>   struct group_device {
>>> @@ -74,6 +75,16 @@ static const char * const
>>> iommu_group_resv_type_string[] = {
>>>   #define IOMMU_CMD_LINE_DMA_API        BIT(0)
>>>   #define IOMMU_CMD_LINE_STRICT        BIT(1)
>>>
>>> +/*
>>> + * To consider a PCI device isolated, we require ACS to support Source
>>> + * Validation, Request Redirection, Completer Redirection, and Upstream
>>> + * Forwarding.  This effectively means that devices cannot spoof their
>>> + * requester ID, requests and completions cannot be redirected, and all
>>> + * transactions are forwarded upstream, even as it passes through a
>>> + * bridge where the target device is downstream.
>>> + */
>>> +#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR |
>>> PCI_ACS_UF)
>>> +
>>>   static int iommu_alloc_default_domain(struct iommu_group *group,
>>>                         struct device *dev);
>>>   static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
>>> @@ -89,6 +100,7 @@ static int
>>> iommu_create_device_direct_mappings(struct iommu_group *group,
>>>   static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
>>>   static ssize_t iommu_group_store_type(struct iommu_group *group,
>>>                         const char *buf, size_t count);
>>> +static int iommu_group_device_count(struct iommu_group *group);
>>>
>>>   #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store)
>>>     \
>>>   struct iommu_group_attribute iommu_group_attr_##_name =        \
>>> @@ -844,6 +856,37 @@ static bool iommu_is_attach_deferred(struct device
>>> *dev)
>>>       return false;
>>>   }
>>>
>>> +static int has_pci_alias(struct pci_dev *pdev, u16 alias, void *opaque)
>>> +{
>>> +    return -EEXIST;
>>> +}
>>> +
>>> +static bool pci_immutably_isolated(struct pci_dev *pdev)
>>> +{
>>> +    /* Skip the bridges. */
>>> +    if (pci_is_bridge(pdev))
>>> +        return false;
>>> +
>>> +    /*
>>> +     * The device could be considered to be fully isolated if
>>> +     * all devices on the path from the parent to the host-PCI
>>> +     * bridge are protected from peer-to-peer DMA by ACS.
>>> +     */
>>> +    if (!pci_is_root_bus(pdev->bus) &&
>>> +        !pci_acs_path_enabled(pdev->bus->self, NULL, REQ_ACS_FLAGS))
>>> +        return false;
>>> +
>>> +    /* Multi-function devices should have ACS enabled. */
>>> +    if (pdev->multifunction && !pci_acs_enabled(pdev, REQ_ACS_FLAGS))
>>> +        return false;
>>
>> Looks my earlier comment was lost, i.e. you can just use
>> pci_acs_path_enabled(pdev) to cover above two checks.
> 
> If a device is directly connected to the root bridge and it is not an
> MFD, do we still need ACS on it? The Intel idxd device seems to be such
> a device. I had a quick check with lspci, it has no ACS support.
> 
> I probably missed anything.

seems not necessary per my knowledge.

> 
>>
>>> +
>>> +    /* Filter out devices which has any alias device. */
>>> +    if (pci_for_each_dma_alias(pdev, has_pci_alias, NULL))
>>> +        return false;
>>> +
>>> +    return true;
>>> +}
>>> +
>>>   /**
>>>    * iommu_group_add_device - add a device to an iommu group
>>>    * @group: the group into which to add the device (reference should be 
>>> held)
>>> @@ -898,6 +941,20 @@ int iommu_group_add_device(struct iommu_group
>>> *group, struct device *dev)
>>>       list_add_tail(&device->list, &group->devices);
>>>       if (group->domain  && !iommu_is_attach_deferred(dev))
>>>           ret = __iommu_attach_device(group->domain, dev);
>>> +
>>> +    /*
>>> +     * Use standard PCI bus topology, isolation features, and DMA
>>> +     * alias quirks to set the immutable singleton attribute. If
>>> +     * the device came from DT, assume it is static and then
>>> +     * singleton can know from the device count in the group.
>>> +     */
>>> +    if (dev_is_pci(dev))
>>> +        group->immutable_singleton =
>>> +                pci_immutably_isolated(to_pci_dev(dev));
>>> +    else if (is_of_node(dev_fwnode(dev)))
>>> +        group->immutable_singleton =
>>> +                (iommu_group_device_count(group) == 1);
>>> +
>>>       mutex_unlock(&group->mutex);
>>>       if (ret)
>>>           goto err_put_group;
>>> @@ -1290,16 +1347,6 @@ EXPORT_SYMBOL_GPL(iommu_group_id);
>>>   static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev,
>>>                              unsigned long *devfns);
>>>
>>> -/*
>>> - * To consider a PCI device isolated, we require ACS to support Source
>>> - * Validation, Request Redirection, Completer Redirection, and Upstream
>>> - * Forwarding.  This effectively means that devices cannot spoof their
>>> - * requester ID, requests and completions cannot be redirected, and all
>>> - * transactions are forwarded upstream, even as it passes through a
>>> - * bridge where the target device is downstream.
>>> - */
>>> -#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR |
>>> PCI_ACS_UF)
>>> -
>>>   /*
>>>    * For multifunction devices which are not isolated from each other, find
>>>    * all the other non-isolated functions and look for existing groups.  
>>> For
>>> -- 
>>> 2.25.1
>>
> 
> Best regards,
> baolu

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

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

* Re: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
@ 2022-04-12  6:34         ` Yi Liu
  0 siblings, 0 replies; 64+ messages in thread
From: Yi Liu @ 2022-04-12  6:34 UTC (permalink / raw)
  To: Lu Baolu, Tian, Kevin, Joerg Roedel, Jason Gunthorpe,
	Christoph Hellwig, Raj, Ashok, Will Deacon, Robin Murphy,
	Jean-Philippe Brucker
  Cc: Eric Auger, Pan, Jacob jun, iommu, linux-kernel

Hi Baolu,

On 2022/4/12 13:08, Lu Baolu wrote:
> Hi Kevin,
> 
> Thanks for your time.
> 
> On 2022/4/12 11:15, Tian, Kevin wrote:
>>> From: Lu Baolu <baolu.lu@linux.intel.com>
>>> Sent: Sunday, April 10, 2022 6:25 PM
>>>
>>> Some features require that a single device must be immutably isolated,
>>> even when hot plug is supported.
>>
>> This reads confusing, as hotplug cannot be allowed in a singleton group.
>> What you actually meant suppose to be:
>>
>> "Enabling certain device features require the device in a singleton iommu
>> group which is immutable in fabric i.e. not affected by hotplug"
> 
> Yours is better. Thank you.
> 
>>
>>> For example, the SVA bind()/unbind()
>>> interfaces require that the device exists in a singleton group. If we
>>> have a singleton group that doesn't have ACS (or similar technologies)
>>> and someone hotplugs in another device on a bridge, then our SVA is
>>> completely broken and we get data corruption.
>>
>> this needs the background that PASID doesn't join PCI packet routing
>> thus the dma address (CPU VA) may hit a p2p range.
> 
> Sure.
> 
>>
>>>
>>> This adds a flag in the iommu_group struct to indicate an immutable
>>> singleton group, and uses standard PCI bus topology, isolation features,
>>> and DMA alias quirks to set the flag. If the device came from DT, assume
>>> it is static and then the singleton attribute can know from the device
>>> count in the group.
>>
>> where does the assumption come from?
> 
> Hotplug is the only factor that can dynamically affect the
> characteristics of IOMMU group singleton as far as I can see. If a
> device node was created from the DT, it could be treated as static,
> hence we can judge the singleton in iommu probe phase during boot.

not sure if hotplug is the only factor. Is it possible that admin modifies
the ACS configuration on the bridge?

>>
>>>
>>> Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
>>> Suggested-by: Kevin Tian <kevin.tian@intel.com>
>>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>>> ---
>>>   drivers/iommu/iommu.c | 67 ++++++++++++++++++++++++++++++++++++----
>>> ---
>>>   1 file changed, 57 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
>>> index 0c42ece25854..56ffbf5fdc18 100644
>>> --- a/drivers/iommu/iommu.c
>>> +++ b/drivers/iommu/iommu.c
>>> @@ -48,6 +48,7 @@ struct iommu_group {
>>>       struct list_head entry;
>>>       unsigned int owner_cnt;
>>>       void *owner;
>>> +    bool immutable_singleton;
>>
>> Just call it 'singleton' with a comment to explain it must be immutable?
> 
> I was just trying to distinguish "singleton" and "immutable singleton".
> A group is singleton if it only contains a single device in the device
> list, while a group is immutable singleton only if the fabric doesn't
> allow to change the state.
> 
>>
>>>   };
>>>
>>>   struct group_device {
>>> @@ -74,6 +75,16 @@ static const char * const
>>> iommu_group_resv_type_string[] = {
>>>   #define IOMMU_CMD_LINE_DMA_API        BIT(0)
>>>   #define IOMMU_CMD_LINE_STRICT        BIT(1)
>>>
>>> +/*
>>> + * To consider a PCI device isolated, we require ACS to support Source
>>> + * Validation, Request Redirection, Completer Redirection, and Upstream
>>> + * Forwarding.  This effectively means that devices cannot spoof their
>>> + * requester ID, requests and completions cannot be redirected, and all
>>> + * transactions are forwarded upstream, even as it passes through a
>>> + * bridge where the target device is downstream.
>>> + */
>>> +#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR |
>>> PCI_ACS_UF)
>>> +
>>>   static int iommu_alloc_default_domain(struct iommu_group *group,
>>>                         struct device *dev);
>>>   static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
>>> @@ -89,6 +100,7 @@ static int
>>> iommu_create_device_direct_mappings(struct iommu_group *group,
>>>   static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
>>>   static ssize_t iommu_group_store_type(struct iommu_group *group,
>>>                         const char *buf, size_t count);
>>> +static int iommu_group_device_count(struct iommu_group *group);
>>>
>>>   #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store)
>>>     \
>>>   struct iommu_group_attribute iommu_group_attr_##_name =        \
>>> @@ -844,6 +856,37 @@ static bool iommu_is_attach_deferred(struct device
>>> *dev)
>>>       return false;
>>>   }
>>>
>>> +static int has_pci_alias(struct pci_dev *pdev, u16 alias, void *opaque)
>>> +{
>>> +    return -EEXIST;
>>> +}
>>> +
>>> +static bool pci_immutably_isolated(struct pci_dev *pdev)
>>> +{
>>> +    /* Skip the bridges. */
>>> +    if (pci_is_bridge(pdev))
>>> +        return false;
>>> +
>>> +    /*
>>> +     * The device could be considered to be fully isolated if
>>> +     * all devices on the path from the parent to the host-PCI
>>> +     * bridge are protected from peer-to-peer DMA by ACS.
>>> +     */
>>> +    if (!pci_is_root_bus(pdev->bus) &&
>>> +        !pci_acs_path_enabled(pdev->bus->self, NULL, REQ_ACS_FLAGS))
>>> +        return false;
>>> +
>>> +    /* Multi-function devices should have ACS enabled. */
>>> +    if (pdev->multifunction && !pci_acs_enabled(pdev, REQ_ACS_FLAGS))
>>> +        return false;
>>
>> Looks my earlier comment was lost, i.e. you can just use
>> pci_acs_path_enabled(pdev) to cover above two checks.
> 
> If a device is directly connected to the root bridge and it is not an
> MFD, do we still need ACS on it? The Intel idxd device seems to be such
> a device. I had a quick check with lspci, it has no ACS support.
> 
> I probably missed anything.

seems not necessary per my knowledge.

> 
>>
>>> +
>>> +    /* Filter out devices which has any alias device. */
>>> +    if (pci_for_each_dma_alias(pdev, has_pci_alias, NULL))
>>> +        return false;
>>> +
>>> +    return true;
>>> +}
>>> +
>>>   /**
>>>    * iommu_group_add_device - add a device to an iommu group
>>>    * @group: the group into which to add the device (reference should be 
>>> held)
>>> @@ -898,6 +941,20 @@ int iommu_group_add_device(struct iommu_group
>>> *group, struct device *dev)
>>>       list_add_tail(&device->list, &group->devices);
>>>       if (group->domain  && !iommu_is_attach_deferred(dev))
>>>           ret = __iommu_attach_device(group->domain, dev);
>>> +
>>> +    /*
>>> +     * Use standard PCI bus topology, isolation features, and DMA
>>> +     * alias quirks to set the immutable singleton attribute. If
>>> +     * the device came from DT, assume it is static and then
>>> +     * singleton can know from the device count in the group.
>>> +     */
>>> +    if (dev_is_pci(dev))
>>> +        group->immutable_singleton =
>>> +                pci_immutably_isolated(to_pci_dev(dev));
>>> +    else if (is_of_node(dev_fwnode(dev)))
>>> +        group->immutable_singleton =
>>> +                (iommu_group_device_count(group) == 1);
>>> +
>>>       mutex_unlock(&group->mutex);
>>>       if (ret)
>>>           goto err_put_group;
>>> @@ -1290,16 +1347,6 @@ EXPORT_SYMBOL_GPL(iommu_group_id);
>>>   static struct iommu_group *get_pci_alias_group(struct pci_dev *pdev,
>>>                              unsigned long *devfns);
>>>
>>> -/*
>>> - * To consider a PCI device isolated, we require ACS to support Source
>>> - * Validation, Request Redirection, Completer Redirection, and Upstream
>>> - * Forwarding.  This effectively means that devices cannot spoof their
>>> - * requester ID, requests and completions cannot be redirected, and all
>>> - * transactions are forwarded upstream, even as it passes through a
>>> - * bridge where the target device is downstream.
>>> - */
>>> -#define REQ_ACS_FLAGS   (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR |
>>> PCI_ACS_UF)
>>> -
>>>   /*
>>>    * For multifunction devices which are not isolated from each other, find
>>>    * all the other non-isolated functions and look for existing groups.  
>>> For
>>> -- 
>>> 2.25.1
>>
> 
> Best regards,
> baolu

-- 
Regards,
Yi Liu

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

* RE: [PATCH RFC v3 04/12] iommu/sva: Basic data structures for SVA
  2022-04-10 10:24   ` Lu Baolu
@ 2022-04-12  6:49     ` Tian, Kevin
  -1 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12  6:49 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, April 10, 2022 6:25 PM
> 
> Use below data structures for SVA implementation in the IOMMU core:
> 
> - struct iommu_sva_ioas
>   Represent the I/O address space shared with an application CPU address
>   space. This structure has a 1:1 relationship with an mm_struct. It
>   graps a "mm->mm_count" refcount during creation and drop it on release.
> 
> - struct iommu_domain (IOMMU_DOMAIN_SVA type)
>   Represent a hardware pagetable that the IOMMU hardware could use for
>   SVA translation. Multiple iommu domains could be bound with an SVA ioas
>   and each graps a refcount from ioas in order to make sure ioas could
>   only be freed after all domains have been unbound.
> 
> - struct iommu_sva
>   Represent a bond relationship between an SVA ioas and an iommu domain.
>   If a bond already exists, it's reused and a reference is taken.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>

This should be patch07. None of following patches touch those structures
until hitting patch08.
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

* RE: [PATCH RFC v3 04/12] iommu/sva: Basic data structures for SVA
@ 2022-04-12  6:49     ` Tian, Kevin
  0 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12  6:49 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, April 10, 2022 6:25 PM
> 
> Use below data structures for SVA implementation in the IOMMU core:
> 
> - struct iommu_sva_ioas
>   Represent the I/O address space shared with an application CPU address
>   space. This structure has a 1:1 relationship with an mm_struct. It
>   graps a "mm->mm_count" refcount during creation and drop it on release.
> 
> - struct iommu_domain (IOMMU_DOMAIN_SVA type)
>   Represent a hardware pagetable that the IOMMU hardware could use for
>   SVA translation. Multiple iommu domains could be bound with an SVA ioas
>   and each graps a refcount from ioas in order to make sure ioas could
>   only be freed after all domains have been unbound.
> 
> - struct iommu_sva
>   Represent a bond relationship between an SVA ioas and an iommu domain.
>   If a bond already exists, it's reused and a reference is taken.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>

This should be patch07. None of following patches touch those structures
until hitting patch08.

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

* RE: [PATCH RFC v3 04/12] iommu/sva: Basic data structures for SVA
  2022-04-10 10:24   ` Lu Baolu
@ 2022-04-12  6:56     ` Tian, Kevin
  -1 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12  6:56 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, April 10, 2022 6:25 PM
> 
> Use below data structures for SVA implementation in the IOMMU core:
> 
> - struct iommu_sva_ioas
>   Represent the I/O address space shared with an application CPU address
>   space. This structure has a 1:1 relationship with an mm_struct. It
>   graps a "mm->mm_count" refcount during creation and drop it on release.

s/graps/grabs

> 
> - struct iommu_domain (IOMMU_DOMAIN_SVA type)
>   Represent a hardware pagetable that the IOMMU hardware could use for
>   SVA translation. Multiple iommu domains could be bound with an SVA ioas
>   and each graps a refcount from ioas in order to make sure ioas could
>   only be freed after all domains have been unbound.
> 
> - struct iommu_sva
>   Represent a bond relationship between an SVA ioas and an iommu domain.
>   If a bond already exists, it's reused and a reference is taken.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>

btw given the actually intention of above structures does it make more
sense to s/iommu_sva_ioas/iommu_sva/ and s/iommu_sva/iommu_sva_bond?

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

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

* RE: [PATCH RFC v3 04/12] iommu/sva: Basic data structures for SVA
@ 2022-04-12  6:56     ` Tian, Kevin
  0 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12  6:56 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, April 10, 2022 6:25 PM
> 
> Use below data structures for SVA implementation in the IOMMU core:
> 
> - struct iommu_sva_ioas
>   Represent the I/O address space shared with an application CPU address
>   space. This structure has a 1:1 relationship with an mm_struct. It
>   graps a "mm->mm_count" refcount during creation and drop it on release.

s/graps/grabs

> 
> - struct iommu_domain (IOMMU_DOMAIN_SVA type)
>   Represent a hardware pagetable that the IOMMU hardware could use for
>   SVA translation. Multiple iommu domains could be bound with an SVA ioas
>   and each graps a refcount from ioas in order to make sure ioas could
>   only be freed after all domains have been unbound.
> 
> - struct iommu_sva
>   Represent a bond relationship between an SVA ioas and an iommu domain.
>   If a bond already exists, it's reused and a reference is taken.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>

btw given the actually intention of above structures does it make more
sense to s/iommu_sva_ioas/iommu_sva/ and s/iommu_sva/iommu_sva_bond?

Thanks
Kevin

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

* RE: [PATCH RFC v3 08/12] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  2022-04-10 10:24   ` Lu Baolu
@ 2022-04-12  7:19     ` Tian, Kevin
  -1 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12  7:19 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, April 10, 2022 6:25 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;
> +	struct iommu_sva_ioas *ioas;
> +
> +	/*
> +	 * TODO: Remove the drvdata parameter after kernel PASID support
> is
> +	 * enabled for the idxd driver.
> +	 */
> +	if (drvdata)
> +		return ERR_PTR(-EOPNOTSUPP);
> +
> +	/* Allocate mm->pasid if necessary. */
> +	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits)
> - 1);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	mutex_lock(&iommu_sva_lock);
> +	ioas = iommu_sva_ioas_get(mm, mm->pasid);
> +	if (!ioas) {
> +		ret = -ENOMEM;

ioas can be NULL for multiple reasons, e.g. :

1) ioas->mm != mm;
2) kzalloc failure;
3) xa_store failure;

It's more sensible to return error from iommu_sva_ioas_get() directly.

> +		goto out_unlock;
> +	}
> +
> +	/* Search for an existing bond. */
> +	list_for_each_entry(handle, &ioas->bonds, node) {
> +		if (handle->dev == dev) {
> +			refcount_inc(&handle->users);
> +			/* No new bond, drop the counter. */
> +			iommu_sva_ioas_put(ioas);
> +			goto out_success;
> +		}
> +	}
> +
> +	handle = kzalloc(sizeof(*handle), GFP_KERNEL);

s/handle/bond/?

> +	if (!handle) {
> +		ret = -ENOMEM;
> +		goto out_put_ioas;
> +	}
> +
> +	/* The reference to ioas will be kept until domain free. */
> +	domain = iommu_sva_alloc_domain(dev, ioas);

Shouldn't we first try whether existing domains are compatible to this
device?

> @@ -1952,6 +1954,7 @@ EXPORT_SYMBOL_GPL(iommu_domain_alloc);
>  void iommu_domain_free(struct iommu_domain *domain)
>  {
>  	iommu_put_dma_cookie(domain);
> +	iommu_sva_ioas_put(domain->sva_ioas);
>  	domain->ops->free(domain);
>  }

is it good to have general iommu_domain_free() to always call a put()
function for a specific domain type? Why cannot it be done before
calling iommu_domain_free() in sva-lib.c?
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

* RE: [PATCH RFC v3 08/12] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
@ 2022-04-12  7:19     ` Tian, Kevin
  0 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12  7:19 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, April 10, 2022 6:25 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;
> +	struct iommu_sva_ioas *ioas;
> +
> +	/*
> +	 * TODO: Remove the drvdata parameter after kernel PASID support
> is
> +	 * enabled for the idxd driver.
> +	 */
> +	if (drvdata)
> +		return ERR_PTR(-EOPNOTSUPP);
> +
> +	/* Allocate mm->pasid if necessary. */
> +	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits)
> - 1);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	mutex_lock(&iommu_sva_lock);
> +	ioas = iommu_sva_ioas_get(mm, mm->pasid);
> +	if (!ioas) {
> +		ret = -ENOMEM;

ioas can be NULL for multiple reasons, e.g. :

1) ioas->mm != mm;
2) kzalloc failure;
3) xa_store failure;

It's more sensible to return error from iommu_sva_ioas_get() directly.

> +		goto out_unlock;
> +	}
> +
> +	/* Search for an existing bond. */
> +	list_for_each_entry(handle, &ioas->bonds, node) {
> +		if (handle->dev == dev) {
> +			refcount_inc(&handle->users);
> +			/* No new bond, drop the counter. */
> +			iommu_sva_ioas_put(ioas);
> +			goto out_success;
> +		}
> +	}
> +
> +	handle = kzalloc(sizeof(*handle), GFP_KERNEL);

s/handle/bond/?

> +	if (!handle) {
> +		ret = -ENOMEM;
> +		goto out_put_ioas;
> +	}
> +
> +	/* The reference to ioas will be kept until domain free. */
> +	domain = iommu_sva_alloc_domain(dev, ioas);

Shouldn't we first try whether existing domains are compatible to this
device?

> @@ -1952,6 +1954,7 @@ EXPORT_SYMBOL_GPL(iommu_domain_alloc);
>  void iommu_domain_free(struct iommu_domain *domain)
>  {
>  	iommu_put_dma_cookie(domain);
> +	iommu_sva_ioas_put(domain->sva_ioas);
>  	domain->ops->free(domain);
>  }

is it good to have general iommu_domain_free() to always call a put()
function for a specific domain type? Why cannot it be done before
calling iommu_domain_free() in sva-lib.c?

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

* RE: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
  2022-04-12  5:08       ` Lu Baolu
@ 2022-04-12  7:37         ` Tian, Kevin
  -1 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12  7:37 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: Tuesday, April 12, 2022 1:09 PM
> On 2022/4/12 11:15, Tian, Kevin wrote:
> >> From: Lu Baolu <baolu.lu@linux.intel.com>
> >> Sent: Sunday, April 10, 2022 6:25 PM
> >
> >>
> >> This adds a flag in the iommu_group struct to indicate an immutable
> >> singleton group, and uses standard PCI bus topology, isolation features,
> >> and DMA alias quirks to set the flag. If the device came from DT, assume
> >> it is static and then the singleton attribute can know from the device
> >> count in the group.
> >
> > where does the assumption come from?
> 
> Hotplug is the only factor that can dynamically affect the
> characteristics of IOMMU group singleton as far as I can see. If a
> device node was created from the DT, it could be treated as static,
> hence we can judge the singleton in iommu probe phase during boot.

I didn't get this. Let's look at your code in iommu_group_add_device():

 +	else if (is_of_node(dev_fwnode(dev)))
 +		group->immutable_singleton =
 +				(iommu_group_device_count(group) == 1);

Even if there is a multi-devices group above logic will set the flag when
the first device in the group is added since at that time there is only
one device in the group. We need other concrete information  to tell
it similar to how you walk PCI hierarchy to find out the fact... 

> >> +	/*
> >> +	 * The device could be considered to be fully isolated if
> >> +	 * all devices on the path from the parent to the host-PCI
> >> +	 * bridge are protected from peer-to-peer DMA by ACS.
> >> +	 */
> >> +	if (!pci_is_root_bus(pdev->bus) &&
> >> +	    !pci_acs_path_enabled(pdev->bus->self, NULL, REQ_ACS_FLAGS))
> >> +		return false;
> >> +
> >> +	/* Multi-function devices should have ACS enabled. */
> >> +	if (pdev->multifunction && !pci_acs_enabled(pdev, REQ_ACS_FLAGS))
> >> +		return false;
> >
> > Looks my earlier comment was lost, i.e. you can just use
> > pci_acs_path_enabled(pdev) to cover above two checks.
> 
> If a device is directly connected to the root bridge and it is not an
> MFD, do we still need ACS on it? The Intel idxd device seems to be such
> a device. I had a quick check with lspci, it has no ACS support.
> 
> I probably missed anything.
> 

single-function RCiEP doesn't need to implement ACS but this has
been covered by pci_acs_enabled() and pci_acs_path_enabled().
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

* RE: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
@ 2022-04-12  7:37         ` Tian, Kevin
  0 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12  7:37 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: Tuesday, April 12, 2022 1:09 PM
> On 2022/4/12 11:15, Tian, Kevin wrote:
> >> From: Lu Baolu <baolu.lu@linux.intel.com>
> >> Sent: Sunday, April 10, 2022 6:25 PM
> >
> >>
> >> This adds a flag in the iommu_group struct to indicate an immutable
> >> singleton group, and uses standard PCI bus topology, isolation features,
> >> and DMA alias quirks to set the flag. If the device came from DT, assume
> >> it is static and then the singleton attribute can know from the device
> >> count in the group.
> >
> > where does the assumption come from?
> 
> Hotplug is the only factor that can dynamically affect the
> characteristics of IOMMU group singleton as far as I can see. If a
> device node was created from the DT, it could be treated as static,
> hence we can judge the singleton in iommu probe phase during boot.

I didn't get this. Let's look at your code in iommu_group_add_device():

 +	else if (is_of_node(dev_fwnode(dev)))
 +		group->immutable_singleton =
 +				(iommu_group_device_count(group) == 1);

Even if there is a multi-devices group above logic will set the flag when
the first device in the group is added since at that time there is only
one device in the group. We need other concrete information  to tell
it similar to how you walk PCI hierarchy to find out the fact... 

> >> +	/*
> >> +	 * The device could be considered to be fully isolated if
> >> +	 * all devices on the path from the parent to the host-PCI
> >> +	 * bridge are protected from peer-to-peer DMA by ACS.
> >> +	 */
> >> +	if (!pci_is_root_bus(pdev->bus) &&
> >> +	    !pci_acs_path_enabled(pdev->bus->self, NULL, REQ_ACS_FLAGS))
> >> +		return false;
> >> +
> >> +	/* Multi-function devices should have ACS enabled. */
> >> +	if (pdev->multifunction && !pci_acs_enabled(pdev, REQ_ACS_FLAGS))
> >> +		return false;
> >
> > Looks my earlier comment was lost, i.e. you can just use
> > pci_acs_path_enabled(pdev) to cover above two checks.
> 
> If a device is directly connected to the root bridge and it is not an
> MFD, do we still need ACS on it? The Intel idxd device seems to be such
> a device. I had a quick check with lspci, it has no ACS support.
> 
> I probably missed anything.
> 

single-function RCiEP doesn't need to implement ACS but this has
been covered by pci_acs_enabled() and pci_acs_path_enabled().

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

* RE: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
  2022-04-10 10:24   ` Lu Baolu
@ 2022-04-12  7:39     ` Tian, Kevin
  -1 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12  7:39 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, April 10, 2022 6:25 PM
> @@ -898,6 +941,20 @@ int iommu_group_add_device(struct iommu_group
> *group, struct device *dev)
>  	list_add_tail(&device->list, &group->devices);
>  	if (group->domain  && !iommu_is_attach_deferred(dev))
>  		ret = __iommu_attach_device(group->domain, dev);
> +
> +	/*
> +	 * Use standard PCI bus topology, isolation features, and DMA
> +	 * alias quirks to set the immutable singleton attribute. If
> +	 * the device came from DT, assume it is static and then
> +	 * singleton can know from the device count in the group.
> +	 */
> +	if (dev_is_pci(dev))
> +		group->immutable_singleton =
> +				pci_immutably_isolated(to_pci_dev(dev));
> +	else if (is_of_node(dev_fwnode(dev)))
> +		group->immutable_singleton =
> +				(iommu_group_device_count(group) == 1);
> +

btw probably we also want to check when a 2nd device is added
to a group marked as singleton, just in case some weird thing happens?
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

* RE: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
@ 2022-04-12  7:39     ` Tian, Kevin
  0 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12  7:39 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, April 10, 2022 6:25 PM
> @@ -898,6 +941,20 @@ int iommu_group_add_device(struct iommu_group
> *group, struct device *dev)
>  	list_add_tail(&device->list, &group->devices);
>  	if (group->domain  && !iommu_is_attach_deferred(dev))
>  		ret = __iommu_attach_device(group->domain, dev);
> +
> +	/*
> +	 * Use standard PCI bus topology, isolation features, and DMA
> +	 * alias quirks to set the immutable singleton attribute. If
> +	 * the device came from DT, assume it is static and then
> +	 * singleton can know from the device count in the group.
> +	 */
> +	if (dev_is_pci(dev))
> +		group->immutable_singleton =
> +				pci_immutably_isolated(to_pci_dev(dev));
> +	else if (is_of_node(dev_fwnode(dev)))
> +		group->immutable_singleton =
> +				(iommu_group_device_count(group) == 1);
> +

btw probably we also want to check when a 2nd device is added
to a group marked as singleton, just in case some weird thing happens?

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

* Re: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
  2022-04-12  6:34         ` Yi Liu
@ 2022-04-12 11:56           ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-12 11:56 UTC (permalink / raw)
  To: Yi Liu, Tian, Kevin, Joerg Roedel, Jason Gunthorpe,
	Christoph Hellwig, Raj, Ashok, Will Deacon, Robin Murphy,
	Jean-Philippe Brucker
  Cc: iommu, Pan, Jacob jun, linux-kernel

Hi Yi,

On 2022/4/12 14:34, Yi Liu wrote:
>>>
>>>>
>>>> This adds a flag in the iommu_group struct to indicate an immutable
>>>> singleton group, and uses standard PCI bus topology, isolation 
>>>> features,
>>>> and DMA alias quirks to set the flag. If the device came from DT, 
>>>> assume
>>>> it is static and then the singleton attribute can know from the device
>>>> count in the group.
>>>
>>> where does the assumption come from?
>>
>> Hotplug is the only factor that can dynamically affect the
>> characteristics of IOMMU group singleton as far as I can see. If a
>> device node was created from the DT, it could be treated as static,
>> hence we can judge the singleton in iommu probe phase during boot.
> 
> not sure if hotplug is the only factor. Is it possible that admin modifies
> the ACS configuration on the bridge?

Not likely. This will completely change the existing iommu_group
settings.

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

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

* Re: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
@ 2022-04-12 11:56           ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-12 11:56 UTC (permalink / raw)
  To: Yi Liu, Tian, Kevin, Joerg Roedel, Jason Gunthorpe,
	Christoph Hellwig, Raj, Ashok, Will Deacon, Robin Murphy,
	Jean-Philippe Brucker
  Cc: baolu.lu, Eric Auger, Pan, Jacob jun, iommu, linux-kernel

Hi Yi,

On 2022/4/12 14:34, Yi Liu wrote:
>>>
>>>>
>>>> This adds a flag in the iommu_group struct to indicate an immutable
>>>> singleton group, and uses standard PCI bus topology, isolation 
>>>> features,
>>>> and DMA alias quirks to set the flag. If the device came from DT, 
>>>> assume
>>>> it is static and then the singleton attribute can know from the device
>>>> count in the group.
>>>
>>> where does the assumption come from?
>>
>> Hotplug is the only factor that can dynamically affect the
>> characteristics of IOMMU group singleton as far as I can see. If a
>> device node was created from the DT, it could be treated as static,
>> hence we can judge the singleton in iommu probe phase during boot.
> 
> not sure if hotplug is the only factor. Is it possible that admin modifies
> the ACS configuration on the bridge?

Not likely. This will completely change the existing iommu_group
settings.

Best regards,
baolu

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

* Re: [PATCH RFC v3 04/12] iommu/sva: Basic data structures for SVA
  2022-04-12  6:49     ` Tian, Kevin
@ 2022-04-12 11:58       ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-12 11:58 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/4/12 14:49, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Sunday, April 10, 2022 6:25 PM
>>
>> Use below data structures for SVA implementation in the IOMMU core:
>>
>> - struct iommu_sva_ioas
>>    Represent the I/O address space shared with an application CPU address
>>    space. This structure has a 1:1 relationship with an mm_struct. It
>>    graps a "mm->mm_count" refcount during creation and drop it on release.
>>
>> - struct iommu_domain (IOMMU_DOMAIN_SVA type)
>>    Represent a hardware pagetable that the IOMMU hardware could use for
>>    SVA translation. Multiple iommu domains could be bound with an SVA ioas
>>    and each graps a refcount from ioas in order to make sure ioas could
>>    only be freed after all domains have been unbound.
>>
>> - struct iommu_sva
>>    Represent a bond relationship between an SVA ioas and an iommu domain.
>>    If a bond already exists, it's reused and a reference is taken.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> 
> This should be patch07. None of following patches touch those structures
> until hitting patch08.

The iommu_sva_domain_mm() helper will be used in the following patches.

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

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

* Re: [PATCH RFC v3 04/12] iommu/sva: Basic data structures for SVA
@ 2022-04-12 11:58       ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-12 11:58 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/4/12 14:49, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Sunday, April 10, 2022 6:25 PM
>>
>> Use below data structures for SVA implementation in the IOMMU core:
>>
>> - struct iommu_sva_ioas
>>    Represent the I/O address space shared with an application CPU address
>>    space. This structure has a 1:1 relationship with an mm_struct. It
>>    graps a "mm->mm_count" refcount during creation and drop it on release.
>>
>> - struct iommu_domain (IOMMU_DOMAIN_SVA type)
>>    Represent a hardware pagetable that the IOMMU hardware could use for
>>    SVA translation. Multiple iommu domains could be bound with an SVA ioas
>>    and each graps a refcount from ioas in order to make sure ioas could
>>    only be freed after all domains have been unbound.
>>
>> - struct iommu_sva
>>    Represent a bond relationship between an SVA ioas and an iommu domain.
>>    If a bond already exists, it's reused and a reference is taken.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> 
> This should be patch07. None of following patches touch those structures
> until hitting patch08.

The iommu_sva_domain_mm() helper will be used in the following patches.

Best regards,
baolu

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

* Re: [PATCH RFC v3 04/12] iommu/sva: Basic data structures for SVA
  2022-04-12  6:56     ` Tian, Kevin
@ 2022-04-12 12:08       ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-12 12:08 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/4/12 14:56, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Sunday, April 10, 2022 6:25 PM
>>
>> Use below data structures for SVA implementation in the IOMMU core:
>>
>> - struct iommu_sva_ioas
>>    Represent the I/O address space shared with an application CPU address
>>    space. This structure has a 1:1 relationship with an mm_struct. It
>>    graps a "mm->mm_count" refcount during creation and drop it on release.
> 
> s/graps/grabs

Thanks!

> 
>>
>> - struct iommu_domain (IOMMU_DOMAIN_SVA type)
>>    Represent a hardware pagetable that the IOMMU hardware could use for
>>    SVA translation. Multiple iommu domains could be bound with an SVA ioas
>>    and each graps a refcount from ioas in order to make sure ioas could
>>    only be freed after all domains have been unbound.
>>
>> - struct iommu_sva
>>    Represent a bond relationship between an SVA ioas and an iommu domain.
>>    If a bond already exists, it's reused and a reference is taken.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> 
> btw given the actually intention of above structures does it make more
> sense to s/iommu_sva_ioas/iommu_sva/ and s/iommu_sva/iommu_sva_bond?

The use of iommu_sva has been scattered in external files as it's the
return type or parameter of the the iommu sva intefaces:

$ git grep "struct iommu_sva" :^drivers/iommu :^include/linux
drivers/dma/idxd/cdev.c:        struct iommu_sva *sva;
drivers/dma/idxd/cdev.c:        struct iommu_sva *sva;
drivers/dma/idxd/idxd.h:        struct iommu_sva *sva;
drivers/dma/idxd/init.c:        struct iommu_sva *sva;
drivers/misc/uacce/uacce.c:     struct iommu_sva *handle;

Your suggestion makes sense to me as I've also thought about it. :-)
It might be easier to arrive there through a separated cleanup series.

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

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

* Re: [PATCH RFC v3 04/12] iommu/sva: Basic data structures for SVA
@ 2022-04-12 12:08       ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-12 12:08 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/4/12 14:56, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Sunday, April 10, 2022 6:25 PM
>>
>> Use below data structures for SVA implementation in the IOMMU core:
>>
>> - struct iommu_sva_ioas
>>    Represent the I/O address space shared with an application CPU address
>>    space. This structure has a 1:1 relationship with an mm_struct. It
>>    graps a "mm->mm_count" refcount during creation and drop it on release.
> 
> s/graps/grabs

Thanks!

> 
>>
>> - struct iommu_domain (IOMMU_DOMAIN_SVA type)
>>    Represent a hardware pagetable that the IOMMU hardware could use for
>>    SVA translation. Multiple iommu domains could be bound with an SVA ioas
>>    and each graps a refcount from ioas in order to make sure ioas could
>>    only be freed after all domains have been unbound.
>>
>> - struct iommu_sva
>>    Represent a bond relationship between an SVA ioas and an iommu domain.
>>    If a bond already exists, it's reused and a reference is taken.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> 
> btw given the actually intention of above structures does it make more
> sense to s/iommu_sva_ioas/iommu_sva/ and s/iommu_sva/iommu_sva_bond?

The use of iommu_sva has been scattered in external files as it's the
return type or parameter of the the iommu sva intefaces:

$ git grep "struct iommu_sva" :^drivers/iommu :^include/linux
drivers/dma/idxd/cdev.c:        struct iommu_sva *sva;
drivers/dma/idxd/cdev.c:        struct iommu_sva *sva;
drivers/dma/idxd/idxd.h:        struct iommu_sva *sva;
drivers/dma/idxd/init.c:        struct iommu_sva *sva;
drivers/misc/uacce/uacce.c:     struct iommu_sva *handle;

Your suggestion makes sense to me as I've also thought about it. :-)
It might be easier to arrive there through a separated cleanup series.

Best regards,
baolu

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

* Re: [PATCH RFC v3 08/12] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  2022-04-12  7:19     ` Tian, Kevin
@ 2022-04-12 12:53       ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-12 12:53 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/4/12 15:19, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Sunday, April 10, 2022 6:25 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;
>> +	struct iommu_sva_ioas *ioas;
>> +
>> +	/*
>> +	 * TODO: Remove the drvdata parameter after kernel PASID support
>> is
>> +	 * enabled for the idxd driver.
>> +	 */
>> +	if (drvdata)
>> +		return ERR_PTR(-EOPNOTSUPP);
>> +
>> +	/* Allocate mm->pasid if necessary. */
>> +	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits)
>> - 1);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	mutex_lock(&iommu_sva_lock);
>> +	ioas = iommu_sva_ioas_get(mm, mm->pasid);
>> +	if (!ioas) {
>> +		ret = -ENOMEM;
> 
> ioas can be NULL for multiple reasons, e.g. :
> 
> 1) ioas->mm != mm;
> 2) kzalloc failure;
> 3) xa_store failure;
> 
> It's more sensible to return error from iommu_sva_ioas_get() directly.

Fair enough.

> 
>> +		goto out_unlock;
>> +	}
>> +
>> +	/* Search for an existing bond. */
>> +	list_for_each_entry(handle, &ioas->bonds, node) {
>> +		if (handle->dev == dev) {
>> +			refcount_inc(&handle->users);
>> +			/* No new bond, drop the counter. */
>> +			iommu_sva_ioas_put(ioas);
>> +			goto out_success;
>> +		}
>> +	}
>> +
>> +	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
> 
> s/handle/bond/?

"handle" is used in the previous implementation but "bond" looks better
to read. :-)

> 
>> +	if (!handle) {
>> +		ret = -ENOMEM;
>> +		goto out_put_ioas;
>> +	}
>> +
>> +	/* The reference to ioas will be kept until domain free. */
>> +	domain = iommu_sva_alloc_domain(dev, ioas);
> 
> Shouldn't we first try whether existing domains are compatible to this
> device?

If we think that here domain represents a hardware pagetable actually
used by IOMMU for a {device, pasid}, we are able to use per-{device,
pasid} domain without checking compatibility. Sharing a domain among
devices under the same IOMMU may be an optimization. That could be done
in the IOMMU driver just like what vt-d driver is doing for pass-through
DMA domains.

> 
>> @@ -1952,6 +1954,7 @@ EXPORT_SYMBOL_GPL(iommu_domain_alloc);
>>   void iommu_domain_free(struct iommu_domain *domain)
>>   {
>>   	iommu_put_dma_cookie(domain);
>> +	iommu_sva_ioas_put(domain->sva_ioas);
>>   	domain->ops->free(domain);
>>   }
> 
> is it good to have general iommu_domain_free() to always call a put()
> function for a specific domain type? Why cannot it be done before
> calling iommu_domain_free() in sva-lib.c?

It's better to have a generic free() helper since an sva domain could be
freed outside of iommu sva code as you can see in the following patches.

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

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

* Re: [PATCH RFC v3 08/12] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
@ 2022-04-12 12:53       ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-12 12:53 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/4/12 15:19, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Sunday, April 10, 2022 6:25 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;
>> +	struct iommu_sva_ioas *ioas;
>> +
>> +	/*
>> +	 * TODO: Remove the drvdata parameter after kernel PASID support
>> is
>> +	 * enabled for the idxd driver.
>> +	 */
>> +	if (drvdata)
>> +		return ERR_PTR(-EOPNOTSUPP);
>> +
>> +	/* Allocate mm->pasid if necessary. */
>> +	ret = iommu_sva_alloc_pasid(mm, 1, (1U << dev->iommu->pasid_bits)
>> - 1);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	mutex_lock(&iommu_sva_lock);
>> +	ioas = iommu_sva_ioas_get(mm, mm->pasid);
>> +	if (!ioas) {
>> +		ret = -ENOMEM;
> 
> ioas can be NULL for multiple reasons, e.g. :
> 
> 1) ioas->mm != mm;
> 2) kzalloc failure;
> 3) xa_store failure;
> 
> It's more sensible to return error from iommu_sva_ioas_get() directly.

Fair enough.

> 
>> +		goto out_unlock;
>> +	}
>> +
>> +	/* Search for an existing bond. */
>> +	list_for_each_entry(handle, &ioas->bonds, node) {
>> +		if (handle->dev == dev) {
>> +			refcount_inc(&handle->users);
>> +			/* No new bond, drop the counter. */
>> +			iommu_sva_ioas_put(ioas);
>> +			goto out_success;
>> +		}
>> +	}
>> +
>> +	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
> 
> s/handle/bond/?

"handle" is used in the previous implementation but "bond" looks better
to read. :-)

> 
>> +	if (!handle) {
>> +		ret = -ENOMEM;
>> +		goto out_put_ioas;
>> +	}
>> +
>> +	/* The reference to ioas will be kept until domain free. */
>> +	domain = iommu_sva_alloc_domain(dev, ioas);
> 
> Shouldn't we first try whether existing domains are compatible to this
> device?

If we think that here domain represents a hardware pagetable actually
used by IOMMU for a {device, pasid}, we are able to use per-{device,
pasid} domain without checking compatibility. Sharing a domain among
devices under the same IOMMU may be an optimization. That could be done
in the IOMMU driver just like what vt-d driver is doing for pass-through
DMA domains.

> 
>> @@ -1952,6 +1954,7 @@ EXPORT_SYMBOL_GPL(iommu_domain_alloc);
>>   void iommu_domain_free(struct iommu_domain *domain)
>>   {
>>   	iommu_put_dma_cookie(domain);
>> +	iommu_sva_ioas_put(domain->sva_ioas);
>>   	domain->ops->free(domain);
>>   }
> 
> is it good to have general iommu_domain_free() to always call a put()
> function for a specific domain type? Why cannot it be done before
> calling iommu_domain_free() in sva-lib.c?

It's better to have a generic free() helper since an sva domain could be
freed outside of iommu sva code as you can see in the following patches.

Best regards,
baolu

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

* Re: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
  2022-04-12  7:37         ` Tian, Kevin
@ 2022-04-12 13:02           ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-12 13:02 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/4/12 15:37, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Tuesday, April 12, 2022 1:09 PM
>> On 2022/4/12 11:15, Tian, Kevin wrote:
>>>> From: Lu Baolu <baolu.lu@linux.intel.com>
>>>> Sent: Sunday, April 10, 2022 6:25 PM
>>>
>>>>
>>>> This adds a flag in the iommu_group struct to indicate an immutable
>>>> singleton group, and uses standard PCI bus topology, isolation features,
>>>> and DMA alias quirks to set the flag. If the device came from DT, assume
>>>> it is static and then the singleton attribute can know from the device
>>>> count in the group.
>>>
>>> where does the assumption come from?
>>
>> Hotplug is the only factor that can dynamically affect the
>> characteristics of IOMMU group singleton as far as I can see. If a
>> device node was created from the DT, it could be treated as static,
>> hence we can judge the singleton in iommu probe phase during boot.
> 
> I didn't get this. Let's look at your code in iommu_group_add_device():
> 
>   +	else if (is_of_node(dev_fwnode(dev)))
>   +		group->immutable_singleton =
>   +				(iommu_group_device_count(group) == 1);
> 
> Even if there is a multi-devices group above logic will set the flag when
> the first device in the group is added since at that time there is only
> one device in the group. We need other concrete information  to tell
> it similar to how you walk PCI hierarchy to find out the fact...

This is a small trick to make things simpler. Once more devices are
added to the group, the flag will be flipped. All iommu_group's should
be settled down before any drivers start to consume this flag.

> 
>>>> +	/*
>>>> +	 * The device could be considered to be fully isolated if
>>>> +	 * all devices on the path from the parent to the host-PCI
>>>> +	 * bridge are protected from peer-to-peer DMA by ACS.
>>>> +	 */
>>>> +	if (!pci_is_root_bus(pdev->bus) &&
>>>> +	    !pci_acs_path_enabled(pdev->bus->self, NULL, REQ_ACS_FLAGS))
>>>> +		return false;
>>>> +
>>>> +	/* Multi-function devices should have ACS enabled. */
>>>> +	if (pdev->multifunction && !pci_acs_enabled(pdev, REQ_ACS_FLAGS))
>>>> +		return false;
>>>
>>> Looks my earlier comment was lost, i.e. you can just use
>>> pci_acs_path_enabled(pdev) to cover above two checks.
>>
>> If a device is directly connected to the root bridge and it is not an
>> MFD, do we still need ACS on it? The Intel idxd device seems to be such
>> a device. I had a quick check with lspci, it has no ACS support.
>>
>> I probably missed anything.
>>
> 
> single-function RCiEP doesn't need to implement ACS but this has
> been covered by pci_acs_enabled() and pci_acs_path_enabled().

Cool! I missed this part. :-) Thanks a lot.

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

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

* Re: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
@ 2022-04-12 13:02           ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-12 13:02 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/4/12 15:37, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Tuesday, April 12, 2022 1:09 PM
>> On 2022/4/12 11:15, Tian, Kevin wrote:
>>>> From: Lu Baolu <baolu.lu@linux.intel.com>
>>>> Sent: Sunday, April 10, 2022 6:25 PM
>>>
>>>>
>>>> This adds a flag in the iommu_group struct to indicate an immutable
>>>> singleton group, and uses standard PCI bus topology, isolation features,
>>>> and DMA alias quirks to set the flag. If the device came from DT, assume
>>>> it is static and then the singleton attribute can know from the device
>>>> count in the group.
>>>
>>> where does the assumption come from?
>>
>> Hotplug is the only factor that can dynamically affect the
>> characteristics of IOMMU group singleton as far as I can see. If a
>> device node was created from the DT, it could be treated as static,
>> hence we can judge the singleton in iommu probe phase during boot.
> 
> I didn't get this. Let's look at your code in iommu_group_add_device():
> 
>   +	else if (is_of_node(dev_fwnode(dev)))
>   +		group->immutable_singleton =
>   +				(iommu_group_device_count(group) == 1);
> 
> Even if there is a multi-devices group above logic will set the flag when
> the first device in the group is added since at that time there is only
> one device in the group. We need other concrete information  to tell
> it similar to how you walk PCI hierarchy to find out the fact...

This is a small trick to make things simpler. Once more devices are
added to the group, the flag will be flipped. All iommu_group's should
be settled down before any drivers start to consume this flag.

> 
>>>> +	/*
>>>> +	 * The device could be considered to be fully isolated if
>>>> +	 * all devices on the path from the parent to the host-PCI
>>>> +	 * bridge are protected from peer-to-peer DMA by ACS.
>>>> +	 */
>>>> +	if (!pci_is_root_bus(pdev->bus) &&
>>>> +	    !pci_acs_path_enabled(pdev->bus->self, NULL, REQ_ACS_FLAGS))
>>>> +		return false;
>>>> +
>>>> +	/* Multi-function devices should have ACS enabled. */
>>>> +	if (pdev->multifunction && !pci_acs_enabled(pdev, REQ_ACS_FLAGS))
>>>> +		return false;
>>>
>>> Looks my earlier comment was lost, i.e. you can just use
>>> pci_acs_path_enabled(pdev) to cover above two checks.
>>
>> If a device is directly connected to the root bridge and it is not an
>> MFD, do we still need ACS on it? The Intel idxd device seems to be such
>> a device. I had a quick check with lspci, it has no ACS support.
>>
>> I probably missed anything.
>>
> 
> single-function RCiEP doesn't need to implement ACS but this has
> been covered by pci_acs_enabled() and pci_acs_path_enabled().

Cool! I missed this part. :-) Thanks a lot.

Best regards,
baolu

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

* Re: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
  2022-04-12  7:39     ` Tian, Kevin
@ 2022-04-12 13:10       ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-12 13:10 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/4/12 15:39, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Sunday, April 10, 2022 6:25 PM
>> @@ -898,6 +941,20 @@ int iommu_group_add_device(struct iommu_group
>> *group, struct device *dev)
>>   	list_add_tail(&device->list, &group->devices);
>>   	if (group->domain  && !iommu_is_attach_deferred(dev))
>>   		ret = __iommu_attach_device(group->domain, dev);
>> +
>> +	/*
>> +	 * Use standard PCI bus topology, isolation features, and DMA
>> +	 * alias quirks to set the immutable singleton attribute. If
>> +	 * the device came from DT, assume it is static and then
>> +	 * singleton can know from the device count in the group.
>> +	 */
>> +	if (dev_is_pci(dev))
>> +		group->immutable_singleton =
>> +				pci_immutably_isolated(to_pci_dev(dev));
>> +	else if (is_of_node(dev_fwnode(dev)))
>> +		group->immutable_singleton =
>> +				(iommu_group_device_count(group) == 1);
>> +
> 
> btw probably we also want to check when a 2nd device is added
> to a group marked as singleton, just in case some weird thing happens?

It depends on how we judge whether the group to which a DT device
belongs is a singleton. As I explained in another thread, current trick
doesn't support doing this.

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

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

* Re: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
@ 2022-04-12 13:10       ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-12 13:10 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/4/12 15:39, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Sunday, April 10, 2022 6:25 PM
>> @@ -898,6 +941,20 @@ int iommu_group_add_device(struct iommu_group
>> *group, struct device *dev)
>>   	list_add_tail(&device->list, &group->devices);
>>   	if (group->domain  && !iommu_is_attach_deferred(dev))
>>   		ret = __iommu_attach_device(group->domain, dev);
>> +
>> +	/*
>> +	 * Use standard PCI bus topology, isolation features, and DMA
>> +	 * alias quirks to set the immutable singleton attribute. If
>> +	 * the device came from DT, assume it is static and then
>> +	 * singleton can know from the device count in the group.
>> +	 */
>> +	if (dev_is_pci(dev))
>> +		group->immutable_singleton =
>> +				pci_immutably_isolated(to_pci_dev(dev));
>> +	else if (is_of_node(dev_fwnode(dev)))
>> +		group->immutable_singleton =
>> +				(iommu_group_device_count(group) == 1);
>> +
> 
> btw probably we also want to check when a 2nd device is added
> to a group marked as singleton, just in case some weird thing happens?

It depends on how we judge whether the group to which a DT device
belongs is a singleton. As I explained in another thread, current trick
doesn't support doing this.

Best regards,
baolu

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

* RE: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
  2022-04-12 13:02           ` Lu Baolu
@ 2022-04-12 23:32             ` Tian, Kevin
  -1 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12 23:32 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: Tuesday, April 12, 2022 9:03 PM
> 
> On 2022/4/12 15:37, Tian, Kevin wrote:
> >> From: Lu Baolu <baolu.lu@linux.intel.com>
> >> Sent: Tuesday, April 12, 2022 1:09 PM
> >> On 2022/4/12 11:15, Tian, Kevin wrote:
> >>>> From: Lu Baolu <baolu.lu@linux.intel.com>
> >>>> Sent: Sunday, April 10, 2022 6:25 PM
> >>>
> >>>>
> >>>> This adds a flag in the iommu_group struct to indicate an immutable
> >>>> singleton group, and uses standard PCI bus topology, isolation features,
> >>>> and DMA alias quirks to set the flag. If the device came from DT,
> assume
> >>>> it is static and then the singleton attribute can know from the device
> >>>> count in the group.
> >>>
> >>> where does the assumption come from?
> >>
> >> Hotplug is the only factor that can dynamically affect the
> >> characteristics of IOMMU group singleton as far as I can see. If a
> >> device node was created from the DT, it could be treated as static,
> >> hence we can judge the singleton in iommu probe phase during boot.
> >
> > I didn't get this. Let's look at your code in iommu_group_add_device():
> >
> >   +	else if (is_of_node(dev_fwnode(dev)))
> >   +		group->immutable_singleton =
> >   +				(iommu_group_device_count(group) == 1);
> >
> > Even if there is a multi-devices group above logic will set the flag when
> > the first device in the group is added since at that time there is only
> > one device in the group. We need other concrete information  to tell
> > it similar to how you walk PCI hierarchy to find out the fact...
> 
> This is a small trick to make things simpler. Once more devices are
> added to the group, the flag will be flipped. All iommu_group's should
> be settled down before any drivers start to consume this flag.
> 

As an immutable flag it cannot be flipped. What about SVA has been
enabled on the 1st device before the 2nd one is added to the group?
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

* RE: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
@ 2022-04-12 23:32             ` Tian, Kevin
  0 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12 23:32 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: Tuesday, April 12, 2022 9:03 PM
> 
> On 2022/4/12 15:37, Tian, Kevin wrote:
> >> From: Lu Baolu <baolu.lu@linux.intel.com>
> >> Sent: Tuesday, April 12, 2022 1:09 PM
> >> On 2022/4/12 11:15, Tian, Kevin wrote:
> >>>> From: Lu Baolu <baolu.lu@linux.intel.com>
> >>>> Sent: Sunday, April 10, 2022 6:25 PM
> >>>
> >>>>
> >>>> This adds a flag in the iommu_group struct to indicate an immutable
> >>>> singleton group, and uses standard PCI bus topology, isolation features,
> >>>> and DMA alias quirks to set the flag. If the device came from DT,
> assume
> >>>> it is static and then the singleton attribute can know from the device
> >>>> count in the group.
> >>>
> >>> where does the assumption come from?
> >>
> >> Hotplug is the only factor that can dynamically affect the
> >> characteristics of IOMMU group singleton as far as I can see. If a
> >> device node was created from the DT, it could be treated as static,
> >> hence we can judge the singleton in iommu probe phase during boot.
> >
> > I didn't get this. Let's look at your code in iommu_group_add_device():
> >
> >   +	else if (is_of_node(dev_fwnode(dev)))
> >   +		group->immutable_singleton =
> >   +				(iommu_group_device_count(group) == 1);
> >
> > Even if there is a multi-devices group above logic will set the flag when
> > the first device in the group is added since at that time there is only
> > one device in the group. We need other concrete information  to tell
> > it similar to how you walk PCI hierarchy to find out the fact...
> 
> This is a small trick to make things simpler. Once more devices are
> added to the group, the flag will be flipped. All iommu_group's should
> be settled down before any drivers start to consume this flag.
> 

As an immutable flag it cannot be flipped. What about SVA has been
enabled on the 1st device before the 2nd one is added to the group?

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

* RE: [PATCH RFC v3 08/12] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  2022-04-12 12:53       ` Lu Baolu
@ 2022-04-12 23:36         ` Tian, Kevin
  -1 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12 23:36 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: Tuesday, April 12, 2022 8:53 PM
> 
> >
> >> +	if (!handle) {
> >> +		ret = -ENOMEM;
> >> +		goto out_put_ioas;
> >> +	}
> >> +
> >> +	/* The reference to ioas will be kept until domain free. */
> >> +	domain = iommu_sva_alloc_domain(dev, ioas);
> >
> > Shouldn't we first try whether existing domains are compatible to this
> > device?
> 
> If we think that here domain represents a hardware pagetable actually
> used by IOMMU for a {device, pasid}, we are able to use per-{device,
> pasid} domain without checking compatibility. Sharing a domain among
> devices under the same IOMMU may be an optimization. That could be done
> in the IOMMU driver just like what vt-d driver is doing for pass-through
> DMA domains.
> 

there is only one hardware page table per mm in this case. Multiple domains
are required only due to compatibility reason as Jason/Robin pointed out
in SMMU case. Given all other places create multiple domains per ioas only
upon incompatibility, probably it's more consistent to doing so in this path
too...
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

* RE: [PATCH RFC v3 08/12] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
@ 2022-04-12 23:36         ` Tian, Kevin
  0 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-12 23:36 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: Tuesday, April 12, 2022 8:53 PM
> 
> >
> >> +	if (!handle) {
> >> +		ret = -ENOMEM;
> >> +		goto out_put_ioas;
> >> +	}
> >> +
> >> +	/* The reference to ioas will be kept until domain free. */
> >> +	domain = iommu_sva_alloc_domain(dev, ioas);
> >
> > Shouldn't we first try whether existing domains are compatible to this
> > device?
> 
> If we think that here domain represents a hardware pagetable actually
> used by IOMMU for a {device, pasid}, we are able to use per-{device,
> pasid} domain without checking compatibility. Sharing a domain among
> devices under the same IOMMU may be an optimization. That could be done
> in the IOMMU driver just like what vt-d driver is doing for pass-through
> DMA domains.
> 

there is only one hardware page table per mm in this case. Multiple domains
are required only due to compatibility reason as Jason/Robin pointed out
in SMMU case. Given all other places create multiple domains per ioas only
upon incompatibility, probably it's more consistent to doing so in this path
too...

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

* Re: [PATCH RFC v3 08/12] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  2022-04-12 23:36         ` Tian, Kevin
@ 2022-04-13 11:57           ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-13 11:57 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/4/13 7:36, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Tuesday, April 12, 2022 8:53 PM
>>
>>>
>>>> +	if (!handle) {
>>>> +		ret = -ENOMEM;
>>>> +		goto out_put_ioas;
>>>> +	}
>>>> +
>>>> +	/* The reference to ioas will be kept until domain free. */
>>>> +	domain = iommu_sva_alloc_domain(dev, ioas);
>>>
>>> Shouldn't we first try whether existing domains are compatible to this
>>> device?
>>
>> If we think that here domain represents a hardware pagetable actually
>> used by IOMMU for a {device, pasid}, we are able to use per-{device,
>> pasid} domain without checking compatibility. Sharing a domain among
>> devices under the same IOMMU may be an optimization. That could be done
>> in the IOMMU driver just like what vt-d driver is doing for pass-through
>> DMA domains.
>>
> 
> there is only one hardware page table per mm in this case. Multiple domains
> are required only due to compatibility reason as Jason/Robin pointed out
> in SMMU case. Given all other places create multiple domains per ioas only
> upon incompatibility, probably it's more consistent to doing so in this path
> too...

Sharing domain for compatible devices is valuable when the domain
supports map/unmap operations. That can reduce the number of map/unmap
calls and the resulting synchronization of IOTLB. But for SVA case, it's
a dumb domain which only provides attach/detach operations.

A similar case could be found on pass-through DMA domains. The iommu
core allocates a default domain for each group although all the domains
represent a same page table for the compatible devices. The VT-d driver
optimizes this by exporting a static identity domain.

Anyway, I am open for this. I can add a compatible domain list if most
of you like that way. :-)

Best regards,
baolu

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

* Re: [PATCH RFC v3 08/12] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
@ 2022-04-13 11:57           ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-13 11:57 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/4/13 7:36, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Tuesday, April 12, 2022 8:53 PM
>>
>>>
>>>> +	if (!handle) {
>>>> +		ret = -ENOMEM;
>>>> +		goto out_put_ioas;
>>>> +	}
>>>> +
>>>> +	/* The reference to ioas will be kept until domain free. */
>>>> +	domain = iommu_sva_alloc_domain(dev, ioas);
>>>
>>> Shouldn't we first try whether existing domains are compatible to this
>>> device?
>>
>> If we think that here domain represents a hardware pagetable actually
>> used by IOMMU for a {device, pasid}, we are able to use per-{device,
>> pasid} domain without checking compatibility. Sharing a domain among
>> devices under the same IOMMU may be an optimization. That could be done
>> in the IOMMU driver just like what vt-d driver is doing for pass-through
>> DMA domains.
>>
> 
> there is only one hardware page table per mm in this case. Multiple domains
> are required only due to compatibility reason as Jason/Robin pointed out
> in SMMU case. Given all other places create multiple domains per ioas only
> upon incompatibility, probably it's more consistent to doing so in this path
> too...

Sharing domain for compatible devices is valuable when the domain
supports map/unmap operations. That can reduce the number of map/unmap
calls and the resulting synchronization of IOTLB. But for SVA case, it's
a dumb domain which only provides attach/detach operations.

A similar case could be found on pass-through DMA domains. The iommu
core allocates a default domain for each group although all the domains
represent a same page table for the compatible devices. The VT-d driver
optimizes this by exporting a static identity domain.

Anyway, I am open for this. I can add a compatible domain list if most
of you like that way. :-)

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

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

* Re: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
  2022-04-12 23:32             ` Tian, Kevin
@ 2022-04-13 12:02               ` Lu Baolu
  -1 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-13 12:02 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/4/13 7:32, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Tuesday, April 12, 2022 9:03 PM
>>
>> On 2022/4/12 15:37, Tian, Kevin wrote:
>>>> From: Lu Baolu <baolu.lu@linux.intel.com>
>>>> Sent: Tuesday, April 12, 2022 1:09 PM
>>>> On 2022/4/12 11:15, Tian, Kevin wrote:
>>>>>> From: Lu Baolu <baolu.lu@linux.intel.com>
>>>>>> Sent: Sunday, April 10, 2022 6:25 PM
>>>>>
>>>>>>
>>>>>> This adds a flag in the iommu_group struct to indicate an immutable
>>>>>> singleton group, and uses standard PCI bus topology, isolation features,
>>>>>> and DMA alias quirks to set the flag. If the device came from DT,
>> assume
>>>>>> it is static and then the singleton attribute can know from the device
>>>>>> count in the group.
>>>>>
>>>>> where does the assumption come from?
>>>>
>>>> Hotplug is the only factor that can dynamically affect the
>>>> characteristics of IOMMU group singleton as far as I can see. If a
>>>> device node was created from the DT, it could be treated as static,
>>>> hence we can judge the singleton in iommu probe phase during boot.
>>>
>>> I didn't get this. Let's look at your code in iommu_group_add_device():
>>>
>>>    +	else if (is_of_node(dev_fwnode(dev)))
>>>    +		group->immutable_singleton =
>>>    +				(iommu_group_device_count(group) == 1);
>>>
>>> Even if there is a multi-devices group above logic will set the flag when
>>> the first device in the group is added since at that time there is only
>>> one device in the group. We need other concrete information  to tell
>>> it similar to how you walk PCI hierarchy to find out the fact...
>>
>> This is a small trick to make things simpler. Once more devices are
>> added to the group, the flag will be flipped. All iommu_group's should
>> be settled down before any drivers start to consume this flag.
>>
> 
> As an immutable flag it cannot be flipped. What about SVA has been
> enabled on the 1st device before the 2nd one is added to the group?

The flipping happens during iommu probe phase before any device driver
binding. Anyway, I have to agree that it doesn't look clever. :-) Let me
try to figure out another way.

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

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

* Re: [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group
@ 2022-04-13 12:02               ` Lu Baolu
  0 siblings, 0 replies; 64+ messages in thread
From: Lu Baolu @ 2022-04-13 12:02 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/4/13 7:32, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Tuesday, April 12, 2022 9:03 PM
>>
>> On 2022/4/12 15:37, Tian, Kevin wrote:
>>>> From: Lu Baolu <baolu.lu@linux.intel.com>
>>>> Sent: Tuesday, April 12, 2022 1:09 PM
>>>> On 2022/4/12 11:15, Tian, Kevin wrote:
>>>>>> From: Lu Baolu <baolu.lu@linux.intel.com>
>>>>>> Sent: Sunday, April 10, 2022 6:25 PM
>>>>>
>>>>>>
>>>>>> This adds a flag in the iommu_group struct to indicate an immutable
>>>>>> singleton group, and uses standard PCI bus topology, isolation features,
>>>>>> and DMA alias quirks to set the flag. If the device came from DT,
>> assume
>>>>>> it is static and then the singleton attribute can know from the device
>>>>>> count in the group.
>>>>>
>>>>> where does the assumption come from?
>>>>
>>>> Hotplug is the only factor that can dynamically affect the
>>>> characteristics of IOMMU group singleton as far as I can see. If a
>>>> device node was created from the DT, it could be treated as static,
>>>> hence we can judge the singleton in iommu probe phase during boot.
>>>
>>> I didn't get this. Let's look at your code in iommu_group_add_device():
>>>
>>>    +	else if (is_of_node(dev_fwnode(dev)))
>>>    +		group->immutable_singleton =
>>>    +				(iommu_group_device_count(group) == 1);
>>>
>>> Even if there is a multi-devices group above logic will set the flag when
>>> the first device in the group is added since at that time there is only
>>> one device in the group. We need other concrete information  to tell
>>> it similar to how you walk PCI hierarchy to find out the fact...
>>
>> This is a small trick to make things simpler. Once more devices are
>> added to the group, the flag will be flipped. All iommu_group's should
>> be settled down before any drivers start to consume this flag.
>>
> 
> As an immutable flag it cannot be flipped. What about SVA has been
> enabled on the 1st device before the 2nd one is added to the group?

The flipping happens during iommu probe phase before any device driver
binding. Anyway, I have to agree that it doesn't look clever. :-) Let me
try to figure out another way.

Best regards,
baolu

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

* RE: [PATCH RFC v3 08/12] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
  2022-04-13 11:57           ` Lu Baolu
@ 2022-04-14  3:44             ` Tian, Kevin
  -1 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-14  3:44 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: Wednesday, April 13, 2022 7:58 PM
> On 2022/4/13 7:36, Tian, Kevin wrote:
> >> From: Lu Baolu <baolu.lu@linux.intel.com>
> >> Sent: Tuesday, April 12, 2022 8:53 PM
> >>
> >>>
> >>>> +	if (!handle) {
> >>>> +		ret = -ENOMEM;
> >>>> +		goto out_put_ioas;
> >>>> +	}
> >>>> +
> >>>> +	/* The reference to ioas will be kept until domain free. */
> >>>> +	domain = iommu_sva_alloc_domain(dev, ioas);
> >>>
> >>> Shouldn't we first try whether existing domains are compatible to this
> >>> device?
> >>
> >> If we think that here domain represents a hardware pagetable actually
> >> used by IOMMU for a {device, pasid}, we are able to use per-{device,
> >> pasid} domain without checking compatibility. Sharing a domain among
> >> devices under the same IOMMU may be an optimization. That could be
> done
> >> in the IOMMU driver just like what vt-d driver is doing for pass-through
> >> DMA domains.
> >>
> >
> > there is only one hardware page table per mm in this case. Multiple
> domains
> > are required only due to compatibility reason as Jason/Robin pointed out
> > in SMMU case. Given all other places create multiple domains per ioas only
> > upon incompatibility, probably it's more consistent to doing so in this path
> > too...
> 
> Sharing domain for compatible devices is valuable when the domain
> supports map/unmap operations. That can reduce the number of
> map/unmap
> calls and the resulting synchronization of IOTLB. But for SVA case, it's
> a dumb domain which only provides attach/detach operations.
> 
> A similar case could be found on pass-through DMA domains. The iommu
> core allocates a default domain for each group although all the domains
> represent a same page table for the compatible devices. The VT-d driver
> optimizes this by exporting a static identity domain.
> 
> Anyway, I am open for this. I can add a compatible domain list if most
> of you like that way. :-)
> 

This is probably fine as long as such domain is purely dumb. Let's see
whether others have different opinions.

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

* RE: [PATCH RFC v3 08/12] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces
@ 2022-04-14  3:44             ` Tian, Kevin
  0 siblings, 0 replies; 64+ messages in thread
From: Tian, Kevin @ 2022-04-14  3:44 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: Wednesday, April 13, 2022 7:58 PM
> On 2022/4/13 7:36, Tian, Kevin wrote:
> >> From: Lu Baolu <baolu.lu@linux.intel.com>
> >> Sent: Tuesday, April 12, 2022 8:53 PM
> >>
> >>>
> >>>> +	if (!handle) {
> >>>> +		ret = -ENOMEM;
> >>>> +		goto out_put_ioas;
> >>>> +	}
> >>>> +
> >>>> +	/* The reference to ioas will be kept until domain free. */
> >>>> +	domain = iommu_sva_alloc_domain(dev, ioas);
> >>>
> >>> Shouldn't we first try whether existing domains are compatible to this
> >>> device?
> >>
> >> If we think that here domain represents a hardware pagetable actually
> >> used by IOMMU for a {device, pasid}, we are able to use per-{device,
> >> pasid} domain without checking compatibility. Sharing a domain among
> >> devices under the same IOMMU may be an optimization. That could be
> done
> >> in the IOMMU driver just like what vt-d driver is doing for pass-through
> >> DMA domains.
> >>
> >
> > there is only one hardware page table per mm in this case. Multiple
> domains
> > are required only due to compatibility reason as Jason/Robin pointed out
> > in SMMU case. Given all other places create multiple domains per ioas only
> > upon incompatibility, probably it's more consistent to doing so in this path
> > too...
> 
> Sharing domain for compatible devices is valuable when the domain
> supports map/unmap operations. That can reduce the number of
> map/unmap
> calls and the resulting synchronization of IOTLB. But for SVA case, it's
> a dumb domain which only provides attach/detach operations.
> 
> A similar case could be found on pass-through DMA domains. The iommu
> core allocates a default domain for each group although all the domains
> represent a same page table for the compatible devices. The VT-d driver
> optimizes this by exporting a static identity domain.
> 
> Anyway, I am open for this. I can add a compatible domain list if most
> of you like that way. :-)
> 

This is probably fine as long as such domain is purely dumb. Let's see
whether others have different opinions.
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

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

end of thread, other threads:[~2022-04-14  3:45 UTC | newest]

Thread overview: 64+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-10 10:24 [PATCH RFC v3 00/12] iommu: SVA and IOPF refactoring Lu Baolu
2022-04-10 10:24 ` Lu Baolu
2022-04-10 10:24 ` [PATCH RFC v3 01/12] iommu: Add pasid_bits field in struct dev_iommu Lu Baolu
2022-04-10 10:24   ` Lu Baolu
2022-04-10 10:24 ` [PATCH RFC v3 02/12] iommu: Add a flag to indicate immutable singleton group Lu Baolu
2022-04-10 10:24   ` Lu Baolu
2022-04-12  3:15   ` Tian, Kevin
2022-04-12  3:15     ` Tian, Kevin
2022-04-12  5:08     ` Lu Baolu
2022-04-12  5:08       ` Lu Baolu
2022-04-12  6:34       ` Yi Liu
2022-04-12  6:34         ` Yi Liu
2022-04-12 11:56         ` Lu Baolu
2022-04-12 11:56           ` Lu Baolu
2022-04-12  7:37       ` Tian, Kevin
2022-04-12  7:37         ` Tian, Kevin
2022-04-12 13:02         ` Lu Baolu
2022-04-12 13:02           ` Lu Baolu
2022-04-12 23:32           ` Tian, Kevin
2022-04-12 23:32             ` Tian, Kevin
2022-04-13 12:02             ` Lu Baolu
2022-04-13 12:02               ` Lu Baolu
2022-04-12  7:39   ` Tian, Kevin
2022-04-12  7:39     ` Tian, Kevin
2022-04-12 13:10     ` Lu Baolu
2022-04-12 13:10       ` Lu Baolu
2022-04-10 10:24 ` [PATCH RFC v3 03/12] iommu: Add attach/detach_dev_pasid domain ops Lu Baolu
2022-04-10 10:24   ` Lu Baolu
2022-04-10 10:24 ` [PATCH RFC v3 04/12] iommu/sva: Basic data structures for SVA Lu Baolu
2022-04-10 10:24   ` Lu Baolu
2022-04-12  6:49   ` Tian, Kevin
2022-04-12  6:49     ` Tian, Kevin
2022-04-12 11:58     ` Lu Baolu
2022-04-12 11:58       ` Lu Baolu
2022-04-12  6:56   ` Tian, Kevin
2022-04-12  6:56     ` Tian, Kevin
2022-04-12 12:08     ` Lu Baolu
2022-04-12 12:08       ` Lu Baolu
2022-04-10 10:24 ` [PATCH RFC v3 05/12] iommu/vt-d: Remove SVM_FLAG_SUPERVISOR_MODE support Lu Baolu
2022-04-10 10:24   ` Lu Baolu
2022-04-10 10:24 ` [PATCH RFC v3 06/12] iommu/vt-d: Add SVA domain support Lu Baolu
2022-04-10 10:24   ` Lu Baolu
2022-04-10 10:24 ` [PATCH RFC v3 07/12] arm-smmu-v3/sva: " Lu Baolu
2022-04-10 10:24   ` Lu Baolu
2022-04-10 10:24 ` [PATCH RFC v3 08/12] iommu/sva: Use attach/detach_pasid_dev in SVA interfaces Lu Baolu
2022-04-10 10:24   ` Lu Baolu
2022-04-12  7:19   ` Tian, Kevin
2022-04-12  7:19     ` Tian, Kevin
2022-04-12 12:53     ` Lu Baolu
2022-04-12 12:53       ` Lu Baolu
2022-04-12 23:36       ` Tian, Kevin
2022-04-12 23:36         ` Tian, Kevin
2022-04-13 11:57         ` Lu Baolu
2022-04-13 11:57           ` Lu Baolu
2022-04-14  3:44           ` Tian, Kevin
2022-04-14  3:44             ` Tian, Kevin
2022-04-10 10:24 ` [PATCH RFC v3 09/12] iommu: Remove SVA related callbacks from iommu ops Lu Baolu
2022-04-10 10:24   ` Lu Baolu
2022-04-10 10:24 ` [PATCH RFC v3 10/12] iommu: Prepare IOMMU domain for IOPF Lu Baolu
2022-04-10 10:24   ` Lu Baolu
2022-04-10 10:24 ` [PATCH RFC v3 11/12] iommu: Per-domain I/O page fault handling Lu Baolu
2022-04-10 10:24   ` Lu Baolu
2022-04-10 10:24 ` [PATCH RFC v3 12/12] iommu: Rename iommu-sva-lib.{c,h} Lu Baolu
2022-04-10 10:24   ` 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.