diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-04-27 10:09:05 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-04-27 10:09:05 -0700 |
commit | cb6fe2ceb667eb78f252d473b03deb23999ab1cf (patch) | |
tree | b230a03a1a7d763add665e6c5868fbe6798438db /drivers/of | |
parent | d42b1c47570eb2ed818dc3fe94b2678124af109d (diff) | |
parent | 1c5e9170ad93d3bd62a7ed8380e60b62c88b90a8 (diff) | |
download | linux-stable-cb6fe2ceb667eb78f252d473b03deb23999ab1cf.tar.gz linux-stable-cb6fe2ceb667eb78f252d473b03deb23999ab1cf.tar.bz2 linux-stable-cb6fe2ceb667eb78f252d473b03deb23999ab1cf.zip |
Merge tag 'devicetree-for-6.4-2' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux
Pull more devicetree updates from Rob Herring:
- First part of DT header detangling dropping cpu.h from of_device.h
and replacing some includes with forward declarations. A handful of
drivers needed some adjustment to their includes as a result.
- Refactor of_device.h to be used by bus drivers rather than various
device drivers. This moves non-bus related functions out of
of_device.h. The end goal is for of_platform.h and of_device.h to
stop including each other.
- Refactor open coded parsing of "ranges" in some bus drivers to use DT
address parsing functions
- Add some new address parsing functions of_property_read_reg(),
of_range_count(), and of_range_to_resource() in preparation to
convert more open coded parsing of DT addresses to use them.
- Treewide clean-ups to use of_property_read_bool() and
of_property_present() as appropriate. The ones here are the ones that
didn't get picked up elsewhere.
* tag 'devicetree-for-6.4-2' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: (34 commits)
bus: tegra-gmi: Replace of_platform.h with explicit includes
hte: Use of_property_present() for testing DT property presence
w1: w1-gpio: Use of_property_read_bool() for boolean properties
virt: fsl: Use of_property_present() for testing DT property presence
soc: fsl: Use of_property_present() for testing DT property presence
sbus: display7seg: Use of_property_read_bool() for boolean properties
sparc: Use of_property_read_bool() for boolean properties
sparc: Use of_property_present() for testing DT property presence
bus: mvebu-mbus: Remove open coded "ranges" parsing
of/address: Add of_property_read_reg() helper
of/address: Add of_range_count() helper
of/address: Add support for 3 address cell bus
of/address: Add of_range_to_resource() helper
of: unittest: Add bus address range parsing tests
of: Drop cpu.h include from of_device.h
OPP: Adjust includes to remove of_device.h
irqchip: loongson-eiointc: Add explicit include for cpuhotplug.h
cpuidle: Adjust includes to remove of_device.h
cpufreq: sun50i: Add explicit include for cpu.h
cpufreq: Adjust includes to remove of_device.h
...
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/Makefile | 2 | ||||
-rw-r--r-- | drivers/of/address.c | 76 | ||||
-rw-r--r-- | drivers/of/base.c | 187 | ||||
-rw-r--r-- | drivers/of/cpu.c | 210 | ||||
-rw-r--r-- | drivers/of/of_private.h | 1 | ||||
-rw-r--r-- | drivers/of/unittest-data/tests-address.dtsi | 9 | ||||
-rw-r--r-- | drivers/of/unittest.c | 150 |
7 files changed, 443 insertions, 192 deletions
diff --git a/drivers/of/Makefile b/drivers/of/Makefile index e0360a44306e..10f704592561 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y = base.o device.o platform.o property.o +obj-y = base.o cpu.o device.o platform.o property.o obj-$(CONFIG_OF_KOBJ) += kobj.o obj-$(CONFIG_OF_DYNAMIC) += dynamic.o obj-$(CONFIG_OF_FLATTREE) += fdt.o diff --git a/drivers/of/address.c b/drivers/of/address.c index 3aaa63e66fcf..0d49f8c9ed88 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -90,11 +90,17 @@ static int of_bus_default_translate(__be32 *addr, u64 offset, int na) return 0; } +static unsigned int of_bus_default_flags_get_flags(const __be32 *addr) +{ + return of_read_number(addr, 1); +} + static unsigned int of_bus_default_get_flags(const __be32 *addr) { return IORESOURCE_MEM; } + #ifdef CONFIG_PCI static unsigned int of_bus_pci_get_flags(const __be32 *addr) { @@ -213,9 +219,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, @@ -248,6 +251,34 @@ invalid_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 */ @@ -303,6 +334,11 @@ static unsigned int of_bus_isa_get_flags(const __be32 *addr) return flags; } +static int of_bus_default_flags_match(struct device_node *np) +{ + return of_bus_n_addr_cells(np) == 3; +} + /* * Array of bus specific translators */ @@ -332,6 +368,17 @@ static struct of_bus of_busses[] = { .has_flags = true, .get_flags = of_bus_isa_get_flags, }, + /* Default with flags cell */ + { + .name = "default-flags", + .addresses = "reg", + .match = of_bus_default_flags_match, + .count_cells = of_bus_default_count_cells, + .map = of_bus_default_map, + .translate = of_bus_default_translate, + .has_flags = true, + .get_flags = of_bus_default_flags_get_flags, + }, /* Default */ { .name = "default", @@ -697,6 +744,29 @@ const __be32 *__of_get_address(struct device_node *dev, int index, int bar_no, } EXPORT_SYMBOL(__of_get_address); +/** + * of_property_read_reg - Retrieve the specified "reg" entry index without translating + * @np: device tree node for which to retrieve "reg" from + * @idx: "reg" entry index to read + * @addr: return value for the untranslated address + * @size: return value for the entry size + * + * Returns -EINVAL if "reg" is not found. Returns 0 on success with addr and + * size values filled in. + */ +int of_property_read_reg(struct device_node *np, int idx, u64 *addr, u64 *size) +{ + const __be32 *prop = of_get_address(np, idx, size, NULL); + + if (!prop) + return -EINVAL; + + *addr = of_read_number(prop, of_n_addr_cells(np)); + + return 0; +} +EXPORT_SYMBOL(of_property_read_reg); + static int parser_init(struct of_pci_range_parser *parser, struct device_node *node, const char *name) { diff --git a/drivers/of/base.c b/drivers/of/base.c index ac6fde53342f..7f1720af813c 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -287,193 +287,6 @@ const void *of_get_property(const struct device_node *np, const char *name, EXPORT_SYMBOL(of_get_property); /** - * of_get_cpu_hwid - Get the hardware ID from a CPU device node - * - * @cpun: CPU number(logical index) for which device node is required - * @thread: The local thread number to get the hardware ID for. - * - * Return: The hardware ID for the CPU node or ~0ULL if not found. - */ -u64 of_get_cpu_hwid(struct device_node *cpun, unsigned int thread) -{ - const __be32 *cell; - int ac, len; - - ac = of_n_addr_cells(cpun); - cell = of_get_property(cpun, "reg", &len); - if (!cell || !ac || ((sizeof(*cell) * ac * (thread + 1)) > len)) - return ~0ULL; - - cell += ac * thread; - return of_read_number(cell, ac); -} - -/* - * arch_match_cpu_phys_id - Match the given logical CPU and physical id - * - * @cpu: logical cpu index of a core/thread - * @phys_id: physical identifier of a core/thread - * - * CPU logical to physical index mapping is architecture specific. - * However this __weak function provides a default match of physical - * id to logical cpu index. phys_id provided here is usually values read - * from the device tree which must match the hardware internal registers. - * - * Returns true if the physical identifier and the logical cpu index - * correspond to the same core/thread, false otherwise. - */ -bool __weak arch_match_cpu_phys_id(int cpu, u64 phys_id) -{ - return (u32)phys_id == cpu; -} - -/* - * Checks if the given "prop_name" property holds the physical id of the - * core/thread corresponding to the logical cpu 'cpu'. If 'thread' is not - * NULL, local thread number within the core is returned in it. - */ -static bool __of_find_n_match_cpu_property(struct device_node *cpun, - const char *prop_name, int cpu, unsigned int *thread) -{ - const __be32 *cell; - int ac, prop_len, tid; - u64 hwid; - - ac = of_n_addr_cells(cpun); - cell = of_get_property(cpun, prop_name, &prop_len); - if (!cell && !ac && arch_match_cpu_phys_id(cpu, 0)) - return true; - if (!cell || !ac) - return false; - prop_len /= sizeof(*cell) * ac; - for (tid = 0; tid < prop_len; tid++) { - hwid = of_read_number(cell, ac); - if (arch_match_cpu_phys_id(cpu, hwid)) { - if (thread) - *thread = tid; - return true; - } - cell += ac; - } - return false; -} - -/* - * arch_find_n_match_cpu_physical_id - See if the given device node is - * for the cpu corresponding to logical cpu 'cpu'. Return true if so, - * else false. If 'thread' is non-NULL, the local thread number within the - * core is returned in it. - */ -bool __weak arch_find_n_match_cpu_physical_id(struct device_node *cpun, - int cpu, unsigned int *thread) -{ - /* Check for non-standard "ibm,ppc-interrupt-server#s" property - * for thread ids on PowerPC. If it doesn't exist fallback to - * standard "reg" property. - */ - if (IS_ENABLED(CONFIG_PPC) && - __of_find_n_match_cpu_property(cpun, - "ibm,ppc-interrupt-server#s", - cpu, thread)) - return true; - - return __of_find_n_match_cpu_property(cpun, "reg", cpu, thread); -} - -/** - * of_get_cpu_node - Get device node associated with the given logical CPU - * - * @cpu: CPU number(logical index) for which device node is required - * @thread: if not NULL, local thread number within the physical core is - * returned - * - * The main purpose of this function is to retrieve the device node for the - * given logical CPU index. It should be used to initialize the of_node in - * cpu device. Once of_node in cpu device is populated, all the further - * references can use that instead. - * - * CPU logical to physical index mapping is architecture specific and is built - * before booting secondary cores. This function uses arch_match_cpu_phys_id - * which can be overridden by architecture specific implementation. - * - * Return: A node pointer for the logical cpu with refcount incremented, use - * of_node_put() on it when done. Returns NULL if not found. - */ -struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) -{ - struct device_node *cpun; - - for_each_of_cpu_node(cpun) { - if (arch_find_n_match_cpu_physical_id(cpun, cpu, thread)) - return cpun; - } - return NULL; -} -EXPORT_SYMBOL(of_get_cpu_node); - -/** - * of_cpu_node_to_id: Get the logical CPU number for a given device_node - * - * @cpu_node: Pointer to the device_node for CPU. - * - * Return: The logical CPU number of the given CPU device_node or -ENODEV if the - * CPU is not found. - */ -int of_cpu_node_to_id(struct device_node *cpu_node) -{ - int cpu; - bool found = false; - struct device_node *np; - - for_each_possible_cpu(cpu) { - np = of_cpu_device_node_get(cpu); - found = (cpu_node == np); - of_node_put(np); - if (found) - return cpu; - } - - return -ENODEV; -} -EXPORT_SYMBOL(of_cpu_node_to_id); - -/** - * of_get_cpu_state_node - Get CPU's idle state node at the given index - * - * @cpu_node: The device node for the CPU - * @index: The index in the list of the idle states - * - * Two generic methods can be used to describe a CPU's idle states, either via - * a flattened description through the "cpu-idle-states" binding or via the - * hierarchical layout, using the "power-domains" and the "domain-idle-states" - * bindings. This function check for both and returns the idle state node for - * the requested index. - * - * 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, - int index) -{ - struct of_phandle_args args; - int err; - - err = of_parse_phandle_with_args(cpu_node, "power-domains", - "#power-domain-cells", 0, &args); - if (!err) { - struct device_node *state_node = - of_parse_phandle(args.np, "domain-idle-states", index); - - of_node_put(args.np); - if (state_node) - return state_node; - } - - return of_parse_phandle(cpu_node, "cpu-idle-states", index); -} -EXPORT_SYMBOL(of_get_cpu_state_node); - -/** * __of_device_is_compatible() - Check if the node matches given constraints * @device: pointer to node * @compat: required compatible string, NULL or "" for any match diff --git a/drivers/of/cpu.c b/drivers/of/cpu.c new file mode 100644 index 000000000000..d17b2f851082 --- /dev/null +++ b/drivers/of/cpu.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/cpu.h> +#include <linux/kernel.h> +#include <linux/of.h> + +/** + * of_get_cpu_hwid - Get the hardware ID from a CPU device node + * + * @cpun: CPU number(logical index) for which device node is required + * @thread: The local thread number to get the hardware ID for. + * + * Return: The hardware ID for the CPU node or ~0ULL if not found. + */ +u64 of_get_cpu_hwid(struct device_node *cpun, unsigned int thread) +{ + const __be32 *cell; + int ac, len; + + ac = of_n_addr_cells(cpun); + cell = of_get_property(cpun, "reg", &len); + if (!cell || !ac || ((sizeof(*cell) * ac * (thread + 1)) > len)) + return ~0ULL; + + cell += ac * thread; + return of_read_number(cell, ac); +} + +/* + * arch_match_cpu_phys_id - Match the given logical CPU and physical id + * + * @cpu: logical cpu index of a core/thread + * @phys_id: physical identifier of a core/thread + * + * CPU logical to physical index mapping is architecture specific. + * However this __weak function provides a default match of physical + * id to logical cpu index. phys_id provided here is usually values read + * from the device tree which must match the hardware internal registers. + * + * Returns true if the physical identifier and the logical cpu index + * correspond to the same core/thread, false otherwise. + */ +bool __weak arch_match_cpu_phys_id(int cpu, u64 phys_id) +{ + return (u32)phys_id == cpu; +} + +/* + * Checks if the given "prop_name" property holds the physical id of the + * core/thread corresponding to the logical cpu 'cpu'. If 'thread' is not + * NULL, local thread number within the core is returned in it. + */ +static bool __of_find_n_match_cpu_property(struct device_node *cpun, + const char *prop_name, int cpu, unsigned int *thread) +{ + const __be32 *cell; + int ac, prop_len, tid; + u64 hwid; + + ac = of_n_addr_cells(cpun); + cell = of_get_property(cpun, prop_name, &prop_len); + if (!cell && !ac && arch_match_cpu_phys_id(cpu, 0)) + return true; + if (!cell || !ac) + return false; + prop_len /= sizeof(*cell) * ac; + for (tid = 0; tid < prop_len; tid++) { + hwid = of_read_number(cell, ac); + if (arch_match_cpu_phys_id(cpu, hwid)) { + if (thread) + *thread = tid; + return true; + } + cell += ac; + } + return false; +} + +/* + * arch_find_n_match_cpu_physical_id - See if the given device node is + * for the cpu corresponding to logical cpu 'cpu'. Return true if so, + * else false. If 'thread' is non-NULL, the local thread number within the + * core is returned in it. + */ +bool __weak arch_find_n_match_cpu_physical_id(struct device_node *cpun, + int cpu, unsigned int *thread) +{ + /* Check for non-standard "ibm,ppc-interrupt-server#s" property + * for thread ids on PowerPC. If it doesn't exist fallback to + * standard "reg" property. + */ + if (IS_ENABLED(CONFIG_PPC) && + __of_find_n_match_cpu_property(cpun, + "ibm,ppc-interrupt-server#s", + cpu, thread)) + return true; + + return __of_find_n_match_cpu_property(cpun, "reg", cpu, thread); +} + +/** + * of_get_cpu_node - Get device node associated with the given logical CPU + * + * @cpu: CPU number(logical index) for which device node is required + * @thread: if not NULL, local thread number within the physical core is + * returned + * + * The main purpose of this function is to retrieve the device node for the + * given logical CPU index. It should be used to initialize the of_node in + * cpu device. Once of_node in cpu device is populated, all the further + * references can use that instead. + * + * CPU logical to physical index mapping is architecture specific and is built + * before booting secondary cores. This function uses arch_match_cpu_phys_id + * which can be overridden by architecture specific implementation. + * + * Return: A node pointer for the logical cpu with refcount incremented, use + * of_node_put() on it when done. Returns NULL if not found. + */ +struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) +{ + struct device_node *cpun; + + for_each_of_cpu_node(cpun) { + if (arch_find_n_match_cpu_physical_id(cpun, cpu, thread)) + return cpun; + } + return NULL; +} +EXPORT_SYMBOL(of_get_cpu_node); + +/** + * of_cpu_device_node_get: Get the CPU device_node for a given logical CPU number + * + * @cpu: The logical CPU number + * + * Return: Pointer to the device_node for CPU with its reference count + * incremented of the given logical CPU number or NULL if the CPU device_node + * is not found. + */ +struct device_node *of_cpu_device_node_get(int cpu) +{ + struct device *cpu_dev; + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) + return of_get_cpu_node(cpu, NULL); + return of_node_get(cpu_dev->of_node); +} +EXPORT_SYMBOL(of_cpu_device_node_get); + +/** + * of_cpu_node_to_id: Get the logical CPU number for a given device_node + * + * @cpu_node: Pointer to the device_node for CPU. + * + * Return: The logical CPU number of the given CPU device_node or -ENODEV if the + * CPU is not found. + */ +int of_cpu_node_to_id(struct device_node *cpu_node) +{ + int cpu; + bool found = false; + struct device_node *np; + + for_each_possible_cpu(cpu) { + np = of_cpu_device_node_get(cpu); + found = (cpu_node == np); + of_node_put(np); + if (found) + return cpu; + } + + return -ENODEV; +} +EXPORT_SYMBOL(of_cpu_node_to_id); + +/** + * of_get_cpu_state_node - Get CPU's idle state node at the given index + * + * @cpu_node: The device node for the CPU + * @index: The index in the list of the idle states + * + * Two generic methods can be used to describe a CPU's idle states, either via + * a flattened description through the "cpu-idle-states" binding or via the + * hierarchical layout, using the "power-domains" and the "domain-idle-states" + * bindings. This function check for both and returns the idle state node for + * the requested index. + * + * 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, + int index) +{ + struct of_phandle_args args; + int err; + + err = of_parse_phandle_with_args(cpu_node, "power-domains", + "#power-domain-cells", 0, &args); + if (!err) { + struct device_node *state_node = + of_parse_phandle(args.np, "domain-idle-states", index); + + of_node_put(args.np); + if (state_node) + return state_node; + } + + return of_parse_phandle(cpu_node, "cpu-idle-states", index); +} +EXPORT_SYMBOL(of_get_cpu_state_node); diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index fb6792d381a6..b57f1014e419 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -38,6 +38,7 @@ struct alias_prop { #define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 extern struct mutex of_mutex; +extern raw_spinlock_t devtree_lock; extern struct list_head aliases_lookup; extern struct kset *of_kset; diff --git a/drivers/of/unittest-data/tests-address.dtsi b/drivers/of/unittest-data/tests-address.dtsi index 6604a52bf6cb..bc0029cbf8ea 100644 --- a/drivers/of/unittest-data/tests-address.dtsi +++ b/drivers/of/unittest-data/tests-address.dtsi @@ -14,7 +14,7 @@ #size-cells = <1>; /* ranges here is to make sure we don't use it for * dma-ranges translation */ - ranges = <0x70000000 0x70000000 0x40000000>, + ranges = <0x70000000 0x70000000 0x50000000>, <0x00000000 0xd0000000 0x20000000>; dma-ranges = <0x0 0x20000000 0x40000000>; @@ -43,6 +43,13 @@ <0x42000000 0x0 0xc0000000 0x20000000 0x0 0x10000000>; }; + bus@a0000000 { + #address-cells = <3>; + #size-cells = <2>; + ranges = <0xf00baa 0x0 0x0 0xa0000000 0x0 0x100000>, + <0xf00bee 0x1 0x0 0xb0000000 0x0 0x200000>; + }; + }; }; }; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index ab3e91445256..2191c0136531 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -1008,6 +1008,153 @@ static void __init of_unittest_pci_dma_ranges(void) of_node_put(np); } +static void __init of_unittest_bus_ranges(void) +{ + struct device_node *np; + struct of_range range; + struct of_range_parser parser; + struct resource res; + int ret, count, i = 0; + + np = of_find_node_by_path("/testcase-data/address-tests"); + if (!np) { + pr_err("missing testcase data\n"); + return; + } + + if (of_range_parser_init(&parser, np)) { + pr_err("missing ranges property\n"); + 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); + + count = of_range_count(&parser); + unittest(count == 2, + "of_range_count wrong size on node %pOF count=%d\n", + np, count); + + /* + * Get the "ranges" from the device tree + */ + for_each_of_range(&parser, &range) { + unittest(range.flags == IORESOURCE_MEM, + "for_each_of_range wrong flags on node %pOF flags=%x (expected %x)\n", + np, range.flags, IORESOURCE_MEM); + if (!i) { + unittest(range.size == 0x50000000, + "for_each_of_range wrong size on node %pOF size=%llx\n", + np, range.size); + unittest(range.cpu_addr == 0x70000000, + "for_each_of_range wrong CPU addr (%llx) on node %pOF", + range.cpu_addr, np); + unittest(range.bus_addr == 0x70000000, + "for_each_of_range wrong bus addr (%llx) on node %pOF", + range.pci_addr, np); + } else { + unittest(range.size == 0x20000000, + "for_each_of_range wrong size on node %pOF size=%llx\n", + np, range.size); + unittest(range.cpu_addr == 0xd0000000, + "for_each_of_range wrong CPU addr (%llx) on node %pOF", + range.cpu_addr, np); + unittest(range.bus_addr == 0x00000000, + "for_each_of_range wrong bus addr (%llx) on node %pOF", + range.pci_addr, np); + } + i++; + } + + of_node_put(np); +} + +static void __init of_unittest_bus_3cell_ranges(void) +{ + struct device_node *np; + struct of_range range; + struct of_range_parser parser; + int i = 0; + + np = of_find_node_by_path("/testcase-data/address-tests/bus@a0000000"); + if (!np) { + pr_err("missing testcase data\n"); + return; + } + + if (of_range_parser_init(&parser, np)) { + pr_err("missing ranges property\n"); + return; + } + + /* + * Get the "ranges" from the device tree + */ + for_each_of_range(&parser, &range) { + if (!i) { + unittest(range.flags == 0xf00baa, + "for_each_of_range wrong flags on node %pOF flags=%x\n", + np, range.flags); + unittest(range.size == 0x100000, + "for_each_of_range wrong size on node %pOF size=%llx\n", + np, range.size); + unittest(range.cpu_addr == 0xa0000000, + "for_each_of_range wrong CPU addr (%llx) on node %pOF", + range.cpu_addr, np); + unittest(range.bus_addr == 0x0, + "for_each_of_range wrong bus addr (%llx) on node %pOF", + range.pci_addr, np); + } else { + unittest(range.flags == 0xf00bee, + "for_each_of_range wrong flags on node %pOF flags=%x\n", + np, range.flags); + unittest(range.size == 0x200000, + "for_each_of_range wrong size on node %pOF size=%llx\n", + np, range.size); + unittest(range.cpu_addr == 0xb0000000, + "for_each_of_range wrong CPU addr (%llx) on node %pOF", + range.cpu_addr, np); + unittest(range.bus_addr == 0x100000000, + "for_each_of_range wrong bus addr (%llx) on node %pOF", + range.pci_addr, np); + } + i++; + } + + of_node_put(np); +} + +static void __init of_unittest_reg(void) +{ + struct device_node *np; + int ret; + u64 addr, size; + + np = of_find_node_by_path("/testcase-data/address-tests/bus@80000000/device@1000"); + if (!np) { + pr_err("missing testcase data\n"); + return; + } + + ret = of_property_read_reg(np, 0, &addr, &size); + unittest(!ret, "of_property_read_reg(%pOF) returned error %d\n", + np, ret); + unittest(addr == 0x1000, "of_property_read_reg(%pOF) untranslated address (%llx) incorrect\n", + np, addr); + + of_node_put(np); +} + static void __init of_unittest_parse_interrupts(void) { struct device_node *np; @@ -3635,6 +3782,9 @@ 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_bus_ranges(); + of_unittest_bus_3cell_ranges(); + of_unittest_reg(); of_unittest_match_node(); of_unittest_platform_populate(); of_unittest_overlay(); |