[coreboot-gerrit] Patch set updated for coreboot: timestamp: add tick frequency to exported table

Aaron Durbin (adurbin@chromium.org) gerrit at coreboot.org
Mon Aug 31 05:30:10 CEST 2015


Aaron Durbin (adurbin at chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/11470

-gerrit

commit 3a405064552db36dc66dfe8c31ba0e160c9fd34e
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Sun Aug 30 21:19:55 2015 -0500

    timestamp: add tick frequency to exported table
    
    Add the timestamp tick frequency within the timestamp table so
    the cbmem utility doesn't try to figure it out on its own. Those
    paths still exist for x86 systems which don't provide tsc_freq_mhz().
    All other non-x86 systems use the monotonic timer which has a 1us
    granularity or 1MHz.
    
    One of the main reasons is that Linux is reporting
    /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq as the true
    turbo frequency on turbo enables machines. This change also fixes
    the p-state values honored in cpufreq for turbo machines in that
    turbo p-pstates were reported as 100MHz greater than nominal.
    
    BUG=chrome-os-partner:44669
    BRANCH=firmware-strago-7287.B
    TEST=Built and booted on glados. Confirmed table frequency honored.
    
    Change-Id: I763fe2d9a7b01d0ef5556e5abff36032062f5801
    Signed-off-by: Aaron Durbin <adurbin at chromium.org>
---
 src/arch/x86/timestamp.c  | 13 +++++++++++
 src/include/cpu/x86/tsc.h |  3 +--
 src/include/timestamp.h   |  5 ++++-
 src/lib/timestamp.c       | 10 +++++++++
 util/cbmem/cbmem.c        | 57 ++++++++++++++++++++++++++---------------------
 5 files changed, 60 insertions(+), 28 deletions(-)

diff --git a/src/arch/x86/timestamp.c b/src/arch/x86/timestamp.c
index 9df505a..d308146 100644
--- a/src/arch/x86/timestamp.c
+++ b/src/arch/x86/timestamp.c
@@ -24,3 +24,16 @@ uint64_t timestamp_get(void)
 {
 	return rdtscll();
 }
+
+unsigned long __attribute__((weak)) tsc_freq_mhz(void)
+{
+	/* Default to not knowing TSC frequency. cbmem will have to fallback
+	 * on trying to determine it in userspace. */
+	return 0;
+}
+
+int timestamp_tick_freq_mhz(void)
+{
+	/* Chipsets that have a constant TSC provide this value correctly. */
+	return tsc_freq_mhz();
+}
diff --git a/src/include/cpu/x86/tsc.h b/src/include/cpu/x86/tsc.h
index 71d253b..5cf4644 100644
--- a/src/include/cpu/x86/tsc.h
+++ b/src/include/cpu/x86/tsc.h
@@ -60,8 +60,7 @@ static inline uint64_t tsc_to_uint64(tsc_t tstamp)
 }
 #endif
 
-#if CONFIG_TSC_CONSTANT_RATE
+/* Provided by CPU/chipset code for the TSC rate in MHz. */
 unsigned long tsc_freq_mhz(void);
-#endif
 
 #endif /* CPU_X86_TSC_H */
diff --git a/src/include/timestamp.h b/src/include/timestamp.h
index 54d69ce..be33b0a 100644
--- a/src/include/timestamp.h
+++ b/src/include/timestamp.h
@@ -29,7 +29,8 @@ struct timestamp_entry {
 
 struct timestamp_table {
 	uint64_t	base_time;
-	uint32_t	max_entries;
+	uint16_t	max_entries;
+	uint16_t	tick_freq_mhz;
 	uint32_t	num_entries;
 	struct timestamp_entry entries[0]; /* Variable number of entries */
 } __attribute__((packed));
@@ -114,5 +115,7 @@ void timestamp_add_now(enum timestamp_id id);
 /* Implemented by the architecture code */
 uint64_t timestamp_get(void);
 uint64_t get_initial_timestamp(void);
+/* Returns timestamp tick frequency in MHz. */
+int timestamp_tick_freq_mhz(void);
 
 #endif
diff --git a/src/lib/timestamp.c b/src/lib/timestamp.c
index ca25093..21b3d29 100644
--- a/src/lib/timestamp.c
+++ b/src/lib/timestamp.c
@@ -278,6 +278,10 @@ static void timestamp_sync_cache_to_cbmem(int is_recovery)
 	if (ts_cbmem_table->base_time == 0)
 		ts_cbmem_table->base_time = ts_cache_table->base_time;
 
+	/* Seed the timestamp tick frequency in ramstage. */
+	if (ENV_RAMSTAGE)
+		ts_cbmem_table->tick_freq_mhz = timestamp_tick_freq_mhz();
+
 	/* Cache no longer required. */
 	ts_cache_table->num_entries = 0;
 	ts_cache->cache_state = TIMESTAMP_CACHE_NOT_NEEDED;
@@ -299,3 +303,9 @@ uint64_t  __attribute__((weak)) timestamp_get(void)
 
 	return mono_time_diff_microseconds(&t1, &t2);
 }
