All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jason Gunthorpe <jgg@nvidia.com>
To: acpica-devel@lists.linux.dev, Andy Gross <agross@kernel.org>,
	Alim Akhtar <alim.akhtar@samsung.com>,
	Alyssa Rosenzweig <alyssa@rosenzweig.io>,
	Bjorn Andersson <andersson@kernel.org>,
	AngeloGioacchino Del Regno
	<angelogioacchino.delregno@collabora.com>,
	asahi@lists.linux.dev,
	Baolin Wang <baolin.wang@linux.alibaba.com>,
	devicetree@vger.kernel.org, Frank Rowand <frowand.list@gmail.com>,
	Hanjun Guo <guohanjun@huawei.com>,
	"Gustavo A. R. Silva" <gustavoars@kernel.org>,
	Heiko Stuebner <heiko@sntech.de>,
	iommu@lists.linux.dev,
	Jean-Philippe Brucker <jean-philippe@linaro.org>,
	Jernej Skrabec <jernej.skrabec@gmail.com>,
	Jonathan Hunter <jonathanh@nvidia.com>,
	Joerg Roedel <joro@8bytes.org>, Kees Cook <keescook@chromium.org>,
	Konrad Dybcio <konrad.dybcio@linaro.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>,
	Len Brown <lenb@kernel.org>,
	linux-acpi@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-arm-msm@vger.kernel.org, linux-hardening@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-rockchip@lists.infradead.org,
	linux-samsung-soc@vger.kernel.org, linux-sunxi@lists.linux.dev,
	linux-tegra@vger.kernel.org,
	Lorenzo Pieralisi <lpieralisi@kernel.org>,
	Marek Szyprowski <m.szyprowski@samsung.com>,
	Hector Martin <marcan@marcan.st>,
	Matthias Brugger <matthias.bgg@gmail.com>,
	Orson Zhai <orsonzhai@gmail.com>,
	"Rafael J. Wysocki" <rafael@kernel.org>,
	Rob Clark <robdclark@gmail.com>,
	Robert Moore <robert.moore@intel.com>,
	Rob Herring <robh+dt@kernel.org>,
	Robin Murphy <robin.murphy@arm.com>,
	Samuel Holland <samuel@sholland.org>,
	Sudeep Holla <sudeep.holla@arm.com>,
	Sven Peter <sven@svenpeter.dev>,
	Thierry Reding <thierry.reding@gmail.com>,
	Krishna Reddy <vdumpa@nvidia.com>,
	virtualization@lists.linux.dev, Chen-Yu Tsai <wens@csie.org>,
	Will Deacon <will@kernel.org>, Yong Wu <yong.wu@mediatek.com>,
	Chunyan Zhang <zhang.lyra@gmail.com>
Cc: "André Draszik" <andre.draszik@linaro.org>, patches@lists.linux.dev
Subject: [PATCH 08/30] iommu/of: Add iommu_of_get_single_iommu()
Date: Wed, 29 Nov 2023 21:10:15 -0400	[thread overview]
Message-ID: <8-v1-f82a05539a64+5042-iommu_fwspec_p2_jgg@nvidia.com> (raw)
In-Reply-To: <0-v1-f82a05539a64+5042-iommu_fwspec_p2_jgg@nvidia.com>

This function can be called by drivers in their probe function to return a
single iommu_device instance associated with the current probe.

All drivers need a way to get the iommu_device instance the FW says the
device should be using. Wrap the function with a macro that does the
container_of().

The driver indicates what instances it accepts by passing in its ops.

num_cells is provided to validate that the args are correctly sized.

This function is all that is required by drivers that only support a
single IOMMU instance and no IDs data. Driver's should follow a typical
pattern in their probe_device:

	iommu = iommu_of_get_single_iommu(pinf, &rk_iommu_ops, -1,
					  struct rk_iommu, iommu);
	if (IS_ERR(iommu)) return ERR_CAST(iommu);

	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data) return ERR_PTR(-ENOMEM);
	[..]
	dev_iommu_priv_set(dev, data);
        return &iommu->iommu;

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/acpi/scan.c          |  1 +
 drivers/iommu/iommu.c        | 52 ++++++++++++++++++++++
 drivers/iommu/of_iommu.c     | 59 +++++++++++++++++++++++++
 include/linux/iommu-driver.h | 85 ++++++++++++++++++++++++++++++++++++
 4 files changed, 197 insertions(+)

diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 9c13df632aa5e0..de36299c3b75bf 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1570,6 +1570,7 @@ static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in)
 	const struct iommu_ops *ops;
 	struct iommu_probe_info pinf = {
 		.dev = dev,
+		.is_dma_configure = true,
 	};
 
 	/* Serialise to make dev->iommu stable under our potential fwspec */
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 45e6543748fd46..ca411ad14c1182 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -3015,6 +3015,58 @@ struct iommu_device *iommu_device_from_fwnode(struct fwnode_handle *fwnode)
 	return NULL;
 }
 
+/*
+ * Helper for FW interfaces to parse the fwnode into an iommu_driver. This
+ * caches past search results to avoid re-searching the linked list and computes
+ * if the FW is describing a single or multi-instance ID list.
+ */
+struct iommu_device *
+iommu_device_from_fwnode_pinf(struct iommu_probe_info *pinf,
+			      const struct iommu_ops *ops,
+			      struct fwnode_handle *fwnode)
+{
+	struct iommu_device *iommu = pinf->cached_iommu;
+
+	if (!pinf->num_ids)
+		pinf->cached_single_iommu = true;
+
+	if (!iommu || iommu->fwnode != fwnode) {
+		iommu = iommu_device_from_fwnode(fwnode);
+		if (!iommu)
+			return ERR_PTR(
+				driver_deferred_probe_check_state(pinf->dev));
+		pinf->cached_iommu = iommu;
+		if (pinf->num_ids)
+			pinf->cached_single_iommu = false;
+	}
+
+	/* NULL ops is used for the -EPROBE_DEFER check, match everything */
+	if (ops && iommu->ops != ops) {
+		if (!pinf->num_ids)
+			return ERR_PTR(-ENODEV);
+		dev_err(pinf->dev,
+			FW_BUG
+			"One device in the FW has iommu's with different Linux drivers, expecting %ps FW wants %ps.",
+			ops, iommu->ops);
+		return ERR_PTR(-EINVAL);
+	}
+	return iommu;
+}
+
+struct iommu_device *iommu_fw_finish_get_single(struct iommu_probe_info *pinf)
+{
+	if (WARN_ON(!pinf->num_ids || !pinf->cached_iommu))
+		return ERR_PTR(-EINVAL);
+	if (!pinf->cached_single_iommu) {
+		dev_err(pinf->dev,
+			FW_BUG
+			"The iommu driver %ps expects only one iommu instance, the FW has more.\n",
+			pinf->cached_iommu->ops);
+		return ERR_PTR(-EINVAL);
+	}
+	return pinf->cached_iommu;
+}
+
 int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
 		      const struct iommu_ops *ops)
 {
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 20266a8edd5c71..37af32a6bc84e5 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -138,6 +138,9 @@ int of_iommu_configure(struct device *dev, struct device_node *master_np,
 {
 	struct iommu_probe_info pinf = {
 		.dev = dev,
+		.of_master_np = master_np,
+		.of_map_id = id,
+		.is_dma_configure = true,
 	};
 	struct iommu_fwspec *fwspec;
 	int err;
@@ -277,3 +280,59 @@ void of_iommu_get_resv_regions(struct device *dev, struct list_head *list)
 #endif
 }
 EXPORT_SYMBOL(of_iommu_get_resv_regions);
+
+struct parse_info {
+	struct iommu_probe_info *pinf;
+	const struct iommu_ops *ops;
+	int num_cells;
+};
+
+static struct iommu_device *parse_iommu(struct parse_info *info,
+					struct of_phandle_args *iommu_spec)
+{
+	if (!of_device_is_available(iommu_spec->np))
+		return ERR_PTR(-ENODEV);
+
+	if (info->num_cells != -1 && iommu_spec->args_count != info->num_cells) {
+		dev_err(info->pinf->dev,
+			FW_BUG
+			"Driver %ps expects number of cells %u but DT has %u\n",
+			info->ops, info->num_cells, iommu_spec->args_count);
+		return ERR_PTR(-EINVAL);
+	}
+	return iommu_device_from_fwnode_pinf(info->pinf, info->ops,
+					     &iommu_spec->np->fwnode);
+}
+
+static int parse_single_iommu(struct of_phandle_args *iommu_spec, void *_info)
+{
+	struct parse_info *info = _info;
+	struct iommu_device *iommu;
+
+	iommu = parse_iommu(info, iommu_spec);
+	if (IS_ERR(iommu))
+		return PTR_ERR(iommu);
+	info->pinf->num_ids++;
+	return 0;
+}
+
+struct iommu_device *__iommu_of_get_single_iommu(struct iommu_probe_info *pinf,
+						 const struct iommu_ops *ops,
+						 int num_cells)
+{
+	struct parse_info info = { .pinf = pinf,
+				   .ops = ops,
+				   .num_cells = num_cells };
+	int err;
+
+	if (!pinf->is_dma_configure || !pinf->of_master_np)
+		return ERR_PTR(-ENODEV);
+
+	iommu_fw_clear_cache(pinf);
+	err = of_iommu_for_each_id(pinf->dev, pinf->of_master_np,
+				   pinf->of_map_id, parse_single_iommu, &info);
+	if (err)
+		return ERR_PTR(err);
+	return iommu_fw_finish_get_single(pinf);
+}
+EXPORT_SYMBOL_GPL(__iommu_of_get_single_iommu);
diff --git a/include/linux/iommu-driver.h b/include/linux/iommu-driver.h
index c572620d3069b4..597998a62b0dd6 100644
--- a/include/linux/iommu-driver.h
+++ b/include/linux/iommu-driver.h
@@ -13,25 +13,110 @@
 #endif
 
 #include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
 
+struct of_phandle_args;
 struct fwnode_handle;
+struct iommu_device;
+struct iommu_ops;
+
+/*
+ * FIXME this is sort of like container_of_safe() that was removed, do we want
+ * to put it in the common header?
+ */
+#define container_of_err(ptr, type, member)                       \
+	({                                                        \
+		void *__mptr = (void *)(ptr);                     \
+								  \
+		(offsetof(type, member) != 0 && IS_ERR(__mptr)) ? \
+			(type *)ERR_CAST(__mptr) :                \
+			container_of(ptr, type, member);          \
+	})
 
 struct iommu_probe_info {
 	struct device *dev;
 	struct list_head *deferred_group_list;
+	struct iommu_device *cached_iommu;
+	struct device_node *of_master_np;
+	const u32 *of_map_id;
+	unsigned int num_ids;
 	bool defer_setup : 1;
+	bool is_dma_configure : 1;
+	bool cached_single_iommu : 1;
 };
 
+static inline void iommu_fw_clear_cache(struct iommu_probe_info *pinf)
+{
+	pinf->num_ids = 0;
+	pinf->cached_single_iommu = true;
+}
+
 int iommu_probe_device_pinf(struct iommu_probe_info *pinf);
 struct iommu_device *iommu_device_from_fwnode(struct fwnode_handle *fwnode);
+struct iommu_device *
+iommu_device_from_fwnode_pinf(struct iommu_probe_info *pinf,
+			      const struct iommu_ops *ops,
+			      struct fwnode_handle *fwnode);
+struct iommu_device *iommu_fw_finish_get_single(struct iommu_probe_info *pinf);
 
 #if IS_ENABLED(CONFIG_OF_IOMMU)
 void of_iommu_get_resv_regions(struct device *dev, struct list_head *list);
+
+struct iommu_device *__iommu_of_get_single_iommu(struct iommu_probe_info *pinf,
+						 const struct iommu_ops *ops,
+						 int num_cells);
 #else
 static inline void of_iommu_get_resv_regions(struct device *dev,
 					     struct list_head *list)
 {
 }
+static inline
+struct iommu_device *__iommu_of_get_single_iommu(struct iommu_probe_info *pinf,
+						 const struct iommu_ops *ops,
+						 int num_cells)
+{
+	return ERR_PTR(-ENODEV);
+}
 #endif
 
+/**
+ * iommu_of_get_single_iommu - Return the driver's iommu instance
+ * @pinf: The iommu_probe_info
+ * @ops: The ops the iommu instance must have
+ * @num_cells: #iommu-cells value to enforce, -1 is no check
+ * @drv_struct: The driver struct containing the struct iommu_device
+ * @member: The name of the iommu_device member
+ *
+ * Parse the OF table describing the iommus and return a pointer to the driver's
+ * iommu_device struct that the OF table points to. Check that the OF table is
+ * well formed with a single iommu for all the entries and that the table refers
+ * to this iommu driver. Integrates a container_of() to simplify all users.
+ */
+#define iommu_of_get_single_iommu(pinf, ops, num_cells, drv_struct, member)  \
+	container_of_err(__iommu_of_get_single_iommu(pinf, ops, num_cells), \
+			  drv_struct, member)
+
+/**
+ * iommu_of_num_ids - Return the number of iommu associations the FW has
+ * @pinf: The iommu_probe_info
+ *
+ * For drivers using iommu_of_get_single_iommu() this will return the number
+ * of ids associated with the iommu instance. For other cases this will return
+ * the sum of all ids across all instances. Returns >= 1.
+ */
+static inline unsigned int iommu_of_num_ids(struct iommu_probe_info *pinf)
+{
+	return pinf->num_ids;
+}
+
+/*
+ * Used temporarily to indicate drivers that have moved to the new probe method.
+ */
+static inline int iommu_dummy_of_xlate(struct device *dev,
+				       struct of_phandle_args *args)
+{
+	return 0;
+}
+
 #endif
-- 
2.42.0


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

WARNING: multiple messages have this Message-ID (diff)
From: Jason Gunthorpe <jgg@nvidia.com>
To: acpica-devel@lists.linux.dev, Andy Gross <agross@kernel.org>,
	Alim Akhtar <alim.akhtar@samsung.com>,
	Alyssa Rosenzweig <alyssa@rosenzweig.io>,
	Bjorn Andersson <andersson@kernel.org>,
	AngeloGioacchino Del Regno
	<angelogioacchino.delregno@collabora.com>,
	asahi@lists.linux.dev,
	Baolin Wang <baolin.wang@linux.alibaba.com>,
	devicetree@vger.kernel.org, Frank Rowand <frowand.list@gmail.com>,
	Hanjun Guo <guohanjun@huawei.com>,
	"Gustavo A. R. Silva" <gustavoars@kernel.org>,
	Heiko Stuebner <heiko@sntech.de>,
	iommu@lists.linux.dev,
	Jean-Philippe Brucker <jean-philippe@linaro.org>,
	Jernej Skrabec <jernej.skrabec@gmail.com>,
	Jonathan Hunter <jonathanh@nvidia.com>,
	Joerg Roedel <joro@8bytes.org>, Kees Cook <keescook@chromium.org>,
	Konrad Dybcio <konrad.dybcio@linaro.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>,
	Len Brown <lenb@kernel.org>,
	linux-acpi@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-arm-msm@vger.kernel.org, linux-hardening@vger.kernel.org,
	linux-mediatek@lists.infradead.org,
	linux-rockchip@lists.infradead.org,
	linux-samsung-soc@vger.kernel.org, linux-sunxi@lists.linux.dev,
	linux-tegra@vger.kernel.org,
	Lorenzo Pieralisi <lpieralisi@kernel.org>,
	Marek Szyprowski <m.szyprowski@samsung.com>,
	Hector Martin <marcan@marcan.st>,
	Matthias Brugger <matthias.bgg@gmail.com>,
	Orson Zhai <orsonzhai@gmail.com>,
	"Rafael J. Wysocki" <rafael@kernel.org>,
	Rob Clark <robdclark@gmail.com>,
	Robert Moore <robert.moore@intel.com>,
	Rob Herring <robh+dt@kernel.org>,
	Robin Murphy <robin.murphy@arm.com>,
	Samuel Holland <samuel@sholland.org>,
	Sudeep Holla <sudeep.holla@arm.com>,
	Sven Peter <sven@svenpeter.dev>,
	Thierry Reding <thierry.reding@gmail.com>,
	Krishna Reddy <vdumpa@nvidia.com>,
	virtualization@lists.linux.dev, Chen-Yu Tsai <wens@csie.org>,
	Will Deacon <will@kernel.org>, Yong Wu <yong.wu@mediatek.com>,
	Chunyan Zhang <zhang.lyra@gmail.com>
Cc: "André Draszik" <andre.draszik@linaro.org>, patches@lists.linux.dev
Subject: [PATCH 08/30] iommu/of: Add iommu_of_get_single_iommu()
Date: Wed, 29 Nov 2023 21:10:15 -0400	[thread overview]
Message-ID: <8-v1-f82a05539a64+5042-iommu_fwspec_p2_jgg@nvidia.com> (raw)
In-Reply-To: <0-v1-f82a05539a64+5042-iommu_fwspec_p2_jgg@nvidia.com>

This function can be called by drivers in their probe function to return a
single iommu_device instance associated with the current probe.

All drivers need a way to get the iommu_device instance the FW says the
device should be using. Wrap the function with a macro that does the
container_of().

The driver indicates what instances it accepts by passing in its ops.

num_cells is provided to validate that the args are correctly sized.

This function is all that is required by drivers that only support a
single IOMMU instance and no IDs data. Driver's should follow a typical
pattern in their probe_device:

	iommu = iommu_of_get_single_iommu(pinf, &rk_iommu_ops, -1,
					  struct rk_iommu, iommu);
	if (IS_ERR(iommu)) return ERR_CAST(iommu);

	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data) return ERR_PTR(-ENOMEM);
	[..]
	dev_iommu_priv_set(dev, data);
        return &iommu->iommu;

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/acpi/scan.c          |  1 +
 drivers/iommu/iommu.c        | 52 ++++++++++++++++++++++
 drivers/iommu/of_iommu.c     | 59 +++++++++++++++++++++++++
 include/linux/iommu-driver.h | 85 ++++++++++++++++++++++++++++++++++++
 4 files changed, 197 insertions(+)

diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 9c13df632aa5e0..de36299c3b75bf 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1570,6 +1570,7 @@ static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in)
 	const struct iommu_ops *ops;
 	struct iommu_probe_info pinf = {
 		.dev = dev,
+		.is_dma_configure = true,
 	};
 
 	/* Serialise to make dev->iommu stable under our potential fwspec */
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 45e6543748fd46..ca411ad14c1182 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -3015,6 +3015,58 @@ struct iommu_device *iommu_device_from_fwnode(struct fwnode_handle *fwnode)
 	return NULL;
 }
 
