X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=env%2Fenv.c;h=5c0842ac07eb2d728fef5f349ab0cd8d1b26dc73;hb=f198bbac6695ecaac281e8dc5c5d74464ac82b3e;hp=43290d0832125f7ad98f78ec5df8db51b8689207;hpb=8197d92843952b376915fdbcbf67c723feab1532;p=u-boot diff --git a/env/env.c b/env/env.c index 43290d0832..5c0842ac07 100644 --- a/env/env.c +++ b/env/env.c @@ -1,8 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2017 Google, Inc * Written by Simon Glass - * - * SPDX-License-Identifier: GPL-2.0+ */ #include @@ -10,7 +9,28 @@ DECLARE_GLOBAL_DATA_PTR; -static struct env_driver *env_driver_lookup(enum env_location loc) +#if defined(CONFIG_NEEDS_MANUAL_RELOC) +void env_fix_drivers(void) +{ + struct env_driver *drv; + const int n_ents = ll_entry_count(struct env_driver, env_driver); + struct env_driver *entry; + + drv = ll_entry_start(struct env_driver, env_driver); + for (entry = drv; entry != drv + n_ents; entry++) { + if (entry->name) + entry->name += gd->reloc_off; + if (entry->load) + entry->load += gd->reloc_off; + if (entry->save) + entry->save += gd->reloc_off; + if (entry->init) + entry->init += gd->reloc_off; + } +} +#endif + +static struct env_driver *_env_driver_lookup(enum env_location loc) { struct env_driver *drv; const int n_ents = ll_entry_count(struct env_driver, env_driver); @@ -26,40 +46,118 @@ static struct env_driver *env_driver_lookup(enum env_location loc) return NULL; } -static enum env_location env_get_default_location(void) +static enum env_location env_locations[] = { +#ifdef CONFIG_ENV_IS_IN_EEPROM + ENVL_EEPROM, +#endif +#ifdef CONFIG_ENV_IS_IN_EXT4 + ENVL_EXT4, +#endif +#ifdef CONFIG_ENV_IS_IN_FAT + ENVL_FAT, +#endif +#ifdef CONFIG_ENV_IS_IN_FLASH + ENVL_FLASH, +#endif +#ifdef CONFIG_ENV_IS_IN_MMC + ENVL_MMC, +#endif +#ifdef CONFIG_ENV_IS_IN_NAND + ENVL_NAND, +#endif +#ifdef CONFIG_ENV_IS_IN_NVRAM + ENVL_NVRAM, +#endif +#ifdef CONFIG_ENV_IS_IN_REMOTE + ENVL_REMOTE, +#endif +#ifdef CONFIG_ENV_IS_IN_SPI_FLASH + ENVL_SPI_FLASH, +#endif +#ifdef CONFIG_ENV_IS_IN_UBI + ENVL_UBI, +#endif +#ifdef CONFIG_ENV_IS_NOWHERE + ENVL_NOWHERE, +#endif +}; + +static bool env_has_inited(enum env_location location) { - if IS_ENABLED(CONFIG_ENV_IS_IN_DATAFLASH) - return ENVL_DATAFLASH; - else if IS_ENABLED(CONFIG_ENV_IS_IN_EEPROM) - return ENVL_EEPROM; - else if IS_ENABLED(CONFIG_ENV_IS_IN_FAT) - return ENVL_FAT; - else if IS_ENABLED(CONFIG_ENV_IS_IN_FLASH) - return ENVL_FLASH; - else if IS_ENABLED(CONFIG_ENV_IS_IN_MMC) - return ENVL_MMC; - else if IS_ENABLED(CONFIG_ENV_IS_IN_NAND) - return ENVL_NAND; - else if IS_ENABLED(CONFIG_ENV_IS_IN_NVRAM) - return ENVL_NVRAM; - else if IS_ENABLED(CONFIG_ENV_IS_IN_REMOTE) - return ENVL_REMOTE; - else if IS_ENABLED(CONFIG_ENV_IS_IN_SPI_FLASH) - return ENVL_SPI_FLASH; - else if IS_ENABLED(CONFIG_ENV_IS_IN_UBI) - return ENVL_UBI; - else if IS_ENABLED(CONFIG_ENV_IS_NOWHERE) - return ENVL_NOWHERE; - else - return ENVL_UNKNOWN; + return gd->env_has_init & BIT(location); } -struct env_driver *env_driver_lookup_default(void) +static void env_set_inited(enum env_location location) +{ + /* + * We're using a 32-bits bitmask stored in gd (env_has_init) + * using the above enum value as the bit index. We need to + * make sure that we're not overflowing it. + */ + BUILD_BUG_ON(ARRAY_SIZE(env_locations) > BITS_PER_LONG); + + gd->env_has_init |= BIT(location); +} + +/** + * env_get_location() - Returns the best env location for a board + * @op: operations performed on the environment + * @prio: priority between the multiple environments, 0 being the + * highest priority + * + * This will return the preferred environment for the given priority. + * This is overridable by boards if they need to. + * + * All implementations are free to use the operation, the priority and + * any other data relevant to their choice, but must take into account + * the fact that the lowest prority (0) is the most important location + * in the system. The following locations should be returned by order + * of descending priorities, from the highest to the lowest priority. + * + * Returns: + * an enum env_location value on success, a negative error code otherwise + */ +__weak enum env_location env_get_location(enum env_operation op, int prio) +{ + switch (op) { + case ENVOP_GET_CHAR: + case ENVOP_INIT: + case ENVOP_LOAD: + if (prio >= ARRAY_SIZE(env_locations)) + return ENVL_UNKNOWN; + + gd->env_load_location = env_locations[prio]; + return gd->env_load_location; + + case ENVOP_SAVE: + return gd->env_load_location; + } + + return ENVL_UNKNOWN; +} + + +/** + * env_driver_lookup() - Finds the most suited environment location + * @op: operations performed on the environment + * @prio: priority between the multiple environments, 0 being the + * highest priority + * + * This will try to find the available environment with the highest + * priority in the system. + * + * Returns: + * NULL on error, a pointer to a struct env_driver otherwise + */ +static struct env_driver *env_driver_lookup(enum env_operation op, int prio) { - enum env_location loc = env_get_default_location(); + enum env_location loc = env_get_location(op, prio); struct env_driver *drv; - drv = env_driver_lookup(loc); + if (loc == ENVL_UNKNOWN) + return NULL; + + drv = _env_driver_lookup(loc); if (!drv) { debug("%s: No environment driver for location %d\n", __func__, loc); @@ -69,83 +167,98 @@ struct env_driver *env_driver_lookup_default(void) return drv; } -int env_get_char(int index) +__weak int env_get_char_spec(int index) { - struct env_driver *drv = env_driver_lookup_default(); - int ret; + return *(uchar *)(gd->env_addr + index); +} +int env_get_char(int index) +{ if (gd->env_valid == ENV_INVALID) return default_environment[index]; - if (!drv) - return -ENODEV; - if (!drv->get_char) - return *(uchar *)(gd->env_addr + index); - ret = drv->get_char(index); - if (ret < 0) { - debug("%s: Environment failed to load (err=%d)\n", - __func__, ret); - } - - return ret; + else + return env_get_char_spec(index); } int env_load(void) { - struct env_driver *drv = env_driver_lookup_default(); - int ret = 0; + struct env_driver *drv; + int prio; - if (!drv) - return -ENODEV; - if (!drv->load) - return 0; - ret = drv->load(); - if (ret) { - debug("%s: Environment failed to load (err=%d)\n", __func__, - ret); - return ret; + for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) { + int ret; + + if (!drv->load) + continue; + + if (!env_has_inited(drv->location)) + continue; + + printf("Loading Environment from %s... ", drv->name); + ret = drv->load(); + if (ret) + printf("Failed (%d)\n", ret); + else + printf("OK\n"); + + if (!ret) + return 0; } - return 0; + return -ENODEV; } int env_save(void) { - struct env_driver *drv = env_driver_lookup_default(); - int ret; + struct env_driver *drv; + int prio; - if (!drv) - return -ENODEV; - if (!drv->save) - return -ENOSYS; - ret = drv->save(); - if (ret) { - debug("%s: Environment failed to save (err=%d)\n", __func__, - ret); - return ret; + for (prio = 0; (drv = env_driver_lookup(ENVOP_SAVE, prio)); prio++) { + int ret; + + if (!drv->save) + continue; + + if (!env_has_inited(drv->location)) + continue; + + printf("Saving Environment to %s... ", drv->name); + ret = drv->save(); + if (ret) + printf("Failed (%d)\n", ret); + else + printf("OK\n"); + + if (!ret) + return 0; } - return 0; + return -ENODEV; } int env_init(void) { - struct env_driver *drv = env_driver_lookup_default(); + struct env_driver *drv; int ret = -ENOENT; + int prio; - if (!drv) + for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) { + if (!drv->init || !(ret = drv->init())) + env_set_inited(drv->location); + + debug("%s: Environment %s init done (ret=%d)\n", __func__, + drv->name, ret); + } + + if (!prio) return -ENODEV; - if (drv->init) - ret = drv->init(); + if (ret == -ENOENT) { gd->env_addr = (ulong)&default_environment[0]; gd->env_valid = ENV_VALID; return 0; - } else if (ret) { - debug("%s: Environment failed to init (err=%d)\n", __func__, - ret); - return ret; } - return 0; + return ret; }