public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6] iommu: Enable user space IOPFs in non-nested and non-svm cases
@ 2024-09-04 13:17 Joel Granados via B4 Relay
  2024-09-04 13:17 ` [PATCH 1/6] iommu/vt-d: Separate page request queue from SVM Joel Granados via B4 Relay
                   ` (5 more replies)
  0 siblings, 6 replies; 24+ messages in thread
From: Joel Granados via B4 Relay @ 2024-09-04 13:17 UTC (permalink / raw)
  To: David Woodhouse, Lu Baolu, Joerg Roedel, Will Deacon,
	Robin Murphy, Jason Gunthorpe, Kevin Tian, Klaus Jensen
  Cc: linux-kernel, iommu, Joel Granados, Klaus Jensen

This series makes use of iommufd_hwpt_replace_device to execute
non-nested and non-svm user space IOPFs. Our main motivation is to
enable user-space driver driven device verification without PASID,
nesting nor SVM.

What?
  * Enable IO page fault handling in user space for a non-nested,
    non-svm and non-virtualised use case.
  * Move IOMMU_IOPF configuration from INTEL_IOMMU_SVM into INTEL_IOMMU.
  * Move all page request queue related logic to a new (prq.c) file.
  * Remove PASID checks from PRQ event handling as well as PRQ
    initialization.
  * Allow execution of IOMMU_HWPT_ALLOC with a valid fault id
    (IOMMU_HWPT_FAULT_ID_VALID)
  * Insert a zero handle into the PASID array in dev->iommu_group when
    replacing the old HWPT with an IOPF enabled HWPT.

Why?
  The PCI ATS Extended Capability allows peripheral devices to
  participate in the caching of translations when operating under an
  IOMMU. Further, the ATS Page Request Interface (PRI) Extension allows
  devices to handle missing mappings. Currently, PRI is mainly used in
  the context of Shared Virtual Addressing, requiring support for the
  Process Address Space Identifier (PASID) capability, but other use
  cases such as enabling user-space driver driven device verification
  and reducing memory pinning exists. This patchest sets out to enable
  these use cases.

Testing?
  The non-nested/non-svm IOPF interface is exercised by first
  initializing an IOPF enabled IOAS and then reading the fault file
  descriptor. Pseudocode on the iopf initializing and handling is in [3]
  and [4] (using libvfn).

  Supplementary repositories supporting this patchset:
    1. A user space library libvfn [1] which is used for testing and
       verification (see examples/iopf.c), and
    2. Basic emulation of PCIe ATS/PRI and Intel VT-d PRQ in QEMU [2].

V1:
  * This is the first version of the series after initial feedback from
    the RFC [5].

Comments and feedback are greatly appreciated
Best

Joel

[1] https://github.com/SamsungDS/libvfn/tree/iommufd-fault-queue
[2] https://gitlab.com/birkelund/qemu/-/tree/pcie-ats-pri

[3] Initializing
```
  int iopf_init(struct iommu_ioas *ioas, const char *bdf)
  {
      // open vfio device from bdf
      int devfd = open('/dev/vfio/devices/VFIO_DEV', O_RDWR);

      struct vfio_device_bind_iommufd bind = {
          .argsz = sizeof(bind),
          .flags = 0,
          .iommufd = __iommufd,
      };
      ioctl(devfd, VFIO_DEVICE_BIND_IOMMUFD, &bind);

      struct iommu_ioas *ioas = ioas;
      struct vfio_device_attach_iommufd_pt attach_data = {
          .argsz = sizeof(attach_data),
          .flags = 0,
          .pt_id = ioas->id,
      };
      ioctl(devfd, VFIO_DEVICE_ATTACH_IOMMUFD_PT, &attach_data);

      struct iommu_fault_alloc fault = {
          .size = sizeof(fault),
          .flags = 0,
      };
      ioctl(__iommufd, IOMMU_FAULT_QUEUE_ALLOC, &fault);

      struct iommu_hwpt_alloc fault_cmd = {
          .size = sizeof(fault_cmd),
          .flags = IOMMU_HWPT_FAULT_ID_VALID,
          .dev_id = bind.out_devid,
          .pt_id = ioas->id,
          .data_len = 0,
          .data_uptr = (uint64_t)NULL,
          .fault_id = fault.out_fault_id,
          .__reserved = 0,
          };
      ioctl(__iommufd, IOMMU_HWPT_ALLOC, &fault_cmd);

      // This is a re-attach
      struct vfio_device_attach_iommufd_pt attach = {
          .argsz = sizeof(attach),
          .flags = 0,
          .pt_id = fault_cmd.out_hwpt_id
      };
      ioctl(dev_fd, VFIO_DEVICE_ATTACH_IOMMUFD_PT, &attach);
  }
```

[4] Handling
```
  int handle_iopf(void *vaddr, int len, uint64_t iova) {
    exec_command(CMD)

    int iopf_fd = fault_cmd.fault_id;

    struct iommu_hwpt_pgfault pgfault = {0};
    if(read(iopf_fd, &pgfault, sizeof(pgfault)) == 0);
      return; // no page fault

    ret = iommu_map_vaddr(__iommmufd, vaddr, len, &iova)
    struct iommu_hwpt_page_response pgfault_response = {
      .cookie = pgfault.cookie,
      .code = ret ? IOMMUFD_PAGE_RESP_SUCCESS : IOMMUFD_PAGE_RESP_INVALID,
    };

    write(iopf_fd, &pgfault_response, sizeof(pgfault_response));

    return;
  }
```

[5] https://lore.kernel.org/20240826-iopf-for-all-v1-0-59174e6a7528@samsung.com

Signed-off-by: Joel Granados <j.granados@samsung.com>
---
Joel Granados (4):
      iommu/vt-d: Separate page request queue from SVM
      iommu: kconfig: Move IOMMU_IOPF into INTEL_IOMMU
      iommufd: Enable PRI when doing the iommufd_hwpt_alloc
      iommu: init pasid array while doing domain_replace and iopf is active

Klaus Jensen (2):
      iommu/vt-d: Remove the pasid present check in prq_event_thread
      iommu/vt-d: drop pasid requirement for prq initialization

 drivers/iommu/intel/Kconfig          |   2 +-
 drivers/iommu/intel/Makefile         |   2 +-
 drivers/iommu/intel/iommu.c          |  29 +--
 drivers/iommu/intel/iommu.h          |  14 +-
 drivers/iommu/intel/prq.c            | 404 +++++++++++++++++++++++++++++++++++
 drivers/iommu/intel/svm.c            | 397 ----------------------------------
 drivers/iommu/iommu-priv.h           |   3 +
 drivers/iommu/iommu.c                |  30 +++
 drivers/iommu/iommufd/fault.c        |  22 ++
 drivers/iommu/iommufd/hw_pagetable.c |   3 +-
 10 files changed, 480 insertions(+), 426 deletions(-)
---
base-commit: 431c1646e1f86b949fa3685efc50b660a364c2b6
change-id: 20240904-jag-iopfv8-1577fd20422d

Best regards,
-- 
Joel Granados <j.granados@samsung.com>



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

* [PATCH 1/6] iommu/vt-d: Separate page request queue from SVM
  2024-09-04 13:17 [PATCH 0/6] iommu: Enable user space IOPFs in non-nested and non-svm cases Joel Granados via B4 Relay
