Merge patch series "Convert extension support to UCLASS and adds its support to boot flows"

Kory Maincent (TI.com) <kory.maincent@bootlin.com> says:

This series converts the extension board framework to use UCLASS as
requested by Simon Glass, then adds extension support to pxe_utils
and bootmeth_efi (not tested) to enable extension boards devicetree load
in the standard boot process.

I can't test the imx8 extension scan enabled by the
imx8mm-cl-iot-gate_defconfig as I don't have this board.
I also can't test the efi bootmeth change as I don't have such board.

Link: https://lore.kernel.org/r/20251030-feature_sysboot_extension_board-v5-0-cfb77672fc68@bootlin.com
This commit is contained in:
Tom Rini
2025-11-03 10:12:05 -06:00
22 changed files with 569 additions and 262 deletions

View File

@@ -1909,6 +1909,10 @@ endmenu
endif # OF_LIBFDT
config SUPPORT_EXTENSION_SCAN
select OF_LIBFDT_OVERLAY
bool
config USE_BOOTARGS
bool "Enable boot arguments"
help

View File

@@ -9,6 +9,7 @@ obj-$(CONFIG_BOOT_RETRY) += bootretry.o
obj-$(CONFIG_CMD_BOOTM) += bootm.o bootm_os.o
obj-$(CONFIG_CMD_BOOTZ) += bootm.o bootm_os.o
obj-$(CONFIG_CMD_BOOTI) += bootm.o bootm_os.o
obj-$(CONFIG_SUPPORT_EXTENSION_SCAN) += extension-uclass.o
obj-$(CONFIG_PXE_UTILS) += pxe_utils.o

View File

