diff --git a/arch/arc/lib/bootm.c b/arch/arc/lib/bootm.c index 91bce5235a5..91165a06a46 100644 --- a/arch/arc/lib/bootm.c +++ b/arch/arc/lib/bootm.c @@ -50,17 +50,13 @@ static void boot_jump_linux(struct bootm_headers *images, int flag) { ulong kernel_entry; unsigned int r0, r2; - int fake = (flag & BOOTM_STATE_OS_FAKE_GO); - kernel_entry = images->ep; debug("## Transferring control to Linux (at address %08lx)...\n", kernel_entry); bootstage_mark(BOOTSTAGE_ID_RUN_OS); - printf("\nStarting kernel ...%s\n\n", fake ? - "(fake run for tracing)" : ""); - bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); + bootm_final(flag); if (CONFIG_IS_ENABLED(OF_LIBFDT) && images->ft_len) { r0 = 2; @@ -72,7 +68,7 @@ static void boot_jump_linux(struct bootm_headers *images, int flag) cleanup_before_linux(); - if (!fake) + if (!(flag & BOOTM_STATE_OS_FAKE_GO)) board_jump_and_run(kernel_entry, r0, 0, r2); } diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 019eca95780..727b9c5ca5b 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -42,42 +42,6 @@ DECLARE_GLOBAL_DATA_PTR; static struct tag *params; -__weak void board_quiesce_devices(void) -{ -} - -/** - * announce_and_cleanup() - Print message and prepare for kernel boot - * - * @fake: non-zero to do everything except actually boot - */ -static void announce_and_cleanup(int fake) -{ - bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); -#ifdef CONFIG_BOOTSTAGE_FDT - bootstage_fdt_add_report(); -#endif - bootstage_stash_default(); -#ifdef CONFIG_BOOTSTAGE_REPORT - bootstage_report(); -#endif - - board_quiesce_devices(); - - printf("\nStarting kernel ...%s\n\n", fake ? - "(fake run for tracing)" : ""); - /* - * Call remove function of all devices with a removal flag set. - * This may be useful for last-stage operations, like cancelling - * of DMA operation or releasing device internal buffers. - * dm_remove_devices_active() ensures that vital devices are removed in - * a second round. - */ - dm_remove_devices_active(); - - cleanup_before_linux(); -} - static void setup_start_tag (struct bd_info *bd) { params = (struct tag *)bd->bi_boot_params; @@ -294,8 +258,6 @@ static void boot_jump_linux(struct bootm_headers *images, int flag) { void (*kernel_entry)(void *fdt_addr, void *res0, void *res1, void *res2); - int fake = (flag & BOOTM_STATE_OS_FAKE_GO); - kernel_entry = (void (*)(void *fdt_addr, void *res0, void *res1, void *res2))images->ep; @@ -303,9 +265,10 @@ static void boot_jump_linux(struct bootm_headers *images, int flag) (ulong) kernel_entry); bootstage_mark(BOOTSTAGE_ID_RUN_OS); - announce_and_cleanup(fake); + bootm_final(flag); + cleanup_before_linux(); - if (!fake) { + if (!(flag & BOOTM_STATE_OS_FAKE_GO)) { #ifdef CONFIG_ARMV8_PSCI armv8_setup_psci(); #endif @@ -340,8 +303,6 @@ static void boot_jump_linux(struct bootm_headers *images, int flag) char *s; void (*kernel_entry)(int zero, int arch, uint params); unsigned long r2; - int fake = (flag & BOOTM_STATE_OS_FAKE_GO); - kernel_entry = (void (*)(int, int, uint))images->ep; #ifdef CONFIG_CPU_V7M ulong addr = (ulong)kernel_entry | 1; @@ -366,14 +327,15 @@ static void boot_jump_linux(struct bootm_headers *images, int flag) debug("## Transferring control to Linux (at address %08lx)" \ "...\n", (ulong) kernel_entry); bootstage_mark(BOOTSTAGE_ID_RUN_OS); - announce_and_cleanup(fake); + bootm_final(flag); + cleanup_before_linux(); if (CONFIG_IS_ENABLED(OF_LIBFDT) && images->ft_len) r2 = (unsigned long)images->ft_addr; else r2 = gd->bd->bi_boot_params; - if (fake) + if (flag & BOOTM_STATE_OS_FAKE_GO) return; #ifdef CONFIG_ARMV7_NONSEC diff --git a/arch/m68k/lib/bootm.c b/arch/m68k/lib/bootm.c index 1fa112f8dbf..7d65f3ea1a8 100644 --- a/arch/m68k/lib/bootm.c +++ b/arch/m68k/lib/bootm.c @@ -62,6 +62,8 @@ int do_bootm_linux(int flag, struct bootm_info *bmi) bootstage_mark(BOOTSTAGE_ID_RUN_OS); + bootm_final(0); + /* * Linux Kernel Parameters (passing board info data): * sp+00: Ignore, side effect of using jsr to jump to kernel diff --git a/arch/microblaze/lib/bootm.c b/arch/microblaze/lib/bootm.c index 2410515f4ac..b54c902602f 100644 --- a/arch/microblaze/lib/bootm.c +++ b/arch/microblaze/lib/bootm.c @@ -26,8 +26,6 @@ static void boot_jump_linux(struct bootm_headers *images, int flag) ulong dt = (ulong)images->ft_addr; ulong rd_start = images->initrd_start; ulong cmdline = images->cmdline_start; - int fake = (flag & BOOTM_STATE_OS_FAKE_GO); - thekernel = (void (*)(char *, ulong, ulong))images->ep; debug("## Transferring control to Linux (at address 0x%08lx) ", @@ -36,13 +34,11 @@ static void boot_jump_linux(struct bootm_headers *images, int flag) cmdline, rd_start, dt); bootstage_mark(BOOTSTAGE_ID_RUN_OS); - printf("\nStarting kernel ...%s\n\n", fake ? - "(fake run for tracing)" : ""); - bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); + bootm_final(flag); flush_cache_all(); - if (!fake) { + if (!(flag & BOOTM_STATE_OS_FAKE_GO)) { /* * Linux Kernel Parameters (passing device tree): * r5: pointer to command line diff --git a/arch/mips/lib/bootm.c b/arch/mips/lib/bootm.c index 87195100023..066c830f3fa 100644 --- a/arch/mips/lib/bootm.c +++ b/arch/mips/lib/bootm.c @@ -268,12 +268,7 @@ static void boot_jump_linux(struct bootm_headers *images) if (CONFIG_IS_ENABLED(MALTA)) linux_extra = gd->ram_size; -#if IS_ENABLED(CONFIG_BOOTSTAGE_FDT) - bootstage_fdt_add_report(); -#endif -#if IS_ENABLED(CONFIG_BOOTSTAGE_REPORT) - bootstage_report(); -#endif + bootm_final(0); if (CONFIG_IS_ENABLED(RESTORE_EXCEPTION_VECTOR_BASE)) trap_restore(); diff --git a/arch/nios2/lib/bootm.c b/arch/nios2/lib/bootm.c index 294ebfb508b..6004e83bf0c 100644 --- a/arch/nios2/lib/bootm.c +++ b/arch/nios2/lib/bootm.c @@ -41,6 +41,8 @@ int do_bootm_linux(int flag, struct bootm_info *bmi) if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; + bootm_final(0); + /* flushes data and instruction caches before calling the kernel */ disable_interrupts(); flush_dcache_all(); diff --git a/arch/powerpc/lib/bootm.c b/arch/powerpc/lib/bootm.c index dc44bf3ab3a..f9351a17a48 100644 --- a/arch/powerpc/lib/bootm.c +++ b/arch/powerpc/lib/bootm.c @@ -54,12 +54,7 @@ static void boot_jump_linux(struct bootm_headers *images) bootstage_mark(BOOTSTAGE_ID_RUN_OS); -#ifdef CONFIG_BOOTSTAGE_FDT - bootstage_fdt_add_report(); -#endif -#ifdef CONFIG_BOOTSTAGE_REPORT - bootstage_report(); -#endif + bootm_final(0); #if defined(CONFIG_SYS_INIT_RAM_LOCK) && !defined(CONFIG_E500) unlock_ram_in_cache(); diff --git a/arch/riscv/include/asm/u-boot-riscv.h b/arch/riscv/include/asm/u-boot-riscv.h index 543a1688db8..3a8fdb57136 100644 --- a/arch/riscv/include/asm/u-boot-riscv.h +++ b/arch/riscv/include/asm/u-boot-riscv.h @@ -16,7 +16,6 @@ int cleanup_before_linux(void); /* board/.../... */ int board_init(void); -void board_quiesce_devices(void); int riscv_board_reserved_mem_fixup(void *fdt); int riscv_fdt_copy_resv_mem_node(const void *src_fdt, void *dest_fdt); diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c index 9544907ab1e..69c9ca5c487 100644 --- a/arch/riscv/lib/bootm.c +++ b/arch/riscv/lib/bootm.c @@ -25,39 +25,6 @@ DECLARE_GLOBAL_DATA_PTR; -__weak void board_quiesce_devices(void) -{ -} - -/** - * announce_and_cleanup() - Print message and prepare for kernel boot - * - * @fake: non-zero to do everything except actually boot - */ -static void announce_and_cleanup(int fake) -{ - printf("\nStarting kernel ...%s\n\n", fake ? - "(fake run for tracing)" : ""); - bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); -#ifdef CONFIG_BOOTSTAGE_FDT - bootstage_fdt_add_report(); -#endif -#if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT) - bootstage_report(); -#endif - - board_quiesce_devices(); - - /* - * Call remove function of all devices with a removal flag set. - * This may be useful for last-stage operations, like cancelling - * of DMA operation or releasing device internal buffers. - */ - dm_remove_devices_active(); - - cleanup_before_linux(); -} - static void boot_prep_linux(struct bootm_headers *images) { if (CONFIG_IS_ENABLED(OF_LIBFDT) && IS_ENABLED(CONFIG_LMB) && images->ft_len) { @@ -75,7 +42,6 @@ static void boot_prep_linux(struct bootm_headers *images) static void boot_jump_linux(struct bootm_headers *images, int flag) { void (*kernel)(ulong hart, void *dtb); - int fake = (flag & BOOTM_STATE_OS_FAKE_GO); #ifdef CONFIG_SMP int ret; #endif @@ -87,9 +53,10 @@ static void boot_jump_linux(struct bootm_headers *images, int flag) debug("## Transferring control to kernel (at address %08lx) ...\n", (ulong)kernel); - announce_and_cleanup(fake); + bootm_final(flag); + cleanup_before_linux(); - if (!fake) { + if (!(flag & BOOTM_STATE_OS_FAKE_GO)) { if (CONFIG_IS_ENABLED(OF_LIBFDT) && images->ft_len) { #ifdef CONFIG_SMP ret = smp_call_function(images->ep, diff --git a/arch/sandbox/lib/bootm.c b/arch/sandbox/lib/bootm.c index 44ba8b52e13..7a5f6f7d36e 100644 --- a/arch/sandbox/lib/bootm.c +++ b/arch/sandbox/lib/bootm.c @@ -73,6 +73,7 @@ int do_bootm_linux(int flag, struct bootm_info *bmi) if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) { bootstage_mark(BOOTSTAGE_ID_RUN_OS); + bootm_final(flag); printf("## Transferring control to Linux (at address %08lx)...\n", images->ep); printf("sandbox: continuing, as we cannot run Linux\n"); diff --git a/arch/sh/lib/bootm.c b/arch/sh/lib/bootm.c index 1c118870dad..81d5957edaa 100644 --- a/arch/sh/lib/bootm.c +++ b/arch/sh/lib/bootm.c @@ -92,6 +92,8 @@ int do_bootm_linux(int flag, struct bootm_info *bmi) images->rd_end - images->rd_start); } + bootm_final(0); + /* Boot kernel */ kernel(); diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 7a94dc877e3..cde4fbf3557 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -34,22 +34,10 @@ DECLARE_GLOBAL_DATA_PTR; void bootm_announce_and_cleanup(void) { - printf("\nStarting kernel ...\n\n"); - #ifdef CONFIG_SYS_COREBOOT timestamp_add_now(TS_START_KERNEL); #endif - bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); -#if IS_ENABLED(CONFIG_BOOTSTAGE_REPORT) - bootstage_report(); -#endif - - /* - * Call remove function of all devices with a removal flag set. - * This may be useful for last-stage operations, like cancelling - * of DMA operation or releasing device internal buffers. - */ - dm_remove_devices_active(); + bootm_final(0); } #if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL) diff --git a/arch/xtensa/lib/bootm.c b/arch/xtensa/lib/bootm.c index 2958f207397..c19ac9d1f9a 100644 --- a/arch/xtensa/lib/bootm.c +++ b/arch/xtensa/lib/bootm.c @@ -178,6 +178,8 @@ int do_bootm_linux(int flag, struct bootm_info *bmi) printf("Transferring Control to Linux @0x%08lx ...\n\n", (ulong)images->ep); + bootm_final(flag); + flush_dcache_range((unsigned long)params_start, (unsigned long)params); if (flag & BOOTM_STATE_OS_FAKE_GO) diff --git a/boot/bootm.c b/boot/bootm.c index 280efb26e90..4836d6b2d41 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -7,6 +7,7 @@ #ifndef USE_HOSTCC #include #include +#include #include #include #include @@ -1194,6 +1195,30 @@ void __weak switch_to_non_secure_mode(void) { } +void bootm_final(int flag) +{ + printf("\nStarting kernel ...%s\n\n", + (flag & BOOTM_STATE_OS_FAKE_GO) ? + " (fake run for tracing)" : ""); + + bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); + + if (IS_ENABLED(CONFIG_BOOTSTAGE_FDT) && IS_ENABLED(CONFIG_CMD_FDT)) + bootstage_fdt_add_report(); + bootstage_stash_default(); + if (IS_ENABLED(CONFIG_BOOTSTAGE_REPORT)) + bootstage_report(); + + board_quiesce_devices(); + + /* + * Call remove function of all devices with a removal flag set. + * This may be useful for last-stage operations, like cancelling + * of DMA operation or releasing device internal buffers. + */ + dm_remove_devices_active(); +} + #else /* USE_HOSTCC */ #if defined(CONFIG_FIT_SIGNATURE) diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index 437080ed778..557afb8d817 100644 --- a/drivers/core/device-remove.c +++ b/drivers/core/device-remove.c @@ -198,7 +198,7 @@ static int flags_remove(uint flags, uint drv_flags) int device_remove(struct udevice *dev, uint flags) { const struct driver *drv; - int ret; + int ret, cret; if (!dev) return -EINVAL; @@ -210,25 +210,35 @@ int device_remove(struct udevice *dev, uint flags) if (ret) return ret; - /* - * If the child returns EKEYREJECTED, continue. It just means that it - * didn't match the flags. - */ - ret = device_chld_remove(dev, NULL, flags); - if (ret && ret != -EKEYREJECTED) - return ret; - /* * Remove the device if called with the "normal" remove flag set, * or if the remove flag matches any of the drivers remove flags */ drv = dev->driver; assert(drv); - ret = flags_remove(flags, drv->flags); - if (ret) { - log_debug("%s: When removing: flags=%x, drv->flags=%x, err=%d\n", - dev->name, flags, drv->flags, ret); + cret = flags_remove(flags, drv->flags); + + /* + * Remove all children. If this device is being removed due to + * active-DMA or OS-prepare flags, drop the active-flag requirement + * for children so they are removed even without matching active + * flags, since a deactivated device must not have activated + * children. Preserve other flags (e.g. DM_REMOVE_NON_VITAL) so + * that vital children are still protected. + * + * If the child returns EKEYREJECTED, continue. It just means that it + * didn't match the flags. + */ + ret = device_chld_remove(dev, NULL, + cret ? flags : + (flags & ~DM_REMOVE_ACTIVE_ALL)); + if (ret && ret != -EKEYREJECTED) return ret; + + if (cret) { + log_debug("%s: When removing: flags=%x, drv->flags=%x, err=%d\n", + dev->name, flags, drv->flags, cret); + return cret; } ret = uclass_pre_remove_device(dev); diff --git a/include/bootm.h b/include/bootm.h index 4060cec7fc0..f6958be751a 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -321,4 +321,14 @@ void zimage_dump(struct boot_params *base_ptr, bool show_cmdline); */ int bootm_boot_start(ulong addr, const char *cmdline); +/** + * bootm_final() - Announce and do cleanup before boot + * + * This performs the common pre-boot steps: printing the "Starting kernel" + * message, recording bootstage data, and removing active devices. + * + * @flag: Boot state flags (BOOTM_STATE_OS_FAKE_GO prints a fake-run message) + */ +void bootm_final(int flag); + #endif diff --git a/include/bootstage.h b/include/bootstage.h index 528d0ca0614..62fb99110f0 100644 --- a/include/bootstage.h +++ b/include/bootstage.h @@ -435,6 +435,14 @@ static inline uint32_t bootstage_accum(enum bootstage_id id) return 0; } +static inline void bootstage_report(void) +{ +} + +static inline void bootstage_fdt_add_report(void) +{ +} + static inline int bootstage_stash(void *base, int size) { return 0; /* Pretend to succeed */