@ 2024-09-04 13:17 ` Joel Granados via B4 Relay
  2024-09-05  3:18   ` Baolu Lu
  2024-09-04 13:17 ` [PATCH 2/6] iommu/vt-d: Remove the pasid present check in prq_event_thread Joel Granados via B4 Relay
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 24+ messages in thread
From: Joel Granados via B4 Relay @ 2024-09-04 13:17 UTC (permalink / raw)
  To: David Woodhouse, Lu Baolu, Joerg Roedel, Will Deacon,
	Robin Murphy, Jason Gunthorpe, Kevin Tian, Klaus Jensen
  Cc: linux-kernel, iommu, Joel Granados

From: Joel Granados <j.granados@samsung.com>

IO page faults are no longer dependent on CONFIG_INTEL_IOMMU_SVM. Move
all Page Request Queue (PRQ) functions that handle prq events to a new
file in drivers/iommu/intel/prq.c. The page_req_des struct is made
available in drivers/iommu/intel/iommu.h.

No functional changes are intended. This is a preparation patch to
enable the use of IO page faults outside the SVM and nested use cases.

Signed-off-by: Joel Granados <j.granados@samsung.com>
---
 drivers/iommu/intel/Makefile |   2 +-
 drivers/iommu/intel/iommu.c  |  18 +-
 drivers/iommu/intel/iommu.h  |  14 +-
 drivers/iommu/intel/prq.c    | 410 +++++++++++++++++++++++++++++++++++++++++++
 drivers/iommu/intel/svm.c    | 397 -----------------------------------------
 5 files changed, 423 insertions(+), 418 deletions(-)

diff --git a/drivers/iommu/intel/Makefile b/drivers/iommu/intel/Makefile
index c8beb0281559..d3bb0798092d 100644
--- a/drivers/iommu/intel/Makefile
+++ b/drivers/iommu/intel/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_DMAR_TABLE) += dmar.o
-obj-$(CONFIG_INTEL_IOMMU) += iommu.o pasid.o nested.o cache.o
+obj-$(CONFIG_INTEL_IOMMU) += iommu.o pasid.o nested.o cache.o prq.o
 obj-$(CONFIG_DMAR_TABLE) += trace.o cap_audit.o
 obj-$(CONFIG_DMAR_PERF) += perf.o
 obj-$(CONFIG_INTEL_IOMMU_DEBUGFS) += debugfs.o
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 4aa070cf56e7..5acc52c62e8c 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -1487,12 +1487,10 @@ static void free_dmar_iommu(struct intel_iommu *iommu)
 	/* free context mapping */
 	free_context_table(iommu);
 
-#ifdef CONFIG_INTEL_IOMMU_SVM
 	if (pasid_supported(iommu)) {
 		if (ecap_prs(iommu->ecap))
-			intel_svm_finish_prq(iommu);
+			intel_finish_prq(iommu);
 	}
-#endif
 }
 
 /*
@@ -2482,19 +2480,18 @@ static int __init init_dmars(void)
 
 		iommu_flush_write_buffer(iommu);
 
-#ifdef CONFIG_INTEL_IOMMU_SVM
 		if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) {
 			/*
 			 * Call dmar_alloc_hwirq() with dmar_global_lock held,
 			 * could cause possible lock race condition.
 			 */
 			up_write(&dmar_global_lock);
-			ret = intel_svm_enable_prq(iommu);
+			ret = intel_enable_prq(iommu);
 			down_write(&dmar_global_lock);
 			if (ret)
 				goto free_iommu;
 		}
-#endif
+
 		ret = dmar_set_interrupt(iommu);
 		if (ret)
 			goto free_iommu;
@@ -2924,13 +2921,12 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru)
 	intel_iommu_init_qi(iommu);
 	iommu_flush_write_buffer(iommu);
 
-#ifdef CONFIG_INTEL_IOMMU_SVM
 	if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) {
-		ret = intel_svm_enable_prq(iommu);
+		ret = intel_enable_prq(iommu);
 		if (ret)
 			goto disable_iommu;
 	}
-#endif
+
 	ret = dmar_set_interrupt(iommu);
 	if (ret)
 		goto disable_iommu;
@@ -4673,9 +4669,7 @@ const struct iommu_ops intel_iommu_ops = {
 	.def_domain_type	= device_def_domain_type,
 	.remove_dev_pasid	= intel_iommu_remove_dev_pasid,
 	.pgsize_bitmap		= SZ_4K,
-#ifdef CONFIG_INTEL_IOMMU_SVM
-	.page_response		= intel_svm_page_response,
-#endif
+	.page_response		= intel_page_response,
 	.default_domain_ops = &(const struct iommu_domain_ops) {
 		.attach_dev		= intel_iommu_attach_device,
 		.set_dev_pasid		= intel_iommu_set_dev_pasid,
diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index a969be2258b1..3bce514e1d88 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -719,12 +719,10 @@ struct intel_iommu {
 
 	struct iommu_flush flush;
 #endif
-#ifdef CONFIG_INTEL_IOMMU_SVM
 	struct page_req_dsc *prq;
 	unsigned char prq_name[16];    /* Name for PRQ interrupt */
 	unsigned long prq_seq_number;
 	struct completion prq_complete;
-#endif
 	struct iopf_queue *iopf_queue;
 	unsigned char iopfq_name[16];
 	/* Synchronization between fault report and iommu device release. */
@@ -1156,18 +1154,18 @@ void intel_context_flush_present(struct device_domain_info *info,
 				 struct context_entry *context,
 				 u16 did, bool affect_domains);
 
+int intel_enable_prq(struct intel_iommu *iommu);
+int intel_finish_prq(struct intel_iommu *iommu);
+void intel_page_response(struct device *dev, struct iopf_fault *evt,
+			struct iommu_page_response *msg);
+void intel_drain_pasid_prq(struct device *dev, u32 pasid);
+
 #ifdef CONFIG_INTEL_IOMMU_SVM
 void intel_svm_check(struct intel_iommu *iommu);
-int intel_svm_enable_prq(struct intel_iommu *iommu);
-int intel_svm_finish_prq(struct intel_iommu *iommu);
-void intel_svm_page_response(struct device *dev, struct iopf_fault *evt,
-			     struct iommu_page_response *msg);
 struct iommu_domain *intel_svm_domain_alloc(struct device *dev,
 					    struct mm_struct *mm);
-void intel_drain_pasid_prq(struct device *dev, u32 pasid);
 #else
 static inline void intel_svm_check(struct intel_iommu *iommu) {}
-static inline void intel_drain_pasid_prq(struct device *dev, u32 pasid) {}
 static inline struct iommu_domain *intel_svm_domain_alloc(struct device *dev,
 							  struct mm_struct *mm)
 {
diff --git a/drivers/iommu/intel/prq.c b/drivers/iommu/intel/prq.c
new file mode 100644
index 000000000000..3376f60082b5
--- /dev/null
+++ b/drivers/iommu/intel/prq.c
@@ -0,0 +1,410 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright © 2015 Intel Corporation.
+ *
+ * Originally split from drivers/iommu/intel/svm.c
+ */
+
+#include <linux/pci.h>
+#include <linux/pci-ats.h>
+
+#include "iommu.h"
+#include "../iommu-pages.h"
+#include "trace.h"
+
+/* Page request queue descriptor */
+struct page_req_dsc {
+	union {
+		struct {
+			u64 type:8;
+			u64 pasid_present:1;
+			u64 rsvd:7;
+			u64 rid:16;
+			u64 pasid:20;
+			u64 exe_req:1;
+			u64 pm_req:1;
+			u64 rsvd2:10;
+		};
+		u64 qw_0;
+	};
+	union {
+		struct {
+			u64 rd_req:1;
+			u64 wr_req:1;
+			u64 lpig:1;
+			u64 prg_index:9;
+			u64 addr:52;
+		};
+		u64 qw_1;
+	};
+	u64 qw_2;
+	u64 qw_3;
+};
+
+/**
+ * intel_drain_pasid_prq - Drain page requests and responses for a pasid
+ * @dev: target device
+ * @pasid: pasid for draining
+ *
+ * Drain all pending page requests and responses related to @pasid in both
+ * software and hardware. This is supposed to be called after the device
+ * driver has stopped DMA, the pasid entry has been cleared, and both IOTLB
+ * and DevTLB have been invalidated.
+ *
+ * It waits until all pending page requests for @pasid in the page fault
+ * queue are completed by the prq handling thread. Then follow the steps
+ * described in VT-d spec CH7.10 to drain all page requests and page
+ * responses pending in the hardware.
+ */
+void intel_drain_pasid_prq(struct device *dev, u32 pasid)
+{
+	struct device_domain_info *info;
+	struct dmar_domain *domain;
+	struct intel_iommu *iommu;
+	struct qi_desc desc[3];
+	struct pci_dev *pdev;
+	int head, tail;
+	u16 sid, did;
+	int qdep;
+
+	info = dev_iommu_priv_get(dev);
+	if (WARN_ON(!info || !dev_is_pci(dev)))
+		return;
+
+	if (!info->pri_enabled)
+		return;
+
+	iommu = info->iommu;
+	domain = info->domain;
+	pdev = to_pci_dev(dev);
+	sid = PCI_DEVID(info->bus, info->devfn);
+	did = domain_id_iommu(domain, iommu);
+	qdep = pci_ats_queue_depth(pdev);
+
+	/*
+	 * Check and wait until all pending page requests in the queue are
+	 * handled by the prq handling thread.
+	 */
+prq_retry:
+	reinit_completion(&iommu->prq_complete);
+	tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK;
+	head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK;
+	while (head != tail) {
+		struct page_req_dsc *req;
+
+		req = &iommu->prq[head / sizeof(*req)];
+		if (!req->pasid_present || req->pasid != pasid) {
+			head = (head + sizeof(*req)) & PRQ_RING_MASK;
+			continue;
+		}
+
+		wait_for_completion(&iommu->prq_complete);
+		goto prq_retry;
+	}
+
+	iopf_queue_flush_dev(dev);
+
+	/*
+	 * Perform steps described in VT-d spec CH7.10 to drain page
+	 * requests and responses in hardware.
+	 */
+	memset(desc, 0, sizeof(desc));
+	desc[0].qw0 = QI_IWD_STATUS_DATA(QI_DONE) |
+			QI_IWD_FENCE |
+			QI_IWD_TYPE;
+	desc[1].qw0 = QI_EIOTLB_PASID(pasid) |
+			QI_EIOTLB_DID(did) |
+			QI_EIOTLB_GRAN(QI_GRAN_NONG_PASID) |
+			QI_EIOTLB_TYPE;
+	desc[2].qw0 = QI_DEV_EIOTLB_PASID(pasid) |
+			QI_DEV_EIOTLB_SID(sid) |
+			QI_DEV_EIOTLB_QDEP(qdep) |
+			QI_DEIOTLB_TYPE |
+			QI_DEV_IOTLB_PFSID(info->pfsid);
+qi_retry:
+	reinit_completion(&iommu->prq_complete);
+	qi_submit_sync(iommu, desc, 3, QI_OPT_WAIT_DRAIN);
+	if (readl(iommu->reg + DMAR_PRS_REG) & DMA_PRS_PRO) {
+		wait_for_completion(&iommu->prq_complete);
+		goto qi_retry;
+	}
+}
+
+
+static bool is_canonical_address(u64 addr)
+{
+	int shift = 64 - (__VIRTUAL_MASK_SHIFT + 1);
+	long saddr = (long) addr;
+
+	return (((saddr << shift) >> shift) == saddr);
+}
+
+static void handle_bad_prq_event(struct intel_iommu *iommu,
+				 struct page_req_dsc *req, int result)
+{
+	struct qi_desc desc = { };
+
+	pr_err("%s: Invalid page request: %08llx %08llx\n",
+	       iommu->name, ((unsigned long long *)req)[0],
+	       ((unsigned long long *)req)[1]);
+
+	if (!req->lpig)
+		return;
+
+	desc.qw0 = QI_PGRP_PASID(req->pasid) |
+			QI_PGRP_DID(req->rid) |
+			QI_PGRP_PASID_P(req->pasid_present) |
+			QI_PGRP_RESP_CODE(result) |
+			QI_PGRP_RESP_TYPE;
+	desc.qw1 = QI_PGRP_IDX(req->prg_index) |
+			QI_PGRP_LPIG(req->lpig);
+
+	qi_submit_sync(iommu, &desc, 1, 0);
+}
+
+static int prq_to_iommu_prot(struct page_req_dsc *req)
+{
+	int prot = 0;
+
+	if (req->rd_req)
+		prot |= IOMMU_FAULT_PERM_READ;
+	if (req->wr_req)
+		prot |= IOMMU_FAULT_PERM_WRITE;
+	if (req->exe_req)
+		prot |= IOMMU_FAULT_PERM_EXEC;
+	if (req->pm_req)
+		prot |= IOMMU_FAULT_PERM_PRIV;
+
+	return prot;
+}
+
+static void intel_prq_report(struct intel_iommu *iommu, struct device *dev,
+				 struct page_req_dsc *desc)
+{
+	struct iopf_fault event = { };
+
+	/* Fill in event data for device specific processing */
+	event.fault.type = IOMMU_FAULT_PAGE_REQ;
+	event.fault.prm.addr = (u64)desc->addr << VTD_PAGE_SHIFT;
+	event.fault.prm.pasid = desc->pasid;
+	event.fault.prm.grpid = desc->prg_index;
+	event.fault.prm.perm = prq_to_iommu_prot(desc);
+
+	if (desc->lpig)
+		event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE;
+	if (desc->pasid_present) {
+		event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
+		event.fault.prm.flags |= IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID;
+	}
+
+	iommu_report_device_fault(dev, &event);
+}
+
+static irqreturn_t prq_event_thread(int irq, void *d)
+{
+	struct intel_iommu *iommu = d;
+	struct page_req_dsc *req;
+	int head, tail, handled;
+	struct device *dev;
+	u64 address;
+
+	/*
+	 * Clear PPR bit before reading head/tail registers, to ensure that
+	 * we get a new interrupt if needed.
+	 */
+	writel(DMA_PRS_PPR, iommu->reg + DMAR_PRS_REG);
+
+	tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK;
+	head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK;
+	handled = (head != tail);
+	while (head != tail) {
+		req = &iommu->prq[head / sizeof(*req)];
+		address = (u64)req->addr << VTD_PAGE_SHIFT;
+
+		if (unlikely(!req->pasid_present)) {
+			pr_err("IOMMU: %s: Page request without PASID\n",
+			       iommu->name);
+bad_req:
+			handle_bad_prq_event(iommu, req, QI_RESP_INVALID);
+			goto prq_advance;
+		}
+
+		if (unlikely(!is_canonical_address(address))) {
+			pr_err("IOMMU: %s: Address is not canonical\n",
+			       iommu->name);
+			goto bad_req;
+		}
+
+		if (unlikely(req->pm_req && (req->rd_req | req->wr_req))) {
+			pr_err("IOMMU: %s: Page request in Privilege Mode\n",
+			       iommu->name);
+			goto bad_req;
+		}
+
+		if (unlikely(req->exe_req && req->rd_req)) {
+			pr_err("IOMMU: %s: Execution request not supported\n",
+			       iommu->name);
+			goto bad_req;
+		}
+
+		/* Drop Stop Marker message. No need for a response. */
+		if (unlikely(req->lpig && !req->rd_req && !req->wr_req))
+			goto prq_advance;
+
+		/*
+		 * If prq is to be handled outside iommu driver via receiver of
+		 * the fault notifiers, we skip the page response here.
+		 */
+		mutex_lock(&iommu->iopf_lock);
+		dev = device_rbtree_find(iommu, req->rid);
+		if (!dev) {
+			mutex_unlock(&iommu->iopf_lock);
+			goto bad_req;
+		}
+
+		intel_prq_report(iommu, dev, req);
+		trace_prq_report(iommu, dev, req->qw_0, req->qw_1,
+				 req->qw_2, req->qw_3,
+				 iommu->prq_seq_number++);
+		mutex_unlock(&iommu->iopf_lock);
+prq_advance:
+		head = (head + sizeof(*req)) & PRQ_RING_MASK;
+	}
+
+	dmar_writeq(iommu->reg + DMAR_PQH_REG, tail);
+
+	/*
+	 * Clear the page request overflow bit and wake up all threads that
+	 * are waiting for the completion of this handling.
+	 */
+	if (readl(iommu->reg + DMAR_PRS_REG) & DMA_PRS_PRO) {
+		pr_info_ratelimited("IOMMU: %s: PRQ overflow detected\n",
+				    iommu->name);
+		head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK;
+		tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK;
+		if (head == tail) {
+			iopf_queue_discard_partial(iommu->iopf_queue);
+			writel(DMA_PRS_PRO, iommu->reg + DMAR_PRS_REG);
+			pr_info_ratelimited("IOMMU: %s: PRQ overflow cleared",
+					    iommu->name);
+		}
+	}
+
+	if (!completion_done(&iommu->prq_complete))
+		complete(&iommu->prq_complete);
+
+	return IRQ_RETVAL(handled);
+}
+
+int intel_enable_prq(struct intel_iommu *iommu)
+{
+	struct iopf_queue *iopfq;
+	int irq, ret;
+
+	iommu->prq = iommu_alloc_pages_node(iommu->node, GFP_KERNEL, PRQ_ORDER);
+	if (!iommu->prq) {
+		pr_warn("IOMMU: %s: Failed to allocate page request queue\n",
+			iommu->name);
+		return -ENOMEM;
+	}
+
+	irq = dmar_alloc_hwirq(IOMMU_IRQ_ID_OFFSET_PRQ + iommu->seq_id, iommu->node, iommu);
+	if (irq <= 0) {
+		pr_err("IOMMU: %s: Failed to create IRQ vector for page request queue\n",
+		       iommu->name);
+		ret = -EINVAL;
+		goto free_prq;
+	}
+	iommu->pr_irq = irq;
+
+	snprintf(iommu->iopfq_name, sizeof(iommu->iopfq_name),
+		 "dmar%d-iopfq", iommu->seq_id);
+	iopfq = iopf_queue_alloc(iommu->iopfq_name);
+	if (!iopfq) {
+		pr_err("IOMMU: %s: Failed to allocate iopf queue\n", iommu->name);
+		ret = -ENOMEM;
+		goto free_hwirq;
+	}
+	iommu->iopf_queue = iopfq;
+
+	snprintf(iommu->prq_name, sizeof(iommu->prq_name), "dmar%d-prq", iommu->seq_id);
+
+	ret = request_threaded_irq(irq, NULL, prq_event_thread, IRQF_ONESHOT,
+				   iommu->prq_name, iommu);
+	if (ret) {
+		pr_err("IOMMU: %s: Failed to request IRQ for page request queue\n",
+		       iommu->name);
+		goto free_iopfq;
+	}
+	dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL);
+	dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL);
+	dmar_writeq(iommu->reg + DMAR_PQA_REG, virt_to_phys(iommu->prq) | PRQ_ORDER);
+
+	init_completion(&iommu->prq_complete);
+
+	return 0;
+
+free_iopfq:
+	iopf_queue_free(iommu->iopf_queue);
+	iommu->iopf_queue = NULL;
+free_hwirq:
+	dmar_free_hwirq(irq);
+	iommu->pr_irq = 0;
+free_prq:
+	iommu_free_pages(iommu->prq, PRQ_ORDER);
+	iommu->prq = NULL;
+
+	return ret;
+}
+
+int intel_finish_prq(struct intel_iommu *iommu)
+{
+	dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL);
+	dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL);
+	dmar_writeq(iommu->reg + DMAR_PQA_REG, 0ULL);
+
+	if (iommu->pr_irq) {
+		free_irq(iommu->pr_irq, iommu);
+		dmar_free_hwirq(iommu->pr_irq);
+		iommu->pr_irq = 0;
+	}
+
+	if (iommu->iopf_queue) {
+		iopf_queue_free(iommu->iopf_queue);
+		iommu->iopf_queue = NULL;
+	}
+
+	iommu_free_pages(iommu->prq, PRQ_ORDER);
+	iommu->prq = NULL;
+
+	return 0;
+}
+
+void intel_page_response(struct device *dev, struct iopf_fault *evt,
+			 struct iommu_page_response *msg)
+{
+	struct device_domain_info *info = dev_iommu_priv_get(dev);
+	struct intel_iommu *iommu = info->iommu;
+	u8 bus = info->bus, devfn = info->devfn;
+	struct iommu_fault_page_request *prm;
+	struct qi_desc desc;
+	bool pasid_present;
+	bool last_page;
+	u16 sid;
+
+	prm = &evt->fault.prm;
+	sid = PCI_DEVID(bus, devfn);
+	pasid_present = prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
+	last_page = prm->flags & IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE;
+
+	desc.qw0 = QI_PGRP_PASID(prm->pasid) | QI_PGRP_DID(sid) |
+			QI_PGRP_PASID_P(pasid_present) |
+			QI_PGRP_RESP_CODE(msg->code) |
+			QI_PGRP_RESP_TYPE;
+	desc.qw1 = QI_PGRP_IDX(prm->grpid) | QI_PGRP_LPIG(last_page);
+	desc.qw2 = 0;
+	desc.qw3 = 0;
+
+	qi_submit_sync(iommu, &desc, 1, 0);
+}
+
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index 0e3a9b38bef2..6ab7d9d03d3d 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -25,92 +25,6 @@
 #include "../iommu-pages.h"
 #include "trace.h"
 
-static irqreturn_t prq_event_thread(int irq, void *d);
-
-int intel_svm_enable_prq(struct intel_iommu *iommu)
-{
-	struct iopf_queue *iopfq;
-	int irq, ret;
-
-	iommu->prq = iommu_alloc_pages_node(iommu->node, GFP_KERNEL, PRQ_ORDER);
-	if (!iommu->prq) {
-		pr_warn("IOMMU: %s: Failed to allocate page request queue\n",
-			iommu->name);
-		return -ENOMEM;
-	}
-
-	irq = dmar_alloc_hwirq(IOMMU_IRQ_ID_OFFSET_PRQ + iommu->seq_id, iommu->node, iommu);
-	if (irq <= 0) {
-		pr_err("IOMMU: %s: Failed to create IRQ vector for page request queue\n",
-		       iommu->name);
-		ret = -EINVAL;
-		goto free_prq;
-	}
-	iommu->pr_irq = irq;
-
-	snprintf(iommu->iopfq_name, sizeof(iommu->iopfq_name),
-		 "dmar%d-iopfq", iommu->seq_id);
-	iopfq = iopf_queue_alloc(iommu->iopfq_name);
-	if (!iopfq) {
-		pr_err("IOMMU: %s: Failed to allocate iopf queue\n", iommu->name);
-		ret = -ENOMEM;
-		goto free_hwirq;
-	}
-	iommu->iopf_queue = iopfq;
-
-	snprintf(iommu->prq_name, sizeof(iommu->prq_name), "dmar%d-prq", iommu->seq_id);
-
-	ret = request_threaded_irq(irq, NULL, prq_event_thread, IRQF_ONESHOT,
-				   iommu->prq_name, iommu);
-	if (ret) {
-		pr_err("IOMMU: %s: Failed to request IRQ for page request queue\n",
-		       iommu->name);
-		goto free_iopfq;
-	}
-	dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL);
-	dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL);
-	dmar_writeq(iommu->reg + DMAR_PQA_REG, virt_to_phys(iommu->prq) | PRQ_ORDER);
-
-	init_completion(&iommu->prq_complete);
-
-	return 0;
-
-free_iopfq:
-	iopf_queue_free(iommu->iopf_queue);
-	iommu->iopf_queue = NULL;
-free_hwirq:
-	dmar_free_hwirq(irq);
-	iommu->pr_irq = 0;
-free_prq:
-	iommu_free_pages(iommu->prq, PRQ_ORDER);
-	iommu->prq = NULL;
-
-	return ret;
-}
-
-int intel_svm_finish_prq(struct intel_iommu *iommu)
-{
-	dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL);
-	dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL);
-	dmar_writeq(iommu->reg + DMAR_PQA_REG, 0ULL);
-
-	if (iommu->pr_irq) {
-		free_irq(iommu->pr_irq, iommu);
-		dmar_free_hwirq(iommu->pr_irq);
-		iommu->pr_irq = 0;
-	}
-
-	if (iommu->iopf_queue) {
-		iopf_queue_free(iommu->iopf_queue);
-		iommu->iopf_queue = NULL;
-	}
-
-	iommu_free_pages(iommu->prq, PRQ_ORDER);
-	iommu->prq = NULL;
-
-	return 0;
-}
-
 void intel_svm_check(struct intel_iommu *iommu)
 {
 	if (!pasid_supported(iommu))
@@ -237,317 +151,6 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
 	return ret;
 }
 
-/* Page request queue descriptor */
-struct page_req_dsc {
-	union {
-		struct {
-			u64 type:8;
-			u64 pasid_present:1;
-			u64 rsvd:7;
-			u64 rid:16;
-			u64 pasid:20;
-			u64 exe_req:1;
-			u64 pm_req:1;
-			u64 rsvd2:10;
-		};
-		u64 qw_0;
-	};
-	union {
-		struct {
-			u64 rd_req:1;
-			u64 wr_req:1;
-			u64 lpig:1;
-			u64 prg_index:9;
-			u64 addr:52;
-		};
-		u64 qw_1;
-	};
-	u64 qw_2;
-	u64 qw_3;
-};
-
-static bool is_canonical_address(u64 addr)
-{
-	int shift = 64 - (__VIRTUAL_MASK_SHIFT + 1);
-	long saddr = (long) addr;
-
-	return (((saddr << shift) >> shift) == saddr);
-}
-
-/**
- * intel_drain_pasid_prq - Drain page requests and responses for a pasid
- * @dev: target device
- * @pasid: pasid for draining
- *
- * Drain all pending page requests and responses related to @pasid in both
- * software and hardware. This is supposed to be called after the device
- * driver has stopped DMA, the pasid entry has been cleared, and both IOTLB
- * and DevTLB have been invalidated.
- *
- * It waits until all pending page requests for @pasid in the page fault
- * queue are completed by the prq handling thread. Then follow the steps
- * described in VT-d spec CH7.10 to drain all page requests and page
- * responses pending in the hardware.
- */
-void intel_drain_pasid_prq(struct device *dev, u32 pasid)
-{
-	struct device_domain_info *info;
-	struct dmar_domain *domain;
-	struct intel_iommu *iommu;
-	struct qi_desc desc[3];
-	struct pci_dev *pdev;
-	int head, tail;
-	u16 sid, did;
-	int qdep;
-
-	info = dev_iommu_priv_get(dev);
-	if (WARN_ON(!info || !dev_is_pci(dev)))
-		return;
-
-	if (!info->pri_enabled)
-		return;
-
-	iommu = info->iommu;
-	domain = info->domain;
-	pdev = to_pci_dev(dev);
-	sid = PCI_DEVID(info->bus, info->devfn);
-	did = domain_id_iommu(domain, iommu);
-	qdep = pci_ats_queue_depth(pdev);
-
-	/*
-	 * Check and wait until all pending page requests in the queue are
-	 * handled by the prq handling thread.
-	 */
-prq_retry:
-	reinit_completion(&iommu->prq_complete);
-	tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK;
-	head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK;
-	while (head != tail) {
-		struct page_req_dsc *req;
-
-		req = &iommu->prq[head / sizeof(*req)];
-		if (!req->pasid_present || req->pasid != pasid) {
-			head = (head + sizeof(*req)) & PRQ_RING_MASK;
-			continue;
-		}
-
-		wait_for_completion(&iommu->prq_complete);
-		goto prq_retry;
-	}
-
-	iopf_queue_flush_dev(dev);
-
-	/*
-	 * Perform steps described in VT-d spec CH7.10 to drain page
-	 * requests and responses in hardware.
-	 */
-	memset(desc, 0, sizeof(desc));
-	desc[0].qw0 = QI_IWD_STATUS_DATA(QI_DONE) |
-			QI_IWD_FENCE |
-			QI_IWD_TYPE;
-	desc[1].qw0 = QI_EIOTLB_PASID(pasid) |
-			QI_EIOTLB_DID(did) |
-			QI_EIOTLB_GRAN(QI_GRAN_NONG_PASID) |
-			QI_EIOTLB_TYPE;
-	desc[2].qw0 = QI_DEV_EIOTLB_PASID(pasid) |
-			QI_DEV_EIOTLB_SID(sid) |
-			QI_DEV_EIOTLB_QDEP(qdep) |
-			QI_DEIOTLB_TYPE |
-			QI_DEV_IOTLB_PFSID(info->pfsid);
-qi_retry:
-	reinit_completion(&iommu->prq_complete);
-	qi_submit_sync(iommu, desc, 3, QI_OPT_WAIT_DRAIN);
-	if (readl(iommu->reg + DMAR_PRS_REG) & DMA_PRS_PRO) {
-		wait_for_completion(&iommu->prq_complete);
-		goto qi_retry;
-	}
-}
-
-static int prq_to_iommu_prot(struct page_req_dsc *req)
-{
-	int prot = 0;
-
-	if (req->rd_req)
-		prot |= IOMMU_FAULT_PERM_READ;
-	if (req->wr_req)
-		prot |= IOMMU_FAULT_PERM_WRITE;
-	if (req->exe_req)
-		prot |= IOMMU_FAULT_PERM_EXEC;
-	if (req->pm_req)
-		prot |= IOMMU_FAULT_PERM_PRIV;
-
-	return prot;
-}
-
-static void intel_svm_prq_report(struct intel_iommu *iommu, struct device *dev,
-				 struct page_req_dsc *desc)
-{
-	struct iopf_fault event = { };
-
-	/* Fill in event data for device specific processing */
-	event.fault.type = IOMMU_FAULT_PAGE_REQ;
-	event.fault.prm.addr = (u64)desc->addr << VTD_PAGE_SHIFT;
-	event.fault.prm.pasid = desc->pasid;
-	event.fault.prm.grpid = desc->prg_index;
-	event.fault.prm.perm = prq_to_iommu_prot(desc);
-
-	if (desc->lpig)
-		event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE;
-	if (desc->pasid_present) {
-		event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
-		event.fault.prm.flags |= IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID;
-	}
-
-	iommu_report_device_fault(dev, &event);
-}
-
-static void handle_bad_prq_event(struct intel_iommu *iommu,
-				 struct page_req_dsc *req, int result)
-{
-	struct qi_desc desc = { };
-
-	pr_err("%s: Invalid page request: %08llx %08llx\n",
-	       iommu->name, ((unsigned long long *)req)[0],
-	       ((unsigned long long *)req)[1]);
-
-	if (!req->lpig)
-		return;
-
-	desc.qw0 = QI_PGRP_PASID(req->pasid) |
-			QI_PGRP_DID(req->rid) |
-			QI_PGRP_PASID_P(req->pasid_present) |
-			QI_PGRP_RESP_CODE(result) |
-			QI_PGRP_RESP_TYPE;
-	desc.qw1 = QI_PGRP_IDX(req->prg_index) |
-			QI_PGRP_LPIG(req->lpig);
-
-	qi_submit_sync(iommu, &desc, 1, 0);
-}
-
-static irqreturn_t prq_event_thread(int irq, void *d)
-{
-	struct intel_iommu *iommu = d;
-	struct page_req_dsc *req;
-	int head, tail, handled;
-	struct device *dev;
-	u64 address;
-
-	/*
-	 * Clear PPR bit before reading head/tail registers, to ensure that
-	 * we get a new interrupt if needed.
-	 */
-	writel(DMA_PRS_PPR, iommu->reg + DMAR_PRS_REG);
-
-	tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK;
-	head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK;
-	handled = (head != tail);
-	while (head != tail) {
-		req = &iommu->prq[head / sizeof(*req)];
-		address = (u64)req->addr << VTD_PAGE_SHIFT;
-
-		if (unlikely(!req->pasid_present)) {
-			pr_err("IOMMU: %s: Page request without PASID\n",
-			       iommu->name);
-bad_req:
-			handle_bad_prq_event(iommu, req, QI_RESP_INVALID);
-			goto prq_advance;
-		}
-
-		if (unlikely(!is_canonical_address(address))) {
-			pr_err("IOMMU: %s: Address is not canonical\n",
-			       iommu->name);
-			goto bad_req;
-		}
-
-		if (unlikely(req->pm_req && (req->rd_req | req->wr_req))) {
-			pr_err("IOMMU: %s: Page request in Privilege Mode\n",
-			       iommu->name);
-			goto bad_req;
-		}
-
-		if (unlikely(req->exe_req && req->rd_req)) {
-			pr_err("IOMMU: %s: Execution request not supported\n",
-			       iommu->name);
-			goto bad_req;
-		}
-
-		/* Drop Stop Marker message. No need for a response. */
-		if (unlikely(req->lpig && !req->rd_req && !req->wr_req))
-			goto prq_advance;
-
-		/*
-		 * If prq is to be handled outside iommu driver via receiver of
-		 * the fault notifiers, we skip the page response here.
-		 */
-		mutex_lock(&iommu->iopf_lock);
-		dev = device_rbtree_find(iommu, req->rid);
-		if (!dev) {
-			mutex_unlock(&iommu->iopf_lock);
-			goto bad_req;
-		}
-
-		intel_svm_prq_report(iommu, dev, req);
-		trace_prq_report(iommu, dev, req->qw_0, req->qw_1,
-				 req->qw_2, req->qw_3,
-				 iommu->prq_seq_number++);
-		mutex_unlock(&iommu->iopf_lock);
-prq_advance:
-		head = (head + sizeof(*req)) & PRQ_RING_MASK;
-	}
-
-	dmar_writeq(iommu->reg + DMAR_PQH_REG, tail);
-
-	/*
-	 * Clear the page request overflow bit and wake up all threads that
-	 * are waiting for the completion of this handling.
-	 */
-	if (readl(iommu->reg + DMAR_PRS_REG) & DMA_PRS_PRO) {
-		pr_info_ratelimited("IOMMU: %s: PRQ overflow detected\n",
-				    iommu->name);
-		head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK;
-		tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK;
-		if (head == tail) {
-			iopf_queue_discard_partial(iommu->iopf_queue);
-			writel(DMA_PRS_PRO, iommu->reg + DMAR_PRS_REG);
-			pr_info_ratelimited("IOMMU: %s: PRQ overflow cleared",
-					    iommu->name);
-		}
-	}
-
-	if (!completion_done(&iommu->prq_complete))
-		complete(&iommu->prq_complete);
-
-	return IRQ_RETVAL(handled);
-}
-
-void intel_svm_page_response(struct device *dev, struct iopf_fault *evt,
-			     struct iommu_page_response *msg)
-{
-	struct device_domain_info *info = dev_iommu_priv_get(dev);
-	struct intel_iommu *iommu = info->iommu;
-	u8 bus = info->bus, devfn = info->devfn;
-	struct iommu_fault_page_request *prm;
-	struct qi_desc desc;
-	bool pasid_present;
-	bool last_page;
-	u16 sid;
-
-	prm = &evt->fault.prm;
-	sid = PCI_DEVID(bus, devfn);
-	pasid_present = prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
-	last_page = prm->flags & IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE;
-
-	desc.qw0 = QI_PGRP_PASID(prm->pasid) | QI_PGRP_DID(sid) |
-			QI_PGRP_PASID_P(pasid_present) |
-			QI_PGRP_RESP_CODE(msg->code) |
-			QI_PGRP_RESP_TYPE;
-	desc.qw1 = QI_PGRP_IDX(prm->grpid) | QI_PGRP_LPIG(last_page);
-	desc.qw2 = 0;
-	desc.qw3 = 0;
-
-	qi_submit_sync(iommu, &desc, 1, 0);
-}
-
 static void intel_svm_domain_free(struct iommu_domain *domain)
 {
 	struct dmar_domain *dmar_domain = to_dmar_domain(domain);

-- 
2.43.0



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

* [PATCH 2/6] iommu/vt-d: Remove the pasid present check in prq_event_thread
  2024-09-04 13:17 [PATCH 0/6] iommu: Enable user space IOPFs in non-nested and non-svm cases Joel Granados via B4 Relay
  2024-09-04 13:17 ` [PATCH 1/6] iommu/vt-d: Separate page request queue from SVM Joel Granados via B4 Relay
