Patrick Georgi (pgeorgi@google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10735
-gerrit
commit 3fa4d5f6c0eb8e20c9643cea58f14c3de6fd7867 Author: Furquan Shaikh furquan@google.com Date: Wed Oct 15 15:17:49 2014 -0700
timestamp: Make timestamp library more flexible and intelligent
Add support for: 1) Using timestamps in bootblock and verstage 2) Allowing the timestamps to be stashed into _timestamp region so that they can be used across multiple stages 3) Performing operations over the timestamps in _timestamp region
Instead of having two separate APIs for stashing and adding timestamps, let the timestamp library decide on its own where to save depending on timestamp cache status. Now the sequence of operations would be something like: timestamp_init / timestamp_early_init : Set the base time timestamp_add / timestamp_add_now cbmem_initialize : It internally calls timestamp_sync timestamp_add / timestamp_add_now
BUG=chrome-os-partner:32973 BRANCH=None TEST=Compiles successfully for ryu and samus. cbmem -t on ryu works fine.
Original-Change-Id: Ie5ffda3112d626068bd1904afcc5a09bc4916d16 Original-Signed-off-by: Furquan Shaikh furquan@google.com Original-Reviewed-on: https://chromium-review.googlesource.com/224024 Original-Reviewed-by: Furquan Shaikh furquan@chromium.org Original-Commit-Queue: Furquan Shaikh furquan@chromium.org Original-Tested-by: Furquan Shaikh furquan@chromium.org
(cherry picked from commit 2f6b472984f4971ece172b789aab3bc82afa8a9d) Signed-off-by: Marc Jones marc.jones@se-eng.com
Change-Id: I4d2ffc99277be6c248c8c70149dc14334a1f536a --- src/arch/x86/Makefile.inc | 3 +- src/arch/x86/init/romstage.ld | 5 + src/include/timestamp.h | 25 ++++ src/lib/timestamp.c | 266 +++++++++++++++++++++++++++++++----------- 4 files changed, 227 insertions(+), 72 deletions(-)
diff --git a/src/arch/x86/Makefile.inc b/src/arch/x86/Makefile.inc index f502bbe..dcb9ff0 100644 --- a/src/arch/x86/Makefile.inc +++ b/src/arch/x86/Makefile.inc @@ -225,7 +225,8 @@ $(objgenerated)/romstage_null.ld: $(obj)/config.h $$(filter %.ld,$$(romstage-src rm -f $@ printf "ROMSTAGE_BASE = 0x0;\n" > $@.tmp printf '$(foreach ldscript,$(^),#include "$(ldscript)"\n)' >> $@.tmp - $(CC_romstage) $(PREPROCESS_ONLY) $@.tmp > $@ + $(CC_romstage) $(PREPROCESS_ONLY) $(CPPFLAGS_common) $@.tmp > $@ +
$(objgenerated)/romstage.ld: $(objgenerated)/romstage_null.ld $(objcbfs)/base_xip.txt @printf " GEN $(subst $(obj)/,,$(@))\n" diff --git a/src/arch/x86/init/romstage.ld b/src/arch/x86/init/romstage.ld index 7b9cb6a..db1c8ee 100644 --- a/src/arch/x86/init/romstage.ld +++ b/src/arch/x86/init/romstage.ld @@ -53,6 +53,11 @@ SECTIONS .car.data . (NOLOAD) : { _car_data_start = .; *(.car.global_data); +#if IS_ENABLED(CONFIG_HAS_PRECBMEM_TIMESTAMP_REGION) + _timestamp = .; + . = . + 0x100; + _etimestamp = .; +#endif _car_data_end = .; /* The preram cbmem console area comes last to take advantage * of a zero-sized array to hold the memconsole contents. diff --git a/src/include/timestamp.h b/src/include/timestamp.h index a248ea4..0a13209 100644 --- a/src/include/timestamp.h +++ b/src/include/timestamp.h @@ -89,10 +89,35 @@ enum timestamp_id { };
#if CONFIG_COLLECT_TIMESTAMPS && (CONFIG_EARLY_CBMEM_INIT || !defined(__PRE_RAM__)) +/* + * Order of usage of timestamp library is: + * Call timestamp_early_init / timestamp_init to set base time before any + * timestamp_add function is called. timestamp_early_init also ensures that the + * cache is valid in _timestamp region. + * After this, timestamp_add / timestamp_add_now can be used to record + * timestamps. Sync will be automatically taken care of by cbmem_initialize. + */ +/* + * Initialize the cache to a valid state and set the base time. + * This function is used before DRAM is set up so that the timestamp cache can + * be initialized in _timestamp region. + * Both, timestamp_init and timestamp_early_init reset the cbmem state to + * "timestamp table reset required". Thus, whenever a timestamp_add or + * timestamp_sync is done to add new entries into the cbmem timestamp table, it + * first resets the table to 0 entries. + */ +void timestamp_early_init(uint64_t base); +/* Initialize the base time for timestamps and mark cache as valid. */ void timestamp_init(uint64_t base); +/* + * Add a new timestamp. Depending on cbmem is available or not, this timestamp + * will be stored to cbmem / timestamp cache. + */ void timestamp_add(enum timestamp_id id, uint64_t ts_time); +/* Calls timestamp_add with current timestamp. */ void timestamp_add_now(enum timestamp_id id); #else +#define timestamp_early_init(base) #define timestamp_init(base) #define timestamp_add(id, time) #define timestamp_add_now(id) diff --git a/src/lib/timestamp.c b/src/lib/timestamp.c index 0c41ea2..f316289 100644 --- a/src/lib/timestamp.c +++ b/src/lib/timestamp.c @@ -17,10 +17,12 @@ * Foundation, Inc. */
+#include <assert.h> #include <stddef.h> #include <stdint.h> #include <console/console.h> #include <cbmem.h> +#include <symbols.h> #include <timer.h> #include <timestamp.h> #include <arch/early_variables.h> @@ -29,12 +31,70 @@
#define MAX_TIMESTAMPS 60
-static struct timestamp_table* ts_table_p CAR_GLOBAL = NULL; -static uint64_t ts_basetime CAR_GLOBAL = 0; +#define MAX_TIMESTAMP_CACHE 16
-static void timestamp_stash(enum timestamp_id id, uint64_t ts_time); +struct __attribute__((__packed__)) timestamp_cache { + uint16_t cache_state; + uint16_t cbmem_state; + struct timestamp_table table; + struct timestamp_entry entries[MAX_TIMESTAMP_CACHE]; +};
-static void timestamp_real_init(uint64_t base) +#define USE_TIMESTAMP_REGION \ + (IS_ENABLED(CONFIG_HAS_PRECBMEM_TIMESTAMP_REGION) && \ + defined(__PRE_RAM__)) + +#define USE_LOCAL_TIMESTAMP_CACHE (!defined(__PRE_RAM__)) + +#define HAS_CBMEM \ + (defined(__ROMSTAGE__) || defined(__RAMSTAGE__)) + +#if USE_LOCAL_TIMESTAMP_CACHE +static struct timestamp_cache timestamp_cache __attribute__((unused)); +#endif + +enum { + TIMESTAMP_CACHE_UNINITIALIZED = 0, + TIMESTAMP_CACHE_INITIALIZED, + TIMESTAMP_CACHE_NOT_NEEDED, +}; + +enum { + TIMESTAMP_CBMEM_RESET_NOT_REQD = 0, + TIMESTAMP_CBMEM_RESET_REQD, +}; + +static void timestamp_cache_init(struct timestamp_cache *ts_cache, + uint64_t base, uint16_t cbmem_state) +{ + ts_cache->table.num_entries = 0; + ts_cache->table.max_entries = MAX_TIMESTAMP_CACHE; + ts_cache->table.base_time = base; + ts_cache->cache_state = TIMESTAMP_CACHE_INITIALIZED; + ts_cache->cbmem_state = cbmem_state; +} + +static struct timestamp_cache *timestamp_cache_get(void) +{ + struct timestamp_cache *ts_cache = NULL; + +#if IS_ENABLED(CONFIG_HAS_PRECBMEM_TIMESTAMP_REGION) + if (_timestamp_size < sizeof(*ts_cache)) + BUG(); + ts_cache = car_get_var_ptr((void *)_timestamp); +#elif USE_LOCAL_TIMESTAMP_CACHE + ts_cache = ×tamp_cache; +#endif + + if (ts_cache && ts_cache->cache_state == TIMESTAMP_CACHE_UNINITIALIZED) + timestamp_cache_init(ts_cache, 0, + TIMESTAMP_CBMEM_RESET_NOT_REQD); + + return ts_cache; +} + +#if HAS_CBMEM +static struct timestamp_table *timestamp_alloc_cbmem_table(void) { struct timestamp_table* tst;
@@ -43,14 +103,15 @@ static void timestamp_real_init(uint64_t base) MAX_TIMESTAMPS * sizeof(struct timestamp_entry));
if (!tst) - return; + return NULL;
- tst->base_time = base; + tst->base_time = 0; tst->max_entries = MAX_TIMESTAMPS; tst->num_entries = 0;
- car_set_var(ts_table_p, tst); + return tst; } +#endif
/* Determine if one should proceed into timestamp code. This is for protecting * systems that have multiple processors running in romstage -- namely AMD @@ -64,97 +125,167 @@ static int timestamp_should_run(void) return 1; }
-void timestamp_add(enum timestamp_id id, uint64_t ts_time) +static struct timestamp_table *timestamp_table_get(void) { - struct timestamp_entry *tse; - struct timestamp_table *ts_table = NULL; + MAYBE_STATIC struct timestamp_table *ts_table = NULL; + struct timestamp_cache *ts_cache;
if (!timestamp_should_run()) - return; + return NULL;
- ts_table = car_get_var(ts_table_p); - if (!ts_table) { - timestamp_stash(id, ts_time); - return; + ts_cache = timestamp_cache_get(); + + if (ts_cache == NULL) { +#if HAS_CBMEM + ts_table = cbmem_find(CBMEM_ID_TIMESTAMP); +#endif + return ts_table; } - if (ts_table->num_entries == ts_table->max_entries) + + if (ts_cache->cache_state != TIMESTAMP_CACHE_NOT_NEEDED) + return &ts_cache->table; + +#if HAS_CBMEM + if (ts_cache->cbmem_state == TIMESTAMP_CBMEM_RESET_REQD) { + ts_table = timestamp_alloc_cbmem_table(); + ts_cache->cbmem_state = TIMESTAMP_CBMEM_RESET_NOT_REQD; + } + + if (!ts_table) + ts_table = cbmem_find(CBMEM_ID_TIMESTAMP); +#endif + + return ts_table; +} + +static void timestamp_add_table_entry(struct timestamp_table *ts_table, + enum timestamp_id id, uint64_t ts_time) +{ + struct timestamp_entry *tse; + + if (ts_table->num_entries == ts_table->max_entries) { + printk(BIOS_ERR, "ERROR: Timestamp table full\n"); return; + }
tse = &ts_table->entries[ts_table->num_entries++]; tse->entry_id = id; tse->entry_stamp = ts_time - ts_table->base_time; }
-void timestamp_add_now(enum timestamp_id id) +static void timestamp_sync(void) { - timestamp_add(id, timestamp_get()); -} + uint32_t i;
-#define MAX_TIMESTAMP_CACHE 8 -struct timestamp_cache { - enum timestamp_id id; - uint64_t time; -} timestamp_cache[MAX_TIMESTAMP_CACHE] CAR_GLOBAL; + struct timestamp_cache *ts_cache; + struct timestamp_table *ts_cache_table; + struct timestamp_table *ts_cbmem_table = NULL;
-static int timestamp_entries CAR_GLOBAL = 0; + ts_cache = timestamp_cache_get();
-/** - * timestamp_stash() allows to temporarily cache timestamps. - * This is needed when timestamping before the CBMEM area - * is initialized. The function timestamp_do_sync() is used to - * write the timestamps to the CBMEM area and this is done as - * part of CAR migration for romstage, and in ramstage main(). - */ + /* No timestamp cache found */ + if (ts_cache == NULL) { + printk(BIOS_ERR, "ERROR: No timestamp cache found\n"); + return; + }
-static void timestamp_stash(enum timestamp_id id, uint64_t ts_time) -{ - struct timestamp_cache *ts_cache = car_get_var(timestamp_cache); - int ts_entries = car_get_var(timestamp_entries); + ts_cache_table = &ts_cache->table; + +#if HAS_CBMEM + ts_cbmem_table = cbmem_find(CBMEM_ID_TIMESTAMP); + + if ((ts_cache->cbmem_state == TIMESTAMP_CBMEM_RESET_REQD) || + (ts_cbmem_table == NULL)) + ts_cbmem_table = timestamp_alloc_cbmem_table(); +#endif + + if (ts_cbmem_table == NULL) { + printk(BIOS_ERR, "ERROR: No timestamp table allocated\n"); + return; + } + + if (ts_cbmem_table == ts_cache_table) { + printk(BIOS_ERR, "ERROR: Table error to sync timestamps\n"); + return; + }
- if (ts_entries >= MAX_TIMESTAMP_CACHE) { - printk(BIOS_ERR, "ERROR: failed to add timestamp to cache\n"); + if (ts_cache->cache_state == TIMESTAMP_CACHE_NOT_NEEDED) { + printk(BIOS_INFO, "Timestamp cache already synced\n"); return; } - ts_cache[ts_entries].id = id; - ts_cache[ts_entries].time = ts_time; - car_set_var(timestamp_entries, ++ts_entries); + + ts_cache->cache_state = TIMESTAMP_CACHE_NOT_NEEDED; + ts_cache->cbmem_state = TIMESTAMP_CBMEM_RESET_NOT_REQD; + + /* + * There can be two cases for timestamp sync: + * 1. Newly added cbmem_table will have base_time of 0. Thus, no + * adjusments are needed for the timestamps being added from cache to + * cbmem table. + * 2. Timestamps added to cache before ramstage: In this case, the + * base_time in cache table would be 0 and add_table_entry will take + * care of subtracting the appropriate base_time. + */ + for (i = 0; i < ts_cache_table->num_entries; i++) { + struct timestamp_entry *tse = &ts_cache_table->entries[i]; + timestamp_add_table_entry(ts_cbmem_table, tse->entry_id, + tse->entry_stamp); + } + + ts_cache_table->num_entries = 0; + /* Freshly added cbmem table has base_time 0. Inherit cache base_time */ + if (ts_cbmem_table->base_time == 0) + ts_cbmem_table->base_time = ts_cache_table->base_time; }
-static void timestamp_do_sync(void) +void timestamp_early_init(uint64_t base) { - struct timestamp_cache *ts_cache = car_get_var(timestamp_cache); - int ts_entries = car_get_var(timestamp_entries); - - int i; - for (i = 0; i < ts_entries; i++) - timestamp_add(ts_cache[i].id, ts_cache[i].time); - car_set_var(timestamp_entries, 0); + struct timestamp_cache *ts_cache; + ts_cache = timestamp_cache_get(); + if (ts_cache == NULL) + BUG(); + timestamp_cache_init(ts_cache, base, TIMESTAMP_CBMEM_RESET_REQD); }
void timestamp_init(uint64_t base) { + struct timestamp_cache *ts_cache; + struct timestamp_table *tst; + if (!timestamp_should_run()) return;
-#ifdef __PRE_RAM__ - /* Copy of basetime, it is too early for CBMEM. */ - car_set_var(ts_basetime, base); -#else - struct timestamp_table *tst = NULL; + ts_cache = timestamp_cache_get();
- /* Locate and use an already existing table. */ - if (!IS_ENABLED(CONFIG_LATE_CBMEM_INIT)) - tst = cbmem_find(CBMEM_ID_TIMESTAMP); + ts_cache->cbmem_state = TIMESTAMP_CBMEM_RESET_REQD;
- if (tst) { - car_set_var(ts_table_p, tst); + tst = timestamp_table_get(); + + if (!tst) { + printk(BIOS_ERR, "ERROR: No timestamp table to init\n"); return; }
- /* Copy of basetime, may be too early for CBMEM. */ - car_set_var(ts_basetime, base); - timestamp_real_init(base); -#endif + tst->base_time = base; +} + +void timestamp_add(enum timestamp_id id, uint64_t ts_time) +{ + struct timestamp_table *ts_table; + + ts_table = timestamp_table_get(); + + if (!ts_table) { + printk(BIOS_ERR, "ERROR: No timestamp table found\n"); + return; + } + + timestamp_add_table_entry(ts_table, id, ts_time); +} + +void timestamp_add_now(enum timestamp_id id) +{ + timestamp_add(id, timestamp_get()); }
static void timestamp_reinit(int is_recovery) @@ -162,14 +293,7 @@ static void timestamp_reinit(int is_recovery) if (!timestamp_should_run()) return;
-#ifdef __PRE_RAM__ - timestamp_real_init(car_get_var(ts_basetime)); -#else - if (!car_get_var(ts_table_p)) - timestamp_init(car_get_var(ts_basetime)); -#endif - if (car_get_var(ts_table_p)) - timestamp_do_sync(); + timestamp_sync(); }
/* Call timestamp_reinit CBMEM init hooks. */