coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
timestamp.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <assert.h>
4 #include <stdint.h>
5 #include <console/console.h>
6 #include <cbmem.h>
7 #include <symbols.h>
8 #include <timer.h>
9 #include <timestamp.h>
10 #include <smp/node.h>
11 
12 #define MAX_TIMESTAMPS 192
13 
14 /* This points to the active timestamp_table and can change within a stage
15  as CBMEM comes available. */
17 
18 static void timestamp_cache_init(struct timestamp_table *ts_cache,
19  uint64_t base)
20 {
21  ts_cache->num_entries = 0;
22  ts_cache->base_time = base;
23  ts_cache->max_entries = (REGION_SIZE(timestamp) -
25  / sizeof(struct timestamp_entry);
26 }
27 
29 {
30  struct timestamp_table *ts_cache = NULL;
31 
33  return NULL;
34 
35  if (REGION_SIZE(timestamp) < sizeof(*ts_cache)) {
36  BUG();
37  } else {
38  ts_cache = (void *)_timestamp;
39  }
40 
41  return ts_cache;
42 }
43 
45 {
46  struct timestamp_table *tst;
47 
49  sizeof(struct timestamp_table) +
50  MAX_TIMESTAMPS * sizeof(struct timestamp_entry));
51 
52  if (!tst)
53  return NULL;
54 
55  tst->base_time = 0;
57  tst->num_entries = 0;
58 
59  return tst;
60 }
61 
62 /* Determine if one should proceed into timestamp code. This is for protecting
63  * systems that have multiple processors running in romstage -- namely AMD
64  * based x86 platforms. */
65 static int timestamp_should_run(void)
66 {
67  /*
68  * Only check boot_cpu() in other stages than
69  * ENV_PAYLOAD_LOADER on x86.
70  */
71  if ((!ENV_PAYLOAD_LOADER && ENV_X86) && !boot_cpu())
72  return 0;
73 
74  return 1;
75 }
76 
78 {
79  if (glob_ts_table)
80  return glob_ts_table;
81 
83 
84  return glob_ts_table;
85 }
86 
87 static void timestamp_table_set(struct timestamp_table *ts)
88 {
89  glob_ts_table = ts;
90 }
91 
92 static const char *timestamp_name(enum timestamp_id id)
93 {
94  int i;
95 
96  for (i = 0; i < ARRAY_SIZE(timestamp_ids); i++) {
97  if (timestamp_ids[i].id == id)
98  return timestamp_ids[i].name;
99  }
100 
101  return "Unknown timestamp ID";
102 }
103 
104 static void timestamp_add_table_entry(struct timestamp_table *ts_table,
105  enum timestamp_id id, int64_t ts_time)
106 {
107  struct timestamp_entry *tse;
108 
109  if (ts_table->num_entries >= ts_table->max_entries)
110  return;
111 
112  tse = &ts_table->entries[ts_table->num_entries++];
113  tse->entry_id = id;
114  tse->entry_stamp = ts_time;
115 
116  if (ts_table->num_entries == ts_table->max_entries)
117  printk(BIOS_ERR, "Timestamp table full\n");
118 }
119 
120 void timestamp_add(enum timestamp_id id, int64_t ts_time)
121 {
122  struct timestamp_table *ts_table;
123 
124  if (!timestamp_should_run())
125  return;
126 
127  ts_table = timestamp_table_get();
128 
129  if (!ts_table) {
130  printk(BIOS_ERR, "No timestamp table found\n");
131  return;
132  }
133 
134  ts_time -= ts_table->base_time;
135  timestamp_add_table_entry(ts_table, id, ts_time);
136 
137  if (CONFIG(TIMESTAMPS_ON_CONSOLE))
138  printk(BIOS_INFO, "Timestamp - %s: %lld\n", timestamp_name(id), ts_time);
139 }
140 
142 {
144 }
145 
147 {
148  struct timestamp_table *ts_cache;
149 
151 
152  if (!timestamp_should_run())
153  return;
154 
155  ts_cache = timestamp_cache_get();
156 
157  if (!ts_cache) {
158  printk(BIOS_ERR, "No timestamp cache to init\n");
159  return;
160  }
161 
162  timestamp_cache_init(ts_cache, base);
163  timestamp_table_set(ts_cache);
164 }
165 
166 static void timestamp_sync_cache_to_cbmem(struct timestamp_table *ts_cbmem_table)
167 {
168  uint32_t i;
169  struct timestamp_table *ts_cache_table;
170 
171  ts_cache_table = timestamp_table_get();
172  if (!ts_cache_table) {
173  printk(BIOS_ERR, "No timestamp cache found\n");
174  return;
175  }
176 
177  /*
178  * There's no need to worry about the base_time fields being out of
179  * sync because only the following configuration is used/supported:
180  *
181  * Timestamps get initialized before ramstage, which implies
182  * CBMEM initialization in romstage.
183  * This requires the board to define a TIMESTAMP() region in its
184  * memlayout.ld (default on x86). The base_time from timestamp_init()
185  * (usually called from bootblock.c on most non-x86 boards) persists
186  * in that region until it gets synced to CBMEM in romstage.
187  * In ramstage, the BSS cache's base_time will be 0 until the second
188  * sync, which will adjust the timestamps in there to the correct
189  * base_time (from CBMEM) with the timestamp_add_table_entry() below.
190  *
191  * If you try to initialize timestamps before ramstage but don't define
192  * a TIMESTAMP region, all operations will fail (safely), and coreboot
193  * will behave as if timestamps collection was disabled.
194  */
195 
196  /* Inherit cache base_time. */
197  ts_cbmem_table->base_time = ts_cache_table->base_time;
198 
199  for (i = 0; i < ts_cache_table->num_entries; i++) {
200  struct timestamp_entry *tse = &ts_cache_table->entries[i];
201  timestamp_add_table_entry(ts_cbmem_table, tse->entry_id,
202  tse->entry_stamp);
203  }
204 
205  /* Cache no longer required. */
206  ts_cache_table->num_entries = 0;
207 }
208 
209 static void timestamp_reinit(int is_recovery)
210 {
211  struct timestamp_table *ts_cbmem_table;
212 
213  if (!timestamp_should_run())
214  return;
215 
216  /* First time into romstage we make a clean new table. For platforms that travel
217  through this path on resume, ARCH_X86 S3, timestamps are also reset. */
218  if (ENV_ROMSTAGE) {
219  ts_cbmem_table = timestamp_alloc_cbmem_table();
220  } else {
221  /* Find existing table in cbmem. */
222  ts_cbmem_table = cbmem_find(CBMEM_ID_TIMESTAMP);
223  }
224 
225  if (ts_cbmem_table == NULL) {
226  printk(BIOS_ERR, "No timestamp table allocated\n");
228  return;
229  }
230 
231  if (ENV_ROMSTAGE)
232  timestamp_sync_cache_to_cbmem(ts_cbmem_table);
233 
234  /* Seed the timestamp tick frequency in ENV_PAYLOAD_LOADER. */
235  if (ENV_PAYLOAD_LOADER)
236  ts_cbmem_table->tick_freq_mhz = timestamp_tick_freq_mhz();
237 
238  timestamp_table_set(ts_cbmem_table);
239 }
240 
242 {
243  uint32_t i;
244  struct timestamp_table *ts_table;
245 
246  if (!timestamp_should_run())
247  return;
248 
249  if (N == 0 || M == 0)
250  return;
251 
252  ts_table = timestamp_table_get();
253 
254  /* No timestamp table found */
255  if (ts_table == NULL) {
256  printk(BIOS_ERR, "No timestamp table found\n");
257  return;
258  }
259 
260  ts_table->base_time /= M;
261  ts_table->base_time *= N;
262  for (i = 0; i < ts_table->num_entries; i++) {
263  struct timestamp_entry *tse = &ts_table->entries[i];
264  tse->entry_stamp /= M;
265  tse->entry_stamp *= N;
266  }
267 }
268 
269 /*
270  * Get the time in microseconds since boot (or more precise: since timestamp
271  * table was initialized).
272  */
274 {
275  struct timestamp_table *ts = timestamp_table_get();
276 
277  if (ts == NULL || ts->tick_freq_mhz == 0)
278  return 0;
279  return (timestamp_get() - ts->base_time) / ts->tick_freq_mhz;
280 }
281 
285 
286 /* Provide default timestamp implementation using monotonic timer. */
288 {
289  struct mono_time t1, t2;
290 
291  if (!CONFIG(HAVE_MONOTONIC_TIMER))
292  return 0;
293 
294  mono_time_set_usecs(&t1, 0);
295  timer_monotonic_get(&t2);
296 
297  return mono_time_diff_microseconds(&t1, &t2);
298 }
299 
300 /* Like timestamp_get() above this matches up with microsecond granularity. */
302 {
303  return 1;
304 }
uint64_t timestamp_get(void)
Definition: timestamp.c:6
int timestamp_tick_freq_mhz(void)
Definition: timestamp.c:11
void timer_monotonic_get(struct mono_time *mt)
Definition: arch_timer.c:6
#define BUG()
Definition: assert.h:65
#define assert(statement)
Definition: assert.h:74
#define ARRAY_SIZE(a)
Definition: helpers.h:12
#define offsetof(TYPE, MEMBER)
Definition: helpers.h:84
void * cbmem_add(u32 id, u64 size)
Definition: imd_cbmem.c:144
void * cbmem_find(u32 id)
Definition: imd_cbmem.c:166
#define ROMSTAGE_CBMEM_INIT_HOOK(init_fn_)
Definition: cbmem.h:134
#define CBMEM_ID_TIMESTAMP
Definition: cbmem_id.h:62
int boot_cpu(void)
Definition: psp.c:5
#define printk(level,...)
Definition: stdlib.h:16
@ CONFIG
Definition: dsi_common.h:201
POSTCAR_CBMEM_INIT_HOOK(migrate_ehci_debug)
RAMSTAGE_CBMEM_INIT_HOOK(migrate_ehci_debug)
#define REGION_SIZE(name)
Definition: symbols.h:10
static void mono_time_set_usecs(struct mono_time *mt, long us)
Definition: timer.h:53
static long mono_time_diff_microseconds(const struct mono_time *t1, const struct mono_time *t2)
Definition: timer.h:105
static int timestamp_should_run(void)
Definition: timestamp.c:65
void timestamp_add_now(enum timestamp_id id)
Definition: timestamp.c:141
static struct timestamp_table * timestamp_cache_get(void)
Definition: timestamp.c:28
static struct timestamp_table * timestamp_table_get(void)
Definition: timestamp.c:77
static void timestamp_table_set(struct timestamp_table *ts)
Definition: timestamp.c:87
void timestamp_rescale_table(uint16_t N, uint16_t M)
Definition: timestamp.c:241
uint32_t get_us_since_boot(void)
Definition: timestamp.c:273
static void timestamp_cache_init(struct timestamp_table *ts_cache, uint64_t base)
Definition: timestamp.c:18
void timestamp_add(enum timestamp_id id, int64_t ts_time)
Definition: timestamp.c:120
static const char * timestamp_name(enum timestamp_id id)
Definition: timestamp.c:92
static void timestamp_reinit(int is_recovery)
Definition: timestamp.c:209
#define MAX_TIMESTAMPS
Definition: timestamp.c:12
static struct timestamp_table * timestamp_alloc_cbmem_table(void)
Definition: timestamp.c:44
static void timestamp_sync_cache_to_cbmem(struct timestamp_table *ts_cbmem_table)
Definition: timestamp.c:166
static void timestamp_add_table_entry(struct timestamp_table *ts_table, enum timestamp_id id, int64_t ts_time)
Definition: timestamp.c:104
static struct timestamp_table * glob_ts_table
Definition: timestamp.c:16
void timestamp_init(uint64_t base)
Definition: timestamp.c:146
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define M
Definition: regs.h:327
#define ENV_X86
Definition: rules.h:248
#define ENV_PAYLOAD_LOADER
Definition: rules.h:260
#define ENV_ROMSTAGE
Definition: rules.h:149
#define ENV_ROMSTAGE_OR_BEFORE
Definition: rules.h:263
const struct smm_save_state_ops *legacy_ops __weak
Definition: save_state.c:8
uintptr_t base
Definition: uart.c:17
#define NULL
Definition: stddef.h:19
unsigned short uint16_t
Definition: stdint.h:11
unsigned int uint32_t
Definition: stdint.h:14
unsigned long long uint64_t
Definition: stdint.h:17
signed long long int64_t
Definition: stdint.h:16
int64_t entry_stamp
uint32_t entry_id
struct timestamp_entry entries[0]
static const struct timestamp_id_to_name timestamp_ids[]