A few users need to convert a specific "ranges" entry into a struct resource. Add a helper to similar to of_address_to_resource(). The existing of_pci_range_to_resource() helper isn't really PCI specific, so it can be used with the CONFIG_PCI check dropped. Signed-off-by: Rob Herring <robh@xxxxxxxxxx> --- drivers/of/address.c | 31 ++++++++++++++++++++++++++++--- drivers/of/unittest.c | 16 +++++++++++++++- include/linux/of_address.h | 8 ++++++++ 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/drivers/of/address.c b/drivers/of/address.c index 4c0b169ef9bf..b79f005834fc 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -229,9 +229,6 @@ int of_pci_range_to_resource(struct of_pci_range *range, res->parent = res->child = res->sibling = NULL; res->name = np->full_name; - if (!IS_ENABLED(CONFIG_PCI)) - return -ENOSYS; - if (res->flags & IORESOURCE_IO) { unsigned long port; err = pci_register_io_range(&np->fwnode, range->cpu_addr, @@ -263,6 +260,34 @@ int of_pci_range_to_resource(struct of_pci_range *range, } EXPORT_SYMBOL(of_pci_range_to_resource); +/* + * of_range_to_resource - Create a resource from a ranges entry + * @np: device node where the range belongs to + * @index: the 'ranges' index to convert to a resource + * @res: pointer to a valid resource that will be updated to + * reflect the values contained in the range. + * + * Returns ENOENT if the entry is not found or EINVAL if the range cannot be + * converted to resource. + */ +int of_range_to_resource(struct device_node *np, int index, struct resource *res) +{ + int ret, i = 0; + struct of_range_parser parser; + struct of_range range; + + ret = of_range_parser_init(&parser, np); + if (ret) + return ret; + + for_each_of_range(&parser, &range) + if (i++ == index) + return of_pci_range_to_resource(&range, np, res); + + return -ENOENT; +} +EXPORT_SYMBOL(of_range_to_resource); + /* * ISA bus specific translator */ diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 1a45df1f354a..945288d5672f 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -1013,7 +1013,8 @@ static void __init of_unittest_bus_ranges(void) struct device_node *np; struct of_range range; struct of_range_parser parser; - int i = 0; + struct resource res; + int ret, i = 0; np = of_find_node_by_path("/testcase-data/address-tests"); if (!np) { @@ -1026,6 +1027,19 @@ static void __init of_unittest_bus_ranges(void) return; } + ret = of_range_to_resource(np, 1, &res); + unittest(!ret, "of_range_to_resource returned error (%d) node %pOF\n", + ret, np); + unittest(resource_type(&res) == IORESOURCE_MEM, + "of_range_to_resource wrong resource type on node %pOF res=%pR\n", + np, &res); + unittest(res.start == 0xd0000000, + "of_range_to_resource wrong resource start address on node %pOF res=%pR\n", + np, &res); + unittest(resource_size(&res) == 0x20000000, + "of_range_to_resource wrong resource start address on node %pOF res=%pR\n", + np, &res); + /* * Get the "ranges" from the device tree */ diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 376671594746..1d005439f026 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -68,6 +68,8 @@ extern int of_pci_address_to_resource(struct device_node *dev, int bar, extern int of_pci_range_to_resource(struct of_pci_range *range, struct device_node *np, struct resource *res); +extern int of_range_to_resource(struct device_node *np, int index, + struct resource *res); extern bool of_dma_is_coherent(struct device_node *np); #else /* CONFIG_OF_ADDRESS */ static inline void __iomem *of_io_request_and_map(struct device_node *device, @@ -120,6 +122,12 @@ static inline int of_pci_range_to_resource(struct of_pci_range *range, return -ENOSYS; } +static inline int of_range_to_resource(struct device_node *np, int index, + struct resource *res) +{ + return -ENOSYS; +} + static inline bool of_dma_is_coherent(struct device_node *np) { return false; -- 2.39.2