@@ -16,6 +16,7 @@
#include <efi.h>
#include <efi_loader.h>
#include <env.h>
#include <extension_board.h>
#include <fs.h>
#include <malloc.h>
#include <mapmem.h>
@@ -99,8 +100,11 @@ static int distro_efi_check(struct udevice *dev, struct bootflow_iter *iter)
static int distro_efi_try_bootflow_files(struct udevice *dev,
struct bootflow *bflow)
{
ulong fdt_addr, size, overlay_addr;
const struct extension *extension;
struct fdt_header *working_fdt;
struct blk_desc *desc = NULL;
ulong fdt_addr, size;
struct alist *extension_list;
char fname[256];
int ret, seq;
@@ -148,23 +152,66 @@ static int distro_efi_try_bootflow_files(struct udevice *dev,
return log_msg_ret("fil", -ENOMEM);
}
if (!ret) {
bflow->fdt_size = size;
bflow->fdt_addr = fdt_addr;
/*
* TODO: Apply extension overlay
*
* Here we need to load and apply the extension overlay. This is
* not implemented. See do_extension_apply(). The extension
* stuff needs an implementation in boot/extension.c so it is
* separate from the command code. Really the extension stuff
* should use the device tree and a uclass / driver interface
* rather than implementing its own list
*/
} else {
if (ret) {
log_debug("No device tree available\n");
bflow->flags |= BOOTFLOWF_USE_BUILTIN_FDT;
return 0;
}
bflow->fdt_size = size;
bflow->fdt_addr = fdt_addr;
if (!CONFIG_IS_ENABLED(SUPPORT_EXTENSION_SCAN))
return 0;
ret = extension_scan();
if (ret < 0)
return 0;
extension_list = extension_get_list();
if (!extension_list)
return 0;
working_fdt = map_sysmem(fdt_addr, 0);
if (fdt_check_header(working_fdt))
return 0;
overlay_addr = env_get_hex("extension_overlay_addr", 0);
if (!overlay_addr) {
log_debug("Environment extension_overlay_addr is missing\n");
return 0;
}
alist_for_each(extension, extension_list) {
char *overlay_file;
int len;
len = sizeof(EFI_DIRNAME) + strlen(extension->overlay);
overlay_file = calloc(1, len);
if (!overlay_file)
return -ENOMEM;
snprintf(overlay_file, len, "%s%s", EFI_DIRNAME,
extension->overlay);
ret = bootmeth_common_read_file(dev, bflow, overlay_file,
overlay_addr,
(enum bootflow_img_t)IH_TYPE_FLATDT,
&size);
if (ret) {
log_debug("Failed loading overlay %s\n", overlay_file);
free(overlay_file);
continue;
}
ret = extension_apply(working_fdt, size);
if (ret) {
log_debug("Failed applying overlay %s\n", overlay_file);
free(overlay_file);
continue;
}
bflow->fdt_size += size;
free(overlay_file);
}
return 0;

93
boot/extension-uclass.c Normal file
View File

@@ -0,0 +1,93 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2025 Köry Maincent <kory.maincent@bootlin.com>
*/
#include <alist.h>
#include <command.h>
#include <env.h>
#include <extension_board.h>
#include <fdt_support.h>
#include <malloc.h>
#include <mapmem.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/uclass.h>
struct alist *extension_get_list(void)
{
struct udevice *dev;
if (uclass_first_device_err(UCLASS_EXTENSION, &dev))
return NULL;
return dev_get_priv(dev);
}
int extension_probe(struct udevice *dev)
{
struct alist *extension_list = dev_get_priv(dev);
alist_init_struct(extension_list, struct extension);
return 0;
}
int extension_remove(struct udevice *dev)
{
struct alist *extension_list = dev_get_priv(dev);
alist_uninit(extension_list);
return 0;
}
int extension_scan(void)
{
struct alist *extension_list = extension_get_list();
const struct extension_ops *ops;
struct udevice *dev;
int ret;
ret = uclass_first_device_err(UCLASS_EXTENSION, &dev);
if (ret)
return ret;
if (!extension_list)
return -ENODEV;
ops = extension_get_ops(dev);
alist_empty(extension_list);
return ops->scan(dev, extension_list);
}
int extension_apply(struct fdt_header *working_fdt, ulong size)
{
struct fdt_header *blob;
ulong overlay_addr;
int ret;
overlay_addr = env_get_hex("extension_overlay_addr", 0);
if (!overlay_addr) {
printf("Environment extension_overlay_addr is missing\n");
return -EINVAL;
}
fdt_shrink_to_minimum(working_fdt, size);
blob = map_sysmem(overlay_addr, 0);
if (!fdt_valid(&blob)) {
printf("Invalid overlay devicetree\n");
return -EINVAL;
}
/* Apply method prints messages on error */
ret = fdt_overlay_apply_verbose(working_fdt, blob);
if (ret)
printf("Failed to apply overlay\n");
return ret;
}
UCLASS_DRIVER(extension) = {
.name = "extension",
.id = UCLASS_EXTENSION,
};

View File

@@ -10,6 +10,7 @@
#include <command.h>
#include <dm.h>
#include <env.h>
#include <extension_board.h>
#include <image.h>
#include <log.h>
#include <malloc.h>
@@ -432,6 +433,95 @@ skip_overlay:
}
#endif
/*
* label_boot_extension - scan extension boards and load overlay associated
*/
static void label_boot_extension(struct pxe_context *ctx,
struct pxe_label *label)
{
#if CONFIG_IS_ENABLED(SUPPORT_EXTENSION_SCAN)
const struct extension *extension;
struct fdt_header *working_fdt;
struct alist *extension_list;
int ret, dir_len, len;
char *overlay_dir;
const char *slash;
ulong fdt_addr;
ret = extension_scan();
if (ret < 0)
return;
extension_list = extension_get_list();
if (!extension_list)
return;
/* Get the main fdt and map it */
fdt_addr = env_get_hex("fdt_addr_r", 0);
working_fdt = map_sysmem(fdt_addr, 0);
if (fdt_check_header(working_fdt))
return;
/* Use fdtdir for now as the overlay devicetree directory */
if (label->fdtdir) {
len = strlen(label->fdtdir);
if (!len)
slash = "./";
else if (label->fdtdir[len - 1] != '/')
slash = "/";
else
slash = "";
dir_len = strlen(label->fdtdir) + strlen(slash) + 1;
overlay_dir = calloc(1, len);
if (!overlay_dir)
return;
snprintf(overlay_dir, dir_len, "%s%s", label->fdtdir,
slash);
} else {
dir_len = 2;
snprintf(overlay_dir, dir_len, "/");
}
alist_for_each(extension, extension_list) {
char *overlay_file;
ulong size;
len = dir_len + strlen(extension->overlay);
overlay_file = calloc(1, len);
if (!overlay_file)
goto cleanup;
snprintf(overlay_file, len, "%s%s", overlay_dir,
extension->overlay);
/* Load extension overlay file */
ret = get_relfile_envaddr(ctx, overlay_file,
"extension_overlay_addr",
(enum bootflow_img_t)IH_TYPE_FLATDT,
&size);
if (ret < 0) {
printf("Failed loading overlay %s\n", overlay_file);
free(overlay_file);
continue;
}
ret = extension_apply(working_fdt, size);
if (ret) {
printf("Failed applying overlay %s\n", overlay_file);
free(overlay_file);
continue;
}
free(overlay_file);
}
cleanup:
free(overlay_dir);
#endif
}
/**
* label_boot() - Boot according to the contents of a pxe_label
*
@@ -685,6 +775,8 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
if (label->fdtoverlays)
label_boot_fdtoverlay(ctx, label);
#endif
label_boot_extension(ctx, label);
} else {
bootm_argv[3] = NULL;
}