aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/x86/timestamp.c13
-rw-r--r--src/include/cpu/x86/tsc.h3
-rw-r--r--src/include/timestamp.h5
-rw-r--r--src/lib/timestamp.c10
-rw-r--r--util/cbmem/cbmem.c57
5 files changed, 60 insertions, 28 deletions
diff --git a/src/arch/x86/timestamp.c b/src/arch/x86/timestamp.c
index 9df505a570..d308146070 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 71d253ba7f..5cf4644328 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 54d69ce132..be33b0ad42 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 ca25093423..21b3d29a53 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 6526384eed..0e2f125080 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_frequency(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_frequency(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_frequency(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_frequency();
+
+ 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]);