mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-26 21:54:37 +08:00
Support late device removal
Allow booting a 32-bit system with a top memory address beyond 4 GiB -----BEGIN PGP SIGNATURE----- iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAmAbVFARHHNqZ0BjaHJv bWl1bS5vcmcACgkQfxc6PpAIrebn/Af9FoJksV/0G+z6AzjJ20+yoOVAOFFhUkFB UTW5m0Sv3wMmlSNdg0+DPuB3o04U6RwlZTdIqK/shc0fEqr0YeJgWAEPSMjQH0xc ou8S9LAnJNrvlqNu5aP2Wq5KFwOxp/ODx5RBNpiSaL+m26dmUi2eeU+Ym996rr06 +m0qycZP07BHLIfm0pWyZjAI2+VzR7Uuyd1pKEIerOTRkAvZzk6pQbs+vv6PLaHa Wcl9grnoO3pDZt6CYpmgv8mbetXteRfrdYMsu2OiHx/2nU3pa7TbOoNcuA2ww2Ko u9NL7s0E0Y1LY6/QNb1O7eGOxcR1H5y/19K6NGrK27BwMkrvb0GKRg== =jMvm -----END PGP SIGNATURE----- Merge tag 'dm-pull-3feb21' of https://gitlab.denx.de/u-boot/custodians/u-boot-dm Support late device removal Allow booting a 32-bit system with a top memory address beyond 4 GiB
This commit is contained in:
commit
21cb717e79
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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 */
|
||||
|
@ -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))
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
||||
|
@ -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;
|
||||
|
52
cmd/bdinfo.c
52
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;
|
||||
|
@ -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
|
||||
---------------
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
* Pavel Herrmann <morpheus.ibis@gmail.com>
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY LOGC_DM
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <log.h>
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user