Andrey Petrov (andrey.petrov@intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/17320
-gerrit
commit bd65fd4af19fdfbdf148b694eee8b3db6be8728c Author: Andrey Petrov andrey.petrov@intel.com Date: Tue Nov 8 08:30:06 2016 -0800
soc/intel/common: Add store/restore for variable MRC data
Piggy-back on existing MRC cache infrastructure to store variable MRC data.
Only one set of data can be valid at given point of time. Currently this magically happens because region alignment is forced to 0x1000 and region itself is of the same size. This needs to be somehow programmatically enforced.
Change-Id: I8a660d356ca760b8ff9907396fb9b34cb16cf1db Signed-off-by: Andrey Petrov andrey.petrov@intel.com --- src/commonlib/include/commonlib/cbmem_id.h | 2 + src/include/elog.h | 1 + src/soc/intel/common/Kconfig | 4 + src/soc/intel/common/mrc_cache.c | 116 +++++++++++++++++++++-------- src/soc/intel/common/mrc_cache.h | 4 + 5 files changed, 96 insertions(+), 31 deletions(-)
diff --git a/src/commonlib/include/commonlib/cbmem_id.h b/src/commonlib/include/commonlib/cbmem_id.h index 0d2a7c3..9fb1606 100644 --- a/src/commonlib/include/commonlib/cbmem_id.h +++ b/src/commonlib/include/commonlib/cbmem_id.h @@ -41,6 +41,7 @@ #define CBMEM_ID_MMA_DATA 0x4D4D4144 #define CBMEM_ID_MPTABLE 0x534d5054 #define CBMEM_ID_MRCDATA 0x4d524344 +#define CBMEM_ID_VAR_MRCDATA 0x4d524345 #define CBMEM_ID_MTC 0xcb31d31c #define CBMEM_ID_NONE 0x00000000 #define CBMEM_ID_PIRQ 0x49525154 @@ -92,6 +93,7 @@ { CBMEM_ID_MMA_DATA, "MMA DATA " }, \ { CBMEM_ID_MPTABLE, "SMP TABLE " }, \ { CBMEM_ID_MRCDATA, "MRC DATA " }, \ + { CBMEM_ID_VAR_MRCDATA, "VARMRC DATA" }, \ { CBMEM_ID_MTC, "MTC " }, \ { CBMEM_ID_PIRQ, "IRQ TABLE " }, \ { CBMEM_ID_POWER_STATE, "POWER STATE" }, \ diff --git a/src/include/elog.h b/src/include/elog.h index f2e587c..501e30d 100644 --- a/src/include/elog.h +++ b/src/include/elog.h @@ -160,6 +160,7 @@ struct elog_event_data_me_extended { #define ELOG_TYPE_MEM_CACHE_UPDATE 0xaa #define ELOG_MEM_CACHE_UPDATE_SLOT_NORMAL 0 #define ELOG_MEM_CACHE_UPDATE_SLOT_RECOVERY 1 +#define ELOG_MEM_CACHE_UPDATE_SLOT_VARIABLE 2 #define ELOG_MEM_CACHE_UPDATE_STATUS_SUCCESS 0 #define ELOG_MEM_CACHE_UPDATE_STATUS_FAIL 1 struct elog_event_mem_cache_update { diff --git a/src/soc/intel/common/Kconfig b/src/soc/intel/common/Kconfig index 7ae7e60..23dd601 100644 --- a/src/soc/intel/common/Kconfig +++ b/src/soc/intel/common/Kconfig @@ -31,6 +31,10 @@ config HAS_RECOVERY_MRC_CACHE bool default n
+config MRC_SETTINGS_VARIABLE_DATA + bool + default n + endif # CACHE_MRC_SETTINGS
config DISPLAY_MTRRS diff --git a/src/soc/intel/common/mrc_cache.c b/src/soc/intel/common/mrc_cache.c index 7b66043..ad01551 100644 --- a/src/soc/intel/common/mrc_cache.c +++ b/src/soc/intel/common/mrc_cache.c @@ -35,6 +35,14 @@ struct mrc_data_region { uint32_t size; };
+enum result { + WRITE_FAILURE = -1, + ERASE_FAILURE = -2, + OTHER_FAILURE = -3, + UPDATE_SUCCESS = 0, + ALREADY_UPTODATE = 1 +}; + /* common code */ static int mrc_cache_get_region(const char *name, struct mrc_data_region *region) @@ -235,6 +243,16 @@ int mrc_cache_get_current(const struct mrc_saved_data **cache) return mrc_cache_get_current_with_version(cache, 0); }
+int mrc_cache_get_vardata(const struct mrc_saved_data **cache, uint32_t version) +{ + struct mrc_data_region region; + + if (mrc_cache_get_region(VARIABLE_MRC_CACHE, ®ion) < 0) + return -1; + + return __mrc_cache_get_current(®ion, cache, version); +} + /* Fill in mrc_saved_data structure with payload. */ static void mrc_cache_fill(struct mrc_saved_data *cache, const void *data, size_t size, uint32_t version) @@ -247,15 +265,15 @@ static void mrc_cache_fill(struct mrc_saved_data *cache, const void *data, cache->size); }
-int mrc_cache_stash_data_with_version(const void *data, size_t size, - uint32_t version) +static int _mrc_stash_data(const void *data, size_t size, uint32_t version, + uint32_t cbmem_id) { int cbmem_size; struct mrc_saved_data *cache;
cbmem_size = sizeof(*cache) + ALIGN(size, 16);
- cache = cbmem_add(CBMEM_ID_MRCDATA, cbmem_size); + cache = cbmem_add(cbmem_id, cbmem_size);
if (cache == NULL) { printk(BIOS_ERR, "MRC: No space in cbmem for training data.\n"); @@ -273,6 +291,18 @@ int mrc_cache_stash_data_with_version(const void *data, size_t size, return 0; }
+int mrc_cache_stash_data_with_version(const void *data, size_t size, + uint32_t version) +{ + return _mrc_stash_data(data, size, version, CBMEM_ID_MRCDATA); +} + +int mrc_cache_stash_vardata(const void *data, size_t size, uint32_t version) +{ + return _mrc_stash_data(data, size, version, CBMEM_ID_VAR_MRCDATA); +} + + int mrc_cache_stash_data(const void *data, size_t size) { return mrc_cache_stash_data_with_version(data, size, 0); @@ -324,51 +354,57 @@ mrc_cache_next_slot(const struct mrc_data_region *region, return next_slot; }
-static void log_event_cache_update(uint8_t slot, uint8_t status) +static void log_event_cache_update(uint8_t slot, enum result res) { const int type = ELOG_TYPE_MEM_CACHE_UPDATE; struct elog_event_mem_cache_update event = { - .slot = slot, - .status = status, + .slot = slot };
+ /* Filter through interesting events only */ + switch (res) { + case WRITE_FAILURE: /* fall-through */ + case ERASE_FAILURE: /* fall-through */ + case OTHER_FAILURE: /* fall-through */ + event.status = ELOG_MEM_CACHE_UPDATE_STATUS_FAIL; + break; + case UPDATE_SUCCESS: + event.status = ELOG_MEM_CACHE_UPDATE_STATUS_SUCCESS; + break; + default: + return; + } + if (elog_add_event_raw(type, &event, sizeof(event)) < 0) printk(BIOS_ERR, "Failed to log mem cache update event.\n"); }
-static void update_mrc_region(void) +static int update_mrc_cache_type(uint32_t cbmem_id, const char *region_name) { const struct mrc_saved_data *current_boot; const struct mrc_saved_data *current_saved; const struct mrc_saved_data *next_slot; struct mrc_data_region region; - const char *region_name = DEFAULT_MRC_CACHE; - uint8_t slot = ELOG_MEM_CACHE_UPDATE_SLOT_NORMAL; + int res;
printk(BIOS_DEBUG, "MRC: Updating cache data.\n");
- if (vboot_recovery_mode_enabled() && - IS_ENABLED(CONFIG_HAS_RECOVERY_MRC_CACHE)) { - region_name = RECOVERY_MRC_CACHE; - slot = ELOG_MEM_CACHE_UPDATE_SLOT_RECOVERY; - } - printk(BIOS_ERR, "MRC: Cache region selected - %s\n", region_name);
if (mrc_cache_get_region(region_name, ®ion)) { printk(BIOS_ERR, "MRC: Could not obtain cache region.\n"); - return; + return OTHER_FAILURE; }
- current_boot = cbmem_find(CBMEM_ID_MRCDATA); + current_boot = cbmem_find(cbmem_id); if (!current_boot) { printk(BIOS_ERR, "MRC: No cache in cbmem.\n"); - return; + return OTHER_FAILURE; }
if (!mrc_cache_valid(®ion, current_boot)) { printk(BIOS_ERR, "MRC: Cache data in cbmem invalid.\n"); - return; + return OTHER_FAILURE; }
current_saved = NULL; @@ -379,7 +415,7 @@ static void update_mrc_region(void) !memcmp(¤t_saved->data[0], ¤t_boot->data[0], current_saved->size)) { printk(BIOS_DEBUG, "MRC: Cache up to date.\n"); - return; + return ALREADY_UPTODATE; } }
@@ -391,21 +427,15 @@ static void update_mrc_region(void) if (nvm_erase(region.base, region.size) < 0) { printk(BIOS_DEBUG, "MRC: Failure erasing " "region %s.\n", region_name); - return; + return ERASE_FAILURE; } } next_slot = region.base; }
- if (nvm_write((void *)next_slot, current_boot, - current_boot->size + sizeof(*current_boot))) { - printk(BIOS_DEBUG, "MRC: Failure writing MRC cache to %s:%p\n", - region_name, next_slot); - log_event_cache_update(slot, ELOG_MEM_CACHE_UPDATE_STATUS_FAIL); - } else { - log_event_cache_update(slot, - ELOG_MEM_CACHE_UPDATE_STATUS_SUCCESS); - } + res = nvm_write((void *)next_slot, current_boot, current_boot->size + + sizeof(*current_boot)); + return res < 0 ? WRITE_FAILURE : UPDATE_SUCCESS; }
static void protect_mrc_region(void) @@ -429,7 +459,31 @@ static void protect_mrc_region(void)
static void update_mrc_cache(void *unused) { - update_mrc_region(); + uint8_t slot; + const char *region_name; + enum result res; + + /* First update either recovery or default cache */ + if (vboot_recovery_mode_enabled() && + IS_ENABLED(CONFIG_HAS_RECOVERY_MRC_CACHE)) { + region_name = RECOVERY_MRC_CACHE; + slot = ELOG_MEM_CACHE_UPDATE_SLOT_RECOVERY; + } else { + region_name = DEFAULT_MRC_CACHE; + slot = ELOG_MEM_CACHE_UPDATE_SLOT_NORMAL; + } + + res = update_mrc_cache_type(CBMEM_ID_MRCDATA, region_name); + log_event_cache_update(slot, res); + + /* Next update variable cache if in use */ + if (IS_ENABLED(CONFIG_MRC_SETTINGS_VARIABLE_DATA)) { + res = update_mrc_cache_type(CBMEM_ID_VAR_MRCDATA, + VARIABLE_MRC_CACHE); + log_event_cache_update(ELOG_MEM_CACHE_UPDATE_SLOT_VARIABLE, + res); + } + protect_mrc_region(); }
diff --git a/src/soc/intel/common/mrc_cache.h b/src/soc/intel/common/mrc_cache.h index 850acd6..6414acc 100644 --- a/src/soc/intel/common/mrc_cache.h +++ b/src/soc/intel/common/mrc_cache.h @@ -20,6 +20,7 @@ #include <stdint.h>
#define DEFAULT_MRC_CACHE "RW_MRC_CACHE" +#define VARIABLE_MRC_CACHE "RW_VAR_MRC_CACHE" #define RECOVERY_MRC_CACHE "RECOVERY_MRC_CACHE" #define UNIFIED_MRC_CACHE "UNIFIED_MRC_CACHE"
@@ -36,6 +37,8 @@ struct mrc_saved_data { int mrc_cache_get_current(const struct mrc_saved_data **cache); int mrc_cache_get_current_with_version(const struct mrc_saved_data **cache, uint32_t version); +int mrc_cache_get_vardata(const struct mrc_saved_data **cache, + uint32_t version); int mrc_cache_get_current_from_region(const struct mrc_saved_data **cache, uint32_t version, const char *region_name); @@ -44,5 +47,6 @@ int mrc_cache_get_current_from_region(const struct mrc_saved_data **cache, int mrc_cache_stash_data(const void *data, size_t size); int mrc_cache_stash_data_with_version(const void *data, size_t size, uint32_t version); +int mrc_cache_stash_vardata(const void *data, size_t size, uint32_t version);
#endif /* _COMMON_MRC_CACHE_H_ */