diff --git a/arch/arm/lib/bdinfo.c b/arch/arm/lib/bdinfo.c index 25bc6e80f47..c905783bdc8 100644 --- a/arch/arm/lib/bdinfo.c +++ b/arch/arm/lib/bdinfo.c @@ -15,23 +15,23 @@ void arch_print_bdinfo(void) { struct bd_info *bd = gd->bd; - bdinfo_print_num("arch_number", bd->bi_arch_number); + bdinfo_print_num_l("arch_number", bd->bi_arch_number); #ifdef CONFIG_SYS_MEM_RESERVE_SECURE if (gd->arch.secure_ram & MEM_RESERVE_SECURE_SECURED) { - bdinfo_print_num("Secure ram", - gd->arch.secure_ram & - MEM_RESERVE_SECURE_ADDR_MASK); + bdinfo_print_num_ll("Secure ram", + gd->arch.secure_ram & + MEM_RESERVE_SECURE_ADDR_MASK); } #endif #ifdef CONFIG_RESV_RAM if (gd->arch.resv_ram) - bdinfo_print_num("Reserved ram", gd->arch.resv_ram); + bdinfo_print_num_ll("Reserved ram", gd->arch.resv_ram); #endif #if !(CONFIG_IS_ENABLED(SYS_ICACHE_OFF) && CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) - bdinfo_print_num("TLB addr", gd->arch.tlb_addr); + bdinfo_print_num_l("TLB addr", gd->arch.tlb_addr); #endif - bdinfo_print_num("irq_sp", gd->irq_sp); /* irq stack pointer */ - bdinfo_print_num("sp start ", gd->start_addr_sp); + bdinfo_print_num_l("irq_sp", gd->irq_sp); /* irq stack pointer */ + bdinfo_print_num_l("sp start ", gd->start_addr_sp); /* * TODO: Currently only support for davinci SOC's is added. * Remove this check once all the board implement this. diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 1206e306db6..f46d51d6553 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -119,6 +119,9 @@ static void announce_and_cleanup(int fake) * This may be useful for last-stage operations, like cancelling * of DMA operation or releasing device internal buffers. */ + dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL | DM_REMOVE_NON_VITAL); + + /* Remove all active vital devices next */ dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); cleanup_before_linux(); diff --git a/arch/arm/mach-rockchip/sdram.c b/arch/arm/mach-rockchip/sdram.c index 4c637b77673..c3d5fed7db3 100644 --- a/arch/arm/mach-rockchip/sdram.c +++ b/arch/arm/mach-rockchip/sdram.c @@ -37,7 +37,7 @@ struct tos_parameter_t { int dram_init_banksize(void) { size_t top = min((unsigned long)(gd->ram_size + CONFIG_SYS_SDRAM_BASE), - gd->ram_top); + (unsigned long)(gd->ram_top)); #ifdef CONFIG_ARM64 /* Reserve 0x200000 for ATF bl31 */ diff --git a/arch/m68k/lib/bdinfo.c b/arch/m68k/lib/bdinfo.c index 404e5f19ed8..92ea1752023 100644 --- a/arch/m68k/lib/bdinfo.c +++ b/arch/m68k/lib/bdinfo.c @@ -38,7 +38,7 @@ void arch_print_bdinfo(void) bdinfo_print_mhz("busfreq", bd->bi_busfreq); #if defined(CONFIG_SYS_MBAR) - bdinfo_print_num("mbar", bd->bi_mbar_base); + bdinfo_print_num_l("mbar", bd->bi_mbar_base); #endif bdinfo_print_mhz("cpufreq", bd->bi_intfreq); if (IS_ENABLED(CONFIG_PCI)) diff --git a/arch/powerpc/lib/bdinfo.c b/arch/powerpc/lib/bdinfo.c index 36c9c99ee6f..b14e75b68ab 100644 --- a/arch/powerpc/lib/bdinfo.c +++ b/arch/powerpc/lib/bdinfo.c @@ -47,9 +47,9 @@ void arch_print_bdinfo(void) bdinfo_print_mhz("busfreq", bd->bi_busfreq); #if defined(CONFIG_MPC8xx) || defined(CONFIG_E500) - bdinfo_print_num("immr_base", bd->bi_immr_base); + bdinfo_print_num_l("immr_base", bd->bi_immr_base); #endif - bdinfo_print_num("bootflags", bd->bi_bootflags); + bdinfo_print_num_l("bootflags", bd->bi_bootflags); bdinfo_print_mhz("intfreq", bd->bi_intfreq); #ifdef CONFIG_ENABLE_36BIT_PHYS if (IS_ENABLED(CONFIG_PHYS_64BIT)) diff --git a/arch/riscv/cpu/fu540/dram.c b/arch/riscv/cpu/fu540/dram.c index 1dc77efeca5..259da65a545 100644 --- a/arch/riscv/cpu/fu540/dram.c +++ b/arch/riscv/cpu/fu540/dram.c @@ -22,7 +22,6 @@ int dram_init_banksize(void) ulong board_get_usable_ram_top(ulong total_size) { -#ifdef CONFIG_64BIT /* * Ensure that we run from first 4GB so that all * addresses used by U-Boot are 32bit addresses. @@ -31,8 +30,8 @@ ulong board_get_usable_ram_top(ulong total_size) * devices work fine because DMA mapping APIs will * provide 32bit DMA addresses only. */ - if (gd->ram_top > SZ_4G) - return SZ_4G; -#endif + if (gd->ram_top >= SZ_4G) + return SZ_4G - 1; + return gd->ram_top; } diff --git a/arch/riscv/cpu/generic/dram.c b/arch/riscv/cpu/generic/dram.c index 1dc77efeca5..259da65a545 100644 --- a/arch/riscv/cpu/generic/dram.c +++ b/arch/riscv/cpu/generic/dram.c @@ -22,7 +22,6 @@ int dram_init_banksize(void) ulong board_get_usable_ram_top(ulong total_size) { -#ifdef CONFIG_64BIT /* * Ensure that we run from first 4GB so that all * addresses used by U-Boot are 32bit addresses. @@ -31,8 +30,8 @@ ulong board_get_usable_ram_top(ulong total_size) * devices work fine because DMA mapping APIs will * provide 32bit DMA addresses only. */ - if (gd->ram_top > SZ_4G) - return SZ_4G; -#endif + if (gd->ram_top >= SZ_4G) + return SZ_4G - 1; + return gd->ram_top; } diff --git a/arch/riscv/include/asm/types.h b/arch/riscv/include/asm/types.h index b800b2d221b..49f7a5d6b3a 100644 --- a/arch/riscv/include/asm/types.h +++ b/arch/riscv/include/asm/types.h @@ -35,8 +35,8 @@ typedef u64 dma_addr_t; typedef u32 dma_addr_t; #endif -typedef unsigned long phys_addr_t; -typedef unsigned long phys_size_t; +typedef unsigned long long phys_addr_t; +typedef unsigned long long phys_size_t; #endif /* __KERNEL__ */ diff --git a/board/AndesTech/ax25-ae350/ax25-ae350.c b/board/AndesTech/ax25-ae350/ax25-ae350.c index 59a43e4dcc4..3125233488f 100644 --- a/board/AndesTech/ax25-ae350/ax25-ae350.c +++ b/board/AndesTech/ax25-ae350/ax25-ae350.c @@ -77,7 +77,7 @@ int smc_init(void) if (addr == FDT_ADDR_T_NONE) return -EINVAL; - regs = (struct ftsmc020_bank *)addr; + regs = (struct ftsmc020_bank *)(uintptr_t)addr; regs->cr &= ~FTSMC020_BANK_WPROT; return 0; diff --git a/cmd/bdinfo.c b/cmd/bdinfo.c index 8d8daa6336a..dfd50ae8491 100644 --- a/cmd/bdinfo.c +++ b/cmd/bdinfo.c @@ -18,11 +18,16 @@ DECLARE_GLOBAL_DATA_PTR; -void bdinfo_print_num(const char *name, ulong value) +void bdinfo_print_num_l(const char *name, ulong value) { printf("%-12s= 0x%0*lx\n", name, 2 * (int)sizeof(value), value); } +void bdinfo_print_num_ll(const char *name, unsigned long long value) +{ + printf("%-12s= 0x%.*llx\n", name, 2 * (int)sizeof(ulong), value); +} + static void print_eth(int idx) { char name[10], *val; @@ -36,12 +41,6 @@ static void print_eth(int idx) printf("%-12s= %s\n", name, val); } -static void print_phys_addr(const char *name, phys_addr_t value) -{ - printf("%-12s= 0x%.*llx\n", name, 2 * (int)sizeof(ulong), - (unsigned long long)value); -} - void bdinfo_print_mhz(const char *name, unsigned long hz) { char buf[32]; @@ -55,9 +54,9 @@ static void print_bi_dram(const struct bd_info *bd) for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) { if (bd->bi_dram[i].size) { - bdinfo_print_num("DRAM bank", i); - bdinfo_print_num("-> start", bd->bi_dram[i].start); - bdinfo_print_num("-> size", bd->bi_dram[i].size); + bdinfo_print_num_l("DRAM bank", i); + bdinfo_print_num_ll("-> start", bd->bi_dram[i].start); + bdinfo_print_num_ll("-> size", bd->bi_dram[i].size); } } } @@ -77,9 +76,10 @@ static void show_video_info(void) if (device_active(dev)) { struct video_priv *upriv = dev_get_uclass_priv(dev); - print_phys_addr("FB base", (ulong)upriv->fb); + bdinfo_print_num_ll("FB base", (ulong)upriv->fb); if (upriv->copy_fb) - print_phys_addr("FB copy", (ulong)upriv->copy_fb); + bdinfo_print_num_ll("FB copy", + (ulong)upriv->copy_fb); printf("%-12s= %dx%dx%d\n", "FB size", upriv->xsize, upriv->ysize, 1 << upriv->bpix); } @@ -91,36 +91,36 @@ int do_bdinfo(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) struct bd_info *bd = gd->bd; #ifdef DEBUG - bdinfo_print_num("bd address", (ulong)bd); + bdinfo_print_num_l("bd address", (ulong)bd); #endif - bdinfo_print_num("boot_params", (ulong)bd->bi_boot_params); + bdinfo_print_num_l("boot_params", (ulong)bd->bi_boot_params); print_bi_dram(bd); if (IS_ENABLED(CONFIG_SYS_HAS_SRAM)) { - bdinfo_print_num("sramstart", (ulong)bd->bi_sramstart); - bdinfo_print_num("sramsize", (ulong)bd->bi_sramsize); + bdinfo_print_num_l("sramstart", (ulong)bd->bi_sramstart); + bdinfo_print_num_l("sramsize", (ulong)bd->bi_sramsize); } - bdinfo_print_num("flashstart", (ulong)bd->bi_flashstart); - bdinfo_print_num("flashsize", (ulong)bd->bi_flashsize); - bdinfo_print_num("flashoffset", (ulong)bd->bi_flashoffset); + bdinfo_print_num_l("flashstart", (ulong)bd->bi_flashstart); + bdinfo_print_num_l("flashsize", (ulong)bd->bi_flashsize); + bdinfo_print_num_l("flashoffset", (ulong)bd->bi_flashoffset); printf("baudrate = %u bps\n", gd->baudrate); - bdinfo_print_num("relocaddr", gd->relocaddr); - bdinfo_print_num("reloc off", gd->reloc_off); + bdinfo_print_num_l("relocaddr", gd->relocaddr); + bdinfo_print_num_l("reloc off", gd->reloc_off); printf("%-12s= %u-bit\n", "Build", (uint)sizeof(void *) * 8); if (IS_ENABLED(CONFIG_CMD_NET)) { printf("current eth = %s\n", eth_get_name()); print_eth(0); printf("IP addr = %s\n", env_get("ipaddr")); } - bdinfo_print_num("fdt_blob", (ulong)gd->fdt_blob); - bdinfo_print_num("new_fdt", (ulong)gd->new_fdt); - bdinfo_print_num("fdt_size", (ulong)gd->fdt_size); + bdinfo_print_num_l("fdt_blob", (ulong)gd->fdt_blob); + bdinfo_print_num_l("new_fdt", (ulong)gd->new_fdt); + bdinfo_print_num_l("fdt_size", (ulong)gd->fdt_size); if (IS_ENABLED(CONFIG_DM_VIDEO)) show_video_info(); #if defined(CONFIG_LCD) || defined(CONFIG_VIDEO) - bdinfo_print_num("FB base ", gd->fb_base); + bdinfo_print_num_l("FB base ", gd->fb_base); #endif #if CONFIG_IS_ENABLED(MULTI_DTB_FIT) - bdinfo_print_num("multi_dtb_fit", (ulong)gd->multi_dtb_fit); + bdinfo_print_num_l("multi_dtb_fit", (ulong)gd->multi_dtb_fit); #endif if (gd->fdt_blob) { struct lmb lmb; diff --git a/doc/driver-model/design.rst b/doc/driver-model/design.rst index ffed7d5f79a..2417976ab74 100644 --- a/doc/driver-model/design.rst +++ b/doc/driver-model/design.rst @@ -880,6 +880,26 @@ If a parent has children these will be destroyed first. After this point the device does not exist and its memory has be deallocated. +Special cases for removal +------------------------- + +Some devices need to do clean-up before the OS is called. For example, a USB +driver may want to stop the bus. This can be done in the remove() method. +Some special flags are used to determine whether to remove the device: + + DM_FLAG_OS_PREPARE - indicates that the device needs to get ready for OS + boot. The device will be removed just before the OS is booted + DM_REMOVE_ACTIVE_DMA - indicates that the device uses DMA. This is + effectively the same as DM_FLAG_OS_PREPARE, so the device is removed + before the OS is booted + DM_FLAG_VITAL - indicates that the device is 'vital' to the operation of + other devices. It is possible to remove this device after all regular + devices are removed. This is useful e.g. for a clock, which need to + be active during the device-removal phase. + +The dm_remove_devices_flags() function can be used to remove devices based on +their driver flags. + Data Structures --------------- diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index 7e8f3afb2d6..616dcf07859 100644 --- a/drivers/core/device-remove.c +++ b/drivers/core/device-remove.c @@ -8,6 +8,8 @@ * Pavel Herrmann */ +#define LOG_CATEGORY LOGC_DM + #include #include #include @@ -45,20 +47,24 @@ int device_chld_remove(struct udevice *dev, struct driver *drv, uint flags) { struct udevice *pos, *n; - int ret; + int result = 0; assert(dev); list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { + int ret; + if (drv && (pos->driver != drv)) continue; ret = device_remove(pos, flags); - if (ret) + if (ret == -EPROBE_DEFER) + result = ret; + else if (ret && ret != -EKEYREJECTED) return ret; } - return 0; + return result; } int device_unbind(struct udevice *dev) @@ -149,13 +155,43 @@ void device_free(struct udevice *dev) devres_release_probe(dev); } -static bool flags_remove(uint flags, uint drv_flags) +/** + * flags_remove() - Figure out whether to remove a device + * + * If this is called with @flags == DM_REMOVE_NON_VITAL | DM_REMOVE_ACTIVE_DMA, + * then it returns 0 (=go head and remove) if the device is not matked vital + * but is marked DM_REMOVE_ACTIVE_DMA. + * + * If this is called with @flags == DM_REMOVE_ACTIVE_DMA, + * then it returns 0 (=go head and remove) if the device is marked + * DM_REMOVE_ACTIVE_DMA, regardless of whether it is marked vital. + * + * @flags: Flags passed to device_remove() + * @drv_flags: Driver flags + * @return 0 if the device should be removed, + * -EKEYREJECTED if @flags includes a flag in DM_REMOVE_ACTIVE_ALL but + * @drv_flags does not (indicates that this device has nothing to do for + * DMA shutdown or OS prepare) + * -EPROBE_DEFER if @flags is DM_REMOVE_NON_VITAL but @drv_flags contains + * DM_FLAG_VITAL (indicates the device is vital and should not be removed) + */ +static int flags_remove(uint flags, uint drv_flags) { - if ((flags & DM_REMOVE_NORMAL) || - (flags && (drv_flags & (DM_FLAG_ACTIVE_DMA | DM_FLAG_OS_PREPARE)))) - return true; + if (!(flags & DM_REMOVE_NORMAL)) { + bool vital_match; + bool active_match; - return false; + active_match = !(flags & DM_REMOVE_ACTIVE_ALL) || + (drv_flags & flags); + vital_match = !(flags & DM_REMOVE_NON_VITAL) || + !(drv_flags & DM_FLAG_VITAL); + if (!vital_match) + return -EPROBE_DEFER; + if (!active_match) + return -EKEYREJECTED; + } + + return 0; } int device_remove(struct udevice *dev, uint flags) @@ -169,22 +205,32 @@ int device_remove(struct udevice *dev, uint flags) if (!(dev_get_flags(dev) & DM_FLAG_ACTIVATED)) return 0; - drv = dev->driver; - assert(drv); - - ret = uclass_pre_remove_device(dev); - 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) - goto err; + 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 */ - if (drv->remove && flags_remove(flags, drv->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); + return ret; + } + + ret = uclass_pre_remove_device(dev); + if (ret) + return ret; + + if (drv->remove) { ret = drv->remove(dev); if (ret) goto err_remove; @@ -200,28 +246,20 @@ int device_remove(struct udevice *dev, uint flags) if (!(flags & DM_REMOVE_NO_PD) && !(drv->flags & - (DM_FLAG_DEFAULT_PD_CTRL_OFF | DM_FLAG_REMOVE_WITH_PD_ON)) && + (DM_FLAG_DEFAULT_PD_CTRL_OFF | DM_FLAG_LEAVE_PD_ON)) && dev != gd->cur_serial_dev) dev_power_domain_off(dev); - if (flags_remove(flags, drv->flags)) { - device_free(dev); + device_free(dev); - dev_bic_flags(dev, DM_FLAG_ACTIVATED); - } + dev_bic_flags(dev, DM_FLAG_ACTIVATED); - return ret; + return 0; err_remove: /* We can't put the children back */ dm_warn("%s: Device '%s' failed to remove, but children are gone\n", __func__, dev->name); -err: - ret = uclass_post_probe_device(dev); - if (ret) { - dm_warn("%s: Device '%s' failed to post_probe on error path\n", - __func__, dev->name); - } return ret; } diff --git a/drivers/core/root.c b/drivers/core/root.c index 2bfa75b4725..7ef2ec2da27 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -162,6 +162,8 @@ int dm_init(bool of_live) int dm_uninit(void) { + /* Remove non-vital devices first */ + device_remove(dm_root(), DM_REMOVE_NON_VITAL); device_remove(dm_root(), DM_REMOVE_NORMAL); device_unbind(dm_root()); gd->dm_root = NULL; diff --git a/drivers/firmware/scmi/sandbox-scmi_devices.c b/drivers/firmware/scmi/sandbox-scmi_devices.c index 414da6f4df1..1a6fafbf531 100644 --- a/drivers/firmware/scmi/sandbox-scmi_devices.c +++ b/drivers/firmware/scmi/sandbox-scmi_devices.c @@ -50,6 +50,9 @@ static int sandbox_scmi_devices_remove(struct udevice *dev) int ret = 0; size_t n; + if (!devices) + return 0; + for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) { int ret2 = reset_free(devices->reset + n); diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 7349a9bc99e..99a1c2e6e2e 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -2526,10 +2526,7 @@ int brcmnand_probe(struct udevice *dev, struct brcmnand_soc *soc) if (ret) return ret; } else { - ret = PTR_ERR(ctrl->clk); - if (ret == -EPROBE_DEFER) - return ret; - + /* Ignore PTR_ERR(ctrl->clk) */ ctrl->clk = NULL; } diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c index 0d672374fda..fc578b03752 100644 --- a/drivers/net/ftmac100.c +++ b/drivers/net/ftmac100.c @@ -35,7 +35,7 @@ struct ftmac100_data { */ static void ftmac100_reset(struct ftmac100_data *priv) { - struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase; + struct ftmac100 *ftmac100 = (struct ftmac100 *)(uintptr_t)priv->iobase; debug ("%s()\n", __func__); @@ -56,7 +56,7 @@ static void ftmac100_reset(struct ftmac100_data *priv) static void ftmac100_set_mac(struct ftmac100_data *priv , const unsigned char *mac) { - struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase; + struct ftmac100 *ftmac100 = (struct ftmac100 *)(uintptr_t)priv->iobase; unsigned int maddr = mac[0] << 8 | mac[1]; unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]; @@ -71,7 +71,7 @@ static void ftmac100_set_mac(struct ftmac100_data *priv , */ static void _ftmac100_halt(struct ftmac100_data *priv) { - struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase; + struct ftmac100 *ftmac100 = (struct ftmac100 *)(uintptr_t)priv->iobase; debug ("%s()\n", __func__); writel (0, &ftmac100->maccr); } @@ -81,7 +81,7 @@ static void _ftmac100_halt(struct ftmac100_data *priv) */ static int _ftmac100_init(struct ftmac100_data *priv, unsigned char enetaddr[6]) { - struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase; + struct ftmac100 *ftmac100 = (struct ftmac100 *)(uintptr_t)priv->iobase; struct ftmac100_txdes *txdes = priv->txdes; struct ftmac100_rxdes *rxdes = priv->rxdes; unsigned int maccr; @@ -186,7 +186,7 @@ static int __ftmac100_recv(struct ftmac100_data *priv) */ static int _ftmac100_send(struct ftmac100_data *priv, void *packet, int length) { - struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase; + struct ftmac100 *ftmac100 = (struct ftmac100 *)(uintptr_t)priv->iobase; struct ftmac100_txdes *curr_des = priv->txdes; ulong start; diff --git a/drivers/pci/pcie_iproc.c b/drivers/pci/pcie_iproc.c index 6725ff64372..12ce9d525ca 100644 --- a/drivers/pci/pcie_iproc.c +++ b/drivers/pci/pcie_iproc.c @@ -1283,5 +1283,5 @@ U_BOOT_DRIVER(pci_iproc) = { .probe = iproc_pcie_probe, .remove = iproc_pcie_remove, .priv_auto = sizeof(struct iproc_pcie), - .flags = DM_REMOVE_OS_PREPARE, + .flags = DM_FLAG_OS_PREPARE, }; diff --git a/drivers/serial/serial_sifive.c b/drivers/serial/serial_sifive.c index d26fe7e7704..97bf20c967a 100644 --- a/drivers/serial/serial_sifive.c +++ b/drivers/serial/serial_sifive.c @@ -178,7 +178,7 @@ static int sifive_serial_of_to_plat(struct udevice *dev) { struct sifive_uart_plat *plat = dev_get_plat(dev); - plat->regs = (struct uart_sifive *)dev_read_addr(dev); + plat->regs = (struct uart_sifive *)(uintptr_t)dev_read_addr(dev); if (IS_ERR(plat->regs)) return PTR_ERR(plat->regs); diff --git a/drivers/smem/msm_smem.c b/drivers/smem/msm_smem.c index 597d425d11f..26462151b3a 100644 --- a/drivers/smem/msm_smem.c +++ b/drivers/smem/msm_smem.c @@ -437,7 +437,7 @@ static int qcom_smem_alloc(unsigned int host, unsigned int item, size_t size) int ret; if (!__smem) - return -EPROBE_DEFER; + return -ENOMEM; if (item < SMEM_ITEM_LAST_FIXED) { dev_err(__smem->dev, @@ -559,7 +559,7 @@ static void *qcom_smem_get(unsigned int host, unsigned int item, size_t *size) { struct smem_partition_header *phdr; size_t cacheln; - void *ptr = ERR_PTR(-EPROBE_DEFER); + void *ptr = ERR_PTR(-ENOMEM); if (!__smem) return ptr; @@ -597,7 +597,7 @@ static int qcom_smem_get_free_space(unsigned int host) unsigned int ret; if (!__smem) - return -EPROBE_DEFER; + return -ENOMEM; if (host < SMEM_HOST_COUNT && __smem->partitions[host]) { phdr = __smem->partitions[host]; diff --git a/drivers/video/meson/meson_vpu.c b/drivers/video/meson/meson_vpu.c index ca6933a6c54..558f9ba766c 100644 --- a/drivers/video/meson/meson_vpu.c +++ b/drivers/video/meson/meson_vpu.c @@ -212,5 +212,5 @@ U_BOOT_DRIVER(meson_vpu) = { .probe = meson_vpu_probe, .bind = meson_vpu_bind, .priv_auto = sizeof(struct meson_vpu_priv), - .flags = DM_FLAG_PRE_RELOC | DM_FLAG_REMOVE_WITH_PD_ON, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_LEAVE_PD_ON, }; diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c index f64a39f6579..8335b20ae84 100644 --- a/drivers/watchdog/rti_wdt.c +++ b/drivers/watchdog/rti_wdt.c @@ -119,5 +119,5 @@ U_BOOT_DRIVER(rti_wdt) = { .ops = &rti_wdt_ops, .probe = rti_wdt_probe, .priv_auto = sizeof(struct rti_wdt_priv), - .flags = DM_FLAG_REMOVE_WITH_PD_ON, + .flags = DM_FLAG_LEAVE_PD_ON, }; diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index b6f707e97e5..998beb01760 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -147,7 +147,7 @@ struct global_data { /** * @ram_top: top address of RAM used by U-Boot */ - unsigned long ram_top; + phys_addr_t ram_top; /** * @relocaddr: start address of U-Boot in RAM * diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index 639bbd293d9..39406c3f352 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -123,7 +123,9 @@ int device_probe(struct udevice *dev); * * @dev: Pointer to device to remove * @flags: Flags for selective device removal (DM_REMOVE_...) - * @return 0 if OK, -ve on error (an error here is normally a very bad thing) + * @return 0 if OK, -EKEYREJECTED if not removed due to flags, -EPROBE_DEFER if + * this is a vital device and flags is DM_REMOVE_NON_VITAL, other -ve on + * error (such an error here is normally a very bad thing) */ #if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE) int device_remove(struct udevice *dev, uint flags); @@ -173,10 +175,19 @@ static inline int device_chld_unbind(struct udevice *dev, struct driver *drv) /** * device_chld_remove() - Stop all device's children + * + * This continues through all children recursively stopping part-way through if + * an error occurs. Return values of -EKEYREJECTED are ignored and processing + * continues, since they just indicate that the child did not elect to be + * removed based on the value of @flags. Return values of -EPROBE_DEFER cause + * processing of other children to continue, but the function will return + * -EPROBE_DEFER. + * * @dev: The device whose children are to be removed * @drv: The targeted driver * @flags: Flag, if this functions is called in the pre-OS stage - * @return 0 on success, -ve on error + * @return 0 on success, -EPROBE_DEFER if any child failed to remove, other + * -ve on error */ #if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE) int device_chld_remove(struct udevice *dev, struct driver *drv, diff --git a/include/dm/device.h b/include/dm/device.h index e665558444b..28533ce0b6d 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -71,12 +71,22 @@ struct driver_info; * Device is removed without switching off its power domain. This might * be required, i. e. for serial console (debug) output when booting OS. */ -#define DM_FLAG_REMOVE_WITH_PD_ON (1 << 13) +#define DM_FLAG_LEAVE_PD_ON (1 << 13) + +/* + * Device is vital to the operation of other devices. It is possible to remove + * removed this device after all regular devices are removed. This is useful + * e.g. for clock, which need to be active during the device-removal phase. + */ +#define DM_FLAG_VITAL (1 << 14) /* * One or multiple of these flags are passed to device_remove() so that * a selective device removal as specified by the remove-stage and the * driver flags can be done. + * + * DO NOT use these flags in your driver's @flags value... + * use the above DM_FLAG_... values instead */ enum { /* Normal remove, remove all devices */ @@ -88,7 +98,8 @@ enum { /* Remove devices which need some final OS preparation steps */ DM_REMOVE_OS_PREPARE = DM_FLAG_OS_PREPARE, - /* Add more use cases here */ + /* Remove only devices that are not marked vital */ + DM_REMOVE_NON_VITAL = DM_FLAG_VITAL, /* Remove devices with any active flag */ DM_REMOVE_ACTIVE_ALL = DM_REMOVE_ACTIVE_DMA | DM_REMOVE_OS_PREPARE, diff --git a/include/init.h b/include/init.h index 980be279936..88f84599e9e 100644 --- a/include/init.h +++ b/include/init.h @@ -326,7 +326,8 @@ void relocate_code(ulong start_addr_sp, struct global_data *new_gd, #endif /* Print a numeric value (for use in arch_print_bdinfo()) */ -void bdinfo_print_num(const char *name, ulong value); +void bdinfo_print_num_l(const char *name, ulong value); +void bdinfo_print_num_ll(const char *name, unsigned long long value); /* Print a clock speed in MHz */ void bdinfo_print_mhz(const char *name, unsigned long hz); diff --git a/include/os.h b/include/os.h index e192e32d592..65bcb232cab 100644 --- a/include/os.h +++ b/include/os.h @@ -341,7 +341,7 @@ void os_localtime(struct rtc_time *rt); /** * os_abort() - raise SIGABRT to exit sandbox (e.g. to debugger) */ -void os_abort(void); +void os_abort(void) __attribute__((noreturn)); /** * os_mprotect_allow() - Remove write-protection on a region of memory diff --git a/lib/fdtdec.c b/lib/fdtdec.c index a2d2fb4e1fe..e048f7777d6 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1572,7 +1572,7 @@ int fdtdec_setup(void) return -1; } # elif defined(CONFIG_OF_PRIOR_STAGE) - gd->fdt_blob = (void *)prior_stage_fdt_address; + gd->fdt_blob = (void *)(uintptr_t)prior_stage_fdt_address; # endif # ifndef CONFIG_SPL_BUILD /* Allow the early environment to override the fdt address */ diff --git a/test/dm/core.c b/test/dm/core.c index 1f5ca570dc7..bfd6565d952 100644 --- a/test/dm/core.c +++ b/test/dm/core.c @@ -72,6 +72,14 @@ static struct driver_info driver_info_act_dma = { .name = "test_act_dma_drv", }; +static struct driver_info driver_info_vital_clk = { + .name = "test_vital_clk_drv", +}; + +static struct driver_info driver_info_act_dma_vital_clk = { + .name = "test_act_dma_vital_clk_drv", +}; + void dm_leak_check_start(struct unit_test_state *uts) { uts->start = mallinfo(); @@ -883,6 +891,92 @@ static int dm_test_remove_active_dma(struct unit_test_state *uts) } DM_TEST(dm_test_remove_active_dma, 0); +/* Test removal of 'vital' devices */ +static int dm_test_remove_vital(struct unit_test_state *uts) +{ + struct dm_test_state *dms = uts->priv; + struct udevice *normal, *dma, *vital, *dma_vital; + + /* Skip the behaviour in test_post_probe() */ + dms->skip_post_probe = 1; + + ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, + &normal)); + ut_assertnonnull(normal); + + ut_assertok(device_bind_by_name(dms->root, false, &driver_info_act_dma, + &dma)); + ut_assertnonnull(dma); + + ut_assertok(device_bind_by_name(dms->root, false, + &driver_info_vital_clk, &vital)); + ut_assertnonnull(vital); + + ut_assertok(device_bind_by_name(dms->root, false, + &driver_info_act_dma_vital_clk, + &dma_vital)); + ut_assertnonnull(dma_vital); + + /* Probe the devices */ + ut_assertok(device_probe(normal)); + ut_assertok(device_probe(dma)); + ut_assertok(device_probe(vital)); + ut_assertok(device_probe(dma_vital)); + + /* Check that devices are active right now */ + ut_asserteq(true, device_active(normal)); + ut_asserteq(true, device_active(dma)); + ut_asserteq(true, device_active(vital)); + ut_asserteq(true, device_active(dma_vital)); + + /* Remove active devices via selective remove flag */ + dm_remove_devices_flags(DM_REMOVE_NON_VITAL | DM_REMOVE_ACTIVE_ALL); + + /* + * Check that this only has an effect on the dma device, since two + * devices are vital and the third does not have active DMA + */ + ut_asserteq(true, device_active(normal)); + ut_asserteq(false, device_active(dma)); + ut_asserteq(true, device_active(vital)); + ut_asserteq(true, device_active(dma_vital)); + + /* Remove active devices via selective remove flag */ + ut_assertok(device_probe(dma)); + dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); + + /* This should have affected both active-dma devices */ + ut_asserteq(true, device_active(normal)); + ut_asserteq(false, device_active(dma)); + ut_asserteq(true, device_active(vital)); + ut_asserteq(false, device_active(dma_vital)); + + /* Remove non-vital devices */ + ut_assertok(device_probe(dma)); + ut_assertok(device_probe(dma_vital)); + dm_remove_devices_flags(DM_REMOVE_NON_VITAL); + + /* This should have affected only non-vital devices */ + ut_asserteq(false, device_active(normal)); + ut_asserteq(false, device_active(dma)); + ut_asserteq(true, device_active(vital)); + ut_asserteq(true, device_active(dma_vital)); + + /* Remove vital devices via normal remove flag */ + ut_assertok(device_probe(normal)); + ut_assertok(device_probe(dma)); + dm_remove_devices_flags(DM_REMOVE_NORMAL); + + /* Check that all devices are inactive right now */ + ut_asserteq(false, device_active(normal)); + ut_asserteq(false, device_active(dma)); + ut_asserteq(false, device_active(vital)); + ut_asserteq(false, device_active(dma_vital)); + + return 0; +} +DM_TEST(dm_test_remove_vital, 0); + static int dm_test_uclass_before_ready(struct unit_test_state *uts) { struct uclass *uc; diff --git a/test/dm/test-driver.c b/test/dm/test-driver.c index a67f5d3f982..ca7626a0668 100644 --- a/test/dm/test-driver.c +++ b/test/dm/test-driver.c @@ -170,3 +170,25 @@ U_BOOT_DRIVER(test_act_dma_drv) = { .unbind = test_manual_unbind, .flags = DM_FLAG_ACTIVE_DMA, }; + +U_BOOT_DRIVER(test_vital_clk_drv) = { + .name = "test_vital_clk_drv", + .id = UCLASS_TEST, + .ops = &test_manual_ops, + .bind = test_manual_bind, + .probe = test_manual_probe, + .remove = test_manual_remove, + .unbind = test_manual_unbind, + .flags = DM_FLAG_VITAL, +}; + +U_BOOT_DRIVER(test_act_dma_vital_clk_drv) = { + .name = "test_act_dma_vital_clk_drv", + .id = UCLASS_TEST, + .ops = &test_manual_ops, + .bind = test_manual_bind, + .probe = test_manual_probe, + .remove = test_manual_remove, + .unbind = test_manual_unbind, + .flags = DM_FLAG_VITAL | DM_FLAG_ACTIVE_DMA, +}; diff --git a/test/dm/virtio.c b/test/dm/virtio.c index ad355981cf4..9a7e658cceb 100644 --- a/test/dm/virtio.c +++ b/test/dm/virtio.c @@ -123,7 +123,9 @@ static int dm_test_virtio_remove(struct unit_test_state *uts) /* check the device can be successfully removed */ dev_or_flags(dev, DM_FLAG_ACTIVATED); - ut_assertok(device_remove(bus, DM_REMOVE_ACTIVE_ALL)); + ut_asserteq(-EKEYREJECTED, device_remove(bus, DM_REMOVE_ACTIVE_ALL)); + + ut_asserteq(false, device_active(dev)); return 0; }