@ 2024-09-04 13:17 ` Joel Granados via B4 Relay
  2024-09-04 13:17 ` [PATCH 3/6] iommu: kconfig: Move IOMMU_IOPF into INTEL_IOMMU Joel Granados via B4 Relay
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 24+ messages in thread
From: Joel Granados via B4 Relay @ 2024-09-04 13:17 UTC (permalink / raw)
  To: David Woodhouse, Lu Baolu, Joerg Roedel, Will Deacon,
	Robin Murphy, Jason Gunthorpe, Kevin Tian, Klaus Jensen
  Cc: linux-kernel, iommu, Joel Granados, Klaus Jensen

From: Klaus Jensen <k.jensen@samsung.com>

PASID is not strictly needed when handling a PRQ event; remove the check
for the pasid present bit in the request. This change was not included
in the creation of prq.c to emphasize the change in capability checks
when handing PRQ events.

Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Signed-off-by: Joel Granados <j.granados@samsung.com>
---
 drivers/iommu/intel/prq.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/drivers/iommu/intel/prq.c b/drivers/iommu/intel/prq.c
index 3376f60082b5..5f2d01a9aa11 100644
--- a/drivers/iommu/intel/prq.c
+++ b/drivers/iommu/intel/prq.c
@@ -221,18 +221,12 @@ static irqreturn_t prq_event_thread(int irq, void *d)
 		req = &iommu->prq[head / sizeof(*req)];
 		address = (u64)req->addr << VTD_PAGE_SHIFT;
 
