[coreboot-gerrit] Patch set updated for coreboot: timestamp: add generic cache region

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Tue Jul 7 19:41:14 CEST 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10790

-gerrit

commit 4e559a6e9db6568c31c4d40b3e6268e211e7051b
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Fri Jul 3 17:04:21 2015 -0500

    timestamp: add generic cache region
    
    In order to accommodate tracking timestamps in all the
    __PRE_RAM__ stages (bootblock, verstage, romstage, etc)
    of a platform one needs to provide a way to specify
    a persistent region of SRAM or cache-as-ram to store
    the timestamps until cbmem comes online. Provide that
    infrastructure.
    
    Based on original patches from chromium.org:
    Original-Change-Id: I4d78653c0595523eeeb02115423e7fecceea5e1e
    Original-Signed-off-by: Furquan Shaikh <furquan at google.com>
    Original-Reviewed-on: https://chromium-review.googlesource.com/223348
    Original-Reviewed-by: Aaron Durbin <adurbin at chromium.org>
    Original-Reviewed-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Tested-by: Furquan Shaikh <furquan at chromium.org>
    Original-Commit-Queue: Furquan Shaikh <furquan at chromium.org>
    
    Original-Change-Id: Ie5ffda3112d626068bd1904afcc5a09bc4916d16
    Original-Signed-off-by: Furquan Shaikh <furquan at google.com>
    Original-Reviewed-on: https://chromium-review.googlesource.com/224024
    Original-Reviewed-by: Furquan Shaikh <furquan at chromium.org>
    Original-Commit-Queue: Furquan Shaikh <furquan at chromium.org>
    Original-Tested-by: Furquan Shaikh <furquan at chromium.org>
    
    Change-Id: I8779526136e89ae61a6f177ce5c74a6530469ae1
    Signed-off-by: Aaron Durbin <adurbin at chromium.org>
---
 src/Kconfig                   |   9 ++
 src/arch/x86/init/romstage.ld |   5 +
 src/include/memlayout.h       |   3 +
 src/include/symbols.h         |   4 +
 src/include/timestamp.h       |  13 +++
 src/lib/timestamp.c           | 261 +++++++++++++++++++++++++++++-------------
 6 files changed, 216 insertions(+), 79 deletions(-)

diff --git a/src/Kconfig b/src/Kconfig
index 269f7d2..84523a2 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -200,6 +200,15 @@ config COLLECT_TIMESTAMPS
 	  Make coreboot create a table of timer-ID/timer-value pairs to
 	  allow measuring time spent at different phases of the boot process.
 
+config HAS_PRECBMEM_TIMESTAMP_REGION
+	bool "Timestamp region exists for pre-cbmem timestamps"
+	default y if ARCH_ROMSTAGE_X86_32 && CACHE_AS_RAM
+	depends on COLLECT_TIMESTAMPS
+	help
+	  A separate region is maintained to allow storing of timestamps before
+	  cbmem comes up. This is useful for storing timestamps across different
+	  stage boundaries.
+
 config USE_BLOBS
 	bool "Allow use of binary-only repository"
 	default n
diff --git a/src/arch/x86/init/romstage.ld b/src/arch/x86/init/romstage.ld
index 7b9cb6a..951ca65 100644
--- a/src/arch/x86/init/romstage.ld
+++ b/src/arch/x86/init/romstage.ld
@@ -52,6 +52,11 @@ SECTIONS
 	. = CONFIG_DCACHE_RAM_BASE;
 	.car.data . (NOLOAD) : {
 		_car_data_start = .;
+#if IS_ENABLED(CONFIG_HAS_PRECBMEM_TIMESTAMP_REGION)
+		_timestamp = .;
+		. = . + 0x100;
+		_etimestamp = .;
+#endif
 		*(.car.global_data);
 		_car_data_end = .;
 		/* The preram cbmem console area comes last to take advantage
diff --git a/src/include/memlayout.h b/src/include/memlayout.h
index 2771f2f..a529628 100644
--- a/src/include/memlayout.h
+++ b/src/include/memlayout.h
@@ -47,6 +47,9 @@
 
 #define DRAM_START(addr) SYMBOL(dram, addr)
 
+#define TIMESTAMP(addr, size) \
+	REGION(timestamp, addr, size, 8)
+
 #define PRERAM_CBMEM_CONSOLE(addr, size) \
 	REGION(preram_cbmem_console, addr, size, 4)
 
diff --git a/src/include/symbols.h b/src/include/symbols.h
index 9102e82..3fbf819 100644
--- a/src/include/symbols.h
+++ b/src/include/symbols.h
@@ -28,6 +28,10 @@ extern u8 _esram[];
 
 extern u8 _dram[];
 
+extern u8 _timestamp[];
+extern u8 _etimestamp[];
+#define _timestamp_size	(_etimestamp - _timestamp)
+
 extern u8 _preram_cbmem_console[];
 extern u8 _epreram_cbmem_console[];
 #define _preram_cbmem_console_size \
diff --git a/src/include/timestamp.h b/src/include/timestamp.h
index a248ea4..54d69ce 100644
--- a/src/include/timestamp.h
+++ b/src/include/timestamp.h
@@ -89,8 +89,21 @@ enum timestamp_id {
 };
 
 #if CONFIG_COLLECT_TIMESTAMPS && (CONFIG_EARLY_CBMEM_INIT || !defined(__PRE_RAM__))
+/*
+ * timestamp_init() needs to be called once for each of these cases:
+ *    1. __PRE_RAM__ (bootblock, romstage, verstage, etc) and
+ *    2. !__PRE_RAM__ (ramstage)
+ * The latter is taken care of by the generic coreboot infrastructure so
+ * it's up to the chipset/arch to call timestamp_init() in *one* of
+ * the __PRE_RAM__ stages. If multiple calls are made timestamps will be lost.
+ */
 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_init(base)
diff --git a/src/lib/timestamp.c b/src/lib/timestamp.c
index 0c41ea2..51e63b2 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,65 @@
 
 #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 {
+	int cache_state;
+	struct timestamp_table table;
+	/* The struct timestamp_table has a 0 length array as its last field.
+	 * The  following 'entries' array serves as the storage space for the
+	 * cache. */
+	struct timestamp_entry entries[MAX_TIMESTAMP_CACHE];
+};
 
