mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Guanghui Feng <guanghuifeng@linux.alibaba.com>
To: jgg@ziepe.ca
Cc: alex@shazbot.org, iommu@lists.linux.dev, joro@8bytes.org,
	kevin.tian@intel.com, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org, robin.murphy@arm.com,
	will@kernel.org
Subject: [PATCH v6 2/3] iommufd: Add IOMMU_GET_RECOMMENDED_RESERVATIONS ioctl
Date: Wed, 28 Oct 2026 17:04:52 +0800	[thread overview]
Message-ID: <20261028090453.2392991-3-guanghuifeng@linux.alibaba.com> (raw)
In-Reply-To: <20261028090453.2392991-1-guanghuifeng@linux.alibaba.com>

Add a per-device query ioctl that reports the IOVA ranges the kernel
recommends reserving for a given device.  For PCI devices these are
the MMIO windows of the host bridge the device sits behind: DMA using
IOVAs inside those windows could be misrouted as peer-to-peer traffic
by a PCIe switch instead of reaching the root complex for IOMMU
translation.

The interface is advisory, and deliberately named after the general
concept of recommended reserved regions rather than its first source:
the kernel reports recommendations and userspace decides whether to
act on them, either by feeding them back through
IOMMU_IOAS_RESERVE_IOVAS or by avoiding the ranges in its own IOVA
allocation.  This follows the principle that PCI window information
should not be forced onto userspace through the IOMMU reserved-region
API, as established when the earlier attempt was reverted in commit
cd2c9fcf5c66 ("iommu/dma: Move PCI window region reservation back into dma specific path.")

The output reuses struct iommu_iova_range and follows the array +
count + EMSGSIZE protocol established by IOMMU_IOAS_IOVA_RANGES.
Per-device granularity is chosen because the recommendations derive
from the device's bus topology and are available immediately after
VFIO_DEVICE_BIND_IOMMUFD, before any IOAS attachment.

Signed-off-by: Guanghui Feng <guanghuifeng@linux.alibaba.com>
---
 drivers/iommu/iommufd/device.c          | 65 +++++++++++++++++++++++++
 drivers/iommu/iommufd/iommufd_private.h |  1 +
 drivers/iommu/iommufd/main.c            |  4 ++
 include/uapi/linux/iommufd.h            | 38 +++++++++++++++
 4 files changed, 108 insertions(+)

diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c
index 1b0bdf57ac8a..eedda48012a1 100644
--- a/drivers/iommu/iommufd/device.c
+++ b/drivers/iommu/iommufd/device.c
@@ -1749,3 +1749,68 @@ int iommufd_get_hw_info(struct iommufd_ucmd *ucmd)
 	iommufd_put_object(ucmd->ictx, &idev->obj);
 	return rc;
 }
+
+struct recommended_resv_ctx {
+	struct iommu_iova_range __user *out_ranges;
+	u32 max_ranges;
+	u32 num_ranges;
+};
+
+static int recommended_resv_window_fn(phys_addr_t start, phys_addr_t end,
+				      void *data)
+{
+	struct recommended_resv_ctx *ctx = data;
+
+	if (ctx->num_ranges < ctx->max_ranges) {
+		struct iommu_iova_range elm = {
+			.start = start,
+			.last = end,
+		};
+
+		if (copy_to_user(&ctx->out_ranges[ctx->num_ranges], &elm,
+				 sizeof(elm)))
+			return -EFAULT;
+	}
+	ctx->num_ranges++;
+	return 0;
+}
+
+int iommufd_device_get_recommended_reservations(struct iommufd_ucmd *ucmd)
+{
+	struct iommu_recommended_reservations *cmd = ucmd->cmd;
+	struct recommended_resv_ctx ctx;
+	struct iommufd_device *idev;
+	int rc;
+
+	if (cmd->flags)
+		return -EOPNOTSUPP;
+
+	idev = iommufd_get_device(ucmd, cmd->dev_id);
+	if (IS_ERR(idev))
+		return PTR_ERR(idev);
+
+	if (!dev_is_pci(idev->dev)) {
+		rc = -EOPNOTSUPP;
+		goto out_put;
+	}
+
+	ctx.out_ranges = u64_to_user_ptr(cmd->out_ranges);
+	ctx.max_ranges = cmd->num_ranges;
+	ctx.num_ranges = 0;
+
+	rc = iommu_for_each_pci_mmio_window(to_pci_dev(idev->dev),
+					    recommended_resv_window_fn, &ctx);
+	if (rc)
+		goto out_put;
+
+	cmd->num_ranges = ctx.num_ranges;
+	rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd));
+	if (rc)
+		goto out_put;
+	if (ctx.num_ranges > ctx.max_ranges)
+		rc = -EMSGSIZE;
+
+out_put:
+	iommufd_put_object(ucmd->ictx, &idev->obj);
+	return rc;
+}
diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h
index eb2e85b27e42..8016c3efca78 100644
--- a/drivers/iommu/iommufd/iommufd_private.h
+++ b/drivers/iommu/iommufd/iommufd_private.h
@@ -534,6 +534,7 @@ iommufd_device_get_iommu_dev(struct iommufd_device *idev)
 
 void iommufd_device_pre_destroy(struct iommufd_object *obj);
 void iommufd_device_destroy(struct iommufd_object *obj);
