diff options
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/.kunitconfig | 1 | ||||
-rw-r--r-- | drivers/of/Kconfig | 8 | ||||
-rw-r--r-- | drivers/of/address.c | 41 | ||||
-rw-r--r-- | drivers/of/base.c | 100 | ||||
-rw-r--r-- | drivers/of/cpu.c | 2 | ||||
-rw-r--r-- | drivers/of/dynamic.c | 48 | ||||
-rw-r--r-- | drivers/of/empty_root.dts | 9 | ||||
-rw-r--r-- | drivers/of/fdt.c | 23 | ||||
-rw-r--r-- | drivers/of/fdt_address.c | 4 | ||||
-rw-r--r-- | drivers/of/irq.c | 6 | ||||
-rw-r--r-- | drivers/of/kexec.c | 2 | ||||
-rw-r--r-- | drivers/of/kobj.c | 8 | ||||
-rw-r--r-- | drivers/of/module.c | 4 | ||||
-rw-r--r-- | drivers/of/of_numa.c | 3 | ||||
-rw-r--r-- | drivers/of/of_private.h | 15 | ||||
-rw-r--r-- | drivers/of/of_reserved_mem.c | 227 | ||||
-rw-r--r-- | drivers/of/overlay.c | 19 | ||||
-rw-r--r-- | drivers/of/overlay_test.c | 2 | ||||
-rw-r--r-- | drivers/of/property.c | 111 | ||||
-rw-r--r-- | drivers/of/resolver.c | 12 | ||||
-rw-r--r-- | drivers/of/unittest-data/tests-address.dtsi | 2 | ||||
-rw-r--r-- | drivers/of/unittest.c | 45 |
22 files changed, 525 insertions, 167 deletions
diff --git a/drivers/of/.kunitconfig b/drivers/of/.kunitconfig index 4c53d2c7a275..7d570cb922a1 100644 --- a/drivers/of/.kunitconfig +++ b/drivers/of/.kunitconfig @@ -1,4 +1,5 @@ CONFIG_KUNIT=y CONFIG_OF=y CONFIG_OF_KUNIT_TEST=y +CONFIG_OF_OVERLAY=y CONFIG_OF_OVERLAY_KUNIT_TEST=y diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 0e2d608c3e20..50697cc3b07e 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -2,6 +2,12 @@ config DTC bool +config GENERIC_BUILTIN_DTB + bool + +config BUILTIN_DTB_ALL + bool + menuconfig OF bool "Device Tree and Open Firmware support" help @@ -111,7 +117,7 @@ config OF_OVERLAY_KUNIT_TEST tristate "Device Tree overlay KUnit tests" if !KUNIT_ALL_TESTS depends on KUNIT default KUNIT_ALL_TESTS - select OF_OVERLAY + select DTC help This option builds KUnit unit tests for the device tree overlay code. diff --git a/drivers/of/address.c b/drivers/of/address.c index 286f0c161e33..c1f1c810e810 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -147,7 +147,7 @@ static unsigned int of_bus_pci_get_flags(const __be32 *addr) * PCI bus specific translator */ -static bool of_node_is_pcie(struct device_node *np) +static bool of_node_is_pcie(const struct device_node *np) { bool is_pcie = of_node_name_eq(np, "pcie"); @@ -230,8 +230,8 @@ static int __of_address_resource_bounds(struct resource *r, u64 start, u64 size) * To guard against that we try to register the IO range first. * If that fails we know that pci_address_to_pio() will do too. */ -int of_pci_range_to_resource(struct of_pci_range *range, - struct device_node *np, struct resource *res) +int of_pci_range_to_resource(const struct of_pci_range *range, + const struct device_node *np, struct resource *res) { u64 start; int err; @@ -333,14 +333,18 @@ static unsigned int of_bus_isa_get_flags(const __be32 *addr) static int of_bus_default_flags_match(struct device_node *np) { - return of_bus_n_addr_cells(np) == 3; + /* + * Check for presence first since of_bus_n_addr_cells() will warn when + * walking parent nodes. + */ + return of_property_present(np, "#address-cells") && (of_bus_n_addr_cells(np) == 3); } /* * Array of bus specific translators */ -static struct of_bus of_busses[] = { +static const struct of_bus of_busses[] = { #ifdef CONFIG_PCI /* PCI */ { @@ -388,7 +392,7 @@ static struct of_bus of_busses[] = { }, }; -static struct of_bus *of_match_bus(struct device_node *np) +static const struct of_bus *of_match_bus(struct device_node *np) { int i; @@ -399,7 +403,7 @@ static struct of_bus *of_match_bus(struct device_node *np) return NULL; } -static int of_empty_ranges_quirk(struct device_node *np) +static int of_empty_ranges_quirk(const struct device_node *np) { if (IS_ENABLED(CONFIG_PPC)) { /* To save cycles, we cache the result for global "Mac" setting */ @@ -419,8 +423,8 @@ static int of_empty_ranges_quirk(struct device_node *np) return false; } -static int of_translate_one(struct device_node *parent, struct of_bus *bus, - struct of_bus *pbus, __be32 *addr, +static int of_translate_one(const struct device_node *parent, const struct of_bus *bus, + const struct of_bus *pbus, __be32 *addr, int na, int ns, int pna, const char *rprop) { const __be32 *ranges; @@ -455,7 +459,8 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, } if (ranges == NULL || rlen == 0) { offset = of_read_number(addr, na); - memset(addr, 0, pna * 4); + /* set address to zero, pass flags through */ + memset(addr + pbus->flag_cells, 0, (pna - pbus->flag_cells) * 4); pr_debug("empty ranges; 1:1 translation\n"); goto finish; } @@ -505,7 +510,7 @@ static u64 __of_translate_address(struct device_node *node, { 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; + const struct of_bus *bus, *pbus; __be32 addr[OF_MAX_ADDR_CELLS]; int na, ns, pna, pns; @@ -615,7 +620,7 @@ struct device_node *__of_get_dma_parent(const struct device_node *np) if (ret < 0) return of_get_parent(np); - return of_node_get(args.np); + return args.np; } #endif @@ -690,7 +695,7 @@ const __be32 *__of_get_address(struct device_node *dev, int index, int bar_no, const __be32 *prop; unsigned int psize; struct device_node *parent __free(device_node) = of_get_parent(dev); - struct of_bus *bus; + const struct of_bus *bus; int onesize, i, na, ns; if (parent == NULL) @@ -701,16 +706,16 @@ const __be32 *__of_get_address(struct device_node *dev, int index, int bar_no, if (strcmp(bus->name, "pci") && (bar_no >= 0)) return NULL; - bus->count_cells(dev, &na, &ns); - if (!OF_CHECK_ADDR_COUNT(na)) - return NULL; - /* Get "reg" or "assigned-addresses" property */ prop = of_get_property(dev, bus->addresses, &psize); if (prop == NULL) return NULL; psize /= 4; + bus->count_cells(dev, &na, &ns); + if (!OF_CHECK_ADDR_COUNT(na)) + return NULL; + onesize = na + ns; for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) { u32 val = be32_to_cpu(prop[0]); @@ -1030,7 +1035,7 @@ EXPORT_SYMBOL_GPL(of_dma_is_coherent); * This is currently only enabled on builds that support Apple ARM devices, as * an optimization. */ -static bool of_mmio_is_nonposted(struct device_node *np) +static bool of_mmio_is_nonposted(const struct device_node *np) { if (!IS_ENABLED(CONFIG_ARCH_APPLE)) return false; diff --git a/drivers/of/base.c b/drivers/of/base.c index 20603d3c9931..6f5abea2462a 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -87,15 +87,26 @@ static bool __of_node_is_type(const struct device_node *np, const char *type) return np && match && type && !strcmp(match, type); } +#define EXCLUDED_DEFAULT_CELLS_PLATFORMS ( \ + IS_ENABLED(CONFIG_SPARC) || \ + of_find_compatible_node(NULL, NULL, "coreboot") \ +) + int of_bus_n_addr_cells(struct device_node *np) { u32 cells; - for (; np; np = np->parent) + for (; np; np = np->parent) { if (!of_property_read_u32(np, "#address-cells", &cells)) return cells; - - /* No #address-cells property for the root node */ + /* + * Default root value and walking parent nodes for "#address-cells" + * is deprecated. Any platforms which hit this warning should + * be added to the excluded list. + */ + WARN_ONCE(!EXCLUDED_DEFAULT_CELLS_PLATFORMS, + "Missing '#address-cells' in %pOF\n", np); + } return OF_ROOT_NODE_ADDR_CELLS_DEFAULT; } @@ -112,11 +123,17 @@ int of_bus_n_size_cells(struct device_node *np) { u32 cells; - for (; np; np = np->parent) + for (; np; np = np->parent) { if (!of_property_read_u32(np, "#size-cells", &cells)) return cells; - - /* No #size-cells property for the root node */ + /* + * Default root value and walking parent nodes for "#size-cells" + * is deprecated. Any platforms which hit this warning should + * be added to the excluded list. + */ + WARN_ONCE(!EXCLUDED_DEFAULT_CELLS_PLATFORMS, + "Missing '#size-cells' in %pOF\n", np); + } return OF_ROOT_NODE_SIZE_CELLS_DEFAULT; } @@ -270,7 +287,7 @@ EXPORT_SYMBOL(of_find_all_nodes); const void *__of_get_property(const struct device_node *np, const char *name, int *lenp) { - struct property *pp = __of_find_property(np, name, lenp); + const struct property *pp = __of_find_property(np, name, lenp); return pp ? pp->value : NULL; } @@ -282,7 +299,7 @@ const void *__of_get_property(const struct device_node *np, const void *of_get_property(const struct device_node *np, const char *name, int *lenp) { - struct property *pp = of_find_property(np, name, lenp); + const struct property *pp = of_find_property(np, name, lenp); return pp ? pp->value : NULL; } @@ -321,7 +338,7 @@ EXPORT_SYMBOL(of_get_property); static int __of_device_is_compatible(const struct device_node *device, const char *compat, const char *type, const char *name) { - struct property *prop; + const struct property *prop; const char *cp; int index = 0, score = 0; @@ -628,6 +645,42 @@ struct device_node *of_get_next_child(const struct device_node *node, } EXPORT_SYMBOL(of_get_next_child); +/** + * of_get_next_child_with_prefix - Find the next child node with prefix + * @node: parent node + * @prev: previous child of the parent node, or NULL to get first + * @prefix: prefix that the node name should have + * + * This function is like of_get_next_child(), except that it automatically + * skips any nodes whose name doesn't have the given prefix. + * + * Return: A node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_get_next_child_with_prefix(const struct device_node *node, + struct device_node *prev, + const char *prefix) +{ + struct device_node *next; + unsigned long flags; + + if (!node) + return NULL; + + raw_spin_lock_irqsave(&devtree_lock, flags); + next = prev ? prev->sibling : node->child; + for (; next; next = next->sibling) { + if (!of_node_name_prefix(next, prefix)) + continue; + if (of_node_get(next)) + break; + } + of_node_put(prev); + raw_spin_unlock_irqrestore(&devtree_lock, flags); + return next; +} +EXPORT_SYMBOL(of_get_next_child_with_prefix); + static struct device_node *of_get_next_status_child(const struct device_node *node, struct device_node *prev, bool (*checker)(const struct device_node *)) @@ -771,7 +824,7 @@ struct device_node *of_get_child_by_name(const struct device_node *node, } EXPORT_SYMBOL(of_get_child_by_name); -struct device_node *__of_find_node_by_path(struct device_node *parent, +struct device_node *__of_find_node_by_path(const struct device_node *parent, const char *path) { struct device_node *child; @@ -828,7 +881,7 @@ struct device_node *__of_find_node_by_full_path(struct device_node *node, struct device_node *of_find_node_opts_by_path(const char *path, const char **opts) { struct device_node *np = NULL; - struct property *pp; + const struct property *pp; unsigned long flags; const char *separator = strchr(path, ':'); @@ -974,7 +1027,7 @@ struct device_node *of_find_node_with_property(struct device_node *from, const char *prop_name) { struct device_node *np; - struct property *pp; + const struct property *pp; unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); @@ -1455,8 +1508,10 @@ int of_parse_phandle_with_args_map(const struct device_node *np, map_len--; /* Check if not found */ - if (!new) + if (!new) { + ret = -EINVAL; goto put; + } if (!of_device_is_available(new)) match = 0; @@ -1466,17 +1521,20 @@ int of_parse_phandle_with_args_map(const struct device_node *np, goto put; /* Check for malformed properties */ - if (WARN_ON(new_size > MAX_PHANDLE_ARGS)) - goto put; - if (map_len < new_size) + if (WARN_ON(new_size > MAX_PHANDLE_ARGS) || + map_len < new_size) { + ret = -EINVAL; goto put; + } /* Move forward by new node's #<list>-cells amount */ map += new_size; map_len -= new_size; } - if (!match) + if (!match) { + ret = -ENOENT; goto put; + } /* Get the <list>-map-pass-thru property (optional) */ pass = of_get_property(cur, pass_name, NULL); @@ -1769,7 +1827,7 @@ static void of_alias_add(struct alias_prop *ap, struct device_node *np, */ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) { - struct property *pp; + const struct property *pp; of_aliases = of_find_node_by_path("/aliases"); of_chosen = of_find_node_by_path("/chosen"); @@ -1840,7 +1898,7 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) * * Return: The alias id if found. */ -int of_alias_get_id(struct device_node *np, const char *stem) +int of_alias_get_id(const struct device_node *np, const char *stem) { struct alias_prop *app; int id = -ENODEV; @@ -1898,7 +1956,7 @@ EXPORT_SYMBOL_GPL(of_alias_get_highest_id); * * Return: TRUE if console successfully setup. Otherwise return FALSE. */ -bool of_console_check(struct device_node *dn, char *name, int index) +bool of_console_check(const struct device_node *dn, char *name, int index) { if (!dn || dn != of_stdout || console_set_on_cmdline) return false; @@ -1986,7 +2044,7 @@ int of_find_last_cache_level(unsigned int cpu) * * Return: 0 on success or a standard error code on failure. */ -int of_map_id(struct device_node *np, u32 id, +int of_map_id(const struct device_node *np, u32 id, const char *map_name, const char *map_mask_name, struct device_node **target, u32 *id_out) { diff --git a/drivers/of/cpu.c b/drivers/of/cpu.c index d17b2f851082..5214dc3d05ae 100644 --- a/drivers/of/cpu.c +++ b/drivers/of/cpu.c @@ -188,7 +188,7 @@ EXPORT_SYMBOL(of_cpu_node_to_id); * Return: An idle state node if found at @index. The refcount is incremented * for it, so call of_node_put() on it when done. Returns NULL if not found. */ -struct device_node *of_get_cpu_state_node(struct device_node *cpu_node, +struct device_node *of_get_cpu_state_node(const struct device_node *cpu_node, int index) { struct of_phandle_args args; diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index 110104a936d9..0aba760f7577 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -536,7 +536,7 @@ static void __of_changeset_entry_destroy(struct of_changeset_entry *ce) kfree(ce); } -static void __of_changeset_entry_invert(struct of_changeset_entry *ce, +static void __of_changeset_entry_invert(const struct of_changeset_entry *ce, struct of_changeset_entry *rce) { memcpy(rce, ce, sizeof(*rce)); @@ -636,7 +636,7 @@ static int __of_changeset_entry_apply(struct of_changeset_entry *ce) return 0; } -static inline int __of_changeset_entry_revert(struct of_changeset_entry *ce) +static inline int __of_changeset_entry_revert(const struct of_changeset_entry *ce) { struct of_changeset_entry ce_inverted; @@ -1072,3 +1072,47 @@ int of_changeset_add_prop_bool(struct of_changeset *ocs, struct device_node *np, return of_changeset_add_prop_helper(ocs, np, &prop); } EXPORT_SYMBOL_GPL(of_changeset_add_prop_bool); + +static int of_changeset_update_prop_helper(struct of_changeset *ocs, + struct device_node *np, + const struct property *pp) +{ + struct property *new_pp; + int ret; + + new_pp = __of_prop_dup(pp, GFP_KERNEL); + if (!new_pp) + return -ENOMEM; + + ret = of_changeset_update_property(ocs, np, new_pp); + if (ret) + __of_prop_free(new_pp); + + return ret; +} + +/** + * of_changeset_update_prop_string - Add a string property update to a changeset + * + * @ocs: changeset pointer + * @np: device node pointer + * @prop_name: name of the property to be updated + * @str: pointer to null terminated string + * + * Create a string property to be updated and add it to a changeset. + * + * Return: 0 on success, a negative error value in case of an error. + */ +int of_changeset_update_prop_string(struct of_changeset *ocs, + struct device_node *np, + const char *prop_name, const char *str) +{ + struct property prop = { + .name = (char *)prop_name, + .length = strlen(str) + 1, + .value = (void *)str, + }; + + return of_changeset_update_prop_helper(ocs, np, &prop); +} +EXPORT_SYMBOL_GPL(of_changeset_update_prop_string); diff --git a/drivers/of/empty_root.dts b/drivers/of/empty_root.dts index cf9e97a60f48..cbe169ba3db5 100644 --- a/drivers/of/empty_root.dts +++ b/drivers/of/empty_root.dts @@ -2,5 +2,12 @@ /dts-v1/; / { - + /* + * #address-cells/#size-cells are required properties at root node. + * Use 2 cells for both address cells and size cells in order to fully + * support 64-bit addresses and sizes on systems using this empty root + * node. + */ + #address-cells = <0x02>; + #size-cells = <0x02>; }; diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 4d528c10df3a..0121100372b4 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -457,6 +457,7 @@ int __initdata dt_root_addr_cells; int __initdata dt_root_size_cells; void *initial_boot_params __ro_after_init; +phys_addr_t initial_boot_params_pa __ro_after_init; #ifdef CONFIG_OF_EARLY_FLATTREE @@ -511,8 +512,6 @@ void __init early_init_fdt_scan_reserved_mem(void) break; memblock_reserve(base, size); } - - fdt_init_reserved_mem(); } /** @@ -938,12 +937,12 @@ int __init early_init_dt_scan_root(void) dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; prop = of_get_flat_dt_prop(node, "#size-cells", NULL); - if (prop) + if (!WARN(!prop, "No '#size-cells' in root node\n")) dt_root_size_cells = be32_to_cpup(prop); pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); prop = of_get_flat_dt_prop(node, "#address-cells", NULL); - if (prop) + if (!WARN(!prop, "No '#address-cells' in root node\n")) dt_root_addr_cells = be32_to_cpup(prop); pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); @@ -1136,17 +1135,18 @@ static void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) return ptr; } -bool __init early_init_dt_verify(void *params) +bool __init early_init_dt_verify(void *dt_virt, phys_addr_t dt_phys) { - if (!params) + if (!dt_virt) return false; /* check device tree validity */ - if (fdt_check_header(params)) + if (fdt_check_header(dt_virt)) return false; /* Setup flat device-tree pointer */ - initial_boot_params = params; + initial_boot_params = dt_virt; + initial_boot_params_pa = dt_phys; of_fdt_crc32 = crc32_be(~0, initial_boot_params, fdt_totalsize(initial_boot_params)); @@ -1173,11 +1173,11 @@ void __init early_init_dt_scan_nodes(void) early_init_dt_check_for_usable_mem_range(); } -bool __init early_init_dt_scan(void *params) +bool __init early_init_dt_scan(void *dt_virt, phys_addr_t dt_phys) { bool status; - status = early_init_dt_verify(params); + status = early_init_dt_verify(dt_virt, dt_phys); if (!status) return false; @@ -1212,6 +1212,9 @@ void __init unflatten_device_tree(void) { void *fdt = initial_boot_params; + /* Save the statically-placed regions in the reserved_mem array */ + fdt_scan_reserved_mem_reg_nodes(); + /* Don't use the bootloader provided DTB if ACPI is enabled */ if (!acpi_disabled) fdt = NULL; diff --git a/drivers/of/fdt_address.c b/drivers/of/fdt_address.c index 1dc15ab78b10..9804d7f06705 100644 --- a/drivers/of/fdt_address.c +++ b/drivers/of/fdt_address.c @@ -55,7 +55,7 @@ static void __init fdt_bus_default_count_cells(const void *blob, int parentoffse if (prop) *addrc = be32_to_cpup(prop); else - *addrc = dt_root_addr_cells; + *addrc = -1; } if (sizec) { @@ -63,7 +63,7 @@ static void __init fdt_bus_default_count_cells(const void *blob, int parentoffse if (prop) *sizec = be32_to_cpup(prop); else - *sizec = dt_root_size_cells; + *sizec = -1; } } diff --git a/drivers/of/irq.c b/drivers/of/irq.c index a494f56a0d0e..98b1cf78ecac 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -111,6 +111,7 @@ const __be32 *of_irq_parse_imap_parent(const __be32 *imap, int len, struct of_ph else np = of_find_node_by_phandle(be32_to_cpup(imap)); imap++; + len--; /* Check if not found */ if (!np) { @@ -354,6 +355,7 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar return of_irq_parse_oldworld(device, index, out_irq); /* Get the reg property (if any) */ + addr_len = 0; addr = of_get_property(device, "reg", &addr_len); /* Prevent out-of-bounds read in case of longer interrupt parent address size */ @@ -720,7 +722,7 @@ struct irq_domain *of_msi_map_get_device_domain(struct device *dev, u32 id, * Returns: the MSI domain for this device (or NULL on failure). */ struct irq_domain *of_msi_get_domain(struct device *dev, - struct device_node *np, + const struct device_node *np, enum irq_domain_bus_token token) { struct of_phandle_iterator it; @@ -742,7 +744,7 @@ EXPORT_SYMBOL_GPL(of_msi_get_domain); * @dev: device structure to associate with an MSI irq domain * @np: device node for that device */ -void of_msi_configure(struct device *dev, struct device_node *np) +void of_msi_configure(struct device *dev, const struct device_node *np) { dev_set_msi_domain(dev, of_msi_get_domain(dev, np, DOMAIN_BUS_PLATFORM_MSI)); diff --git a/drivers/of/kexec.c b/drivers/of/kexec.c index 9ccde2fd77cb..5b924597a4de 100644 --- a/drivers/of/kexec.c +++ b/drivers/of/kexec.c @@ -301,7 +301,7 @@ void *of_kexec_alloc_and_setup_fdt(const struct kimage *image, } /* Remove memory reservation for the current device tree. */ - ret = fdt_find_and_del_mem_rsv(fdt, __pa(initial_boot_params), + ret = fdt_find_and_del_mem_rsv(fdt, initial_boot_params_pa, fdt_totalsize(initial_boot_params)); if (ret == -EINVAL) { pr_err("Error removing memory reservation.\n"); diff --git a/drivers/of/kobj.c b/drivers/of/kobj.c index 3dbce1e6f184..cab9b169dc67 100644 --- a/drivers/of/kobj.c +++ b/drivers/of/kobj.c @@ -37,7 +37,7 @@ static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj, } /* always return newly allocated name, caller must free after use */ -static const char *safe_name(struct kobject *kobj, const char *orig_name) +static const char *safe_name(const struct kobject *kobj, const char *orig_name) { const char *name = orig_name; struct kernfs_node *kn; @@ -84,7 +84,7 @@ int __of_add_property_sysfs(struct device_node *np, struct property *pp) return rc; } -void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop) +void __of_sysfs_remove_bin_file(struct device_node *np, const struct property *prop) { if (!IS_ENABLED(CONFIG_SYSFS)) return; @@ -93,7 +93,7 @@ void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop) kfree(prop->attr.attr.name); } -void __of_remove_property_sysfs(struct device_node *np, struct property *prop) +void __of_remove_property_sysfs(struct device_node *np, const struct property *prop) { /* at early boot, bail here and defer setup to of_init() */ if (of_kset && of_node_is_attached(np)) @@ -101,7 +101,7 @@ void __of_remove_property_sysfs(struct device_node *np, struct property *prop) } void __of_update_property_sysfs(struct device_node *np, struct property *newprop, - struct property *oldprop) + const struct property *oldprop) { /* At early boot, bail out and defer setup to of_init() */ if (!of_kset) diff --git a/drivers/of/module.c b/drivers/of/module.c index 780fd82a7ecc..1e735fc130ad 100644 --- a/drivers/of/module.c +++ b/drivers/of/module.c @@ -35,12 +35,10 @@ ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len) str += csize; of_property_for_each_string(np, "compatible", p, compat) { - csize = strlen(compat) + 1; + csize = snprintf(str, len, "C%s", compat); tsize += csize; if (csize >= len) continue; - - csize = snprintf(str, len, "C%s", compat); for (c = str; c; ) { c = strchr(c, ' '); if (c) diff --git a/drivers/of/of_numa.c b/drivers/of/of_numa.c index 2ec20886d176..230d5f628c1b 100644 --- a/drivers/of/of_numa.c +++ b/drivers/of/of_numa.c @@ -14,9 +14,6 @@ #include <asm/numa.h> -/* define default numa node to 0 */ -#define DEFAULT_NODE 0 - /* * Even though we connect cpus to numa domains later in SMP * init, we need to know the node ids now for all cpus. diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index c235d6c909a1..ea5a0951ec5e 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -9,6 +9,7 @@ */ #define FDT_ALIGN_SIZE 8 +#define MAX_RESERVED_REGIONS 64 /** * struct alias_prop - Alias property in 'aliases' node @@ -72,9 +73,9 @@ static inline void of_platform_register_reconfig_notifier(void) { } #if defined(CONFIG_OF_KOBJ) int of_node_is_attached(const struct device_node *node); int __of_add_property_sysfs(struct device_node *np, struct property *pp); -void __of_remove_property_sysfs(struct device_node *np, struct property *prop); +void __of_remove_property_sysfs(struct device_node *np, const struct property *prop); void __of_update_property_sysfs(struct device_node *np, struct property *newprop, - struct property *oldprop); + const struct property *oldprop); int __of_attach_node_sysfs(struct device_node *np); void __of_detach_node_sysfs(struct device_node *np); #else @@ -82,9 +83,9 @@ static inline int __of_add_property_sysfs(struct device_node *np, struct propert { return 0; } -static inline void __of_remove_property_sysfs(struct device_node *np, struct property *prop) {} +static inline void __of_remove_property_sysfs(struct device_node *np, const struct property *prop) {} static inline void __of_update_property_sysfs(struct device_node *np, - struct property *newprop, struct property *oldprop) {} + struct property *newprop, const struct property *oldprop) {} static inline int __of_attach_node_sysfs(struct device_node *np) { return 0; @@ -130,7 +131,7 @@ void __of_prop_free(struct property *prop); struct device_node *__of_node_dup(const struct device_node *np, const char *full_name); -struct device_node *__of_find_node_by_path(struct device_node *parent, +struct device_node *__of_find_node_by_path(const struct device_node *parent, const char *path); struct device_node *__of_find_node_by_full_path(struct device_node *node, const char *path); @@ -145,7 +146,7 @@ extern int __of_update_property(struct device_node *np, extern void __of_detach_node(struct device_node *np); extern void __of_sysfs_remove_bin_file(struct device_node *np, - struct property *prop); + const struct property *prop); /* illegal phandle value (set when unresolved) */ #define OF_PHANDLE_ILLEGAL 0xdeadbeef @@ -183,7 +184,7 @@ static inline struct device_node *__of_get_dma_parent(const struct device_node * #endif int fdt_scan_reserved_mem(void); -void fdt_init_reserved_mem(void); +void __init fdt_scan_reserved_mem_reg_nodes(void); bool of_fdt_device_is_available(const void *blob, unsigned long node); diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 46e1c3fbc769..45517b9e57b1 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -27,8 +27,9 @@ #include "of_private.h" -#define MAX_RESERVED_REGIONS 64 -static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; +static struct reserved_mem reserved_mem_array[MAX_RESERVED_REGIONS] __initdata; +static struct reserved_mem *reserved_mem __refdata = reserved_mem_array; +static int total_reserved_mem_cnt = MAX_RESERVED_REGIONS; static int reserved_mem_count; static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size, @@ -57,6 +58,51 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size, } /* + * alloc_reserved_mem_array() - allocate memory for the reserved_mem + * array using memblock + * + * This function is used to allocate memory for the reserved_mem + * array according to the total number of reserved memory regions + * defined in the DT. + * After the new array is allocated, the information stored in + * the initial static array is copied over to this new array and + * the new array is used from this point on. + */ +static void __init alloc_reserved_mem_array(void) +{ + struct reserved_mem *new_array; + size_t alloc_size, copy_size, memset_size; + + alloc_size = array_size(total_reserved_mem_cnt, sizeof(*new_array)); + if (alloc_size == SIZE_MAX) { + pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW); + return; + } + + new_array = memblock_alloc(alloc_size, SMP_CACHE_BYTES); + if (!new_array) { + pr_err("Failed to allocate memory for reserved_mem array with err: %d", -ENOMEM); + return; + } + + copy_size = array_size(reserved_mem_count, sizeof(*new_array)); + if (copy_size == SIZE_MAX) { + memblock_free(new_array, alloc_size); + total_reserved_mem_cnt = MAX_RESERVED_REGIONS; + pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW); + return; + } + + memset_size = alloc_size - copy_size; + + memcpy(new_array, reserved_mem, copy_size); + memset(new_array + reserved_mem_count, 0, memset_size); + + reserved_mem = new_array; +} + +static void __init fdt_init_reserved_mem_node(struct reserved_mem *rmem); +/* * fdt_reserved_mem_save_node() - save fdt node for second pass initialization */ static void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname, @@ -64,7 +110,7 @@ static void __init fdt_reserved_mem_save_node(unsigned long node, const char *un { struct reserved_mem *rmem = &reserved_mem[reserved_mem_count]; - if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) { + if (reserved_mem_count == total_reserved_mem_cnt) { pr_err("not enough space for all defined regions.\n"); return; } @@ -74,6 +120,9 @@ static void __init fdt_reserved_mem_save_node(unsigned long node, const char *un rmem->base = base; rmem->size = size; + /* Call the region specific initialization function */ + fdt_init_reserved_mem_node(rmem); + reserved_mem_count++; return; } @@ -106,7 +155,6 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, phys_addr_t base, size; int len; const __be32 *prop; - int first = 1; bool nomap; prop = of_get_flat_dt_prop(node, "reg", &len); @@ -134,10 +182,6 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, uname, &base, (unsigned long)(size / SZ_1M)); len -= t_len; - if (first) { - fdt_reserved_mem_save_node(node, uname, base, size); - first = 0; - } } return 0; } @@ -165,12 +209,80 @@ static int __init __reserved_mem_check_root(unsigned long node) return 0; } +static void __init __rmem_check_for_overlap(void); + +/** + * fdt_scan_reserved_mem_reg_nodes() - Store info for the "reg" defined + * reserved memory regions. + * + * This function is used to scan through the DT and store the + * information for the reserved memory regions that are defined using + * the "reg" property. The region node number, name, base address, and + * size are all stored in the reserved_mem array by calling the + * fdt_reserved_mem_save_node() function. + */ +void __init fdt_scan_reserved_mem_reg_nodes(void) +{ + int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); + const void *fdt = initial_boot_params; + phys_addr_t base, size; + const __be32 *prop; + int node, child; + int len; + + if (!fdt) + return; + + node = fdt_path_offset(fdt, "/reserved-memory"); + if (node < 0) { + pr_info("Reserved memory: No reserved-memory node in the DT\n"); + return; + } + + /* Attempt dynamic allocation of a new reserved_mem array */ + alloc_reserved_mem_array(); + + if (__reserved_mem_check_root(node)) { + pr_err("Reserved memory: unsupported node format, ignoring\n"); + return; + } + + fdt_for_each_subnode(child, fdt, node) { + const char *uname; + + prop = of_get_flat_dt_prop(child, "reg", &len); + if (!prop) + continue; + if (!of_fdt_device_is_available(fdt, child)) + continue; + + uname = fdt_get_name(fdt, child, NULL); + if (len && len % t_len != 0) { + pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n", + uname); + continue; + } + base = dt_mem_next_cell(dt_root_addr_cells, &prop); + size = dt_mem_next_cell(dt_root_size_cells, &prop); + + if (size) + fdt_reserved_mem_save_node(child, uname, base, size); + } + + /* check for overlapping reserved regions */ + __rmem_check_for_overlap(); +} + +static int __init __reserved_mem_alloc_size(unsigned long node, const char *uname); + /* * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory */ int __init fdt_scan_reserved_mem(void) { int node, child; + int dynamic_nodes_cnt = 0, count = 0; + int dynamic_nodes[MAX_RESERVED_REGIONS]; const void *fdt = initial_boot_params; node = fdt_path_offset(fdt, "/reserved-memory"); @@ -192,9 +304,31 @@ int __init fdt_scan_reserved_mem(void) uname = fdt_get_name(fdt, child, NULL); err = __reserved_mem_reserve_reg(child, uname); - if (err == -ENOENT && of_get_flat_dt_prop(child, "size", NULL)) - fdt_reserved_mem_save_node(child, uname, 0, 0); + if (!err) + count++; + /* + * Save the nodes for the dynamically-placed regions + * into an array which will be used for allocation right + * after all the statically-placed regions are reserved + * or marked as no-map. This is done to avoid dynamically + * allocating from one of the statically-placed regions. + */ + if (err == -ENOENT && of_get_flat_dt_prop(child, "size", NULL)) { + dynamic_nodes[dynamic_nodes_cnt] = child; + dynamic_nodes_cnt++; + } } + for (int i = 0; i < dynamic_nodes_cnt; i++) { + const char *uname; + int err; + + child = dynamic_nodes[i]; + uname = fdt_get_name(fdt, child, NULL); + err = __reserved_mem_alloc_size(child, uname); + if (!err) + count++; + } + total_reserved_mem_cnt = count; return 0; } @@ -253,8 +387,7 @@ static int __init __reserved_mem_alloc_in_range(phys_addr_t size, * __reserved_mem_alloc_size() - allocate reserved memory described by * 'size', 'alignment' and 'alloc-ranges' properties. */ -static int __init __reserved_mem_alloc_size(unsigned long node, - const char *uname, phys_addr_t *res_base, phys_addr_t *res_size) +static int __init __reserved_mem_alloc_size(unsigned long node, const char *uname) { int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); phys_addr_t start = 0, end = 0; @@ -334,9 +467,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node, return -ENOMEM; } - *res_base = base; - *res_size = size; - + /* Save region in the reserved_mem array */ + fdt_reserved_mem_save_node(node, uname, base, size); return 0; } @@ -425,48 +557,37 @@ static void __init __rmem_check_for_overlap(void) } /** - * fdt_init_reserved_mem() - allocate and init all saved reserved memory regions + * fdt_init_reserved_mem_node() - Initialize a reserved memory region + * @rmem: reserved_mem struct of the memory region to be initialized. + * + * This function is used to call the region specific initialization + * function for a reserved memory region. */ -void __init fdt_init_reserved_mem(void) +static void __init fdt_init_reserved_mem_node(struct reserved_mem *rmem) { - int i; - - /* check for overlapping reserved regions */ - __rmem_check_for_overlap(); - - for (i = 0; i < reserved_mem_count; i++) { - struct reserved_mem *rmem = &reserved_mem[i]; - unsigned long node = rmem->fdt_node; - int err = 0; - bool nomap; + unsigned long node = rmem->fdt_node; + int err = 0; + bool nomap; - nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; + nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; - if (rmem->size == 0) - err = __reserved_mem_alloc_size(node, rmem->name, - &rmem->base, &rmem->size); - if (err == 0) { - err = __reserved_mem_init_node(rmem); - if (err != 0 && err != -ENOENT) { - pr_info("node %s compatible matching fail\n", - rmem->name); - if (nomap) - memblock_clear_nomap(rmem->base, rmem->size); - else - memblock_phys_free(rmem->base, - rmem->size); - } else { - phys_addr_t end = rmem->base + rmem->size - 1; - bool reusable = - (of_get_flat_dt_prop(node, "reusable", NULL)) != NULL; - - pr_info("%pa..%pa (%lu KiB) %s %s %s\n", - &rmem->base, &end, (unsigned long)(rmem->size / SZ_1K), - nomap ? "nomap" : "map", - reusable ? "reusable" : "non-reusable", - rmem->name ? rmem->name : "unknown"); - } - } + err = __reserved_mem_init_node(rmem); + if (err != 0 && err != -ENOENT) { + pr_info("node %s compatible matching fail\n", rmem->name); + if (nomap) + memblock_clear_nomap(rmem->base, rmem->size); + else + memblock_phys_free(rmem->base, rmem->size); + } else { + phys_addr_t end = rmem->base + rmem->size - 1; + bool reusable = + (of_get_flat_dt_prop(node, "reusable", NULL)) != NULL; + + pr_info("%pa..%pa (%lu KiB) %s %s %s\n", + &rmem->base, &end, (unsigned long)(rmem->size / SZ_1K), + nomap ? "nomap" : "map", + reusable ? "reusable" : "non-reusable", + rmem->name ? rmem->name : "unknown"); } } diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index cbdecccca097..434f6dd6a86c 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -296,10 +296,11 @@ err_free_target_path: * invalid @overlay. */ static int add_changeset_property(struct overlay_changeset *ovcs, - struct target *target, struct property *overlay_prop, + struct target *target, const struct property *overlay_prop, bool is_symbols_prop) { - struct property *new_prop = NULL, *prop; + struct property *new_prop = NULL; + const struct property *prop; int ret = 0; if (target->in_livetree) @@ -398,7 +399,7 @@ static int add_changeset_property(struct overlay_changeset *ovcs, * invalid @overlay. */ static int add_changeset_node(struct overlay_changeset *ovcs, - struct target *target, struct device_node *node) + struct target *target, const struct device_node *node) { const char *node_kbasename; const __be32 *phandle; @@ -675,8 +676,8 @@ static int build_changeset(struct overlay_changeset *ovcs) * 1) "target" property containing the phandle of the target * 2) "target-path" property containing the path of the target */ -static struct device_node *find_target(struct device_node *info_node, - struct device_node *target_base) +static struct device_node *find_target(const struct device_node *info_node, + const struct device_node *target_base) { struct device_node *node; char *target_path; @@ -735,7 +736,7 @@ static struct device_node *find_target(struct device_node *info_node, * init_overlay_changeset() must call free_overlay_changeset(). */ static int init_overlay_changeset(struct overlay_changeset *ovcs, - struct device_node *target_base) + const struct device_node *target_base) { struct device_node *node, *overlay_node; struct fragment *fragment; @@ -910,7 +911,7 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs) */ static int of_overlay_apply(struct overlay_changeset *ovcs, - struct device_node *base) + const struct device_node *base) { int ret = 0, ret_revert, ret_tmp; @@ -978,7 +979,7 @@ out: */ int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size, - int *ret_ovcs_id, struct device_node *base) + int *ret_ovcs_id, const struct device_node *base) { void *new_fdt; void *new_fdt_align; @@ -1074,7 +1075,7 @@ EXPORT_SYMBOL_GPL(of_overlay_fdt_apply); * * Returns 1 if @np is @tree or is contained in @tree, else 0 */ -static int find_node(struct device_node *tree, struct device_node *np) +static int find_node(const struct device_node *tree, struct device_node *np) { if (tree == np) return 1; diff --git a/drivers/of/overlay_test.c b/drivers/of/overlay_test.c index 1f76d50fb16a..c787524c5a88 100644 --- a/drivers/of/overlay_test.c +++ b/drivers/of/overlay_test.c @@ -65,6 +65,8 @@ static void of_overlay_apply_kunit_cleanup(struct kunit *test) struct device_node *np; of_root_kunit_skip(test); + if (!IS_ENABLED(CONFIG_OF_OVERLAY)) + kunit_skip(test, "requires CONFIG_OF_OVERLAY to apply overlay"); if (!IS_ENABLED(CONFIG_OF_EARLY_FLATTREE)) kunit_skip(test, "requires CONFIG_OF_EARLY_FLATTREE for root node"); diff --git a/drivers/of/property.c b/drivers/of/property.c index 11b922fde7af..cfc8aea002e4 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -68,7 +68,7 @@ EXPORT_SYMBOL(of_graph_is_present); int of_property_count_elems_of_size(const struct device_node *np, const char *propname, int elem_size) { - struct property *prop = of_find_property(np, propname, NULL); + const struct property *prop = of_find_property(np, propname, NULL); if (!prop) return -EINVAL; @@ -104,7 +104,7 @@ EXPORT_SYMBOL_GPL(of_property_count_elems_of_size); static void *of_find_property_value_of_size(const struct device_node *np, const char *propname, u32 min, u32 max, size_t *len) { - struct property *prop = of_find_property(np, propname, NULL); + const struct property *prop = of_find_property(np, propname, NULL); if (!prop) return ERR_PTR(-EINVAL); @@ -530,7 +530,7 @@ int of_property_read_string_helper(const struct device_node *np, } EXPORT_SYMBOL_GPL(of_property_read_string_helper); -const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur, +const __be32 *of_prop_next_u32(const struct property *prop, const __be32 *cur, u32 *pu) { const void *curv = cur; @@ -553,7 +553,7 @@ out_val: } EXPORT_SYMBOL_GPL(of_prop_next_u32); -const char *of_prop_next_string(struct property *prop, const char *cur) +const char *of_prop_next_string(const struct property *prop, const char *cur) { const void *curv = cur; @@ -631,6 +631,70 @@ struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id) EXPORT_SYMBOL(of_graph_get_port_by_id); /** + * of_graph_get_next_port() - get next port node. + * @parent: pointer to the parent device node, or parent ports node + * @prev: previous port node, or NULL to get first + * + * Parent device node can be used as @parent whether device node has ports node + * or not. It will work same as ports@0 node. + * + * Return: A 'port' node pointer with refcount incremented. Refcount + * of the passed @prev node is decremented. + */ +struct device_node *of_graph_get_next_port(const struct device_node *parent, + struct device_node *prev) +{ + if (!parent) + return NULL; + + if (!prev) { + struct device_node *node __free(device_node) = + of_get_child_by_name(parent, "ports"); + + if (node) + parent = node; + + return of_get_child_by_name(parent, "port"); + } + + do { + prev = of_get_next_child(parent, prev); + if (!prev) + break; + } while (!of_node_name_eq(prev, "port")); + + return prev; +} +EXPORT_SYMBOL(of_graph_get_next_port); + +/** + * of_graph_get_next_port_endpoint() - get next endpoint node in port. + * If it reached to end of the port, it will return NULL. + * @port: pointer to the target port node + * @prev: previous endpoint node, or NULL to get first + * + * Return: An 'endpoint' node pointer with refcount incremented. Refcount + * of the passed @prev node is decremented. + */ +struct device_node *of_graph_get_next_port_endpoint(const struct device_node *port, + struct device_node *prev) +{ + while (1) { + prev = of_get_next_child(port, prev); + if (!prev) + break; + if (WARN(!of_node_name_eq(prev, "endpoint"), + "non endpoint node is used (%pOF)", prev)) + continue; + + break; + } + + return prev; +} +EXPORT_SYMBOL(of_graph_get_next_port_endpoint); + +/** * of_graph_get_next_endpoint() - get next endpoint node * @parent: pointer to the parent device node * @prev: previous endpoint node, or NULL to get first @@ -653,13 +717,7 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, * parent port node. */ if (!prev) { - struct device_node *node __free(device_node) = - of_get_child_by_name(parent, "ports"); - - if (node) - parent = node; - - port = of_get_child_by_name(parent, "port"); + port = of_graph_get_next_port(parent, NULL); if (!port) { pr_debug("graph: no port node found in %pOF\n", parent); return NULL; @@ -677,7 +735,7 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, * getting the next child. If the previous endpoint is NULL this * will return the first child. */ - endpoint = of_get_next_child(port, prev); + endpoint = of_graph_get_next_port_endpoint(port, prev); if (endpoint) { of_node_put(port); return endpoint; @@ -686,11 +744,9 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, /* No more endpoints under this port, try the next one. */ prev = NULL; - do { - port = of_get_next_child(parent, port); - if (!port) - return NULL; - } while (!of_node_name_eq(port, "port")); + port = of_graph_get_next_port(parent, port); + if (!port) + return NULL; } } EXPORT_SYMBOL(of_graph_get_next_endpoint); @@ -824,6 +880,23 @@ unsigned int of_graph_get_endpoint_count(const struct device_node *np) EXPORT_SYMBOL(of_graph_get_endpoint_count); /** + * of_graph_get_port_count() - get the number of port in a device or ports node + * @np: pointer to the device or ports node + * + * Return: count of port of this device or ports node + */ +unsigned int of_graph_get_port_count(struct device_node *np) +{ + unsigned int num = 0; + + for_each_of_graph_port(np, port) + num++; + + return num; +} +EXPORT_SYMBOL(of_graph_get_port_count); + +/** * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint * @node: pointer to parent device_node containing graph port/endpoint * @port: identifier (value of reg property) of the parent port node @@ -1213,7 +1286,6 @@ DEFINE_SIMPLE_PROP(iommus, "iommus", "#iommu-cells") DEFINE_SIMPLE_PROP(mboxes, "mboxes", "#mbox-cells") DEFINE_SIMPLE_PROP(io_channels, "io-channels", "#io-channel-cells") DEFINE_SIMPLE_PROP(io_backends, "io-backends", "#io-backend-cells") -DEFINE_SIMPLE_PROP(interrupt_parent, "interrupt-parent", NULL) DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-cells") DEFINE_SIMPLE_PROP(power_domains, "power-domains", "#power-domain-cells") DEFINE_SIMPLE_PROP(hwlocks, "hwlocks", "#hwlock-cells") @@ -1359,7 +1431,6 @@ static const struct supplier_bindings of_supplier_bindings[] = { { .parse_prop = parse_mboxes, }, { .parse_prop = parse_io_channels, }, { .parse_prop = parse_io_backends, }, - { .parse_prop = parse_interrupt_parent, }, { .parse_prop = parse_dmas, .optional = true, }, { .parse_prop = parse_power_domains, }, { .parse_prop = parse_hwlocks, }, @@ -1466,7 +1537,7 @@ static int of_fwnode_irq_get(const struct fwnode_handle *fwnode, static int of_fwnode_add_links(struct fwnode_handle *fwnode) { - struct property *p; + const struct property *p; struct device_node *con_np = to_of_node(fwnode); if (IS_ENABLED(CONFIG_X86)) diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index 5cf96776dd7d..779db058c42f 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -42,7 +42,7 @@ static void adjust_overlay_phandles(struct device_node *overlay, int phandle_delta) { struct device_node *child; - struct property *prop; + const struct property *prop; phandle phandle; /* adjust node's phandle in node */ @@ -71,10 +71,10 @@ static void adjust_overlay_phandles(struct device_node *overlay, } static int update_usages_of_a_phandle_reference(struct device_node *overlay, - struct property *prop_fixup, phandle phandle) + const struct property *prop_fixup, phandle phandle) { struct device_node *refnode; - struct property *prop; + const struct property *prop; char *value __free(kfree) = kmemdup(prop_fixup->value, prop_fixup->length, GFP_KERNEL); char *cur, *end, *node_path, *prop_name, *s; int offset, len; @@ -147,11 +147,11 @@ static int node_name_cmp(const struct device_node *dn1, * of offsets of the phandle reference(s) within the respective property * value(s). The values at these offsets will be fixed up. */ -static int adjust_local_phandle_references(struct device_node *local_fixups, - struct device_node *overlay, int phandle_delta) +static int adjust_local_phandle_references(const struct device_node *local_fixups, + const struct device_node *overlay, int phandle_delta) { struct device_node *overlay_child; - struct property *prop_fix, *prop; + const struct property *prop_fix, *prop; int err, i, count; unsigned int off; diff --git a/drivers/of/unittest-data/tests-address.dtsi b/drivers/of/unittest-data/tests-address.dtsi index 3344f15c3755..f02a181bb125 100644 --- a/drivers/of/unittest-data/tests-address.dtsi +++ b/drivers/of/unittest-data/tests-address.dtsi @@ -114,6 +114,7 @@ device_type = "pci"; ranges = <0x82000000 0 0xe8000000 0 0xe8000000 0 0x7f00000>, <0x81000000 0 0x00000000 0 0xefff0000 0 0x0010000>; + dma-ranges = <0x43000000 0x10 0x00 0x00 0x00 0x00 0x10000000>; reg = <0x00000000 0xd1070000 0x20000>; pci@0,0 { @@ -142,6 +143,7 @@ #size-cells = <0x01>; ranges = <0xa0000000 0 0 0 0x2000000>, <0xb0000000 1 0 0 0x1000000>; + dma-ranges = <0xc0000000 0x43000000 0x10 0x00 0x10000000>; dev@e0000000 { reg = <0xa0001000 0x1000>, diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index daf9a2dddd7e..438fd70fa995 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -1213,6 +1213,44 @@ static void __init of_unittest_pci_dma_ranges(void) of_node_put(np); } +static void __init of_unittest_pci_empty_dma_ranges(void) +{ + struct device_node *np; + struct of_pci_range range; + struct of_pci_range_parser parser; + + if (!IS_ENABLED(CONFIG_PCI)) + return; + + np = of_find_node_by_path("/testcase-data/address-tests2/pcie@d1070000/pci@0,0/dev@0,0/local-bus@0"); + if (!np) { + pr_err("missing testcase data\n"); + return; + } + + if (of_pci_dma_range_parser_init(&parser, np)) { + pr_err("missing dma-ranges property\n"); + return; + } + + /* + * Get the dma-ranges from the device tree + */ + for_each_of_pci_range(&parser, &range) { + unittest(range.size == 0x10000000, + "for_each_of_pci_range wrong size on node %pOF size=%llx\n", + np, range.size); + unittest(range.cpu_addr == 0x00000000, + "for_each_of_pci_range wrong CPU addr (%llx) on node %pOF", + range.cpu_addr, np); + unittest(range.pci_addr == 0xc0000000, + "for_each_of_pci_range wrong DMA addr (%llx) on node %pOF", + range.pci_addr, np); + } + + of_node_put(np); +} + static void __init of_unittest_bus_ranges(void) { struct device_node *np; @@ -1970,7 +2008,7 @@ static const struct of_device_id unittest_match[] = { static struct platform_driver unittest_driver = { .probe = unittest_probe, - .remove_new = unittest_remove, + .remove = unittest_remove, .driver = { .name = "unittest", .of_match_table = unittest_match, @@ -2071,7 +2109,7 @@ static const struct of_device_id unittest_gpio_id[] = { static struct platform_driver unittest_gpio_driver = { .probe = unittest_gpio_probe, - .remove_new = unittest_gpio_remove, + .remove = unittest_gpio_remove, .driver = { .name = "unittest-gpio", .of_match_table = unittest_gpio_id, @@ -2891,7 +2929,7 @@ static const struct of_device_id unittest_i2c_bus_match[] = { static struct platform_driver unittest_i2c_bus_driver = { .probe = unittest_i2c_bus_probe, - .remove_new = unittest_i2c_bus_remove, + .remove = unittest_i2c_bus_remove, .driver = { .name = "unittest-i2c-bus", .of_match_table = unittest_i2c_bus_match, @@ -4272,6 +4310,7 @@ static int __init of_unittest(void) of_unittest_dma_get_max_cpu_address(); of_unittest_parse_dma_ranges(); of_unittest_pci_dma_ranges(); + of_unittest_pci_empty_dma_ranges(); of_unittest_bus_ranges(); of_unittest_bus_3cell_ranges(); of_unittest_reg(); |