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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
93
boot/extension-uclass.c
Normal 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,
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user