-		if (unlikely(!req->pasid_present)) {
-			pr_err("IOMMU: %s: Page request without PASID\n",
-			       iommu->name);
-bad_req:
-			handle_bad_prq_event(iommu, req, QI_RESP_INVALID);
-			goto prq_advance;
-		}
-
 		if (unlikely(!is_canonical_address(address))) {
 			pr_err("IOMMU: %s: Address is not canonical\n",
 			       iommu->name);
-			goto bad_req;
+bad_req:
+			handle_bad_prq_event(iommu, req, QI_RESP_INVALID);
+			goto prq_advance;
 		}
 
 		if (unlikely(req->pm_req && (req->rd_req | req->wr_req))) {

-- 
2.43.0



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

* [PATCH 3/6] iommu: kconfig: Move IOMMU_IOPF into INTEL_IOMMU
  2024-09-04 13:17 [PATCH 0/6] iommu: Enable user space IOPFs in non-nested and non-svm cases Joel Granados via B4 Relay
  2024-09-04 13:17 ` [PATCH 1/6] iommu/vt-d: Separate page request queue from SVM Joel Granados via B4 Relay
  2024-09-04 13:17 ` [PATCH 2/6] iommu/vt-d: Remove the pasid present check in prq_event_thread Joel Granados via B4 Relay
@ 2024-09-04 13:17 ` Joel Granados via B4 Relay
  2024-09-07 12:20   ` Jason Gunthorpe
  2024-09-04 13:17 ` [PATCH 4/6] iommufd: Enable PRI when doing the iommufd_hwpt_alloc Joel Granados via B4 Relay
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 24+ messages in thread
From: Joel Granados via B4 Relay @ 2024-09-04 13:17 UTC (permalink / raw)
  To: David Woodhouse, Lu Baolu, Joerg Roedel, Will Deacon,
	Robin Murphy, Jason Gunthorpe, Kevin Tian, Klaus Jensen
  Cc: linux-kernel, iommu, Joel Granados

From: Joel Granados <j.granados@samsung.com>

Move IOMMU_IOPF from under INTEL_IOMMU_SVM into INTEL_IOMMU. This
certifies that the core intel iommu utilizes the IOPF library
functions, independent of the INTEL_IOMMU_SVM config.

Signed-off-by: Joel Granados <j.granados@samsung.com>
---
 drivers/iommu/intel/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/intel/Kconfig b/drivers/iommu/intel/Kconfig
index f52fb39c968e..2888671c9278 100644
--- a/drivers/iommu/intel/Kconfig
+++ b/drivers/iommu/intel/Kconfig
@@ -15,6 +15,7 @@ config INTEL_IOMMU
 	select DMA_OPS
 	select IOMMU_API
 	select IOMMU_IOVA
+	select IOMMU_IOPF
 	select IOMMUFD_DRIVER if IOMMUFD
 	select NEED_DMA_MAP_STATE
 	select DMAR_TABLE
@@ -51,7 +52,6 @@ config INTEL_IOMMU_SVM
 	depends on X86_64
 	select MMU_NOTIFIER
 	select IOMMU_SVA
-	select IOMMU_IOPF
 	help
 	  Shared Virtual Memory (SVM) provides a facility for devices
 	  to access DMA resources through process address space by

-- 
2.43.0



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

* [PATCH 4/6] iommufd: Enable PRI when doing the iommufd_hwpt_alloc
  2024-09-04 13:17 [PATCH 0/6] iommu: Enable user space IOPFs in non-nested and non-svm cases Joel Granados via B4 Relay
                   ` (2 preceding siblings ...)
  2024-09-04 13:17 ` [PATCH 3/6] iommu: kconfig: Move IOMMU_IOPF into INTEL_IOMMU Joel Granados via B4 Relay
@ 2024-09-04 13:17 ` Joel Granados via B4 Relay
  2024-09-04 13:17 ` [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active Joel Granados via B4 Relay
  2024-09-04 13:17 ` [PATCH 6/6] iommu/vt-d: drop pasid requirement for prq initialization Joel Granados via B4 Relay
  5 siblings, 0 replies; 24+ messages in thread
From: Joel Granados via B4 Relay @ 2024-09-04 13:17 UTC (permalink / raw)
  To: David Woodhouse, Lu Baolu, Joerg Roedel, Will Deacon,
	Robin Murphy, Jason Gunthorpe, Kevin Tian, Klaus Jensen
  Cc: linux-kernel, iommu, Joel Granados

From: Joel Granados <j.granados@samsung.com>

Add IOMMU_HWPT_FAULT_ID_VALID as part of the valid flags when doing an
iommufd_hwpt_alloc allowing the use of an iommu fault allocation
(iommu_fault_alloc) with the IOMMU_HWPT_ALLOC ioctl.

Signed-off-by: Joel Granados <j.granados@samsung.com>
---
 drivers/iommu/intel/iommu.c          | 3 ++-
 drivers/iommu/iommufd/hw_pagetable.c | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 5acc52c62e8c..3d1c971eb9e5 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -3718,7 +3718,8 @@ intel_iommu_domain_alloc_user(struct device *dev, u32 flags,
 	}
 
 	if (flags &
-	    (~(IOMMU_HWPT_ALLOC_NEST_PARENT | IOMMU_HWPT_ALLOC_DIRTY_TRACKING)))
+	    (~(IOMMU_HWPT_ALLOC_NEST_PARENT | IOMMU_HWPT_ALLOC_DIRTY_TRACKING
+	       | IOMMU_HWPT_FAULT_ID_VALID)))
 		return ERR_PTR(-EOPNOTSUPP);
 	if (nested_parent && !nested_supported(iommu))
 		return ERR_PTR(-EOPNOTSUPP);
