diff options
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/Kconfig | 2 | ||||
-rw-r--r-- | drivers/of/base.c | 28 | ||||
-rw-r--r-- | drivers/of/fdt.c | 24 | ||||
-rw-r--r-- | drivers/of/unittest.c | 62 |
4 files changed, 110 insertions, 6 deletions
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 1470b5227834..07bb3c8f191b 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -50,7 +50,7 @@ config OF_ADDRESS_PCI config OF_IRQ def_bool y - depends on !SPARC + depends on !SPARC && IRQ_DOMAIN config OF_NET depends on NETDEVICES diff --git a/drivers/of/base.c b/drivers/of/base.c index a1aa0c7dee50..99764db0875a 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -568,6 +568,29 @@ bool of_device_is_available(const struct device_node *device) EXPORT_SYMBOL(of_device_is_available); /** + * of_device_is_big_endian - check if a device has BE registers + * + * @device: Node to check for endianness + * + * Returns true if the device has a "big-endian" property, or if the kernel + * was compiled for BE *and* the device has a "native-endian" property. + * Returns false otherwise. + * + * Callers would nominally use ioread32be/iowrite32be if + * of_device_is_big_endian() == true, or readl/writel otherwise. + */ +bool of_device_is_big_endian(const struct device_node *device) +{ + if (of_property_read_bool(device, "big-endian")) + return true; + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && + of_property_read_bool(device, "native-endian")) + return true; + return false; +} +EXPORT_SYMBOL(of_device_is_big_endian); + +/** * of_get_parent - Get a node's parent if any * @node: Node to get parent * @@ -640,8 +663,9 @@ static struct device_node *__of_get_next_child(const struct device_node *node, * @node: parent node * @prev: previous child of the parent node, or NULL to get first * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. + * Returns a node pointer with refcount incremented, use of_node_put() on + * it when done. Returns NULL when prev is the last child. Decrements the + * refcount of prev. */ struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 3a896c9aeb74..cde35c5d0191 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -109,6 +109,25 @@ int of_fdt_is_compatible(const void *blob, } /** + * of_fdt_is_big_endian - Return true if given node needs BE MMIO accesses + * @blob: A device tree blob + * @node: node to test + * + * Returns true if the node has a "big-endian" property, or if the kernel + * was compiled for BE *and* the node has a "native-endian" property. + * Returns false otherwise. + */ +bool of_fdt_is_big_endian(const void *blob, unsigned long node) +{ + if (fdt_getprop(blob, node, "big-endian", NULL)) + return true; + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && + fdt_getprop(blob, node, "native-endian", NULL)) + return true; + return false; +} + +/** * of_fdt_match - Return true if node matches a list of compatible values */ int of_fdt_match(const void *blob, unsigned long node, @@ -172,7 +191,7 @@ static void * unflatten_dt_node(void *blob, if (!pathp) return mem; - allocl = l++; + allocl = ++l; /* version 0x10 has a more compact unit name here instead of the full * path. we accumulate the full path size using "fpsize", we'll rebuild @@ -879,8 +898,7 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname, endp = reg + (l / sizeof(__be32)); - pr_debug("memory scan node %s, reg size %d, data: %x %x %x %x,\n", - uname, l, reg[0], reg[1], reg[2], reg[3]); + pr_debug("memory scan node %s, reg size %d,\n", uname, l); while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { u64 base, size; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index e844907c9efa..18016341d5a9 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -23,6 +23,8 @@ #include <linux/i2c.h> #include <linux/i2c-mux.h> +#include <linux/bitops.h> + #include "of_private.h" static struct unittest_results { @@ -1109,6 +1111,59 @@ static const char *overlay_path(int nr) static const char *bus_path = "/testcase-data/overlay-node/test-bus"; +/* it is guaranteed that overlay ids are assigned in sequence */ +#define MAX_UNITTEST_OVERLAYS 256 +static unsigned long overlay_id_bits[BITS_TO_LONGS(MAX_UNITTEST_OVERLAYS)]; +static int overlay_first_id = -1; + +static void of_unittest_track_overlay(int id) +{ + if (overlay_first_id < 0) + overlay_first_id = id; + id -= overlay_first_id; + + /* we shouldn't need that many */ + BUG_ON(id >= MAX_UNITTEST_OVERLAYS); + overlay_id_bits[BIT_WORD(id)] |= BIT_MASK(id); +} + +static void of_unittest_untrack_overlay(int id) +{ + if (overlay_first_id < 0) + return; + id -= overlay_first_id; + BUG_ON(id >= MAX_UNITTEST_OVERLAYS); + overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id); +} + +static void of_unittest_destroy_tracked_overlays(void) +{ + int id, ret, defers; + + if (overlay_first_id < 0) + return; + + /* try until no defers */ + do { + defers = 0; + /* remove in reverse order */ + for (id = MAX_UNITTEST_OVERLAYS - 1; id >= 0; id--) { + if (!(overlay_id_bits[BIT_WORD(id)] & BIT_MASK(id))) + continue; + + ret = of_overlay_destroy(id + overlay_first_id); + if (ret != 0) { + defers++; + pr_warn("%s: overlay destroy failed for #%d\n", + __func__, id + overlay_first_id); + continue; + } + + overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id); + } + } while (defers > 0); +} + static int of_unittest_apply_overlay(int unittest_nr, int overlay_nr, int *overlay_id) { @@ -1130,6 +1185,7 @@ static int of_unittest_apply_overlay(int unittest_nr, int overlay_nr, goto out; } id = ret; + of_unittest_track_overlay(id); ret = 0; @@ -1343,6 +1399,7 @@ static void of_unittest_overlay_6(void) return; } ov_id[i] = ret; + of_unittest_track_overlay(ov_id[i]); } for (i = 0; i < 2; i++) { @@ -1367,6 +1424,7 @@ static void of_unittest_overlay_6(void) PDEV_OVERLAY)); return; } + of_unittest_untrack_overlay(ov_id[i]); } for (i = 0; i < 2; i++) { @@ -1411,6 +1469,7 @@ static void of_unittest_overlay_8(void) return; } ov_id[i] = ret; + of_unittest_track_overlay(ov_id[i]); } /* now try to remove first overlay (it should fail) */ @@ -1433,6 +1492,7 @@ static void of_unittest_overlay_8(void) PDEV_OVERLAY)); return; } + of_unittest_untrack_overlay(ov_id[i]); } unittest(1, "overlay test %d passed\n", 8); @@ -1855,6 +1915,8 @@ static void __init of_unittest_overlay(void) of_unittest_overlay_i2c_cleanup(); #endif + of_unittest_destroy_tracked_overlays(); + out: of_node_put(bus_np); } |