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 ab6ba3d10bf91482c7f1bfb294cb92b6748373a0 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 | 259 ++++++++++++++++++++++++++++++------------ 4 files changed, 221 insertions(+), 71 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..a2301fb 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 setup 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..c6799ac 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; +#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 USE_LOCAL_TIMESTAMP_CACHE + ts_cache = ×tamp_cache; +#elif IS_ENABLED(CONFIG_HAS_PRECBMEM_TIMESTAMP_REGION) + if (_timestamp_size < sizeof(*ts_cache)) + BUG(); + ts_cache = car_get_var_ptr((void *)_timestamp); +#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,162 @@ 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_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->num_entries == ts_table->max_entries) + + 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: Dropped a timestamp entry\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; + + struct timestamp_cache *ts_cache; + struct timestamp_table *ts_cache_table; + struct timestamp_table *ts_cbmem_table = NULL; + + ts_cache = timestamp_cache_get(); + + /* No timestamp cache found */ + if (ts_cache == NULL) { + printk(BIOS_ERR, "ERROR: No timestamp cache found\n"); + return; }
-#define MAX_TIMESTAMP_CACHE 8 -struct timestamp_cache { - enum timestamp_id id; - uint64_t time; -} timestamp_cache[MAX_TIMESTAMP_CACHE] CAR_GLOBAL; + ts_cache_table = &ts_cache->table;
-static int timestamp_entries CAR_GLOBAL = 0; +#if HAS_CBMEM + ts_cbmem_table = cbmem_find(CBMEM_ID_TIMESTAMP);
-/** - * 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(). - */ + if ((ts_cache->cbmem_state == TIMESTAMP_CBMEM_RESET_REQD) || + (ts_cbmem_table == NULL)) + ts_cbmem_table = timestamp_alloc_cbmem_table(); +#endif
-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); + if (ts_cbmem_table == NULL) { + printk(BIOS_ERR, "ERROR: No timestamp table allocated\n"); + return; + }
- if (ts_entries >= MAX_TIMESTAMP_CACHE) { - printk(BIOS_ERR, "ERROR: failed to add timestamp to cache\n"); + if (ts_cbmem_table == ts_cache_table) { + printk(BIOS_ERR, "ERROR: Table error to sync timestamps\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); }
-static void timestamp_do_sync(void) -{ - struct timestamp_cache *ts_cache = car_get_var(timestamp_cache); - int ts_entries = car_get_var(timestamp_entries); + 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; +}
- 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); +void timestamp_early_init(uint64_t base) +{ + 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(); + + ts_cache->cbmem_state = TIMESTAMP_CBMEM_RESET_REQD; + + tst = timestamp_table_get(); + + if (!tst) { + printk(BIOS_ERR, "ERROR: No timestamp table to init\n"); + return; + } + + tst->base_time = base; +} + +void timestamp_add(enum timestamp_id id, uint64_t ts_time) +{ + struct timestamp_table *ts_table;
- /* Locate and use an already existing table. */ - if (!IS_ENABLED(CONFIG_LATE_CBMEM_INIT)) - tst = cbmem_find(CBMEM_ID_TIMESTAMP); + ts_table = timestamp_table_get();
- if (tst) { - car_set_var(ts_table_p, tst); + if (!ts_table) { + printk(BIOS_ERR, "ERROR: No timestamp table found\n"); return; }
- /* Copy of basetime, may be too early for CBMEM. */ - car_set_var(ts_basetime, base); - timestamp_real_init(base); -#endif + 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 +288,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. */