diff --git a/drivers/iommu/iommufd/hw_pagetable.c b/drivers/iommu/iommufd/hw_pagetable.c
index aefde4443671..88074e459995 100644
--- a/drivers/iommu/iommufd/hw_pagetable.c
+++ b/drivers/iommu/iommufd/hw_pagetable.c
@@ -107,7 +107,8 @@ iommufd_hwpt_paging_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
 			  const struct iommu_user_data *user_data)
 {
 	const u32 valid_flags = IOMMU_HWPT_ALLOC_NEST_PARENT |
-				IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
+				IOMMU_HWPT_ALLOC_DIRTY_TRACKING |
+				IOMMU_HWPT_FAULT_ID_VALID;
 	const struct iommu_ops *ops = dev_iommu_ops(idev->dev);
 	struct iommufd_hwpt_paging *hwpt_paging;
 	struct iommufd_hw_pagetable *hwpt;

-- 
2.43.0



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

* [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active
  2024-09-04 13:17 [PATCH 0/6] iommu: Enable user space IOPFs in non-nested and non-svm cases Joel Granados via B4 Relay
                   ` (3 preceding siblings ...)
  2024-09-04 13:17 ` [PATCH 4/6] iommufd: Enable PRI when doing the iommufd_hwpt_alloc Joel Granados via B4 Relay
@ 2024-09-04 13:17 ` Joel Granados via B4 Relay
  2024-09-05  3:30   ` Baolu Lu
  2024-09-04 13:17 ` [PATCH 6/6] iommu/vt-d: drop pasid requirement for prq initialization Joel Granados via B4 Relay
  5 siblings, 1 reply; 24+ messages in thread
From: Joel Granados via B4 Relay @ 2024-09-04 13:17 UTC (permalink / raw)
  To: David Woodhouse, Lu Baolu, Joerg Roedel, Will Deacon,
	Robin Murphy, Jason Gunthorpe, Kevin Tian, Klaus Jensen
  Cc: linux-kernel, iommu, Joel Granados

From: Joel Granados <j.granados@samsung.com>

iommu_report_device_fault expects a pasid array to have an
iommu_attach_handle when a fault is detected. Add this handle when the
replacing hwpt has a valid iommufd fault object. Remove it when we
release ownership of the group.

Signed-off-by: Joel Granados <j.granados@samsung.com>
---
 drivers/iommu/iommu-priv.h    |  3 +++
 drivers/iommu/iommu.c         | 30 ++++++++++++++++++++++++++++++
 drivers/iommu/iommufd/fault.c | 22 ++++++++++++++++++++++
 3 files changed, 55 insertions(+)

diff --git a/drivers/iommu/iommu-priv.h b/drivers/iommu/iommu-priv.h
index de5b54eaa8bf..493e501badc7 100644
--- a/drivers/iommu/iommu-priv.h
+++ b/drivers/iommu/iommu-priv.h
@@ -38,6 +38,9 @@ void iommu_device_unregister_bus(struct iommu_device *iommu,
 struct iommu_attach_handle *iommu_attach_handle_get(struct iommu_group *group,
 						    ioasid_t pasid,
 						    unsigned int type);
+int iommu_init_pasid_array(struct iommu_domain *domain,
+			   struct iommu_group *group,
+			   struct iommu_attach_handle *handle);
 int iommu_attach_group_handle(struct iommu_domain *domain,
 			      struct iommu_group *group,
 			      struct iommu_attach_handle *handle);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index ed6c5cb60c5a..64ae1cf571aa 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -3262,6 +3262,9 @@ EXPORT_SYMBOL_GPL(iommu_device_claim_dma_owner);
 
 static void __iommu_release_dma_ownership(struct iommu_group *group)
 {
+	if (!xa_empty(&group->pasid_array))
+		xa_erase(&group->pasid_array, IOMMU_NO_PASID);
+
 	if (WARN_ON(!group->owner_cnt || !group->owner ||
 		    !xa_empty(&group->pasid_array)))
 		return;
@@ -3495,6 +3498,33 @@ iommu_attach_handle_get(struct iommu_group *group, ioasid_t pasid, unsigned int
 }
 EXPORT_SYMBOL_NS_GPL(iommu_attach_handle_get, IOMMUFD_INTERNAL);
 
+/**
+ * iommu_init_pasid_array - Initialize pasid array in the domain group
+ *
+ * Returns 0 on success. Error code on failure
+ *
+ * An IOMMU_NO_PASID element is *NOT* replaced if there is one already there.
+ */
+int iommu_init_pasid_array(struct iommu_domain *domain,
+			   struct iommu_group *group,
+			   struct iommu_attach_handle *handle)
+{
+	int ret;
+
+	if (handle)
+		handle->domain = domain;
+
+	mutex_lock(&group->mutex);
+	ret = xa_insert(&group->pasid_array, IOMMU_NO_PASID, handle, GFP_KERNEL);
+	mutex_unlock(&group->mutex);
+
+	if (ret == -EBUSY)
+		ret = 0;
+
+	return ret;
+}
+EXPORT_SYMBOL_NS_GPL(iommu_init_pasid_array, IOMMUFD_INTERNAL);
+
 /**
  * iommu_attach_group_handle - Attach an IOMMU domain to an IOMMU group
  * @domain: IOMMU domain to attach
diff --git a/drivers/iommu/iommufd/fault.c b/drivers/iommu/iommufd/fault.c
index a643d5c7c535..ea7f1bf64892 100644
--- a/drivers/iommu/iommufd/fault.c
+++ b/drivers/iommu/iommufd/fault.c
@@ -178,6 +178,25 @@ static int __fault_domain_replace_dev(struct iommufd_device *idev,
 	return ret;
 }
 
+static int iommufd_init_pasid_array(struct iommu_domain *domain,
+				  struct iommufd_device *idev)
+{
+	int ret;
+	struct iommufd_attach_handle *handle;
+	struct iommu_group *group = idev->igroup->group;
+
+	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+	if (!handle)
+		return -ENOMEM;
+	handle->idev = idev;
+
+	ret = iommu_init_pasid_array(domain, group, &handle->handle);
+	if (ret)
+		kfree(handle);
+
+	return ret;
+}
+
 int iommufd_fault_domain_replace_dev(struct iommufd_device *idev,
 				     struct iommufd_hw_pagetable *hwpt,
 				     struct iommufd_hw_pagetable *old)
@@ -190,6 +209,9 @@ int iommufd_fault_domain_replace_dev(struct iommufd_device *idev,
 		ret = iommufd_fault_iopf_enable(idev);
 		if (ret)
 			return ret;
+
+		if (iommufd_init_pasid_array(hwpt->domain, idev))
+			return -EINVAL;
 	}
 
 	ret = __fault_domain_replace_dev(idev, hwpt, old);

-- 
2.43.0



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

* [PATCH 6/6] iommu/vt-d: drop pasid requirement for prq initialization
  2024-09-04 13:17 [PATCH 0/6] iommu: Enable user space IOPFs in non-nested and non-svm cases Joel Granados via B4 Relay
                   ` (4 preceding siblings ...)
  2024-09-04 13:17 ` [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active Joel Granados via B4 Relay
@ 2024-09-04 13:17 ` Joel Granados via B4 Relay
  5 siblings, 0 replies; 24+ messages in thread
From: Joel Granados via B4 Relay @ 2024-09-04 13:17 UTC (permalink / raw)
  To: David Woodhouse, Lu Baolu, Joerg Roedel, Will Deacon,
	Robin Murphy, Jason Gunthorpe, Kevin Tian, Klaus Jensen
  Cc: linux-kernel, iommu, Joel Granados, Klaus Jensen

From: Klaus Jensen <k.jensen@samsung.com>

PASID support within the IOMMU is not required to enable the Page
Request Queue, only the PRS capability.

Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Signed-off-by: Joel Granados <j.granados@samsung.com>
---
 drivers/iommu/intel/iommu.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 3d1c971eb9e5..9f3bbdbd6372 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -1487,10 +1487,8 @@ static void free_dmar_iommu(struct intel_iommu *iommu)
 	/* free context mapping */
 	free_context_table(iommu);
 
-	if (pasid_supported(iommu)) {
-		if (ecap_prs(iommu->ecap))
-			intel_finish_prq(iommu);
-	}
+	if (ecap_prs(iommu->ecap))
+		intel_finish_prq(iommu);
 }
 
 /*
@@ -2480,7 +2478,7 @@ static int __init init_dmars(void)
 
 		iommu_flush_write_buffer(iommu);
 
-		if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) {
+		if (ecap_prs(iommu->ecap)) {
 			/*
 			 * Call dmar_alloc_hwirq() with dmar_global_lock held,
 			 * could cause possible lock race condition.
@@ -2921,7 +2919,7 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru)
 	intel_iommu_init_qi(iommu);
 	iommu_flush_write_buffer(iommu);
 
-	if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) {
+	if (ecap_prs(iommu->ecap)) {
 		ret = intel_enable_prq(iommu);
 		if (ret)
 			goto disable_iommu;

-- 
2.43.0



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

* Re: [PATCH 1/6] iommu/vt-d: Separate page request queue from SVM
  2024-09-04 13:17 ` [PATCH 1/6] iommu/vt-d: Separate page request queue from SVM Joel Granados via B4 Relay
@ 2024-09-05  3:18   ` Baolu Lu
  2024-09-11  7:28     ` Joel Granados
  0 siblings, 1 reply; 24+ messages in thread
From: Baolu Lu @ 2024-09-05  3:18 UTC (permalink / raw)
  To: j.granados, David Woodhouse, Joerg Roedel, Will Deacon,
	Robin Murphy, Jason Gunthorpe, Kevin Tian, Klaus Jensen
  Cc: baolu.lu, linux-kernel, iommu

On 9/4/24 9:17 PM, Joel Granados via B4 Relay wrote:
> From: Joel Granados<j.granados@samsung.com>
> 
> IO page faults are no longer dependent on CONFIG_INTEL_IOMMU_SVM. Move
> all Page Request Queue (PRQ) functions that handle prq events to a new
> file in drivers/iommu/intel/prq.c. The page_req_des struct is made
> available in drivers/iommu/intel/iommu.h.

Above last sentence needs to be updated.

Thanks,
baolu

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

* Re: [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active
  2024-09-04 13:17 ` [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active Joel Granados via B4 Relay
@ 2024-09-05  3:30   ` Baolu Lu
  2024-09-05  3:32     ` Baolu Lu
                       ` (2 more replies)
  0 siblings, 3 replies; 24+ messages in thread
From: Baolu Lu @ 2024-09-05  3:30 UTC (permalink / raw)
  To: j.granados, David Woodhouse, Joerg Roedel, Will Deacon,
	Robin Murphy, Jason Gunthorpe, Kevin Tian, Klaus Jensen
  Cc: baolu.lu, linux-kernel, iommu

On 9/4/24 9:17 PM, Joel Granados via B4 Relay wrote:
> From: Joel Granados<j.granados@samsung.com>
> 
> iommu_report_device_fault expects a pasid array to have an
> iommu_attach_handle when a fault is detected.

The iommu_attach_handle is expected only when an iopf-capable domain is
attached to the device or PASID. The iommu_report_device_fault() treats
it as a fault when a fault occurs, but no iopf-capable domain is
attached.

> Add this handle when the
> replacing hwpt has a valid iommufd fault object. Remove it when we
> release ownership of the group.

The iommu_attach_handle is managed by the caller (iommufd here for
example). Therefore, before iommu_attach_handle tries to attach a domain
to an iopf-capable device or pasid, it should allocate the handle and
pass it to the domain attachment interfaces. Conversely, the handle can
only be freed after the domain is detached.

Thanks,
baolu

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

* Re: [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active
  2024-09-05  3:30   ` Baolu Lu
@ 2024-09-05  3:32     ` Baolu Lu
  2024-09-11  9:55     ` Joel Granados
  2024-09-11 10:56     ` Joel Granados
  2 siblings, 0 replies; 24+ messages in thread
From: Baolu Lu @ 2024-09-05  3:32 UTC (permalink / raw)
  To: j.granados, David Woodhouse, Joerg Roedel, Will Deacon,
	Robin Murphy, Jason Gunthorpe, Kevin Tian, Klaus Jensen
  Cc: baolu.lu, linux-kernel, iommu

On 9/5/24 11:30 AM, Baolu Lu wrote:
> On 9/4/24 9:17 PM, Joel Granados via B4 Relay wrote:
>> From: Joel Granados<j.granados@samsung.com>
>>
>> iommu_report_device_fault expects a pasid array to have an
>> iommu_attach_handle when a fault is detected.
> 
> The iommu_attach_handle is expected only when an iopf-capable domain is
> attached to the device or PASID. The iommu_report_device_fault() treats
> it as a fault when a fault occurs, but no iopf-capable domain is
> attached.
> 
>> Add this handle when the
>> replacing hwpt has a valid iommufd fault object. Remove it when we
>> release ownership of the group.
> 
> The iommu_attach_handle is managed by the caller (iommufd here for
> example). Therefore, before iommu_attach_handle tries to attach a domain
> to an iopf-capable device or pasid, it should allocate the handle and

Correct:

"... attach an iopf-capable domain to device or pasid ..."

Sorry for the typo.

> pass it to the domain attachment interfaces. Conversely, the handle can
> only be freed after the domain is detached.
> 
> Thanks,
> baolu

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

* Re: [PATCH 3/6] iommu: kconfig: Move IOMMU_IOPF into INTEL_IOMMU
  2024-09-04 13:17 ` [PATCH 3/6] iommu: kconfig: Move IOMMU_IOPF into INTEL_IOMMU Joel Granados via B4 Relay
@ 2024-09-07 12:20   ` Jason Gunthorpe
  2024-09-11  7:40     ` Joel Granados
  0 siblings, 1 reply; 24+ messages in thread
From: Jason Gunthorpe @ 2024-09-07 12:20 UTC (permalink / raw)
  To: j.granados
  Cc: David Woodhouse, Lu Baolu, Joerg Roedel, Will Deacon,
	Robin Murphy, Kevin Tian, Klaus Jensen, linux-kernel, iommu

On Wed, Sep 04, 2024 at 03:17:14PM +0200, Joel Granados via B4 Relay wrote:
> @@ -51,7 +52,6 @@ config INTEL_IOMMU_SVM
>  	depends on X86_64
>  	select MMU_NOTIFIER
>  	select IOMMU_SVA
> -	select IOMMU_IOPF

Does patch 1 still compile if INTEL_IOMMU_SVM=n?

Jason

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

* Re: [PATCH 1/6] iommu/vt-d: Separate page request queue from SVM
  2024-09-05  3:18   ` Baolu Lu
@ 2024-09-11  7:28     ` Joel Granados
  0 siblings, 0 replies; 24+ messages in thread
From: Joel Granados @ 2024-09-11  7:28 UTC (permalink / raw)
  To: Baolu Lu
  Cc: David Woodhouse, Joerg Roedel, Will Deacon, Robin Murphy,
	Jason Gunthorpe, Kevin Tian, Klaus Jensen, linux-kernel, iommu

On Thu, Sep 05, 2024 at 11:18:39AM +0800, Baolu Lu wrote:
> On 9/4/24 9:17 PM, Joel Granados via B4 Relay wrote:
> > From: Joel Granados<j.granados@samsung.com>
> > 
> > IO page faults are no longer dependent on CONFIG_INTEL_IOMMU_SVM. Move
> > all Page Request Queue (PRQ) functions that handle prq events to a new
> > file in drivers/iommu/intel/prq.c. The page_req_des struct is made
> > available in drivers/iommu/intel/iommu.h.
> 
> Above last sentence needs to be updated.
oops. missed that. thx.

-- 

Joel Granados

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

* Re: [PATCH 3/6] iommu: kconfig: Move IOMMU_IOPF into INTEL_IOMMU
  2024-09-07 12:20   ` Jason Gunthorpe
@ 2024-09-11  7:40     ` Joel Granados
  2024-09-15 13:37       ` Jason Gunthorpe
  0 siblings, 1 reply; 24+ messages in thread
From: Joel Granados @ 2024-09-11  7:40 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: David Woodhouse, Lu Baolu, Joerg Roedel, Will Deacon,
	Robin Murphy, Kevin Tian, Klaus Jensen, linux-kernel, iommu

On Sat, Sep 07, 2024 at 09:20:19AM -0300, Jason Gunthorpe wrote:
> On Wed, Sep 04, 2024 at 03:17:14PM +0200, Joel Granados via B4 Relay wrote:
> > @@ -51,7 +52,6 @@ config INTEL_IOMMU_SVM
> >  	depends on X86_64
> >  	select MMU_NOTIFIER
> >  	select IOMMU_SVA
> > -	select IOMMU_IOPF
> 
> Does patch 1 still compile if INTEL_IOMMU_SVM=n?
It does for me. With and without INTEL_IOMMU_SVM. Is there a config that
is not compiling for you? You can send that you to me and I can give it
a try, to see if I get the same issue.

Best

-- 

Joel Granados

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

* Re: [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active
  2024-09-05  3:30   ` Baolu Lu
  2024-09-05  3:32     ` Baolu Lu
@ 2024-09-11  9:55     ` Joel Granados
  2024-09-12  4:17       ` Baolu Lu
  2024-09-11 10:56     ` Joel Granados
  2 siblings, 1 reply; 24+ messages in thread
From: Joel Granados @ 2024-09-11  9:55 UTC (permalink / raw)
  To: Baolu Lu
  Cc: David Woodhouse, Joerg Roedel, Will Deacon, Robin Murphy,
	Jason Gunthorpe, Kevin Tian, Klaus Jensen, linux-kernel, iommu

On Thu, Sep 05, 2024 at 11:30:05AM +0800, Baolu Lu wrote:
> On 9/4/24 9:17 PM, Joel Granados via B4 Relay wrote:
> > From: Joel Granados<j.granados@samsung.com>
> > 
> > iommu_report_device_fault expects a pasid array to have an
> > iommu_attach_handle when a fault is detected.
> 
> The iommu_attach_handle is expected only when an iopf-capable domain is
> attached to the device or PASID. The iommu_report_device_fault() treats
> it as a fault when a fault occurs, but no iopf-capable domain is
> attached.
I don't follow. The way that I read it: if the pasid_array x-array does
not have an iommu_attach_handle indexed by either fault->prm.pasid or
IOMMU_NO_PASID, it will follow the err_bad_iopf and return -EINVAL
(please correct me if I'm wrong). So the iommu_attach_handle is *always*
expected.

Would it be more clear for it to be:
"""
The iommu_report_device_fault function expects the pasid_array x-array
to have an iommu_attach_handle indexed by a PASID. Add one indexed with
IOMMU_NO_PASID when the replacing HWPT has a valid iommufd fault object.
Remove it when we release ownership of the group.
"""

best

-- 

Joel Granados

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

* Re: [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active
  2024-09-05  3:30   ` Baolu Lu
  2024-09-05  3:32     ` Baolu Lu
  2024-09-11  9:55     ` Joel Granados
@ 2024-09-11 10:56     ` Joel Granados
  2024-09-12  4:21       ` Baolu Lu
  2 siblings, 1 reply; 24+ messages in thread
From: Joel Granados @ 2024-09-11 10:56 UTC (permalink / raw)
  To: Baolu Lu
  Cc: David Woodhouse, Joerg Roedel, Will Deacon, Robin Murphy,
	Jason Gunthorpe, Kevin Tian, Klaus Jensen, linux-kernel, iommu

On Thu, Sep 05, 2024 at 11:30:05AM +0800, Baolu Lu wrote:
> On 9/4/24 9:17 PM, Joel Granados via B4 Relay wrote:
> > From: Joel Granados<j.granados@samsung.com>
> > 
> > iommu_report_device_fault expects a pasid array to have an
> > iommu_attach_handle when a fault is detected.
> 
> The iommu_attach_handle is expected only when an iopf-capable domain is
> attached to the device or PASID. The iommu_report_device_fault() treats
> it as a fault when a fault occurs, but no iopf-capable domain is
> attached.
> 
> > Add this handle when the
> > replacing hwpt has a valid iommufd fault object. Remove it when we
> > release ownership of the group.
> 
> The iommu_attach_handle is managed by the caller (iommufd here for
> example). Therefore, before iommu_attach_handle tries to attach a domain
> to an iopf-capable device or pasid, it should allocate the handle and
> pass it to the domain attachment interfaces.
What do you mean here?
1. Do you want to move the iommufd_init_pasid_array call up to
iommufd_hwpt_replace_device?
2. Do you want to move it further up to iommufd_device_do_replace?

Note that all this implemented on a call to replace HWPT. So a
non-iopf-capable VFIO_DEVICE_ATTACH_IOMMUFD_PT ioctl has already been
completed before the one that calls iommufd_device_do_replace.

> Conversely, the handle can
> only be freed after the domain is detached.
Do you have a function in specific where you would put the free handle
logic?

Best

-- 

Joel Granados

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

* Re: [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active
  2024-09-11  9:55     ` Joel Granados
@ 2024-09-12  4:17       ` Baolu Lu
  2024-09-12 10:22         ` Joel Granados
  0 siblings, 1 reply; 24+ messages in thread
From: Baolu Lu @ 2024-09-12  4:17 UTC (permalink / raw)
  To: Joel Granados
  Cc: baolu.lu, David Woodhouse, Joerg Roedel, Will Deacon,
	Robin Murphy, Jason Gunthorpe, Kevin Tian, Klaus Jensen,
	linux-kernel, iommu

On 9/11/24 5:55 PM, Joel Granados wrote:
> On Thu, Sep 05, 2024 at 11:30:05AM +0800, Baolu Lu wrote:
>> On 9/4/24 9:17 PM, Joel Granados via B4 Relay wrote:
>>> From: Joel Granados<j.granados@samsung.com>
>>>
>>> iommu_report_device_fault expects a pasid array to have an
>>> iommu_attach_handle when a fault is detected.
>> The iommu_attach_handle is expected only when an iopf-capable domain is
>> attached to the device or PASID. The iommu_report_device_fault() treats
>> it as a fault when a fault occurs, but no iopf-capable domain is
>> attached.
> I don't follow. The way that I read it: if the pasid_array x-array does
> not have an iommu_attach_handle indexed by either fault->prm.pasid or
> IOMMU_NO_PASID, it will follow the err_bad_iopf and return -EINVAL
> (please correct me if I'm wrong). So the iommu_attach_handle is*always*
> expected.
> 
> Would it be more clear for it to be:
> """
> The iommu_report_device_fault function expects the pasid_array x-array
> to have an iommu_attach_handle indexed by a PASID. Add one indexed with
> IOMMU_NO_PASID when the replacing HWPT has a valid iommufd fault object.
> Remove it when we release ownership of the group.

Can you please explain why iommu core needs to remove the attach handle
when the ownership of the group is changed?

Thanks,
baolu

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

* Re: [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active
  2024-09-11 10:56     ` Joel Granados
@ 2024-09-12  4:21       ` Baolu Lu
  2024-09-12  8:25         ` Joel Granados
  2024-09-12 10:00         ` Joel Granados
  0 siblings, 2 replies; 24+ messages in thread
From: Baolu Lu @ 2024-09-12  4:21 UTC (permalink / raw)
  To: Joel Granados
  Cc: baolu.lu, David Woodhouse, Joerg Roedel, Will Deacon,
	Robin Murphy, Jason Gunthorpe, Kevin Tian, Klaus Jensen,
	linux-kernel, iommu

On 9/11/24 6:56 PM, Joel Granados wrote:
> On Thu, Sep 05, 2024 at 11:30:05AM +0800, Baolu Lu wrote:
>> On 9/4/24 9:17 PM, Joel Granados via B4 Relay wrote:
>>> From: Joel Granados<j.granados@samsung.com>
>>>
>>> iommu_report_device_fault expects a pasid array to have an
>>> iommu_attach_handle when a fault is detected.
>> The iommu_attach_handle is expected only when an iopf-capable domain is
>> attached to the device or PASID. The iommu_report_device_fault() treats
>> it as a fault when a fault occurs, but no iopf-capable domain is
>> attached.
>>
>>> Add this handle when the
>>> replacing hwpt has a valid iommufd fault object. Remove it when we
>>> release ownership of the group.
>> The iommu_attach_handle is managed by the caller (iommufd here for
>> example). Therefore, before iommu_attach_handle tries to attach a domain
>> to an iopf-capable device or pasid, it should allocate the handle and
>> pass it to the domain attachment interfaces.
> What do you mean here?
> 1. Do you want to move the iommufd_init_pasid_array call up to
> iommufd_hwpt_replace_device?
> 2. Do you want to move it further up to iommufd_device_do_replace?

I'm having trouble understanding the need for iommu_init_pasid_array()
in the core.

> 
> Note that all this implemented on a call to replace HWPT. So a
> non-iopf-capable VFIO_DEVICE_ATTACH_IOMMUFD_PT ioctl has already been
> completed before the one that calls iommufd_device_do_replace.
> 
>> Conversely, the handle can
>> only be freed after the domain is detached.
> Do you have a function in specific where you would put the free handle
> logic?

drivers/iommu/iommufd/fault.c

void iommufd_fault_domain_detach_dev(struct iommufd_hw_pagetable *hwpt,
                                      struct iommufd_device *idev)
{
         struct iommufd_attach_handle *handle;

         handle = iommufd_device_get_attach_handle(idev);
         iommu_detach_group_handle(hwpt->domain, idev->igroup->group);
         iommufd_auto_response_faults(hwpt, handle);
         iommufd_fault_iopf_disable(idev);
         kfree(handle);
}

Thanks,
baolu

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

* Re: [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active
  2024-09-12  4:21       ` Baolu Lu
@ 2024-09-12  8:25         ` Joel Granados
  2024-09-12 11:22           ` Baolu Lu
  2024-09-12 10:00         ` Joel Granados
  1 sibling, 1 reply; 24+ messages in thread
From: Joel Granados @ 2024-09-12  8:25 UTC (permalink / raw)
  To: Baolu Lu
  Cc: David Woodhouse, Joerg Roedel, Will Deacon, Robin Murphy,
	Jason Gunthorpe, Kevin Tian, Klaus Jensen, linux-kernel, iommu

On Thu, Sep 12, 2024 at 12:21:53PM +0800, Baolu Lu wrote:
> On 9/11/24 6:56 PM, Joel Granados wrote:
> > On Thu, Sep 05, 2024 at 11:30:05AM +0800, Baolu Lu wrote:
> >> On 9/4/24 9:17 PM, Joel Granados via B4 Relay wrote:
> >>> From: Joel Granados<j.granados@samsung.com>
> >>>
> >>> iommu_report_device_fault expects a pasid array to have an
> >>> iommu_attach_handle when a fault is detected.
> >> The iommu_attach_handle is expected only when an iopf-capable domain is
> >> attached to the device or PASID. The iommu_report_device_fault() treats
> >> it as a fault when a fault occurs, but no iopf-capable domain is
> >> attached.
> >>
> >>> Add this handle when the
> >>> replacing hwpt has a valid iommufd fault object. Remove it when we
> >>> release ownership of the group.
> >> The iommu_attach_handle is managed by the caller (iommufd here for
> >> example). Therefore, before iommu_attach_handle tries to attach a domain
> >> to an iopf-capable device or pasid, it should allocate the handle and
> >> pass it to the domain attachment interfaces.
> > What do you mean here?
> > 1. Do you want to move the iommufd_init_pasid_array call up to
> > iommufd_hwpt_replace_device?
> > 2. Do you want to move it further up to iommufd_device_do_replace?
> 
> I'm having trouble understanding the need for iommu_init_pasid_array()
> in the core.

The iommu_init_pasid_array function is there because I needed to access
struct iommu_group->pasid_array. The struct declaration for iommu_group
is in the core (drivers/iommu/iommu.c), so I thought that the function
to modify a member of that struct would go in core also.

To move all the logic into iommufd_init_pasid_array in iommufd, we would
need to move the iommu_group struct (include/linux/iommu.h?). Here is a
proposed patch that would make that happen (and removes
iommu_init_pasid_array). What do you think?


diff --git i/drivers/iommu/iommu-priv.h w/drivers/iommu/iommu-priv.h
index 493e501badc7..de5b54eaa8bf 100644
--- i/drivers/iommu/iommu-priv.h
+++ w/drivers/iommu/iommu-priv.h
@@ -38,9 +38,6 @@ void iommu_device_unregister_bus(struct iommu_device *iommu,
 struct iommu_attach_handle *iommu_attach_handle_get(struct iommu_group *group,
 						    ioasid_t pasid,
 						    unsigned int type);
-int iommu_init_pasid_array(struct iommu_domain *domain,
-			   struct iommu_group *group,
-			   struct iommu_attach_handle *handle);
 int iommu_attach_group_handle(struct iommu_domain *domain,
 			      struct iommu_group *group,
 			      struct iommu_attach_handle *handle);
diff --git i/drivers/iommu/iommu.c w/drivers/iommu/iommu.c
index 64ae1cf571aa..83bc0bfd7bb0 100644
--- i/drivers/iommu/iommu.c
+++ w/drivers/iommu/iommu.c
@@ -44,24 +44,6 @@ static unsigned int iommu_def_domain_type __read_mostly;
 static bool iommu_dma_strict __read_mostly = IS_ENABLED(CONFIG_IOMMU_DEFAULT_DMA_STRICT);
 static u32 iommu_cmd_line __read_mostly;
 
-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);
-	char *name;
-	int id;
-	struct iommu_domain *default_domain;
-	struct iommu_domain *blocking_domain;
-	struct iommu_domain *domain;
-	struct list_head entry;
-	unsigned int owner_cnt;
-	void *owner;
-};
-
 struct group_device {
 	struct list_head list;
 	struct device *dev;
@@ -3498,33 +3480,6 @@ iommu_attach_handle_get(struct iommu_group *group, ioasid_t pasid, unsigned int
 }
 EXPORT_SYMBOL_NS_GPL(iommu_attach_handle_get, IOMMUFD_INTERNAL);
 
-/**
- * iommu_init_pasid_array - Initialize pasid array in the domain group
- *
- * Returns 0 on success. Error code on failure
- *
- * An IOMMU_NO_PASID element is *NOT* replaced if there is one already there.
- */
-int iommu_init_pasid_array(struct iommu_domain *domain,
-			   struct iommu_group *group,
-			   struct iommu_attach_handle *handle)
-{
-	int ret;
-
-	if (handle)
-		handle->domain = domain;
-
-	mutex_lock(&group->mutex);
-	ret = xa_insert(&group->pasid_array, IOMMU_NO_PASID, handle, GFP_KERNEL);
-	mutex_unlock(&group->mutex);
-
-	if (ret == -EBUSY)
-		ret = 0;
-
-	return ret;
-}
-EXPORT_SYMBOL_NS_GPL(iommu_init_pasid_array, IOMMUFD_INTERNAL);
-
 /**
  * iommu_attach_group_handle - Attach an IOMMU domain to an IOMMU group
  * @domain: IOMMU domain to attach
diff --git i/drivers/iommu/iommufd/fault.c w/drivers/iommu/iommufd/fault.c
index ea7f1bf64892..51cb70465b87 100644
--- i/drivers/iommu/iommufd/fault.c
+++ w/drivers/iommu/iommufd/fault.c
@@ -189,8 +189,15 @@ static int iommufd_init_pasid_array(struct iommu_domain *domain,
 	if (!handle)
 		return -ENOMEM;
 	handle->idev = idev;
+	handle->handle.domain = domain;
+
+	mutex_lock(&group->mutex);
+	ret = xa_insert(&group->pasid_array, IOMMU_NO_PASID, handle, GFP_KERNEL);
+	mutex_unlock(&group->mutex);
+
+	if (ret == -EBUSY)
+		ret = 0;
 
-	ret = iommu_init_pasid_array(domain, group, &handle->handle);
 	if (ret)
 		kfree(handle);
 
diff --git i/include/linux/iommu.h w/include/linux/iommu.h
index bd722f473635..c34aa737aeb2 100644
--- i/include/linux/iommu.h
+++ w/include/linux/iommu.h
@@ -31,8 +31,25 @@
  */
 #define IOMMU_PRIV	(1 << 5)
 
+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);
+	char *name;
+	int id;
+	struct iommu_domain *default_domain;
+	struct iommu_domain *blocking_domain;
+	struct iommu_domain *domain;
+	struct list_head entry;
+	unsigned int owner_cnt;
+	void *owner;
+};
+
 struct iommu_ops;
