]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
of: Create of_root if no dtb provided by firmware
authorFrank Rowand <frowand.list@gmail.com>
Sat, 17 Feb 2024 01:05:51 +0000 (17:05 -0800)
committerRob Herring <robh@kernel.org>
Fri, 8 Mar 2024 18:50:39 +0000 (12:50 -0600)
When enabling CONFIG_OF on a platform where 'of_root' is not populated
by firmware, we end up without a root node. In order to apply overlays
and create subnodes of the root node, we need one. Create this root node
by unflattening an empty builtin dtb.

If firmware provides a flattened device tree (FDT) then the FDT is
unflattened via setup_arch(). Otherwise, the call to
unflatten(_and_copy)?_device_tree() will create an empty root node.

We make of_have_populated_dt() return true only if the DTB was loaded by
firmware so that existing callers don't change behavior after this
patch. The call in the of platform code is removed because it prevents
overlays from creating platform devices when the empty root node is
used.

[sboyd@kernel.org: Update of_have_populated_dt() to treat this empty dtb
as not populated. Drop setup_of() initcall]

Signed-off-by: Frank Rowand <frowand.list@gmail.com>
Link: https://lore.kernel.org/r/20230317053415.2254616-2-frowand.list@gmail.com
Cc: Rob Herring <robh+dt@kernel.org>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Link: https://lore.kernel.org/r/20240217010557.2381548-3-sboyd@kernel.org
Signed-off-by: Rob Herring <robh@kernel.org>
drivers/of/Kconfig
drivers/of/Makefile
drivers/of/empty_root.dts [new file with mode: 0644]
drivers/of/fdt.c
drivers/of/platform.c
include/linux/of.h

index da9826accb1b5d7d90d37c7fd8a0d39bdc4fcb5e..d738fbad9c36a1f0538c6d0c53f65c70a400c265 100644 (file)
@@ -14,9 +14,8 @@ if OF
 
 config OF_UNITTEST
        bool "Device Tree runtime unit tests"
-       depends on !SPARC
+       depends on OF_EARLY_FLATTREE
        select IRQ_DOMAIN
-       select OF_EARLY_FLATTREE
        select OF_RESOLVE
        help
          This option builds in test cases for the device tree infrastructure
@@ -54,7 +53,7 @@ config OF_FLATTREE
        select CRC32
 
 config OF_EARLY_FLATTREE
-       bool
+       def_bool OF && !(SPARC || ALPHA || HEXAGON || M68K || PARISC || S390)
        select DMA_DECLARE_COHERENT if HAS_DMA && HAS_IOMEM
        select OF_FLATTREE
 
index eff624854575c56be5b7832cdbbcf83a3b7143ec..df305348d1cb885621149a8eef1907344a700200 100644 (file)
@@ -2,7 +2,7 @@
 obj-y = base.o cpu.o device.o module.o platform.o property.o
 obj-$(CONFIG_OF_KOBJ) += kobj.o
 obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
-obj-$(CONFIG_OF_FLATTREE) += fdt.o
+obj-$(CONFIG_OF_FLATTREE) += fdt.o empty_root.dtb.o
 obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
 obj-$(CONFIG_OF_PROMTREE) += pdt.o
 obj-$(CONFIG_OF_ADDRESS)  += address.o
diff --git a/drivers/of/empty_root.dts b/drivers/of/empty_root.dts
new file mode 100644 (file)
index 0000000..cf9e97a
--- /dev/null
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/dts-v1/;
+
+/ {
+
+};
index dfeba8b8ce9453f335ad6c882efd814cbfcf18af..e5a385285149ee1a3f0550e053b9743d5813848d 100644 (file)
@@ -8,6 +8,7 @@
 
 #define pr_fmt(fmt)    "OF: fdt: " fmt
 
+#include <linux/acpi.h>
 #include <linux/crash_dump.h>
 #include <linux/crc32.h>
 #include <linux/kernel.h>
 
 #include "of_private.h"
 
+/*
+ * __dtb_empty_root_begin[] and __dtb_empty_root_end[] magically created by
+ * cmd_dt_S_dtb in scripts/Makefile.lib
+ */
+extern uint8_t __dtb_empty_root_begin[];
+extern uint8_t __dtb_empty_root_end[];
+
 /*
  * of_fdt_limit_memory - limit the number of regions in the /memory node
  * @limit: maximum entries
@@ -1343,7 +1351,29 @@ static void *__init copy_device_tree(void *fdt)
  */
 void __init unflatten_device_tree(void)
 {
-       __unflatten_device_tree(initial_boot_params, NULL, &of_root,
+       void *fdt = initial_boot_params;
+
+       /* Don't use the bootloader provided DTB if ACPI is enabled */
+       if (!acpi_disabled)
+               fdt = NULL;
+
+       /*
+        * Populate an empty root node when ACPI is enabled or bootloader
+        * doesn't provide one.
+        */
+       if (!fdt) {
+               fdt = (void *) __dtb_empty_root_begin;
+               /* fdt_totalsize() will be used for copy size */
+               if (fdt_totalsize(fdt) >
+                   __dtb_empty_root_end - __dtb_empty_root_begin) {
+                       pr_err("invalid size in dtb_empty_root\n");
+                       return;
+               }
+               of_fdt_crc32 = crc32_be(~0, fdt, fdt_totalsize(fdt));
+               fdt = copy_device_tree(fdt);
+       }
+
+       __unflatten_device_tree(fdt, NULL, &of_root,
                                early_init_dt_alloc_memory_arch, false);
 
        /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
index ba964df6b6db10d9a8c912d18164ffb96f3a4859..389d4ea6bfc1591dee8321e99a322916c23b9017 100644 (file)
@@ -512,9 +512,6 @@ static int __init of_platform_default_populate_init(void)
 
        device_links_supplier_sync_state_pause();
 
-       if (!of_have_populated_dt())
-               return -ENODEV;
-
        if (IS_ENABLED(CONFIG_PPC)) {
                struct device_node *boot_display = NULL;
                struct platform_device *dev;
index a3e8e429ad7f14fed7444afba5288e3fb7c934f8..d5e7acdc8c8ef02e8cdf41ca57751bf5caf5c51c 100644 (file)
@@ -180,11 +180,6 @@ static inline bool is_of_node(const struct fwnode_handle *fwnode)
                        &__of_fwnode_handle_node->fwnode : NULL;        \
        })
 
-static inline bool of_have_populated_dt(void)
-{
-       return of_root != NULL;
-}
-
 static inline bool of_node_is_root(const struct device_node *node)
 {
        return node && (node->parent == NULL);
@@ -546,11 +541,6 @@ static inline struct device_node *of_find_node_with_property(
 
 #define of_fwnode_handle(node) NULL
 
-static inline bool of_have_populated_dt(void)
-{
-       return false;
-}
-
 static inline struct device_node *of_get_compatible_child(const struct device_node *parent,
                                        const char *compatible)
 {
@@ -1634,6 +1624,21 @@ static inline bool of_device_is_system_power_controller(const struct device_node
        return of_property_read_bool(np, "system-power-controller");
 }
 
+/**
+ * of_have_populated_dt() - Has DT been populated by bootloader
+ *
+ * Return: True if a DTB has been populated by the bootloader and it isn't the
+ * empty builtin one. False otherwise.
+ */
+static inline bool of_have_populated_dt(void)
+{
+#ifdef CONFIG_OF
+       return of_property_present(of_root, "compatible");
+#else
+       return false;
+#endif
+}
+
 /*
  * Overlay support
  */