Message ID | 20240112200750.4062441-5-sboyd@kernel.org |
---|---|
State | New |
Headers | show |
Series | of: populate of_root node if bootloader doesn't | expand |
On Tue, Jan 16, 2024 at 05:18:15PM -0800, Stephen Boyd wrote: > Quoting Rob Herring (2024-01-15 12:32:30) > > On Fri, Jan 12, 2024 at 12:07:47PM -0800, Stephen Boyd wrote: > > > diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig > > > index da9826accb1b..9628e48baa15 100644 > > > --- a/drivers/of/Kconfig > > > +++ b/drivers/of/Kconfig > > > @@ -54,9 +54,14 @@ config OF_FLATTREE > > > select CRC32 > > > > > > config OF_EARLY_FLATTREE > > > - bool > > > + bool "Functions for accessing Flat Devicetree (FDT) early in boot" > > > > I think we could instead just get rid of this kconfig option. Or > > always enable with CONFIG_OF (except on Sparc). The only cost of > > enabling it is init section functions which get freed anyways. > > Getting rid of it is a more massive change. It can be the default and > kept hidden instead? If it can't be selected on Sparc then it should be > hidden there anyway. The easier option is certainly fine for this series. I just don't want it visible. > > > select DMA_DECLARE_COHERENT if HAS_DMA && HAS_IOMEM > > > select OF_FLATTREE > > > + help > > > + Normally selected by platforms that process an FDT that has been > > > + passed to the kernel by the bootloader. If the bootloader does not > > > + pass an FDT to the kernel and you need an empty devicetree that > > > + contains only a root node to exist, then say Y here. > > > > > > config OF_PROMTREE > > > bool > [...] > > > @@ -195,6 +191,17 @@ static inline int of_node_check_flag(const struct device_node *n, unsigned long > > > return test_bit(flag, &n->_flags); > > > } > > > > > > +/** > > > + * 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) > > > +{ > > > + return of_root != NULL && !of_node_check_flag(of_root, OF_EMPTY_ROOT); > > > > Just a side comment, but I think many/all callers of this function could > > just be removed. > > > > I don't love new flags. Another possible way to handle this would be > > checking for "compatible" being present in the root node. I guess this > > is fine as-is for now at least. > > Ok. I can add a check for a compatible property. That's probably better > anyway. Should there be a compatible property there to signal that this > DT isn't compatible with anything? I worry about DT overlays injecting a > compatible string into the root node, but maybe that is already > prevented. I worry about DT overlays injecting anything... I don't think it is explicitly forbidden, but I have asked that any general purpose interface to apply overlays be restricted to nodes explicitly allowed (e.g. downstream of a connector node). For now, the places (i.e. drivers) overlays are applied are limited. We could probably restrict the root node to new nodes only and no new or changed properties. Rob
On Thu, Jan 18, 2024 at 2:46 AM Geert Uytterhoeven <geert@linux-m68k.org> wrote: > > Hi Rob, > > On Wed, Jan 17, 2024 at 6:41 PM Rob Herring <robh@kernel.org> wrote: > > On Tue, Jan 16, 2024 at 05:18:15PM -0800, Stephen Boyd wrote: > > > Quoting Rob Herring (2024-01-15 12:32:30) > > > > On Fri, Jan 12, 2024 at 12:07:47PM -0800, Stephen Boyd wrote: > > > > > diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig > > > > > index da9826accb1b..9628e48baa15 100644 > > > > > --- a/drivers/of/Kconfig > > > > > +++ b/drivers/of/Kconfig > > > > > @@ -54,9 +54,14 @@ config OF_FLATTREE > > > > > select CRC32 > > > > > > > > > > config OF_EARLY_FLATTREE > > > > > - bool > > > > > + bool "Functions for accessing Flat Devicetree (FDT) early in boot" > > > > > > > > I think we could instead just get rid of this kconfig option. Or > > > > always enable with CONFIG_OF (except on Sparc). The only cost of > > > > enabling it is init section functions which get freed anyways. > > > > > > Getting rid of it is a more massive change. It can be the default and > > > kept hidden instead? If it can't be selected on Sparc then it should be > > > hidden there anyway. > > > > The easier option is certainly fine for this series. I just don't want > > it visible. > > > > > > > select DMA_DECLARE_COHERENT if HAS_DMA && HAS_IOMEM > > > > > select OF_FLATTREE > > > > > + help > > > > > + Normally selected by platforms that process an FDT that has been > > > > > + passed to the kernel by the bootloader. If the bootloader does not > > > > > + pass an FDT to the kernel and you need an empty devicetree that > > > > > + contains only a root node to exist, then say Y here. > > > > > > > > > > config OF_PROMTREE > > > > > bool > > > [...] > > > > > @@ -195,6 +191,17 @@ static inline int of_node_check_flag(const struct device_node *n, unsigned long > > > > > return test_bit(flag, &n->_flags); > > > > > } > > > > > > > > > > +/** > > > > > + * 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) > > > > > +{ > > > > > + return of_root != NULL && !of_node_check_flag(of_root, OF_EMPTY_ROOT); > > > > > > > > Just a side comment, but I think many/all callers of this function could > > > > just be removed. > > > > > > > > I don't love new flags. Another possible way to handle this would be > > > > checking for "compatible" being present in the root node. I guess this > > > > is fine as-is for now at least. > > > > > > Ok. I can add a check for a compatible property. That's probably better > > > anyway. Should there be a compatible property there to signal that this > > > DT isn't compatible with anything? I worry about DT overlays injecting a > > > compatible string into the root node, but maybe that is already > > > prevented. > > > > I worry about DT overlays injecting anything... > > > > I don't think it is explicitly forbidden, but I have asked that any > > general purpose interface to apply overlays be restricted to nodes > > explicitly allowed (e.g. downstream of a connector node). For now, the > > places (i.e. drivers) overlays are applied are limited. > > > > We could probably restrict the root node to new nodes only and no new > > or changed properties. > > Changing (<wild dream>or appending to</wild dream>) the root > "compatible" and/or "model" properties is useful in case of large > extension boards, though. This is also the case for DTBs created from > a base DTB and one or more overlays using fdtoverlay. I think appending by adding another compatible value could be okay. Removing or appending to an existing entry is not. We don't want the following sequence to be possible: of_machine_is_compatible("foo") --> true apply overlay of_machine_is_compatible("foo") --> false For Stephen's case, it's going from no root compatible at all to something. I don't think your case would apply here. To put it another way, if we've booted with ACPI, compatible in the root node is not valid. > For the latter, see also the following threads, where you weren't > (but probably should have been) CCed: > > [1] "[PATCH v9 2/2] arm64: boot: Support Flat Image Tree" > https://lore.kernel.org/all/20231202035511.487946-3-sjg@chromium.org > [2] "Proposal: FIT support for extension boards / overlays" > https://lore.kernel.org/all/CAPnjgZ06s64C2ux1rABNAnMv3q4W++sjhNGCO_uPMH_9sTF7Mw@mail.gmail.com That all seems pretty orthogonal to the issues here. Rob
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index da9826accb1b..9628e48baa15 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -54,9 +54,14 @@ config OF_FLATTREE select CRC32 config OF_EARLY_FLATTREE - bool + bool "Functions for accessing Flat Devicetree (FDT) early in boot" select DMA_DECLARE_COHERENT if HAS_DMA && HAS_IOMEM select OF_FLATTREE + help + Normally selected by platforms that process an FDT that has been + passed to the kernel by the bootloader. If the bootloader does not + pass an FDT to the kernel and you need an empty devicetree that + contains only a root node to exist, then say Y here. config OF_PROMTREE bool diff --git a/drivers/of/Makefile b/drivers/of/Makefile index eff624854575..df305348d1cb 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -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 index 000000000000..cf9e97a60f48 --- /dev/null +++ b/drivers/of/empty_root.dts @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only +/dts-v1/; + +/ { + +}; diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index b488ad86d456..9fc7f8b4f48a 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -32,6 +32,13 @@ #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,8 +1350,26 @@ static void __init copy_device_tree(void) */ void __init unflatten_device_tree(void) { + bool firmware_loaded = true; + + if (!initial_boot_params) { + initial_boot_params = (void *) __dtb_empty_root_begin; + /* fdt_totalsize() will be used for copy size */ + if (fdt_totalsize(initial_boot_params) > + __dtb_empty_root_end - __dtb_empty_root_begin) { + pr_err("invalid size in dtb_empty_root\n"); + return; + } + of_fdt_crc32 = crc32_be(~0, initial_boot_params, + fdt_totalsize(initial_boot_params)); + copy_device_tree(); + firmware_loaded = false; + } + __unflatten_device_tree(initial_boot_params, NULL, &of_root, early_init_dt_alloc_memory_arch, false); + if (!firmware_loaded) + of_node_set_flag(of_root, OF_EMPTY_ROOT); /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ of_alias_scan(early_init_dt_alloc_memory_arch); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 126d265aa7d8..20087bb8a46b 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -549,9 +549,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; diff --git a/include/linux/of.h b/include/linux/of.h index 6a9ddf20e79a..390ad961ef01 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -151,6 +151,7 @@ extern struct device_node *of_stdout; #define OF_POPULATED_BUS 4 /* platform bus created for children */ #define OF_OVERLAY 5 /* allocated for an overlay */ #define OF_OVERLAY_FREE_CSET 6 /* in overlay cset being freed */ +#define OF_EMPTY_ROOT 7 /* the builtin empty root node */ #define OF_BAD_ADDR ((u64)-1) @@ -180,11 +181,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); @@ -195,6 +191,17 @@ static inline int of_node_check_flag(const struct device_node *n, unsigned long return test_bit(flag, &n->_flags); } +/** + * 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) +{ + return of_root != NULL && !of_node_check_flag(of_root, OF_EMPTY_ROOT); +} + static inline int of_node_test_and_set_flag(struct device_node *n, unsigned long flag) {