+int iommufd_device_get_recommended_reservations(struct iommufd_ucmd *ucmd);
 int iommufd_get_hw_info(struct iommufd_ucmd *ucmd);
 
 struct device *iommufd_global_device(void);
diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c
index 9a921b153162..85f8ea154218 100644
--- a/drivers/iommu/iommufd/main.c
+++ b/drivers/iommu/iommufd/main.c
@@ -449,6 +449,7 @@ union ucmd_buffer {
 	struct iommu_ioas_map map;
 	struct iommu_ioas_unmap unmap;
 	struct iommu_option option;
+	struct iommu_recommended_reservations recommended_reservations;
 	struct iommu_vdevice_alloc vdev;
 	struct iommu_veventq_alloc veventq;
 	struct iommu_vfio_ioas vfio_ioas;
@@ -480,6 +481,9 @@ static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = {
 		 struct iommu_fault_alloc, out_fault_fd),
 	IOCTL_OP(IOMMU_GET_HW_INFO, iommufd_get_hw_info, struct iommu_hw_info,
 		 __reserved),
+	IOCTL_OP(IOMMU_GET_RECOMMENDED_RESERVATIONS,
+		 iommufd_device_get_recommended_reservations,
+		 struct iommu_recommended_reservations, out_ranges),
 	IOCTL_OP(IOMMU_HW_QUEUE_ALLOC, iommufd_hw_queue_alloc_ioctl,
 		 struct iommu_hw_queue_alloc, length),
 	IOCTL_OP(IOMMU_HWPT_ALLOC, iommufd_hwpt_alloc, struct iommu_hwpt_alloc,
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 010f47f7d3d2..45ba7bd7abd5 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -58,6 +58,7 @@ enum {
 	IOMMUFD_CMD_VEVENTQ_ALLOC = 0x93,
 	IOMMUFD_CMD_HW_QUEUE_ALLOC = 0x94,
 	IOMMUFD_CMD_IOAS_NOIOMMU_GET_PA = 0x95,
+	IOMMUFD_CMD_GET_RECOMMENDED_RESERVATIONS = 0x96,
 };
 
 /**
@@ -1398,4 +1399,41 @@ struct iommu_hw_queue_alloc {
 	__aligned_u64 length;
 };
 #define IOMMU_HW_QUEUE_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HW_QUEUE_ALLOC)
+
+/**
+ * struct iommu_recommended_reservations - ioctl(IOMMU_GET_RECOMMENDED_RESERVATIONS)
+ * @size: sizeof(struct iommu_recommended_reservations)
+ * @flags: Must be 0
+ * @dev_id: The device bound to iommufd to query
+ * @num_ranges: Input/output number of recommended ranges
+ * @out_ranges: Pointer to the output array of struct iommu_iova_range
+ *
+ * Query the IOVA ranges the kernel recommends reserving for @dev_id.
+ * For a PCI device these are the MMIO windows of its host bridge,
+ * where a PCIe switch could misroute DMA as peer-to-peer traffic.
+ * Advisory only: userspace may feed the ranges back through
+ * IOMMU_IOAS_RESERVE_IOVAS or handle them itself.
+ *
+ * Ranges are reported in resource order, not guaranteed sorted, and
+ * should be treated as a set.  Query each device and take the union
+ * when multiple devices are in use.
+ *
+ * On input num_ranges is the length of the out_ranges array.  On
+ * output it is the total number of ranges.  The ioctl will return
+ * -EMSGSIZE and set num_ranges to the required value if num_ranges is
+ * too small.
+ *
+ * Return: 0 on success, -EOPNOTSUPP if the device has no
+ * recommendations, -ENOENT if @dev_id is invalid, -EMSGSIZE if the
+ * output array is too small.
+ */
+struct iommu_recommended_reservations {
+	__u32 size;
+	__u32 flags;
+	__u32 dev_id;
+	__u32 num_ranges;
+	__aligned_u64 out_ranges;
+};
+#define IOMMU_GET_RECOMMENDED_RESERVATIONS \
+	_IO(IOMMUFD_TYPE, IOMMUFD_CMD_GET_RECOMMENDED_RESERVATIONS)
 #endif
-- 
2.43.7


  parent reply	other threads:[~2026-10-28  9:05 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-21  7:02 [PATCH] iommu: Reserve PCI host bridge MMIO windows in group reserved regions Guanghui Feng
2026-09-21 10:39 ` [PATCH v2 0/2] iommu: Reserve PCI host bridge MMIO windows for IOVA Guanghui Feng
2026-09-21 10:39   ` [PATCH v2 1/2] iommu: Reserve PCI host bridge MMIO windows in group reserved regions Guanghui Feng
2026-09-21 10:39   ` [PATCH v2 2/2] iommufd: Reserve PCI host bridge MMIO windows in IOAS " Guanghui Feng
2026-09-21 11:24   ` [PATCH v2 0/2] iommu: Reserve PCI host bridge MMIO windows for IOVA Robin Murphy
2026-09-21 11:55     ` Jason Gunthorpe
2026-10-04 16:22       ` [PATCH v3 0/2] iommu/iommufd: Expose PCI host bridge MMIO windows for opt-in IOVA avoidance Guanghui Feng
2026-10-04 16:22         ` [PATCH v3 1/2] iommu: Add iommu_get_pci_resv_windows() helper Guanghui Feng
2026-10-22 19:35           ` Jason Gunthorpe
2026-10-04 16:22         ` [PATCH v3 2/2] iommufd: Add IOMMU_GET_PCI_MMIO_WINDOWS ioctl Guanghui Feng
2026-10-22 19:33           ` Jason Gunthorpe
2026-10-25 13:29             ` [PATCH v4 0/2] iommu/iommufd: Expose PCI host bridge MMIO windows for opt-in IOVA avoidance Guanghui Feng
2026-10-25 13:29               ` [PATCH v4 1/2] iommu: Add iommu_for_each_pci_mmio_window() iterator Guanghui Feng
2026-10-27 18:29                 ` Jason Gunthorpe
2026-10-25 13:30               ` [PATCH v4 2/2] iommufd: Add IOMMU_GET_PCI_MMIO_WINDOWS ioctl Guanghui Feng
2026-10-27 18:34                 ` Jason Gunthorpe
2026-10-28  7:19                   ` [PATCH v5 0/3] iommufd: Recommended reservations query and opt-in IOAS reservation Guanghui Feng
2026-10-28  7:19                     ` [PATCH v5 1/3] iommu: Add iommu_for_each_pci_mmio_window() iterator Guanghui Feng
2026-10-28  7:19                     ` [PATCH v5 2/3] iommufd: Add IOMMU_GET_RECOMMENDED_RESERVATIONS ioctl Guanghui Feng
2026-10-28  7:19                     ` [PATCH v5 3/3] iommufd: Add IOMMU_IOAS_RESERVE_IOVAS ioctl Guanghui Feng
2026-10-28  9:04                     ` [PATCH v6 0/3] iommufd: Recommended reservations query and opt-in IOAS reservation Guanghui Feng
2026-10-28  9:04                       ` [PATCH v6 1/3] iommu: Add iommu_for_each_pci_mmio_window() iterator Guanghui Feng
2026-10-28  9:04                       ` Guanghui Feng [this message]
2026-10-28  9:04                       ` [PATCH v6 3/3] iommufd: Add IOMMU_IOAS_RESERVE_IOVAS ioctl Guanghui Feng

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261028090453.2392991-3-guanghuifeng@linux.alibaba.com \
    --to=guanghuifeng@linux.alibaba.com \
    --cc=alex@shazbot.org \
    --cc=iommu@lists.linux.dev \
    --cc=jgg@ziepe.ca \
    --cc=joro@8bytes.org \
    --cc=kevin.tian@intel.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=robin.murphy@arm.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®