+/*
+ * Helper for FW interfaces to parse the fwnode into an iommu_driver. This
+ * caches past search results to avoid re-searching the linked list and computes
+ * if the FW is describing a single or multi-instance ID list.
+ */
+struct iommu_device *
+iommu_device_from_fwnode_pinf(struct iommu_probe_info *pinf,
+			      const struct iommu_ops *ops,
+			      struct fwnode_handle *fwnode)
+{
+	struct iommu_device *iommu = pinf->cached_iommu;
+
+	if (!pinf->num_ids)
+		pinf->cached_single_iommu = true;
+
+	if (!iommu || iommu->fwnode != fwnode) {
+		iommu = iommu_device_from_fwnode(fwnode);
+		if (!iommu)
+			return ERR_PTR(
+				driver_deferred_probe_check_state(pinf->dev));
+		pinf->cached_iommu = iommu;
+		if (pinf->num_ids)
+			pinf->cached_single_iommu = false;
+	}
+
+	/* NULL ops is used for the -EPROBE_DEFER check, match everything */
+	if (ops && iommu->ops != ops) {
+		if (!pinf->num_ids)
+			return ERR_PTR(-ENODEV);
+		dev_err(pinf->dev,
+			FW_BUG
+			"One device in the FW has iommu's with different Linux drivers, expecting %ps FW wants %ps.",
+			ops, iommu->ops);
+		return ERR_PTR(-EINVAL);
+	}
+	return iommu;
+}
+
+struct iommu_device *iommu_fw_finish_get_single(struct iommu_probe_info *pinf)
+{
+	if (WARN_ON(!pinf->num_ids || !pinf->cached_iommu))
+		return ERR_PTR(-EINVAL);
+	if (!pinf->cached_single_iommu) {
+		dev_err(pinf->dev,
+			FW_BUG
+			"The iommu driver %ps expects only one iommu instance, the FW has more.\n",
+			pinf->cached_iommu->ops);
+		return ERR_PTR(-EINVAL);
+	}
+	return pinf->cached_iommu;
+}
+
 int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
 		      const struct iommu_ops *ops)
 {
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 20266a8edd5c71..37af32a6bc84e5 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -138,6 +138,9 @@ int of_iommu_configure(struct device *dev, struct device_node *master_np,
 {
 	struct iommu_probe_info pinf = {
 		.dev = dev,
+		.of_master_np = master_np,
+		.of_map_id = id,
+		.is_dma_configure = true,
 	};
 	struct iommu_fwspec *fwspec;
 	int err;
@@ -277,3 +280,59 @@ void of_iommu_get_resv_regions(struct device *dev, struct list_head *list)
 #endif
 }
 EXPORT_SYMBOL(of_iommu_get_resv_regions);
+
+struct parse_info {
+	struct iommu_probe_info *pinf;
+	const struct iommu_ops *ops;
+	int num_cells;
+};
+
+static struct iommu_device *parse_iommu(struct parse_info *info,
+					struct of_phandle_args *iommu_spec)
+{
+	if (!of_device_is_available(iommu_spec->np))
+		return ERR_PTR(-ENODEV);
+
+	if (info->num_cells != -1 && iommu_spec->args_count != info->num_cells) {
+		dev_err(info->pinf->dev,
+			FW_BUG
+			"Driver %ps expects number of cells %u but DT has %u\n",
+			info->ops, info->num_cells, iommu_spec->args_count);
+		return ERR_PTR(-EINVAL);
+	}
+	return iommu_device_from_fwnode_pinf(info->pinf, info->ops,
+					     &iommu_spec->np->fwnode);
+}
+
+static int parse_single_iommu(struct of_phandle_args *iommu_spec, void *_info)
+{
+	struct parse_info *info = _info;
+	struct iommu_device *iommu;
+
+	iommu = parse_iommu(info, iommu_spec);
+	if (IS_ERR(iommu))
+		return PTR_ERR(iommu);
+	info->pinf->num_ids++;
+	return 0;
+}
+
+struct iommu_device *__iommu_of_get_single_iommu(struct iommu_probe_info *pinf,
+						 const struct iommu_ops *ops,
+						 int num_cells)
+{
+	struct parse_info info = { .pinf = pinf,
+				   .ops = ops,
+				   .num_cells = num_cells };
+	int err;
+
+	if (!pinf->is_dma_configure || !pinf->of_master_np)
+		return ERR_PTR(-ENODEV);
+
+	iommu_fw_clear_cache(pinf);
+	err = of_iommu_for_each_id(pinf->dev, pinf->of_master_np,
+				   pinf->of_map_id, parse_single_iommu, &info);
+	if (err)
+		return ERR_PTR(err);
+	return iommu_fw_finish_get_single(pinf);
+}
+EXPORT_SYMBOL_GPL(__iommu_of_get_single_iommu);
diff --git a/include/linux/iommu-driver.h b/include/linux/iommu-driver.h
index c572620d3069b4..597998a62b0dd6 100644
--- a/include/linux/iommu-driver.h
+++ b/include/linux/iommu-driver.h
@@ -13,25 +13,110 @@
 #endif
 
 #include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
 
+struct of_phandle_args;
 struct fwnode_handle;
+struct iommu_device;
+struct iommu_ops;
+
+/*
+ * FIXME this is sort of like container_of_safe() that was removed, do we want
+ * to put it in the common header?
+ */
+#define container_of_err(ptr, type, member)                       \
+	({                                                        \
+		void *__mptr = (void *)(ptr);                     \
+								  \
+		(offsetof(type, member) != 0 && IS_ERR(__mptr)) ? \
+			(type *)ERR_CAST(__mptr) :                \
+			container_of(ptr, type, member);          \
+	})
 
 struct iommu_probe_info {
 	struct device *dev;
 	struct list_head *deferred_group_list;
+	struct iommu_device *cached_iommu;
+	struct device_node *of_master_np;
+	const u32 *of_map_id;
+	unsigned int num_ids;
 	bool defer_setup : 1;
+	bool is_dma_configure : 1;
+	bool cached_single_iommu : 1;
 };
 
+static inline void iommu_fw_clear_cache(struct iommu_probe_info *pinf)
+{
+	pinf->num_ids = 0;
+	pinf->cached_single_iommu = true;
+}
+
 int iommu_probe_device_pinf(struct iommu_probe_info *pinf);
 struct iommu_device *iommu_device_from_fwnode(struct fwnode_handle *fwnode);
+struct iommu_device *
+iommu_device_from_fwnode_pinf(struct iommu_probe_info *pinf,
+			      const struct iommu_ops *ops,
+			      struct fwnode_handle *fwnode);
+struct iommu_device *iommu_fw_finish_get_single(struct iommu_probe_info *pinf);
 
 #if IS_ENABLED(CONFIG_OF_IOMMU)
 void of_iommu_get_resv_regions(struct device *dev, struct list_head *list);
+
+struct iommu_device *__iommu_of_get_single_iommu(struct iommu_probe_info *pinf,
+						 const struct iommu_ops *ops,
+						 int num_cells);
 #else
 static inline void of_iommu_get_resv_regions(struct device *dev,
 					     struct list_head *list)
 {
 }
+static inline
+struct iommu_device *__iommu_of_get_single_iommu(struct iommu_probe_info *pinf,
+						 const struct iommu_ops *ops,
+						 int num_cells)
+{
+	return ERR_PTR(-ENODEV);
+}
 #endif
 
+/**
+ * iommu_of_get_single_iommu - Return the driver's iommu instance
+ * @pinf: The iommu_probe_info
+ * @ops: The ops the iommu instance must have
+ * @num_cells: #iommu-cells value to enforce, -1 is no check
+ * @drv_struct: The driver struct containing the struct iommu_device
+ * @member: The name of the iommu_device member
+ *
+ * Parse the OF table describing the iommus and return a pointer to the driver's
+ * iommu_device struct that the OF table points to. Check that the OF table is
+ * well formed with a single iommu for all the entries and that the table refers
+ * to this iommu driver. Integrates a container_of() to simplify all users.
+ */
+#define iommu_of_get_single_iommu(pinf, ops, num_cells, drv_struct, member)  \
+	container_of_err(__iommu_of_get_single_iommu(pinf, ops, num_cells), \
+			  drv_struct, member)
+
+/**
+ * iommu_of_num_ids - Return the number of iommu associations the FW has
+ * @pinf: The iommu_probe_info
+ *
+ * For drivers using iommu_of_get_single_iommu() this will return the number
+ * of ids associated with the iommu instance. For other cases this will return
+ * the sum of all ids across all instances. Returns >= 1.
+ */
+static inline unsigned int iommu_of_num_ids(struct iommu_probe_info *pinf)
+{
+	return pinf->num_ids;
+}
+
+/*
+ * Used temporarily to indicate drivers that have moved to the new probe method.
+ */
+static inline int iommu_dummy_of_xlate(struct device *dev,
+				       struct of_phandle_args *args)
+{
+	return 0;
+}
+
 #endif
-- 
2.42.0


  parent reply	other threads:[~2023-11-30  1:12 UTC|newest]

Thread overview: 68+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-30  1:10 [PATCH 00/30] Make a new API for drivers to use to get their FW Jason Gunthorpe
2023-11-30  1:10 ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 01/30] iommu/of: Make a of_iommu_for_each_id() Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 02/30] ACPI: VIOT: Make a viot_iommu_for_each_id() Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30 13:22   ` Rafael J. Wysocki
2023-11-30 13:22     ` Rafael J. Wysocki
2023-11-30  1:10 ` [PATCH 03/30] ACPI: IORT: Make a iort_iommu_for_each_id() Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30 13:21   ` Rafael J. Wysocki
2023-11-30 13:21     ` Rafael J. Wysocki
2023-11-30  1:10 ` [PATCH 04/30] ACPI: IORT: Remove fwspec from the reserved region code Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30 13:23   ` Rafael J. Wysocki
2023-11-30 13:23     ` Rafael J. Wysocki
2023-11-30  1:10 ` [PATCH 05/30] iommu: Add iommu_probe_info Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 06/30] iommu: Make iommu_ops_from_fwnode() return the iommu_device Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 07/30] iommu/of: Call of_iommu_get_resv_regions() directly Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` Jason Gunthorpe [this message]
2023-11-30  1:10   ` [PATCH 08/30] iommu/of: Add iommu_of_get_single_iommu() Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 09/30] iommu/rockchip: Move to iommu_of_get_single_iommu() Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 10/30] iommu/sprd: " Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 11/30] iommu/sun50i: " Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 12/30] iommu/of: Add iommu_of_xlate() Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 13/30] iommu/dart: Move to iommu_of_xlate() Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 14/30] iommu/exynos: " Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 15/30] iommu/msm: " Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 16/30] iommu/tegra: Route tegra_dev_iommu_get_stream_id() through an op Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 17/30] iommu: Add iommu_fw_alloc_per_device_ids() Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 18/30] iommu/tegra: Move to iommu_fw_alloc_per_device_ids() Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 19/30] iommu/mtk: " Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 20/30] iommu/ipmmu-vmsa: " Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 21/30] iommu/mtk_v1: " Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 22/30] iommu/qcom: " Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 23/30] iommu/viot: Add iommu_viot_get_single_iommu() Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 24/30] iommu/virtio: Move to iommu_fw_alloc_per_device_ids() Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 25/30] iommu/iort: Add iommu_iort_get_single_iommu() Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 26/30] iommu/arm-smmu-v3: Move to iommu_fw_alloc_per_device_ids() Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 27/30] iommu/arm-smmu: Move to iommu_of_xlate() Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 28/30] iommu: Call all drivers if there is no fwspec Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 29/30] iommu: Check for EPROBE_DEFER using the new FW parsers Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe
2023-11-30  1:10 ` [PATCH 30/30] iommu: Remove fwspec and related Jason Gunthorpe
2023-11-30  1:10   ` Jason Gunthorpe

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=8-v1-f82a05539a64+5042-iommu_fwspec_p2_jgg@nvidia.com \
    --to=jgg@nvidia.com \
    --cc=acpica-devel@lists.linux.dev \
    --cc=agross@kernel.org \
    --cc=alim.akhtar@samsung.com \
    --cc=alyssa@rosenzweig.io \
    --cc=andersson@kernel.org \
    --cc=andre.draszik@linaro.org \
    --cc=angelogioacchino.delregno@collabora.com \
    --cc=asahi@lists.linux.dev \
    --cc=baolin.wang@linux.alibaba.com \
    --cc=devicetree@vger.kernel.org \
    --cc=frowand.list@gmail.com \
    --cc=guohanjun@huawei.com \
    --cc=gustavoars@kernel.org \
    --cc=heiko@sntech.de \
    --cc=iommu@lists.linux.dev \
    --cc=jean-philippe@linaro.org \
    --cc=jernej.skrabec@gmail.com \
    --cc=jonathanh@nvidia.com \
    --cc=joro@8bytes.org \
    --cc=keescook@chromium.org \
    --cc=konrad.dybcio@linaro.org \
    --cc=krzysztof.kozlowski@linaro.org \
    --cc=lenb@kernel.org \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=linux-rockchip@lists.infradead.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=linux-sunxi@lists.linux.dev \
    --cc=linux-tegra@vger.kernel.org \
    --cc=lpieralisi@kernel.org \
    --cc=m.szyprowski@samsung.com \
    --cc=marcan@marcan.st \
    --cc=matthias.bgg@gmail.com \
    --cc=orsonzhai@gmail.com \
    --cc=patches@lists.linux.dev \
    --cc=rafael@kernel.org \
    --cc=robdclark@gmail.com \
    --cc=robert.moore@intel.com \
    --cc=robh+dt@kernel.org \
    --cc=robin.murphy@arm.com \
    --cc=samuel@sholland.org \
    --cc=sudeep.holla@arm.com \
    --cc=sven@svenpeter.dev \
    --cc=thierry.reding@gmail.com \
    --cc=vdumpa@nvidia.com \
    --cc=virtualization@lists.linux.dev \
    --cc=wens@csie.org \
    --cc=will@kernel.org \
    --cc=yong.wu@mediatek.com \
    --cc=zhang.lyra@gmail.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.