[PATCH 12/30] iommu/of: Add iommu_of_xlate()
Jason Gunthorpe
jgg at nvidia.com
Wed Nov 29 17:10:19 PST 2023
This function can be called by drivers in their probe function if they
want to parse their own ID table, almost always because the driver
supports a multi-instance configuration and needs to extract the list of
iommu_driver's and data from the ID into some internal format.
The core code will find the iommu_driver for each ID table entry and
validate that it matches the driver's ops. A driver provided function is
called to handle the (iommu_driver, ID) tuple.
Before calling this function the driver should allocate its per-driver
private data and pass it through the opaque cookie priv argument.
Driver's should follow a typical pattern in their probe_device:
static int apple_dart_of_xlate(struct iommu_device *iommu,
struct of_phandle_args *args, void *priv);
[..]
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg) return ERR_PTR(-ENOMEM);
ret = iommu_of_xlate(pinf, &apple_dart_iommu_ops, 1,
&apple_dart_of_xlate, cfg);
if (ret) goto err_free;
dev_iommu_priv_set(dev, cfg);
return &??->iommu; // The first iommu_device parsed
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
---
drivers/iommu/of_iommu.c | 58 ++++++++++++++++++++++++++++++++++++
include/linux/iommu-driver.h | 13 ++++++++
2 files changed, 71 insertions(+)
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 37af32a6bc84e5..9c1d398aa2cd9c 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -285,6 +285,8 @@ struct parse_info {
struct iommu_probe_info *pinf;
const struct iommu_ops *ops;
int num_cells;
+ iommu_of_xlate_fn xlate_fn;
+ void *priv;
};
static struct iommu_device *parse_iommu(struct parse_info *info,
@@ -336,3 +338,59 @@ struct iommu_device *__iommu_of_get_single_iommu(struct iommu_probe_info *pinf,
return iommu_fw_finish_get_single(pinf);
}
EXPORT_SYMBOL_GPL(__iommu_of_get_single_iommu);
+
+static int parse_of_xlate(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 info->xlate_fn(iommu, iommu_spec, info->priv);
+}
+
+/**
+ * iommu_of_xlate - Parse all OF ids for an IOMMU
+ * @pinf: The iommu_probe_info
+ * @ops: The ops the iommu instance must have
+ * @num_cells: #iommu-cells value to enforce, -1 is no check
+ * @fn: Call for each Instance and ID
+ * @priv: Opaque cookie for fn
+ *
+ * Drivers that support multiple iommu instances must call this function to
+ * parse each instance from the OF table. fn will be called with the driver's
+ * iommu_driver instance and the raw of_phandle_args that contains the ID.
+ *
+ * Drivers that need to parse a complex ID format should also use this function.
+ */
+int iommu_of_xlate(struct iommu_probe_info *pinf, const struct iommu_ops *ops,
+ int num_cells, iommu_of_xlate_fn fn, void *priv)
+{
+ struct parse_info info = { .pinf = pinf,
+ .ops = ops,
+ .num_cells = num_cells,
+ .xlate_fn = fn,
+ .priv = priv };
+
+ pinf->num_ids = 0;
+ return of_iommu_for_each_id(pinf->dev, pinf->of_master_np,
+ pinf->of_map_id, parse_of_xlate, &info);
+}
+EXPORT_SYMBOL_GPL(iommu_of_xlate);
+
+/*
+ * Temporary approach to allow drivers to opt into the bus probe. It configures
+ * the iommu_probe_info to probe the dev->of_node. This is a bit hacky because
+ * it mutates the iommu_probe_info and thus assumes there is only one op in the
+ * system. Remove when we call probe from the bus always anyhow.
+ */
+void iommu_of_allow_bus_probe(struct iommu_probe_info *pinf)
+{
+ if (pinf->is_dma_configure)
+ return;
+ pinf->of_master_np = pinf->dev->of_node;
+ pinf->is_dma_configure = true;
+}
+EXPORT_SYMBOL_GPL(iommu_of_allow_bus_probe);
diff --git a/include/linux/iommu-driver.h b/include/linux/iommu-driver.h
index 597998a62b0dd6..622d6ad9056ce0 100644
--- a/include/linux/iommu-driver.h
+++ b/include/linux/iommu-driver.h
@@ -60,9 +60,16 @@ iommu_device_from_fwnode_pinf(struct iommu_probe_info *pinf,
struct fwnode_handle *fwnode);
struct iommu_device *iommu_fw_finish_get_single(struct iommu_probe_info *pinf);
+typedef int (*iommu_of_xlate_fn)(struct iommu_device *iommu,
+ struct of_phandle_args *args, void *priv);
+void iommu_of_allow_bus_probe(struct iommu_probe_info *pinf);
+
#if IS_ENABLED(CONFIG_OF_IOMMU)
void of_iommu_get_resv_regions(struct device *dev, struct list_head *list);
+int iommu_of_xlate(struct iommu_probe_info *pinf, const struct iommu_ops *ops,
+ int num_cells, iommu_of_xlate_fn fn, void *priv);
+
struct iommu_device *__iommu_of_get_single_iommu(struct iommu_probe_info *pinf,
const struct iommu_ops *ops,
int num_cells);
@@ -71,6 +78,12 @@ static inline void of_iommu_get_resv_regions(struct device *dev,
struct list_head *list)
{
}
+static inline int iommu_of_xlate(struct iommu_probe_info *pinf,
+ const struct iommu_ops *ops, int num_cells,
+ iommu_of_xlate_fn fn, void *priv)
+{
+ return -ENODEV;
+}
static inline
struct iommu_device *__iommu_of_get_single_iommu(struct iommu_probe_info *pinf,
const struct iommu_ops *ops,
--
2.42.0
More information about the Linux-mediatek
mailing list