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@xxxxxxxxxx> --- 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