From 15cc283d1ba4f0821bf96dd709cc805513746da7 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Mon, 18 May 2026 16:32:05 -0600 Subject: bootdev: Fix the case where the driver ops field is null. In the case where a bootdev does not have a custom get_bootflow function but instead relies on default_get_bootflow to provide one, bootdev_get_bootflow was not handling the case where ops was simply not set. Restructure the function to check for "ops && ops->get_bootflow" and add appropriate log_debug calls for both cases. Signed-off-by: Tom Rini --- boot/bootdev-uclass.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index 3f8dc2c3c4e..657804949f8 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -566,13 +566,18 @@ int bootdev_get_bootflow(struct udevice *dev, struct bootflow_iter *iter, { const struct bootdev_ops *ops = bootdev_get_ops(dev); - log_debug("->get_bootflow %s,%x=%p\n", dev->name, iter->part, - ops->get_bootflow); bootflow_init(bflow, dev, iter->method); - if (!ops->get_bootflow) - return default_get_bootflow(dev, iter, bflow); - return ops->get_bootflow(dev, iter, bflow); + if (ops && ops->get_bootflow) { + log_debug("->get_bootflow %s,%x=%p\n", dev->name, iter->part, + ops->get_bootflow); + + return ops->get_bootflow(dev, iter, bflow); + } + + log_debug("->get_bootflow %s,%x is unset\n", dev->name, iter->part); + + return default_get_bootflow(dev, iter, bflow); } int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp, -- cgit v1.3.1 From 83cf74a01a836d662db2413b80d50264fa7bdcfb Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Mon, 18 May 2026 15:49:52 -0600 Subject: block: ide: Drop empty bootdev_ops structure We don't need to provide an empty struct here now that the caller can handle this being empty. Signed-off-by: Tom Rini --- drivers/block/ide.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/block/ide.c b/drivers/block/ide.c index cab5e1bc92b..c1a46dd2a94 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -969,9 +969,6 @@ static int ide_bootdev_hunt(struct bootdev_hunter *info, bool show) return 0; } -struct bootdev_ops ide_bootdev_ops = { -}; - static const struct udevice_id ide_bootdev_ids[] = { { .compatible = "u-boot,bootdev-ide" }, { } @@ -980,7 +977,6 @@ static const struct udevice_id ide_bootdev_ids[] = { U_BOOT_DRIVER(ide_bootdev) = { .name = "ide_bootdev", .id = UCLASS_BOOTDEV, - .ops = &ide_bootdev_ops, .bind = ide_bootdev_bind, .of_match = ide_bootdev_ids, }; -- cgit v1.3.1 From ce12ad70b8b7984cceeaa236ad61498bdcfdc5bd Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Tue, 19 May 2026 07:53:14 -0600 Subject: ata: sata: Drop empty bootdev_ops structure We don't need to provide an empty struct here now that the caller can handle this being empty. Signed-off-by: Tom Rini --- drivers/ata/sata_bootdev.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/ata/sata_bootdev.c b/drivers/ata/sata_bootdev.c index a5ca6f6fd5b..7d5ef3c94bf 100644 --- a/drivers/ata/sata_bootdev.c +++ b/drivers/ata/sata_bootdev.c @@ -37,9 +37,6 @@ static int sata_bootdev_hunt(struct bootdev_hunter *info, bool show) return 0; } -struct bootdev_ops sata_bootdev_ops = { -}; - static const struct udevice_id sata_bootdev_ids[] = { { .compatible = "u-boot,bootdev-sata" }, { } @@ -48,7 +45,6 @@ static const struct udevice_id sata_bootdev_ids[] = { U_BOOT_DRIVER(sata_bootdev) = { .name = "sata_bootdev", .id = UCLASS_BOOTDEV, - .ops = &sata_bootdev_ops, .bind = sata_bootdev_bind, .of_match = sata_bootdev_ids, }; -- cgit v1.3.1 From e84d147bd3e60ae1bce6b6f4bd50f088521a7da1 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Tue, 19 May 2026 07:53:19 -0600 Subject: scsi: Drop empty bootdev_ops structure We don't need to provide an empty struct here now that the caller can handle this being empty. Signed-off-by: Tom Rini --- drivers/scsi/scsi_bootdev.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/scsi/scsi_bootdev.c b/drivers/scsi/scsi_bootdev.c index 28e4612f337..541b021b732 100644 --- a/drivers/scsi/scsi_bootdev.c +++ b/drivers/scsi/scsi_bootdev.c @@ -37,9 +37,6 @@ static int scsi_bootdev_hunt(struct bootdev_hunter *info, bool show) return 0; } -struct bootdev_ops scsi_bootdev_ops = { -}; - static const struct udevice_id scsi_bootdev_ids[] = { { .compatible = "u-boot,bootdev-scsi" }, { } @@ -48,7 +45,6 @@ static const struct udevice_id scsi_bootdev_ids[] = { U_BOOT_DRIVER(scsi_bootdev) = { .name = "scsi_bootdev", .id = UCLASS_BOOTDEV, - .ops = &scsi_bootdev_ops, .bind = scsi_bootdev_bind, .of_match = scsi_bootdev_ids, }; -- cgit v1.3.1 From e81c552171d8793f872f2ff2de1e07bd1d9949cf Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Tue, 19 May 2026 07:53:26 -0600 Subject: virtio: Drop empty bootdev_ops structure We don't need to provide an empty struct here now that the caller can handle this being empty. Signed-off-by: Tom Rini --- drivers/virtio/virtio-uclass.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c index c36e9e9b3a7..a871a1439d4 100644 --- a/drivers/virtio/virtio-uclass.c +++ b/drivers/virtio/virtio-uclass.c @@ -400,9 +400,6 @@ UCLASS_DRIVER(virtio) = { .per_device_auto = sizeof(struct virtio_dev_priv), }; -struct bootdev_ops virtio_bootdev_ops = { -}; - static const struct udevice_id virtio_bootdev_ids[] = { { .compatible = "u-boot,bootdev-virtio" }, { } @@ -411,7 +408,6 @@ static const struct udevice_id virtio_bootdev_ids[] = { U_BOOT_DRIVER(virtio_bootdev) = { .name = "virtio_bootdev", .id = UCLASS_BOOTDEV, - .ops = &virtio_bootdev_ops, .bind = virtio_bootdev_bind, .of_match = virtio_bootdev_ids, }; -- cgit v1.3.1 From 679eb25fb8fd75bc6877e8c03f264bf80f71a4b9 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Tue, 19 May 2026 10:20:54 -0600 Subject: bloblist / handoff: Make this depend on BLOBLIST_FIXED Currently, the only way we support passing a bloblist from one stage to the next is via the BLOBLIST_FIXED mechanism. Update the Kconfig logic to express this constraint. Reviewed-by: Raymond Mao Tested-by: Alexander Stein Signed-off-by: Tom Rini --- common/spl/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 5fa94098e49..cc819344cad 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -220,7 +220,7 @@ source "common/spl/Kconfig.nxp" config HANDOFF bool "Pass hand-off information from SPL to U-Boot proper" - depends on BLOBLIST + depends on BLOBLIST_FIXED help It is useful to be able to pass information from SPL to U-Boot proper to preserve state that is known in SPL and is needed in U-Boot. -- cgit v1.3.1 From b4858d2afcf7fc819ed33643370a2b3ccf7055ac Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Tue, 19 May 2026 10:20:55 -0600 Subject: bloblist: Demote not finding a bloblist to a debug The message about not finding a bloblist will quite often be seen at least once, and is non-fatal. Demote this to a log_debug message from a log_warning message. Reviewed-by: Raymond Mao Tested-by: Alexander Stein Signed-off-by: Tom Rini --- common/bloblist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/bloblist.c b/common/bloblist.c index d084be89958..09afdd1f96b 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -613,8 +613,8 @@ int bloblist_init(void) ret = bloblist_check(addr, size); if (ret) - log_warning("Bloblist at %lx not found (err=%d)\n", - addr, ret); + log_debug("Bloblist at %lx not found (err=%d)\n", + addr, ret); else /* Get the real size */ size = gd->bloblist->total_size; -- cgit v1.3.1 From 5ab1600213608129ea63fc3046f46349515821d6 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Tue, 19 May 2026 10:20:56 -0600 Subject: bloblist: Rework bloblist_init and bloblist_maybe_init With bloblist, we need to both see if one already exists as well as create one if it does not. However, the current implementation leads to odd cases where we attempt to create a bloblist before this is possible and have things be overly complicated when we are given one to work with. This reworks things to instead have a bloblist_exists function, which as the name implies checks for an existing bloblist. This is used in the case of booting, to see if we have one and in turn if we have a device tree there as well as in the bloblist_init function to see if we need to do anything. In practical details, we move the logic from bloblist_init that was checking for a bloblist to the new bloblist_exists function and then can clarify the logic as it is much easier to state when we know we do not have one rather than all the ways we might have one. Then we have the locations that set gd->bloblist now also set the GD_FLG_BLOBLIST_READY flag. Reviewed-by: Raymond Mao Tested-by: Alexander Stein Signed-off-by: Tom Rini --- common/bloblist.c | 144 +++++++++++++++++++++++++++-------------------------- common/board_f.c | 4 +- include/bloblist.h | 32 ++++++------ lib/fdtdec.c | 15 ++---- 4 files changed, 96 insertions(+), 99 deletions(-) diff --git a/common/bloblist.c b/common/bloblist.c index 09afdd1f96b..51ae9cc50a5 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -448,6 +448,7 @@ int bloblist_new(ulong addr, uint size, uint flags, uint align_log2) hdr->align_log2 = align_log2 ? align_log2 : BLOBLIST_BLOB_ALIGN_LOG2; hdr->chksum = 0; gd->bloblist = hdr; + gd->flags |= GD_FLG_BLOBLIST_READY; return 0; } @@ -475,6 +476,7 @@ int bloblist_check(ulong addr, uint size) return log_msg_ret("Bad checksum", -EIO); } gd->bloblist = hdr; + gd->flags |= GD_FLG_BLOBLIST_READY; return 0; } @@ -576,90 +578,88 @@ int __weak xferlist_from_boot_arg(ulong __always_unused *addr) return -ENOENT; } -int bloblist_init(void) +bool bloblist_exists(void) { - bool fixed = IS_ENABLED(CONFIG_BLOBLIST_FIXED); - int ret = 0; - ulong addr = 0, size; + int ret; + ulong addr = 0; /* Check if a valid transfer list passed in */ - if (!xferlist_from_boot_arg(&addr)) { - size = bloblist_get_total_size(); - } else { - /* - * If U-Boot is not in the first phase, an existing bloblist must - * be at a fixed address. - */ - bool from_addr = fixed && !xpl_is_first_phase(); - - /* - * If Firmware Handoff is mandatory but no transfer list is - * observed, report it as an error. - */ - if (IS_ENABLED(CONFIG_BLOBLIST_PASSAGE_MANDATORY)) - return -ENOENT; - - ret = -ENOENT; - - if (xpl_prev_phase() == PHASE_TPL && - !IS_ENABLED(CONFIG_TPL_BLOBLIST)) - from_addr = false; - if (fixed) - addr = IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, - CONFIG_BLOBLIST_ADDR); - size = CONFIG_BLOBLIST_SIZE; - - if (from_addr) - ret = bloblist_check(addr, size); + if (!xferlist_from_boot_arg(&addr)) + goto found; - if (ret) - log_debug("Bloblist at %lx not found (err=%d)\n", - addr, ret); - else - /* Get the real size */ - size = gd->bloblist->total_size; - } + /* + * If Firmware Handoff is mandatory but no transfer list is + * observed, report it as an error. + */ + if (IS_ENABLED(CONFIG_BLOBLIST_PASSAGE_MANDATORY)) + return false; - if (ret) { - /* - * If we don't have a bloblist from a fixed address, or the one - * in the fixed address is not valid. we must allocate the - * memory for it now. - */ - if (CONFIG_IS_ENABLED(BLOBLIST_ALLOC)) { - void *ptr = memalign(BLOBLIST_ALIGN, size); - - if (!ptr) - return log_msg_ret("alloc", -ENOMEM); - addr = map_to_sysmem(ptr); - } else if (!fixed) { - return log_msg_ret("BLOBLIST_FIXED is not enabled", - ret); - } - log_debug("Creating new bloblist size %lx at %lx\n", size, - addr); - ret = bloblist_new(addr, size, 0, 0); - } else { - log_debug("Found existing bloblist size %lx at %lx\n", size, - addr); - } + /* + * We have checked for a valid transfer list being passed. At this + * point, if we do not have a fixed address for the bloblist, we cannot + * be provided with one. + */ + if (xpl_is_first_phase() || !IS_ENABLED(CONFIG_BLOBLIST_FIXED)) + return false; - if (ret) - return log_msg_ret("ini", ret); - gd->flags |= GD_FLG_BLOBLIST_READY; + /* + * Check for a valid list as the configured address. + */ + addr = IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, + CONFIG_BLOBLIST_ADDR); + ret = bloblist_check(addr, CONFIG_BLOBLIST_SIZE); + if (!ret) + goto found; + + log_debug("Bloblist at %lx not found (err=%d)\n", addr, ret); + return false; +found: #ifdef DEBUG bloblist_show_stats(); bloblist_show_list(); #endif - - return 0; + return true; } -int bloblist_maybe_init(void) +int bloblist_init(void) { - if (CONFIG_IS_ENABLED(BLOBLIST) && !(gd->flags & GD_FLG_BLOBLIST_READY)) - return bloblist_init(); + int ret; + ulong addr = 0, size = CONFIG_BLOBLIST_SIZE; + + if (gd->flags & GD_FLG_BLOBLIST_READY) { + log_debug("Found existing bloblist size %x at %p\n", + gd->bloblist->total_size, gd->bloblist); + return 0; + } + + /* + * If Firmware Handoff is mandatory but no transfer list has been + * observed by fdtdec_setup, report it as an error. + */ + if (IS_ENABLED(CONFIG_BLOBLIST_PASSAGE_MANDATORY)) + return -ENOENT; + + /* + * If we don't have an existing bloblist, we either need + * to allocate one now, or initialize the fixed address + * space as a bloblist. + */ + if (CONFIG_IS_ENABLED(BLOBLIST_ALLOC)) { + void *ptr = memalign(BLOBLIST_ALIGN, size); + + if (!ptr) + return log_msg_ret("alloc", -ENOMEM); + addr = map_to_sysmem(ptr); + } else + addr = IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, + CONFIG_BLOBLIST_ADDR); + + log_debug("Creating new bloblist size %lx at %lx\n", size, + addr); + ret = bloblist_new(addr, size, 0, 0); + if (ret) + return log_msg_ret("ini", ret); return 0; } @@ -687,7 +687,9 @@ int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig, ulong xlist) return ret; if (rfdt != (ulong)bloblist_find(BLOBLISTT_CONTROL_FDT, 0)) { - gd->bloblist = NULL; /* Reset the gd bloblist pointer */ + /* Remove this bloblist from gd */ + gd->bloblist = NULL; + gd->flags &= ~GD_FLG_BLOBLIST_READY; return -EIO; } diff --git a/common/board_f.c b/common/board_f.c index ce87c619e68..c39e3b940d3 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -894,7 +894,9 @@ static void initcall_run_f(void) INITCALL(log_init); INITCALL(initf_bootstage); /* uses its own timer, so does not need DM */ INITCALL(event_init); - INITCALL(bloblist_maybe_init); +#if CONFIG_IS_ENABLED(BLOBLIST) + INITCALL(bloblist_init); +#endif INITCALL(setup_spl_handoff); #if CONFIG_IS_ENABLED(CONSOLE_RECORD_INIT_F) INITCALL(console_record_init); diff --git a/include/bloblist.h b/include/bloblist.h index e67b2a76358..4c578772965 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -488,10 +488,24 @@ const char *bloblist_tag_name(enum bloblist_tag_t tag); */ int bloblist_reloc(void *to, uint to_size); +/** + * bloblist_exists() - Check for the prior existence of a bloblist + * + * This will check for a transfer list having been passed via standard + * convention. If CONFIG_BLOBLIST_PASSAGE_MANDATORY is selected and one is not + * found, we return false. + * + * If CONFIG_BLOBLIST_FIXED is selected, it uses CONFIG_BLOBLIST_ADDR and + * CONFIG_BLOBLIST_SIZE to check for a bloblist. + * + * Return: true if found, false if not + */ +bool bloblist_exists(void); + /** * bloblist_init() - Init the bloblist system with a single bloblist * - * This locates and sets up the blocklist for use. + * This creates a bloblist for use, if not already found. * * If CONFIG_BLOBLIST_FIXED is selected, it uses CONFIG_BLOBLIST_ADDR and * CONFIG_BLOBLIST_SIZE to set up a bloblist for use by U-Boot. @@ -508,22 +522,6 @@ int bloblist_reloc(void *to, uint to_size); */ int bloblist_init(void); -#if CONFIG_IS_ENABLED(BLOBLIST) -/** - * bloblist_maybe_init() - Init the bloblist system if not already done - * - * Calls bloblist_init() if the GD_FLG_BLOBLIST_READY flag is not set - * - * Return: 0 if OK, -ve on error - */ -int bloblist_maybe_init(void); -#else -static inline int bloblist_maybe_init(void) -{ - return 0; -} -#endif /* BLOBLIST */ - /** * bloblist_check_reg_conv() - Check whether the bloblist is compliant to * the register conventions according to the diff --git a/lib/fdtdec.c b/lib/fdtdec.c index c67b6e8c133..d0a84b5034b 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1822,17 +1822,12 @@ int fdtdec_setup(void) int ret = -ENOENT; /* - * If allowing a bloblist, check that first. There was discussion about - * adding an OF_BLOBLIST Kconfig, but this was rejected. - * - * The necessary test is whether the previous phase passed a bloblist, - * not whether this phase creates one. + * If allowing a bloblist, check that first. The necessary test is + * whether the previous phase passed a bloblist, not whether this phase + * creates one. */ - if (CONFIG_IS_ENABLED(BLOBLIST) && - (xpl_prev_phase() != PHASE_TPL || - IS_ENABLED(CONFIG_TPL_BLOBLIST))) { - ret = bloblist_maybe_init(); - if (!ret) { + if (CONFIG_IS_ENABLED(BLOBLIST) && (xpl_phase() > PHASE_TPL)) { + if (bloblist_exists()) { gd->fdt_blob = bloblist_find(BLOBLISTT_CONTROL_FDT, 0); if (gd->fdt_blob) { gd->fdt_src = FDTSRC_BLOBLIST; -- cgit v1.3.1