-static void timestamp_real_init(uint64_t base)
+#if (IS_ENABLED(CONFIG_HAS_PRECBMEM_TIMESTAMP_REGION) && defined(__PRE_RAM__))
+#define USE_TIMESTAMP_REGION 1
+#else
+#define USE_TIMESTAMP_REGION 0
+#endif
+
+/* The cache location will sit in BSS when in ramstage. */
+#define TIMESTAMP_CACHE_IN_BSS ENV_RAMSTAGE
+
+#define HAS_CBMEM (ENV_ROMSTAGE || ENV_RAMSTAGE)
+
+/* Storage of cache entries during ramstage prior to cbmem coming online. */
+static struct timestamp_cache timestamp_cache;
+
+enum {
+	TIMESTAMP_CACHE_UNINITIALIZED = 0,
+	TIMESTAMP_CACHE_INITIALIZED,
+	TIMESTAMP_CACHE_NOT_NEEDED,
+};
+
+static void timestamp_cache_init(struct timestamp_cache *ts_cache,
+				 uint64_t base)
+{
+	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;
+}
+
+static struct timestamp_cache *timestamp_cache_get(void)
+{
+	struct timestamp_cache *ts_cache = NULL;
+
+	if (TIMESTAMP_CACHE_IN_BSS) {
+		ts_cache = &timestamp_cache;
+	} else if (USE_TIMESTAMP_REGION) {
+		if (_timestamp_size < sizeof(*ts_cache))
+			BUG();
+		ts_cache = car_get_var_ptr((void *)_timestamp);
+	}
+
+	if (ts_cache && ts_cache->cache_state == TIMESTAMP_CACHE_UNINITIALIZED)
+		timestamp_cache_init(ts_cache, 0);
+
+	return ts_cache;
+}
+
+static struct timestamp_table *timestamp_alloc_cbmem_table(void)
 {
 	struct timestamp_table* tst;
 
@@ -43,13 +98,13 @@ 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;
 }
 
 /* Determine if one should proceed into timestamp code. This is for protecting
@@ -64,117 +119,165 @@ 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;
+	if (ts_table != NULL)
+		return ts_table;
+
+	ts_cache = timestamp_cache_get();
+
+	if (ts_cache == NULL) {
+		if (HAS_CBMEM)
+			ts_table = cbmem_find(CBMEM_ID_TIMESTAMP);
+		return ts_table;
 	}
-	if (ts_table->num_entries == ts_table->max_entries)
+
+	/* Cache is required. */
+	if (ts_cache->cache_state != TIMESTAMP_CACHE_NOT_NEEDED)
+		return &ts_cache->table;
+
+	/* Cache shouldn't be used but there's no backing store. */
+	if (!HAS_CBMEM)
+		return NULL;
+
+	ts_table = cbmem_find(CBMEM_ID_TIMESTAMP);
+
+	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)
+void timestamp_add(enum timestamp_id id, uint64_t ts_time)
 {
-	timestamp_add(id, timestamp_get());
-}
-
-#define MAX_TIMESTAMP_CACHE 8
-struct timestamp_cache {
-	enum timestamp_id id;
-	uint64_t time;
-} timestamp_cache[MAX_TIMESTAMP_CACHE] CAR_GLOBAL;
-
-static int timestamp_entries CAR_GLOBAL = 0;
-
-/**
- * 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().
- */
+	struct timestamp_table *ts_table;
 
-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_table = timestamp_table_get();
 
-	if (ts_entries >= MAX_TIMESTAMP_CACHE) {
-		printk(BIOS_ERR, "ERROR: failed to add timestamp to cache\n");
+	if (!ts_table) {
+		printk(BIOS_ERR, "ERROR: No timestamp table found\n");
 		return;
 	}
-	ts_cache[ts_entries].id = id;
-	ts_cache[ts_entries].time = ts_time;
-	car_set_var(timestamp_entries, ++ts_entries);
+
+	timestamp_add_table_entry(ts_table, id, ts_time);
 }
 
-static void timestamp_do_sync(void)
+void timestamp_add_now(enum timestamp_id id)
 {
-	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);
+	timestamp_add(id, timestamp_get());
 }
 
 void timestamp_init(uint64_t base)
 {
+	struct timestamp_cache *ts_cache;
+
 	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;
-
-	/* Locate and use an already existing table. */
-	if (!IS_ENABLED(CONFIG_LATE_CBMEM_INIT))
-		tst = cbmem_find(CBMEM_ID_TIMESTAMP);
+	ts_cache = timestamp_cache_get();
 
-	if (tst) {
-		car_set_var(ts_table_p, tst);
+	if (!ts_cache) {
+		printk(BIOS_ERR, "ERROR: No timestamp cache to init\n");
 		return;
 	}
 
-	/* Copy of basetime, may be too early for CBMEM. */
-	car_set_var(ts_basetime, base);
-	timestamp_real_init(base);
-#endif
+	timestamp_cache_init(ts_cache, base);
 }
 
-static void timestamp_reinit(int is_recovery)
+static void timestamp_sync_cache_to_cbmem(int is_recovery)
 {
+	uint32_t i;
+	struct timestamp_cache *ts_cache;
+	struct timestamp_table *ts_cache_table;
+	struct timestamp_table *ts_cbmem_table = NULL;
+
 	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();
+	ts_cache = timestamp_cache_get();
+
+	/* No timestamp cache found */
+	if (ts_cache == NULL) {
+		printk(BIOS_ERR, "ERROR: No timestamp cache found\n");
+		return;
+	}
+
+	ts_cache_table = &ts_cache->table;
+
+	/* cbmem is being recovered. */
+	if (is_recovery) {
+		/* x86 resume path expects timestamps to be reset. */
+		if (IS_ENABLED(CONFIG_ARCH_ROMSTAGE_X86_32) && ENV_ROMSTAGE)
+			ts_cbmem_table = timestamp_alloc_cbmem_table();
+		else {
+			/* Find existing table in cbmem. */
+			ts_cbmem_table = cbmem_find(CBMEM_ID_TIMESTAMP);
+			/* No existing timestamp table. */
+			if (ts_cbmem_table == NULL)
+				ts_cbmem_table = timestamp_alloc_cbmem_table();
+		}
+	} else
+		/* First time sync. Add new table. */
+		ts_cbmem_table = timestamp_alloc_cbmem_table();
+
+	if (ts_cbmem_table == NULL) {
+		printk(BIOS_ERR, "ERROR: No timestamp table allocated\n");
+		return;
+	}
+
+	/*
+	 * There's no need to worry about the base_time fields being out of
+	 * sync because the following configurations are used/supported:
+	 *
+	 * 1. CONFIG_HAS_PRECBMEM_TIMESTAMP_REGION is enabled. This
+	 *    implies CONFIG_EARLY_CBMEM_INIT so once cbmem comes
+	 *    online we sync the timestamps to the cbmem storage while
+	 *    running in romstage. In ramstage the cbmem area is
+	 *    recovered and utilized.
+	 *
+	 * 2. CONFIG_LATE_CBMEM_INIT (!CONFIG_EARLY_CBMEM_INIT) is
+	 *    being used. That means the only cache that exists is
+	 *    in ramstage. Once cbmem comes online in ramstage those
+	 *    values are sync'd over.
+	 *
+	 * Any other combinations will result in inconsistent base_time
+	 * values including bizarre timestamp values.
+	 */
+	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);
+	}
+
+	/* 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;
+
+	/* Cache no longer required. */
+	ts_cache_table->num_entries = 0;
+	ts_cache->cache_state = TIMESTAMP_CACHE_NOT_NEEDED;
 }
 
-/* Call timestamp_reinit CBMEM init hooks. */
-ROMSTAGE_CBMEM_INIT_HOOK(timestamp_reinit)
-RAMSTAGE_CBMEM_INIT_HOOK(timestamp_reinit)
+ROMSTAGE_CBMEM_INIT_HOOK(timestamp_sync_cache_to_cbmem)
+RAMSTAGE_CBMEM_INIT_HOOK(timestamp_sync_cache_to_cbmem)
 
 /* Provide default timestamp implementation using monotonic timer. */
 uint64_t  __attribute__((weak)) timestamp_get(void)



More information about the coreboot-gerrit mailing list