diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-05-17 17:27:49 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-05-17 17:27:49 -0700 |
commit | 06f054b1fee83415fe35204845708988fc16ef22 (patch) | |
tree | ec956c313bb90cd440fe5d50444eed1cea32501c /drivers/of | |
parent | 7ee332c9f12bc5b380e36919cd7d056592a7073f (diff) | |
parent | d976c6f4b32c2d273d44ff9ad7099efe16279a39 (diff) |
Merge tag 'devicetree-for-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux
Pull devicetree updates from Rob Herring:
"DT Bindings:
- Convert samsung,exynos5-dp, atmel,lcdc, aspeed,ast2400-wdt bindings
to schemas
- Add bindings for Allwinner H616 NMI controller, Renesas r8a779g0
irqc, Renesas R-Car V4M TMU and CMT timers, Freescale S32G3
linflexuart, and Mediatek MT7988 XHCI
- Add 'reg' constraints on DSI and SPI display panels
- More dropping of unnecessary quotes in schemas
- Use full paths rather than relative paths in schema $refs
- Drop redundant storing of phandle for reserved memory
DT Core:
- Use scope based cleanups for kfree() and of_node_put()
- Track interrupt-map and power-supplies for fw_devlink
- Add buffer overflow check in of_modalias()
- Add and use __of_prop_free() helper for freeing struct property"
* tag 'devicetree-for-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: (25 commits)
of: property: Add fw_devlink support for interrupt-map property
dt-bindings: display: panel: constrain 'reg' in DSI panels
dt-bindings: display: panel: constrain 'reg' in SPI panels
dt-bindings: display: samsung,ams495qa01: add missing SPI properties ref
dt-bindings: Use full path to other schemas
dt-bindings: PCI: qcom,pcie-sm8350: Drop redundant 'oneOf' sub-schema
of: module: add buffer overflow check in of_modalias()
dt-bindings: PCI: microchip: increase number of items in ranges property
dt-bindings: Drop unnecessary quotes on keys
dt-bindings: interrupt-controller: mediatek,mt6577-sysirq: Drop unnecessary quotes
of: property: Use scope based cleanup on port_node
of: reserved_mem: Remove the use of phandle from the reserved_mem APIs
of: property: fw_devlink: Add support for "power-supplies" binding
dt-bindings: watchdog: aspeed,ast2400-wdt: Convert to DT schema
dt-bindings: irq: sun7i-nmi: Add binding for the H616 NMI controller
dt-bindings: interrupt-controller: renesas,irqc: Add r8a779g0 support
dt-bindings: timer: renesas,tmu: Add R-Car V4M support
dt-bindings: timer: renesas,cmt: Add R-Car V4M support
of: Use scope based of_node_put() cleanups
of: Use scope based kfree() cleanups
...
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/address.c | 113 | ||||
-rw-r--r-- | drivers/of/base.c | 34 | ||||
-rw-r--r-- | drivers/of/dynamic.c | 37 | ||||
-rw-r--r-- | drivers/of/module.c | 7 | ||||
-rw-r--r-- | drivers/of/of_private.h | 1 | ||||
-rw-r--r-- | drivers/of/of_reserved_mem.c | 22 | ||||
-rw-r--r-- | drivers/of/overlay.c | 11 | ||||
-rw-r--r-- | drivers/of/property.c | 87 | ||||
-rw-r--r-- | drivers/of/resolver.c | 35 | ||||
-rw-r--r-- | drivers/of/unittest.c | 12 |
10 files changed, 153 insertions, 206 deletions
diff --git a/drivers/of/address.c b/drivers/of/address.c index ae46a3605904..d669ce25b5f9 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -486,34 +486,30 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, * device that had registered logical PIO mapping, and the return code is * relative to that node. */ -static u64 __of_translate_address(struct device_node *dev, +static u64 __of_translate_address(struct device_node *node, struct device_node *(*get_parent)(const struct device_node *), const __be32 *in_addr, const char *rprop, struct device_node **host) { - struct device_node *parent = NULL; + struct device_node *dev __free(device_node) = of_node_get(node); + struct device_node *parent __free(device_node) = get_parent(dev); struct of_bus *bus, *pbus; __be32 addr[OF_MAX_ADDR_CELLS]; int na, ns, pna, pns; - u64 result = OF_BAD_ADDR; pr_debug("** translation for device %pOF **\n", dev); - /* Increase refcount at current level */ - of_node_get(dev); - *host = NULL; - /* Get parent & match bus type */ - parent = get_parent(dev); + if (parent == NULL) - goto bail; + return OF_BAD_ADDR; bus = of_match_bus(parent); /* Count address cells & copy address locally */ bus->count_cells(dev, &na, &ns); if (!OF_CHECK_COUNTS(na, ns)) { pr_debug("Bad cell count for %pOF\n", dev); - goto bail; + return OF_BAD_ADDR; } memcpy(addr, in_addr, na * 4); @@ -533,8 +529,7 @@ static u64 __of_translate_address(struct device_node *dev, /* If root, we have finished */ if (parent == NULL) { pr_debug("reached root node\n"); - result = of_read_number(addr, na); - break; + return of_read_number(addr, na); } /* @@ -543,11 +538,11 @@ static u64 __of_translate_address(struct device_node *dev, */ iorange = find_io_range_by_fwnode(&dev->fwnode); if (iorange && (iorange->flags != LOGIC_PIO_CPU_MMIO)) { - result = of_read_number(addr + 1, na - 1); + u64 result = of_read_number(addr + 1, na - 1); pr_debug("indirectIO matched(%pOF) 0x%llx\n", dev, result); - *host = of_node_get(dev); - break; + *host = no_free_ptr(dev); + return result; } /* Get new parent bus and counts */ @@ -555,7 +550,7 @@ static u64 __of_translate_address(struct device_node *dev, pbus->count_cells(dev, &pna, &pns); if (!OF_CHECK_COUNTS(pna, pns)) { pr_err("Bad cell count for %pOF\n", dev); - break; + return OF_BAD_ADDR; } pr_debug("parent bus is %s (na=%d, ns=%d) on %pOF\n", @@ -563,7 +558,7 @@ static u64 __of_translate_address(struct device_node *dev, /* Apply bus translation */ if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop)) - break; + return OF_BAD_ADDR; /* Complete the move up one level */ na = pna; @@ -572,11 +567,8 @@ static u64 __of_translate_address(struct device_node *dev, of_dump_addr("one level translation:", addr, na); } - bail: - of_node_put(parent); - of_node_put(dev); - return result; + unreachable(); } u64 of_translate_address(struct device_node *dev, const __be32 *in_addr) @@ -654,19 +646,16 @@ EXPORT_SYMBOL(of_translate_dma_address); const __be32 *of_translate_dma_region(struct device_node *dev, const __be32 *prop, phys_addr_t *start, size_t *length) { - struct device_node *parent; + struct device_node *parent __free(device_node) = __of_get_dma_parent(dev); u64 address, size; int na, ns; - parent = __of_get_dma_parent(dev); if (!parent) return NULL; na = of_bus_n_addr_cells(parent); ns = of_bus_n_size_cells(parent); - of_node_put(parent); - address = of_translate_dma_address(dev, prop); if (address == OF_BAD_ADDR) return NULL; @@ -688,21 +677,19 @@ const __be32 *__of_get_address(struct device_node *dev, int index, int bar_no, { const __be32 *prop; unsigned int psize; - struct device_node *parent; + struct device_node *parent __free(device_node) = of_get_parent(dev); struct of_bus *bus; int onesize, i, na, ns; - /* Get parent & match bus type */ - parent = of_get_parent(dev); if (parent == NULL) return NULL; + + /* match the parent's bus type */ bus = of_match_bus(parent); - if (strcmp(bus->name, "pci") && (bar_no >= 0)) { - of_node_put(parent); + if (strcmp(bus->name, "pci") && (bar_no >= 0)) return NULL; - } + bus->count_cells(dev, &na, &ns); - of_node_put(parent); if (!OF_CHECK_ADDR_COUNT(na)) return NULL; @@ -888,14 +875,13 @@ static u64 of_translate_ioport(struct device_node *dev, const __be32 *in_addr, */ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map) { - struct device_node *node = of_node_get(np); + struct device_node *node __free(device_node) = of_node_get(np); const __be32 *ranges = NULL; bool found_dma_ranges = false; struct of_range_parser parser; struct of_range range; struct bus_dma_region *r; int len, num_ranges = 0; - int ret = 0; while (node) { ranges = of_get_property(node, "dma-ranges", &len); @@ -905,10 +891,9 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map) break; /* Once we find 'dma-ranges', then a missing one is an error */ - if (found_dma_ranges && !ranges) { - ret = -ENODEV; - goto out; - } + if (found_dma_ranges && !ranges) + return -ENODEV; + found_dma_ranges = true; node = of_get_next_dma_parent(node); @@ -916,10 +901,8 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map) if (!node || !ranges) { pr_debug("no dma-ranges found for node(%pOF)\n", np); - ret = -ENODEV; - goto out; + return -ENODEV; } - of_dma_range_parser_init(&parser, node); for_each_of_range(&parser, &range) { if (range.cpu_addr == OF_BAD_ADDR) { @@ -930,16 +913,12 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map) num_ranges++; } - if (!num_ranges) { - ret = -EINVAL; - goto out; - } + if (!num_ranges) + return -EINVAL; r = kcalloc(num_ranges + 1, sizeof(*r), GFP_KERNEL); - if (!r) { - ret = -ENOMEM; - goto out; - } + if (!r) + return -ENOMEM; /* * Record all info in the generic DMA ranges array for struct device, @@ -957,9 +936,7 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map) r->size = range.size; r++; } -out: - of_node_put(node); - return ret; + return 0; } #endif /* CONFIG_HAS_DMA */ @@ -1016,24 +993,18 @@ phys_addr_t __init of_dma_get_max_cpu_address(struct device_node *np) */ bool of_dma_is_coherent(struct device_node *np) { - struct device_node *node; - bool is_coherent = dma_default_coherent; - - node = of_node_get(np); + struct device_node *node __free(device_node) = of_node_get(np); while (node) { - if (of_property_read_bool(node, "dma-coherent")) { - is_coherent = true; - break; - } - if (of_property_read_bool(node, "dma-noncoherent")) { - is_coherent = false; - break; - } + if (of_property_read_bool(node, "dma-coherent")) + return true; + + if (of_property_read_bool(node, "dma-noncoherent")) + return false; + node = of_get_next_dma_parent(node); } - of_node_put(node); - return is_coherent; + return dma_default_coherent; } EXPORT_SYMBOL_GPL(of_dma_is_coherent); @@ -1049,20 +1020,14 @@ EXPORT_SYMBOL_GPL(of_dma_is_coherent); */ static bool of_mmio_is_nonposted(struct device_node *np) { - struct device_node *parent; - bool nonposted; - if (!IS_ENABLED(CONFIG_ARCH_APPLE)) return false; - parent = of_get_parent(np); + struct device_node *parent __free(device_node) = of_get_parent(np); if (!parent) return false; - nonposted = of_property_read_bool(parent, "nonposted-mmio"); - - of_node_put(parent); - return nonposted; + return of_property_read_bool(parent, "nonposted-mmio"); } static int __of_address_to_resource(struct device_node *dev, int index, int bar_no, diff --git a/drivers/of/base.c b/drivers/of/base.c index 8856c67c466a..20603d3c9931 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -16,6 +16,7 @@ #define pr_fmt(fmt) "OF: " fmt +#include <linux/cleanup.h> #include <linux/console.h> #include <linux/ctype.h> #include <linux/cpu.h> @@ -1393,8 +1394,10 @@ int of_parse_phandle_with_args_map(const struct device_node *np, const char *stem_name, int index, struct of_phandle_args *out_args) { - char *cells_name, *map_name = NULL, *mask_name = NULL; - char *pass_name = NULL; + char *cells_name __free(kfree) = kasprintf(GFP_KERNEL, "#%s-cells", stem_name); + char *map_name __free(kfree) = kasprintf(GFP_KERNEL, "%s-map", stem_name); + char *mask_name __free(kfree) = kasprintf(GFP_KERNEL, "%s-map-mask", stem_name); + char *pass_name __free(kfree) = kasprintf(GFP_KERNEL, "%s-map-pass-thru", stem_name); struct device_node *cur, *new = NULL; const __be32 *map, *mask, *pass; static const __be32 dummy_mask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) }; @@ -1407,27 +1410,13 @@ int of_parse_phandle_with_args_map(const struct device_node *np, if (index < 0) return -EINVAL; - cells_name = kasprintf(GFP_KERNEL, "#%s-cells", stem_name); - if (!cells_name) + if (!cells_name || !map_name || !mask_name || !pass_name) return -ENOMEM; - ret = -ENOMEM; - map_name = kasprintf(GFP_KERNEL, "%s-map", stem_name); - if (!map_name) - goto free; - - mask_name = kasprintf(GFP_KERNEL, "%s-map-mask", stem_name); - if (!mask_name) - goto free; - - pass_name = kasprintf(GFP_KERNEL, "%s-map-pass-thru", stem_name); - if (!pass_name) - goto free; - ret = __of_parse_phandle_with_args(np, list_name, cells_name, -1, index, out_args); if (ret) - goto free; + return ret; /* Get the #<list>-cells property */ cur = out_args->np; @@ -1444,8 +1433,7 @@ int of_parse_phandle_with_args_map(const struct device_node *np, /* Get the <list>-map property */ map = of_get_property(cur, map_name, &map_len); if (!map) { - ret = 0; - goto free; + return 0; } map_len /= sizeof(u32); @@ -1521,12 +1509,6 @@ int of_parse_phandle_with_args_map(const struct device_node *np, put: of_node_put(cur); of_node_put(new); -free: - kfree(mask_name); - kfree(map_name); - kfree(cells_name); - kfree(pass_name); - return ret; } EXPORT_SYMBOL(of_parse_phandle_with_args_map); diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index 4d57a4e34105..dda6092e6d3a 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -9,6 +9,7 @@ #define pr_fmt(fmt) "OF: " fmt +#include <linux/cleanup.h> #include <linux/device.h> #include <linux/of.h> #include <linux/spinlock.h> @@ -306,15 +307,20 @@ int of_detach_node(struct device_node *np) } EXPORT_SYMBOL_GPL(of_detach_node); +void __of_prop_free(struct property *prop) +{ + kfree(prop->name); + kfree(prop->value); + kfree(prop); +} + static void property_list_free(struct property *prop_list) { struct property *prop, *next; for (prop = prop_list; prop != NULL; prop = next) { next = prop->next; - kfree(prop->name); - kfree(prop->value); - kfree(prop); + __of_prop_free(prop); } } @@ -427,9 +433,7 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags) return new; err_free: - kfree(new->name); - kfree(new->value); - kfree(new); + __of_prop_free(new); return NULL; } @@ -471,9 +475,7 @@ struct device_node *__of_node_dup(const struct device_node *np, if (!new_pp) goto err_prop; if (__of_add_property(node, new_pp)) { - kfree(new_pp->name); - kfree(new_pp->value); - kfree(new_pp); + __of_prop_free(new_pp); goto err_prop; } } @@ -933,11 +935,8 @@ static int of_changeset_add_prop_helper(struct of_changeset *ocs, return -ENOMEM; ret = of_changeset_add_property(ocs, np, new_pp); - if (ret) { - kfree(new_pp->name); - kfree(new_pp->value); - kfree(new_pp); - } + if (ret) + __of_prop_free(new_pp); return ret; } @@ -1033,10 +1032,9 @@ int of_changeset_add_prop_u32_array(struct of_changeset *ocs, const u32 *array, size_t sz) { struct property prop; - __be32 *val; - int i, ret; + __be32 *val __free(kfree) = kcalloc(sz, sizeof(__be32), GFP_KERNEL); + int i; - val = kcalloc(sz, sizeof(__be32), GFP_KERNEL); if (!val) return -ENOMEM; @@ -1046,9 +1044,6 @@ int of_changeset_add_prop_u32_array(struct of_changeset *ocs, prop.length = sizeof(u32) * sz; prop.value = (void *)val; - ret = of_changeset_add_prop_helper(ocs, np, &prop); - kfree(val); - - return ret; + return of_changeset_add_prop_helper(ocs, np, &prop); } EXPORT_SYMBOL_GPL(of_changeset_add_prop_u32_array); diff --git a/drivers/of/module.c b/drivers/of/module.c index f58e624953a2..780fd82a7ecc 100644 --- a/drivers/of/module.c +++ b/drivers/of/module.c @@ -29,14 +29,15 @@ ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len) csize = snprintf(str, len, "of:N%pOFn%c%s", np, 'T', of_node_get_device_type(np)); tsize = csize; + if (csize >= len) + csize = len > 0 ? len - 1 : 0; len -= csize; - if (str) - str += csize; + str += csize; of_property_for_each_string(np, "compatible", p, compat) { csize = strlen(compat) + 1; tsize += csize; - if (csize > len) + if (csize >= len) continue; csize = snprintf(str, len, "C%s", compat); diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index 485483524b7f..94fc0aa07af9 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -123,6 +123,7 @@ extern void *__unflatten_device_tree(const void *blob, * own the devtree lock or work on detached trees only. */ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags); +void __of_prop_free(struct property *prop); struct device_node *__of_node_dup(const struct device_node *np, const char *full_name); diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 8236ecae2953..46e1c3fbc769 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -437,17 +437,10 @@ void __init fdt_init_reserved_mem(void) for (i = 0; i < reserved_mem_count; i++) { struct reserved_mem *rmem = &reserved_mem[i]; unsigned long node = rmem->fdt_node; - int len; - const __be32 *prop; int err = 0; bool nomap; nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; - prop = of_get_flat_dt_prop(node, "phandle", &len); - if (!prop) - prop = of_get_flat_dt_prop(node, "linux,phandle", &len); - if (prop) - rmem->phandle = of_read_number(prop, len/4); if (rmem->size == 0) err = __reserved_mem_alloc_size(node, rmem->name, @@ -477,19 +470,6 @@ void __init fdt_init_reserved_mem(void) } } -static inline struct reserved_mem *__find_rmem(struct device_node *node) -{ - unsigned int i; - - if (!node->phandle) - return NULL; - - for (i = 0; i < reserved_mem_count; i++) - if (reserved_mem[i].phandle == node->phandle) - return &reserved_mem[i]; - return NULL; -} - struct rmem_assigned_device { struct device *dev; struct reserved_mem *rmem; @@ -534,7 +514,7 @@ int of_reserved_mem_device_init_by_idx(struct device *dev, return 0; } - rmem = __find_rmem(target); + rmem = of_reserved_mem_lookup(target); of_node_put(target); if (!rmem || !rmem->ops || !rmem->ops->device_init) diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index 2ae7e9d24a64..4d861a75d694 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -262,9 +262,7 @@ static struct property *dup_and_fixup_symbol_prop( return new_prop; err_free_new_prop: - kfree(new_prop->name); - kfree(new_prop->value); - kfree(new_prop); + __of_prop_free(new_prop); err_free_target_path: kfree(target_path); @@ -361,11 +359,8 @@ static int add_changeset_property(struct overlay_changeset *ovcs, pr_err("WARNING: memory leak will occur if overlay removed, property: %pOF/%s\n", target->np, new_prop->name); - if (ret) { - kfree(new_prop->name); - kfree(new_prop->value); - kfree(new_prop); - } + if (ret) + __of_prop_free(new_prop); return ret; } diff --git a/drivers/of/property.c b/drivers/of/property.c index 0320f1ae9b4d..1c83e68f805b 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -40,15 +40,12 @@ */ bool of_graph_is_present(const struct device_node *node) { - struct device_node *ports, *port; + struct device_node *ports __free(device_node) = of_get_child_by_name(node, "ports"); - ports = of_get_child_by_name(node, "ports"); if (ports) node = ports; - port = of_get_child_by_name(node, "port"); - of_node_put(ports); - of_node_put(port); + struct device_node *port __free(device_node) = of_get_child_by_name(node, "port"); return !!port; } @@ -579,7 +576,8 @@ EXPORT_SYMBOL_GPL(of_prop_next_string); int of_graph_parse_endpoint(const struct device_node *node, struct of_endpoint *endpoint) { - struct device_node *port_node = of_get_parent(node); + struct device_node *port_node __free(device_node) = + of_get_parent(node); WARN_ONCE(!port_node, "%s(): endpoint %pOF has no parent node\n", __func__, node); @@ -594,8 +592,6 @@ int of_graph_parse_endpoint(const struct device_node *node, of_property_read_u32(port_node, "reg", &endpoint->port); of_property_read_u32(node, "reg", &endpoint->id); - of_node_put(port_node); - return 0; } EXPORT_SYMBOL(of_graph_parse_endpoint); @@ -610,25 +606,22 @@ EXPORT_SYMBOL(of_graph_parse_endpoint); */ struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id) { - struct device_node *node, *port; + struct device_node *node __free(device_node) = of_get_child_by_name(parent, "ports"); - node = of_get_child_by_name(parent, "ports"); if (node) parent = node; - for_each_child_of_node(parent, port) { + for_each_child_of_node_scoped(parent, port) { u32 port_id = 0; if (!of_node_name_eq(port, "port")) continue; of_property_read_u32(port, "reg", &port_id); if (id == port_id) - break; + return_ptr(port); } - of_node_put(node); - - return port; + return NULL; } EXPORT_SYMBOL(of_graph_get_port_by_id); @@ -655,15 +648,13 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, * parent port node. */ if (!prev) { - struct device_node *node; + struct device_node *node __free(device_node) = + of_get_child_by_name(parent, "ports"); - node = of_get_child_by_name(parent, "ports"); if (node) parent = node; port = of_get_child_by_name(parent, "port"); - of_node_put(node); - if (!port) { pr_debug("graph: no port node found in %pOF\n", parent); return NULL; @@ -1052,15 +1043,13 @@ static int of_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, struct fwnode_endpoint *endpoint) { const struct device_node *node = to_of_node(fwnode); - struct device_node *port_node = of_get_parent(node); + struct device_node *port_node __free(device_node) = of_get_parent(node); endpoint->local_fwnode = fwnode; of_property_read_u32(port_node, "reg", &endpoint->port); of_property_read_u32(node, "reg", &endpoint->id); - of_node_put(port_node); - return 0; } @@ -1254,6 +1243,7 @@ DEFINE_SIMPLE_PROP(msi_parent, "msi-parent", "#msi-cells") DEFINE_SIMPLE_PROP(post_init_providers, "post-init-providers", NULL) DEFINE_SIMPLE_PROP(access_controllers, "access-controllers", "#access-controller-cells") DEFINE_SIMPLE_PROP(pses, "pses", "#pse-cells") +DEFINE_SIMPLE_PROP(power_supplies, "power-supplies", NULL) DEFINE_SUFFIX_PROP(regulators, "-supply", NULL) DEFINE_SUFFIX_PROP(gpio, "-gpio", "#gpio-cells") @@ -1313,6 +1303,57 @@ static struct device_node *parse_interrupts(struct device_node *np, return of_irq_parse_one(np, index, &sup_args) ? NULL : sup_args.np; } +static struct device_node *parse_interrupt_map(struct device_node *np, + const char *prop_name, int index) +{ + const __be32 *imap, *imap_end, *addr; + struct of_phandle_args sup_args; + u32 addrcells, intcells; + int i, imaplen; + + if (!IS_ENABLED(CONFIG_OF_IRQ)) + return NULL; + + if (strcmp(prop_name, "interrupt-map")) + return NULL; + + if (of_property_read_u32(np, "#interrupt-cells", &intcells)) + return NULL; + addrcells = of_bus_n_addr_cells(np); + + imap = of_get_property(np, "interrupt-map", &imaplen); + if (!imap || imaplen <= (addrcells + intcells)) + return NULL; + imap_end = imap + imaplen; + + while (imap < imap_end) { + addr = imap; + imap += addrcells; + + sup_args.np = np; + sup_args.args_count = intcells; + for (i = 0; i < intcells; i++) + sup_args.args[i] = be32_to_cpu(imap[i]); + imap += intcells; + + /* + * Upon success, the function of_irq_parse_raw() returns + * interrupt controller DT node pointer in sup_args.np. + */ + if (of_irq_parse_raw(addr, &sup_args)) + return NULL; + + if (!index) + return sup_args.np; + + of_node_put(sup_args.np); + imap += sup_args.args_count + 1; + index--; + } + + return NULL; +} + static struct device_node *parse_remote_endpoint(struct device_node *np, const char *prop_name, int index) @@ -1360,8 +1401,10 @@ static const struct supplier_bindings of_supplier_bindings[] = { { .parse_prop = parse_panel, }, { .parse_prop = parse_msi_parent, }, { .parse_prop = parse_pses, }, + { .parse_prop = parse_power_supplies, }, { .parse_prop = parse_gpio_compat, }, { .parse_prop = parse_interrupts, }, + { .parse_prop = parse_interrupt_map, }, { .parse_prop = parse_access_controllers, }, { .parse_prop = parse_regulators, }, { .parse_prop = parse_gpio, }, diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index b278ab4338ce..2780928764a4 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) "OF: resolver: " fmt +#include <linux/cleanup.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> @@ -74,11 +75,11 @@ static int update_usages_of_a_phandle_reference(struct device_node *overlay, { struct device_node *refnode; struct property *prop; - char *value, *cur, *end, *node_path, *prop_name, *s; + char *value __free(kfree) = kmemdup(prop_fixup->value, prop_fixup->length, GFP_KERNEL); + char *cur, *end, *node_path, *prop_name, *s; int offset, len; int err = 0; - value = kmemdup(prop_fixup->value, prop_fixup->length, GFP_KERNEL); if (!value) return -ENOMEM; @@ -89,23 +90,19 @@ static int update_usages_of_a_phandle_reference(struct device_node *overlay, node_path = cur; s = strchr(cur, ':'); - if (!s) { - err = -EINVAL; - goto err_fail; - } + if (!s) + return -EINVAL; *s++ = '\0'; prop_name = s; s = strchr(s, ':'); - if (!s) { - err = -EINVAL; - goto err_fail; - } + if (!s) + return -EINVAL; *s++ = '\0'; err = kstrtoint(s, 10, &offset); if (err) - goto err_fail; + return err; refnode = __of_find_node_by_full_path(of_node_get(overlay), node_path); if (!refnode) @@ -117,22 +114,16 @@ static int update_usages_of_a_phandle_reference(struct device_node *overlay, } of_node_put(refnode); - if (!prop) { - err = -ENOENT; - goto err_fail; - } + if (!prop) + return -ENOENT; - if (offset < 0 || offset + sizeof(__be32) > prop->length) { - err = -EINVAL; - goto err_fail; - } + if (offset < 0 || offset + sizeof(__be32) > prop->length) + return -EINVAL; *(__be32 *)(prop->value + offset) = cpu_to_be32(phandle); } -err_fail: - kfree(value); - return err; + return 0; } /* compare nodes taking into account that 'name' strips out the @ part */ diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 6b5c36b6a758..a8c01c953a29 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -795,15 +795,11 @@ static void __init of_unittest_property_copy(void) new = __of_prop_dup(&p1, GFP_KERNEL); unittest(new && propcmp(&p1, new), "empty property didn't copy correctly\n"); - kfree(new->value); - kfree(new->name); - kfree(new); + __of_prop_free(new); new = __of_prop_dup(&p2, GFP_KERNEL); unittest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n"); - kfree(new->value); - kfree(new->name); - kfree(new); + __of_prop_free(new); #endif } @@ -3718,9 +3714,7 @@ static __init void of_unittest_overlay_high_level(void) goto err_unlock; } if (__of_add_property(of_symbols, new_prop)) { - kfree(new_prop->name); - kfree(new_prop->value); - kfree(new_prop); + __of_prop_free(new_prop); /* "name" auto-generated by unflatten */ if (!strcmp(prop->name, "name")) continue; |