+
+/* Like timestamp_get() above this matches up with microsecond granularity. */
+int __attribute__((weak)) timestamp_tick_freq_mhz(void)
+{
+	return 1;
+}
diff --git a/util/cbmem/cbmem.c b/util/cbmem/cbmem.c
index 6526384..4f3dd1f 100644
--- a/util/cbmem/cbmem.c
+++ b/util/cbmem/cbmem.c
@@ -304,7 +304,7 @@ static int parse_cbtable(u64 address, size_t table_size)
  * read CPU frequency from a sysfs file, return an frequency in Kilohertz as
  * an int or exit on any error.
  */
-static u64 get_cpu_freq_KHz(void)
+static unsigned long arch_tick_frquency(void)
 {
 	FILE *cpuf;
 	char freqs[100];
@@ -338,44 +338,49 @@ static u64 get_cpu_freq_KHz(void)
 		freqs, freq_file);
 	exit(1);
 }
-
-/* On x86 platforms timestamps are stored
- * in CPU cycles (from rdtsc). Hence the
- * timestamp divider is the CPU frequency
- * in MHz.
- */
-u64 arch_convert_raw_ts_entry(u64 ts)
-{
-	static u64 cpu_freq_mhz = 0;
-
-	if (!cpu_freq_mhz)
-		cpu_freq_mhz = get_cpu_freq_KHz() / 1000;
-
-	return ts / cpu_freq_mhz;
-}
-
 #elif defined(__OpenBSD__) && (defined(__i386__) || defined(__x86_64__))
-u64 arch_convert_raw_ts_entry(u64 ts)
+static unsigned long arch_tick_frquency(void)
 {
 	int mib[2] = { CTL_HW, HW_CPUSPEED };
 	static int value = 0;
 	size_t value_len = sizeof(value);
 
+	/* Return 1 MHz when sysctl fails. */
 	if ((value == 0) && (sysctl(mib, 2, &value, &value_len, NULL, 0) == -1))
-		return ts;
+		return 1;
 
-	return ts / value;
+	return value;
 }
 #else
+static unsigned long arch_tick_frquency(void)
+{
+	/* 1 MHz = 1us. */
+	return 1;
+}
+#endif
+
+static unsigned long tick_freq_mhz;
+
+static void timestamp_set_tick_freq(unsigned long table_tick_freq_mhz)
+{
+	tick_freq_mhz = table_tick_freq_mhz;
+
+	/* Honor table frequency. */
+	if (tick_freq_mhz)
+		return;
+
+	tick_freq_mhz = arch_tick_frquency();
+
+	if (!tick_freq_mhz) {
+		fprintf(stderr, "Cannot determine timestamp tick frequency.\n");
+		exit(1);
+	}
+}
 
-/* On non-x86 platforms the timestamp entries
- * are not in clock cycles but in usecs
- */
 u64 arch_convert_raw_ts_entry(u64 ts)
 {
-	return ts;
+	return ts / tick_freq_mhz;
 }
-#endif
 
 /*
  * Print an integer in 'normalized' form - with commas separating every three
@@ -521,6 +526,8 @@ static void dump_timestamps(void)
 	size = sizeof(*tst_p);
 	tst_p = map_memory_size((unsigned long)timestamps.cbmem_addr, size);
 
+	timestamp_set_tick_freq(tst_p->tick_freq_mhz);
+
 	printf("%d entries total:\n\n", tst_p->num_entries);
 	size += tst_p->num_entries * sizeof(tst_p->entries[0]);
 



More information about the coreboot-gerrit mailing list