-struct iommu_group;
 struct bus_type;
 struct device;
 struct iommu_domain;



-- 

Joel Granados

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

* Re: [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active
  2024-09-12  4:21       ` Baolu Lu
  2024-09-12  8:25         ` Joel Granados
@ 2024-09-12 10:00         ` Joel Granados
  1 sibling, 0 replies; 24+ messages in thread
From: Joel Granados @ 2024-09-12 10:00 UTC (permalink / raw)
  To: Baolu Lu
  Cc: David Woodhouse, Joerg Roedel, Will Deacon, Robin Murphy,
	Jason Gunthorpe, Kevin Tian, Klaus Jensen, linux-kernel, iommu

On Thu, Sep 12, 2024 at 12:21:53PM +0800, Baolu Lu wrote:
> On 9/11/24 6:56 PM, Joel Granados wrote:
> > On Thu, Sep 05, 2024 at 11:30:05AM +0800, Baolu Lu wrote:
> >> On 9/4/24 9:17 PM, Joel Granados via B4 Relay wrote:
> >>> From: Joel Granados<j.granados@samsung.com>
> >>>
> >>> iommu_report_device_fault expects a pasid array to have an
> >>> iommu_attach_handle when a fault is detected.
> >> The iommu_attach_handle is expected only when an iopf-capable domain is
> >> attached to the device or PASID. The iommu_report_device_fault() treats
> >> it as a fault when a fault occurs, but no iopf-capable domain is
> >> attached.
> >>
> >>> Add this handle when the
> >>> replacing hwpt has a valid iommufd fault object. Remove it when we
> >>> release ownership of the group.
> >> The iommu_attach_handle is managed by the caller (iommufd here for
> >> example). Therefore, before iommu_attach_handle tries to attach a domain
> >> to an iopf-capable device or pasid, it should allocate the handle and
> >> pass it to the domain attachment interfaces.
> > What do you mean here?
> > 1. Do you want to move the iommufd_init_pasid_array call up to
> > iommufd_hwpt_replace_device?
> > 2. Do you want to move it further up to iommufd_device_do_replace?
> 
> I'm having trouble understanding the need for iommu_init_pasid_array()
> in the core.
> 
> > 
> > Note that all this implemented on a call to replace HWPT. So a
> > non-iopf-capable VFIO_DEVICE_ATTACH_IOMMUFD_PT ioctl has already been
> > completed before the one that calls iommufd_device_do_replace.
> > 
> >> Conversely, the handle can
> >> only be freed after the domain is detached.
> > Do you have a function in specific where you would put the free handle
> > logic?
> 
> drivers/iommu/iommufd/fault.c
> 
> void iommufd_fault_domain_detach_dev(struct iommufd_hw_pagetable *hwpt,
>                                       struct iommufd_device *idev)
> {
>          struct iommufd_attach_handle *handle;
> 
>          handle = iommufd_device_get_attach_handle(idev);
>          iommu_detach_group_handle(hwpt->domain, idev->igroup->group);
>          iommufd_auto_response_faults(hwpt, handle);
>          iommufd_fault_iopf_disable(idev);
>          kfree(handle);
> }
Actually there is no need to add the xa_erase call in
__iommu_release_dma_ownership because it is *already* handled here.
Sorry about this, I think this was left from a previous version of the
patch. I'll remove the superfluous xa_erase call.

Thx for the review

-- 

Joel Granados

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

* Re: [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active
  2024-09-12  4:17       ` Baolu Lu
@ 2024-09-12 10:22         ` Joel Granados
  0 siblings, 0 replies; 24+ messages in thread
From: Joel Granados @ 2024-09-12 10:22 UTC (permalink / raw)
  To: Baolu Lu
  Cc: David Woodhouse, Joerg Roedel, Will Deacon, Robin Murphy,
	Jason Gunthorpe, Kevin Tian, Klaus Jensen, linux-kernel, iommu

On Thu, Sep 12, 2024 at 12:17:35PM +0800, Baolu Lu wrote:
> On 9/11/24 5:55 PM, Joel Granados wrote:
> > On Thu, Sep 05, 2024 at 11:30:05AM +0800, Baolu Lu wrote:
> >> On 9/4/24 9:17 PM, Joel Granados via B4 Relay wrote:
> >>> From: Joel Granados<j.granados@samsung.com>
> >>>
> >>> iommu_report_device_fault expects a pasid array to have an
> >>> iommu_attach_handle when a fault is detected.
> >> The iommu_attach_handle is expected only when an iopf-capable domain is
> >> attached to the device or PASID. The iommu_report_device_fault() treats
> >> it as a fault when a fault occurs, but no iopf-capable domain is
> >> attached.
> > I don't follow. The way that I read it: if the pasid_array x-array does
> > not have an iommu_attach_handle indexed by either fault->prm.pasid or
> > IOMMU_NO_PASID, it will follow the err_bad_iopf and return -EINVAL
> > (please correct me if I'm wrong). So the iommu_attach_handle is*always*
> > expected.
> > 
> > Would it be more clear for it to be:
> > """
> > The iommu_report_device_fault function expects the pasid_array x-array
> > to have an iommu_attach_handle indexed by a PASID. Add one indexed with
> > IOMMU_NO_PASID when the replacing HWPT has a valid iommufd fault object.
> > Remove it when we release ownership of the group.
> 
> Can you please explain why iommu core needs to remove the attach handle
> when the ownership of the group is changed?

It does not. Probably left from a previous version of the patch. Sorry
for the noise. I have reamoved the xa_erase from
__iommu_release_dma_ownership. Will send a V2 once we finish discussing
the rest of your comments.

Best and thankyou for your feedback

-- 

Joel Granados

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

* Re: [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active
  2024-09-12  8:25         ` Joel Granados
@ 2024-09-12 11:22           ` Baolu Lu
  2024-09-13  8:02             ` Joel Granados
  0 siblings, 1 reply; 24+ messages in thread
From: Baolu Lu @ 2024-09-12 11:22 UTC (permalink / raw)
  To: Joel Granados
  Cc: baolu.lu, David Woodhouse, Joerg Roedel, Will Deacon,
	Robin Murphy, Jason Gunthorpe, Kevin Tian, Klaus Jensen,
	linux-kernel, iommu

On 2024/9/12 16:25, Joel Granados wrote:
>   /**
>    * iommu_attach_group_handle - Attach an IOMMU domain to an IOMMU group
>    * @domain: IOMMU domain to attach
> diff --git i/drivers/iommu/iommufd/fault.c w/drivers/iommu/iommufd/fault.c
> index ea7f1bf64892..51cb70465b87 100644
> --- i/drivers/iommu/iommufd/fault.c
> +++ w/drivers/iommu/iommufd/fault.c
> @@ -189,8 +189,15 @@ static int iommufd_init_pasid_array(struct iommu_domain *domain,
>   	if (!handle)
>   		return -ENOMEM;
>   	handle->idev = idev;
> +	handle->handle.domain = domain;
> +
> +	mutex_lock(&group->mutex);
> +	ret = xa_insert(&group->pasid_array, IOMMU_NO_PASID, handle, GFP_KERNEL);
> +	mutex_unlock(&group->mutex);
> +
> +	if (ret == -EBUSY)
> +		ret = 0;
>   
> -	ret = iommu_init_pasid_array(domain, group, &handle->handle);
>   	if (ret)
>   		kfree(handle);

This is supposed to be done automatically when an iopf capable domain is
attached to or replaced with a device. Please refer to
iommufd_fault_domain_attach_dev() and
iommufd_fault_domain_replace_dev().

Is there anything preventing this from happening?

Thanks,
baolu

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

* Re: [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active
  2024-09-12 11:22           ` Baolu Lu
@ 2024-09-13  8:02             ` Joel Granados
  0 siblings, 0 replies; 24+ messages in thread
From: Joel Granados @ 2024-09-13  8:02 UTC (permalink / raw)
  To: Baolu Lu
  Cc: David Woodhouse, Joerg Roedel, Will Deacon, Robin Murphy,
	Jason Gunthorpe, Kevin Tian, Klaus Jensen, linux-kernel, iommu

On Thu, Sep 12, 2024 at 07:22:30PM +0800, Baolu Lu wrote:
> On 2024/9/12 16:25, Joel Granados wrote:
> >   /**
> >    * iommu_attach_group_handle - Attach an IOMMU domain to an IOMMU group
> >    * @domain: IOMMU domain to attach
> > diff --git i/drivers/iommu/iommufd/fault.c w/drivers/iommu/iommufd/fault.c
> > index ea7f1bf64892..51cb70465b87 100644
> > --- i/drivers/iommu/iommufd/fault.c
> > +++ w/drivers/iommu/iommufd/fault.c
> > @@ -189,8 +189,15 @@ static int iommufd_init_pasid_array(struct iommu_domain *domain,
> >   	if (!handle)
> >   		return -ENOMEM;
> >   	handle->idev = idev;
> > +	handle->handle.domain = domain;
> > +
> > +	mutex_lock(&group->mutex);
> > +	ret = xa_insert(&group->pasid_array, IOMMU_NO_PASID, handle, GFP_KERNEL);
> > +	mutex_unlock(&group->mutex);
> > +
> > +	if (ret == -EBUSY)
> > +		ret = 0;
> >   
> > -	ret = iommu_init_pasid_array(domain, group, &handle->handle);
> >   	if (ret)
> >   		kfree(handle);
> 
> This is supposed to be done automatically when an iopf capable domain is
> attached to or replaced with a device. Please refer to
> iommufd_fault_domain_attach_dev() and
> iommufd_fault_domain_replace_dev().
> 
> Is there anything preventing this from happening?
Nope, You are correct. This does indeed happen through
iommufd_fault_domain_replace_dev
  -> __fault_domain_replace_dev
    -> iommu_replace_group_handle.

This was probably left from trying to do this outside the replace path.
Sorry for the noise; will remove it in V2.

Thx for the review

Best

-- 

Joel Granados

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

* Re: [PATCH 3/6] iommu: kconfig: Move IOMMU_IOPF into INTEL_IOMMU
  2024-09-11  7:40     ` Joel Granados
@ 2024-09-15 13:37       ` Jason Gunthorpe
  2024-09-16 12:24         ` Joel Granados
  0 siblings, 1 reply; 24+ messages in thread
From: Jason Gunthorpe @ 2024-09-15 13:37 UTC (permalink / raw)
  To: Joel Granados
  Cc: David Woodhouse, Lu Baolu, Joerg Roedel, Will Deacon,
	Robin Murphy, Kevin Tian, Klaus Jensen, linux-kernel, iommu

On Wed, Sep 11, 2024 at 09:40:59AM +0200, Joel Granados wrote:
> On Sat, Sep 07, 2024 at 09:20:19AM -0300, Jason Gunthorpe wrote:
> > On Wed, Sep 04, 2024 at 03:17:14PM +0200, Joel Granados via B4 Relay wrote:
> > > @@ -51,7 +52,6 @@ config INTEL_IOMMU_SVM
> > >  	depends on X86_64
> > >  	select MMU_NOTIFIER
> > >  	select IOMMU_SVA
> > > -	select IOMMU_IOPF
> > 
> > Does patch 1 still compile if INTEL_IOMMU_SVM=n?
> It does for me. With and without INTEL_IOMMU_SVM. Is there a config that
> is not compiling for you? You can send that you to me and I can give it
> a try, to see if I get the same issue.

Okay, it compiles, but it is broken right? This hunk just can't be
correct, SVM needs IOPF to work

Jason

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

* Re: [PATCH 3/6] iommu: kconfig: Move IOMMU_IOPF into INTEL_IOMMU
  2024-09-15 13:37       ` Jason Gunthorpe
@ 2024-09-16 12:24         ` Joel Granados
  0 siblings, 0 replies; 24+ messages in thread
From: Joel Granados @ 2024-09-16 12:24 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: David Woodhouse, Lu Baolu, Joerg Roedel, Will Deacon,
	Robin Murphy, Kevin Tian, Klaus Jensen, linux-kernel, iommu

On Sun, Sep 15, 2024 at 10:37:34AM -0300, Jason Gunthorpe wrote:
> On Wed, Sep 11, 2024 at 09:40:59AM +0200, Joel Granados wrote:
> > On Sat, Sep 07, 2024 at 09:20:19AM -0300, Jason Gunthorpe wrote:
> > > On Wed, Sep 04, 2024 at 03:17:14PM +0200, Joel Granados via B4 Relay wrote:
> > > > @@ -51,7 +52,6 @@ config INTEL_IOMMU_SVM
> > > >  	depends on X86_64
> > > >  	select MMU_NOTIFIER
> > > >  	select IOMMU_SVA
> > > > -	select IOMMU_IOPF
> > > 

Will answer this based on https://lore.kernel.org/20240913-jag-iopfv8-v2-0-dea01c2343bc@samsung.com
as there are small differences with the current version of this patch.

> > > Does patch 1 still compile if INTEL_IOMMU_SVM=n?
> > It does for me. With and without INTEL_IOMMU_SVM. Is there a config that
> > is not compiling for you? You can send that you to me and I can give it
> > a try, to see if I get the same issue.
> 
> Okay, it compiles, but it is broken right? This hunk just can't be
> correct, SVM needs IOPF to work

AFAIK Yes: SVM *does* need IOPF to work. But IOMMU_IOPF *will* be
selected if INTEL_IOMMU_SVM is selected because INTEL_IOMMU_SVM is
covered by the `if INTEL_IOMMU` condition. Its the same way that the
relation between INTEL_IOMMU_SVM and PCI_PASID is handled: PCI_PASID
will be set if INTEL_IOMMU_SVM is set.

Please let me know if I'm misreading or have missed something.

Best

-- 

Joel Granados

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

end of thread, other threads:[~2024-09-16 12:25 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-04 13:17 [PATCH 0/6] iommu: Enable user space IOPFs in non-nested and non-svm cases Joel Granados via B4 Relay
2024-09-04 13:17 ` [PATCH 1/6] iommu/vt-d: Separate page request queue from SVM Joel Granados via B4 Relay
2024-09-05  3:18   ` Baolu Lu
2024-09-11  7:28     ` Joel Granados
2024-09-04 13:17 ` [PATCH 2/6] iommu/vt-d: Remove the pasid present check in prq_event_thread Joel Granados via B4 Relay
2024-09-04 13:17 ` [PATCH 3/6] iommu: kconfig: Move IOMMU_IOPF into INTEL_IOMMU Joel Granados via B4 Relay
2024-09-07 12:20   ` Jason Gunthorpe
2024-09-11  7:40     ` Joel Granados
2024-09-15 13:37       ` Jason Gunthorpe
2024-09-16 12:24         ` Joel Granados
2024-09-04 13:17 ` [PATCH 4/6] iommufd: Enable PRI when doing the iommufd_hwpt_alloc Joel Granados via B4 Relay
2024-09-04 13:17 ` [PATCH 5/6] iommu: init pasid array while doing domain_replace and iopf is active Joel Granados via B4 Relay
2024-09-05  3:30   ` Baolu Lu
2024-09-05  3:32     ` Baolu Lu
2024-09-11  9:55     ` Joel Granados
2024-09-12  4:17       ` Baolu Lu
2024-09-12 10:22         ` Joel Granados
2024-09-11 10:56     ` Joel Granados
2024-09-12  4:21       ` Baolu Lu
2024-09-12  8:25         ` Joel Granados
2024-09-12 11:22           ` Baolu Lu
2024-09-13  8:02             ` Joel Granados
2024-09-12 10:00         ` Joel Granados
2024-09-04 13:17 ` [PATCH 6/6] iommu/vt-d: drop pasid requirement for prq initialization Joel Granados via B4 Relay

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox