blob: db73f15a345be9240e6f5585ca82282089421fbb [file] [log] [blame]
Vadim Bendebury6f72d692011-09-21 16:12:39 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
Mario Scheithauera39aede2017-11-06 16:47:27 +01005 * Copyright (C) 2017 Siemens AG
Vadim Bendebury6f72d692011-09-21 16:12:39 -07006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Vadim Bendebury6f72d692011-09-21 16:12:39 -070015 */
16
Aaron Durbin1936f6c2015-07-03 17:04:21 -050017#include <assert.h>
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +030018#include <stddef.h>
Vadim Bendebury6f72d692011-09-21 16:12:39 -070019#include <stdint.h>
20#include <console/console.h>
21#include <cbmem.h>
Aaron Durbin1936f6c2015-07-03 17:04:21 -050022#include <symbols.h>
Aaron Durbin2daadf82015-05-01 16:48:54 -050023#include <timer.h>
Vadim Bendebury6f72d692011-09-21 16:12:39 -070024#include <timestamp.h>
Stefan Reinauerfd4f4132013-06-19 12:25:44 -070025#include <arch/early_variables.h>
Kyösti Mälkki5a5c8862014-01-26 14:41:54 +020026#include <smp/node.h>
Vadim Bendebury6f72d692011-09-21 16:12:39 -070027
Raul E Rangelb3e02202018-05-11 11:08:08 -060028#define MAX_TIMESTAMPS 192
Vadim Bendebury6f72d692011-09-21 16:12:39 -070029
Julius Werner85b1aad2016-08-19 15:17:42 -070030/* When changing this number, adjust TIMESTAMP() size ASSERT() in memlayout.h */
Julius Werner69d20c42016-02-08 19:48:11 -080031#define MAX_BSS_TIMESTAMP_CACHE 16
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +030032
Stefan Reinauer6a001132017-07-13 02:20:27 +020033struct __packed timestamp_cache {
Aaron Durbin1936f6c2015-07-03 17:04:21 -050034 struct timestamp_table table;
35 /* The struct timestamp_table has a 0 length array as its last field.
36 * The following 'entries' array serves as the storage space for the
Julius Werner69d20c42016-02-08 19:48:11 -080037 * cache when allocated in the BSS. */
38 struct timestamp_entry entries[MAX_BSS_TIMESTAMP_CACHE];
Aaron Durbin1936f6c2015-07-03 17:04:21 -050039};
Vadim Bendebury6f72d692011-09-21 16:12:39 -070040
Julius Werner8c093772016-02-09 16:09:15 -080041DECLARE_OPTIONAL_REGION(timestamp);
42
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +030043#if ENV_ROMSTAGE_OR_BEFORE
Julius Werner7e0dea62019-02-20 18:39:22 -080044#define USE_TIMESTAMP_REGION (REGION_SIZE(timestamp) > 0)
Aaron Durbin1936f6c2015-07-03 17:04:21 -050045#else
46#define USE_TIMESTAMP_REGION 0
47#endif
48
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +030049/* Currently we never store timestamp cache in .bss. */
50#define TIMESTAMP_CACHE_IN_BSS 0
Aaron Durbin1936f6c2015-07-03 17:04:21 -050051
Furquan Shaikhef179ab2019-05-18 13:47:39 -070052/*
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +030053 * Storage of cache entries prior to cbmem coming online.
Furquan Shaikhef179ab2019-05-18 13:47:39 -070054 */
Aaron Durbin1936f6c2015-07-03 17:04:21 -050055static struct timestamp_cache timestamp_cache;
56
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +030057/* This points to the active timestamp_table and can change within a stage.
58 as CBMEM comes available. */
59static struct timestamp_table *glob_ts_table CAR_GLOBAL;
Aaron Durbin1936f6c2015-07-03 17:04:21 -050060
Kyösti Mälkki3c559e72019-09-07 13:25:47 +030061static void timestamp_cache_init(struct timestamp_table *ts_cache,
Aaron Durbin1936f6c2015-07-03 17:04:21 -050062 uint64_t base)
63{
Kyösti Mälkki3c559e72019-09-07 13:25:47 +030064 ts_cache->num_entries = 0;
65 ts_cache->max_entries = MAX_BSS_TIMESTAMP_CACHE;
66 ts_cache->base_time = base;
Julius Werner69d20c42016-02-08 19:48:11 -080067
68 if (USE_TIMESTAMP_REGION)
Kyösti Mälkki3c559e72019-09-07 13:25:47 +030069 ts_cache->max_entries = (REGION_SIZE(timestamp) -
70 offsetof(struct timestamp_table, entries))
Julius Werner69d20c42016-02-08 19:48:11 -080071 / sizeof(struct timestamp_entry);
Aaron Durbin1936f6c2015-07-03 17:04:21 -050072}
73
Kyösti Mälkki3c559e72019-09-07 13:25:47 +030074static struct timestamp_table *timestamp_cache_get(void)
Aaron Durbin1936f6c2015-07-03 17:04:21 -050075{
Kyösti Mälkki3c559e72019-09-07 13:25:47 +030076 struct timestamp_table *ts_cache = NULL;
Aaron Durbin1936f6c2015-07-03 17:04:21 -050077
78 if (TIMESTAMP_CACHE_IN_BSS) {
Kyösti Mälkki3c559e72019-09-07 13:25:47 +030079 ts_cache = &timestamp_cache.table;
Aaron Durbin1936f6c2015-07-03 17:04:21 -050080 } else if (USE_TIMESTAMP_REGION) {
Julius Werner7e0dea62019-02-20 18:39:22 -080081 if (REGION_SIZE(timestamp) < sizeof(*ts_cache))
Aaron Durbin1936f6c2015-07-03 17:04:21 -050082 BUG();
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +030083 ts_cache = (void *)_timestamp;
Aaron Durbin1936f6c2015-07-03 17:04:21 -050084 }
85
Aaron Durbin1936f6c2015-07-03 17:04:21 -050086 return ts_cache;
87}
88
89static struct timestamp_table *timestamp_alloc_cbmem_table(void)
Vadim Bendebury6f72d692011-09-21 16:12:39 -070090{
Lee Leahyb2d834a2017-03-08 16:52:22 -080091 struct timestamp_table *tst;
Vadim Bendebury6f72d692011-09-21 16:12:39 -070092
93 tst = cbmem_add(CBMEM_ID_TIMESTAMP,
94 sizeof(struct timestamp_table) +
95 MAX_TIMESTAMPS * sizeof(struct timestamp_entry));
96
Kyösti Mälkkie0344172015-05-26 06:23:02 +030097 if (!tst)
Aaron Durbin1936f6c2015-07-03 17:04:21 -050098 return NULL;
Vadim Bendebury6f72d692011-09-21 16:12:39 -070099
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500100 tst->base_time = 0;
Vadim Bendebury6f72d692011-09-21 16:12:39 -0700101 tst->max_entries = MAX_TIMESTAMPS;
102 tst->num_entries = 0;
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300103
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500104 return tst;
Vadim Bendebury6f72d692011-09-21 16:12:39 -0700105}
106
Aaron Durbin2daadf82015-05-01 16:48:54 -0500107/* Determine if one should proceed into timestamp code. This is for protecting
108 * systems that have multiple processors running in romstage -- namely AMD
109 * based x86 platforms. */
110static int timestamp_should_run(void)
111{
Subrata Banik42c44c22019-05-15 20:27:04 +0530112 /*
113 * Only check boot_cpu() in other stages than
114 * ENV_PAYLOAD_LOADER on x86.
115 */
116 if ((!ENV_PAYLOAD_LOADER && CONFIG(ARCH_X86)) && !boot_cpu())
Aaron Durbin2daadf82015-05-01 16:48:54 -0500117 return 0;
118
119 return 1;
120}
121
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500122static struct timestamp_table *timestamp_table_get(void)
Vadim Bendebury6f72d692011-09-21 16:12:39 -0700123{
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +0300124 struct timestamp_table *ts_table;
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300125
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +0300126 ts_table = car_get_ptr(glob_ts_table);
127 if (ts_table)
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500128 return ts_table;
129
Kyösti Mälkki3c559e72019-09-07 13:25:47 +0300130 ts_table = timestamp_cache_get();
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +0300131 car_set_ptr(glob_ts_table, ts_table);
Kyösti Mälkki3c559e72019-09-07 13:25:47 +0300132
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500133 return ts_table;
134}
135
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +0300136static void timestamp_table_set(struct timestamp_table *ts)
137{
138 car_set_ptr(glob_ts_table, ts);
139}
140
Martin Rothb22bbe22018-03-07 15:32:16 -0700141static const char *timestamp_name(enum timestamp_id id)
142{
143 int i;
144
145 for (i = 0; i < ARRAY_SIZE(timestamp_ids); i++) {
146 if (timestamp_ids[i].id == id)
147 return timestamp_ids[i].name;
148 }
149
150 return "Unknown timestamp ID";
151}
152
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500153static void timestamp_add_table_entry(struct timestamp_table *ts_table,
154 enum timestamp_id id, uint64_t ts_time)
155{
156 struct timestamp_entry *tse;
157
Ben Gardnerf5fd4c92015-11-20 13:25:25 -0600158 if (ts_table->num_entries >= ts_table->max_entries)
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300159 return;
Vadim Bendebury6f72d692011-09-21 16:12:39 -0700160
161 tse = &ts_table->entries[ts_table->num_entries++];
162 tse->entry_id = id;
Stefan Reinauer3a6550d2013-08-01 13:31:44 -0700163 tse->entry_stamp = ts_time - ts_table->base_time;
Ben Gardnerf5fd4c92015-11-20 13:25:25 -0600164
Julius Wernercd49cce2019-03-05 16:53:33 -0800165 if (CONFIG(TIMESTAMPS_ON_CONSOLE))
Jacob Garber3a323802019-08-07 19:10:52 -0600166 printk(BIOS_SPEW, "Timestamp - %s: %llu\n", timestamp_name(id), ts_time);
Martin Rothb22bbe22018-03-07 15:32:16 -0700167
Ben Gardnerf5fd4c92015-11-20 13:25:25 -0600168 if (ts_table->num_entries == ts_table->max_entries)
169 printk(BIOS_ERR, "ERROR: Timestamp table full\n");
Vadim Bendebury6f72d692011-09-21 16:12:39 -0700170}
171
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500172void timestamp_add(enum timestamp_id id, uint64_t ts_time)
173{
174 struct timestamp_table *ts_table;
175
Kyösti Mälkki187e4c42019-02-20 17:38:45 +0200176 if (!timestamp_should_run())
177 return;
178
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500179 ts_table = timestamp_table_get();
180
181 if (!ts_table) {
182 printk(BIOS_ERR, "ERROR: No timestamp table found\n");
183 return;
184 }
185
186 timestamp_add_table_entry(ts_table, id, ts_time);
187}
188
Vadim Bendebury6f72d692011-09-21 16:12:39 -0700189void timestamp_add_now(enum timestamp_id id)
190{
Stefan Reinauer3a6550d2013-08-01 13:31:44 -0700191 timestamp_add(id, timestamp_get());
Vadim Bendebury6f72d692011-09-21 16:12:39 -0700192}
Stefan Reinauer4221a192012-10-15 15:23:20 -0700193
Stefan Reinauer3a6550d2013-08-01 13:31:44 -0700194void timestamp_init(uint64_t base)
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300195{
Kyösti Mälkki3c559e72019-09-07 13:25:47 +0300196 struct timestamp_table *ts_cache;
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500197
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +0300198 assert(ENV_ROMSTAGE_OR_BEFORE);
199
Aaron Durbin2daadf82015-05-01 16:48:54 -0500200 if (!timestamp_should_run())
Kyösti Mälkkif56ff902013-09-08 13:10:28 +0300201 return;
202
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500203 ts_cache = timestamp_cache_get();
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300204
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500205 if (!ts_cache) {
206 printk(BIOS_ERR, "ERROR: No timestamp cache to init\n");
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300207 return;
208 }
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300209
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500210 timestamp_cache_init(ts_cache, base);
Kyösti Mälkki3c559e72019-09-07 13:25:47 +0300211 timestamp_table_set(ts_cache);
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300212}
213
Kyösti Mälkki72e634f2019-09-05 18:16:25 +0300214static void timestamp_sync_cache_to_cbmem(struct timestamp_table *ts_cbmem_table)
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300215{
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500216 uint32_t i;
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500217 struct timestamp_table *ts_cache_table;
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +0300218
219 ts_cache_table = timestamp_table_get();
220 if (!ts_cache_table) {
Kyösti Mälkki72e634f2019-09-05 18:16:25 +0300221 printk(BIOS_ERR, "ERROR: No timestamp cache found\n");
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500222 return;
223 }
224
225 /*
226 * There's no need to worry about the base_time fields being out of
Kyösti Mälkki513a1a82018-06-03 12:29:50 +0300227 * sync because only the following configuration is used/supported:
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500228 *
Kyösti Mälkki513a1a82018-06-03 12:29:50 +0300229 * Timestamps get initialized before ramstage, which implies
230 * CBMEM initialization in romstage.
Julius Werner8c093772016-02-09 16:09:15 -0800231 * This requires the board to define a TIMESTAMP() region in its
232 * memlayout.ld (default on x86). The base_time from timestamp_init()
233 * (usually called from bootblock.c on most non-x86 boards) persists
234 * in that region until it gets synced to CBMEM in romstage.
235 * In ramstage, the BSS cache's base_time will be 0 until the second
236 * sync, which will adjust the timestamps in there to the correct
237 * base_time (from CBMEM) with the timestamp_add_table_entry() below.
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500238 *
Julius Werner8c093772016-02-09 16:09:15 -0800239 * If you try to initialize timestamps before ramstage but don't define
240 * a TIMESTAMP region, all operations will fail (safely), and coreboot
241 * will behave as if timestamps only get initialized in ramstage.
242 *
Kyösti Mälkki513a1a82018-06-03 12:29:50 +0300243 * If timestamps only get initialized in ramstage, the base_time from
244 * timestamp_init() will get ignored and all timestamps will be 0-based.
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500245 */
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +0300246
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500247 for (i = 0; i < ts_cache_table->num_entries; i++) {
248 struct timestamp_entry *tse = &ts_cache_table->entries[i];
249 timestamp_add_table_entry(ts_cbmem_table, tse->entry_id,
250 tse->entry_stamp);
251 }
252
253 /* Freshly added cbmem table has base_time 0. Inherit cache base_time */
254 if (ts_cbmem_table->base_time == 0)
255 ts_cbmem_table->base_time = ts_cache_table->base_time;
256
257 /* Cache no longer required. */
258 ts_cache_table->num_entries = 0;
Kyösti Mälkki3d45c402013-09-07 20:26:36 +0300259}
Kyösti Mälkkicbf5bdf2013-09-10 00:07:21 +0300260
Kyösti Mälkki72e634f2019-09-05 18:16:25 +0300261static void timestamp_reinit(int is_recovery)
262{
263 struct timestamp_table *ts_cbmem_table;
264
265 if (!timestamp_should_run())
266 return;
267
268 /* cbmem is being recovered. */
269 if (is_recovery) {
270 /* x86 resume path expects timestamps to be reset. */
271 if (CONFIG(ARCH_ROMSTAGE_X86_32) && ENV_ROMSTAGE)
272 ts_cbmem_table = timestamp_alloc_cbmem_table();
273 else {
274 /* Find existing table in cbmem. */
275 ts_cbmem_table = cbmem_find(CBMEM_ID_TIMESTAMP);
276 /* No existing timestamp table. */
277 if (ts_cbmem_table == NULL)
278 ts_cbmem_table = timestamp_alloc_cbmem_table();
279 }
280 } else
281 /* First time sync. Add new table. */
282 ts_cbmem_table = timestamp_alloc_cbmem_table();
283
284 if (ts_cbmem_table == NULL) {
285 printk(BIOS_ERR, "ERROR: No timestamp table allocated\n");
286 timestamp_table_set(NULL);
287 return;
288 }
289
290 if (ENV_ROMSTAGE)
291 timestamp_sync_cache_to_cbmem(ts_cbmem_table);
292
293 /* Seed the timestamp tick frequency in ENV_PAYLOAD_LOADER. */
294 if (ENV_PAYLOAD_LOADER)
295 ts_cbmem_table->tick_freq_mhz = timestamp_tick_freq_mhz();
296
297 timestamp_table_set(ts_cbmem_table);
298}
299
Kyösti Mälkki806ea08b2017-07-15 20:42:20 +0300300void timestamp_rescale_table(uint16_t N, uint16_t M)
301{
302 uint32_t i;
303 struct timestamp_table *ts_table;
304
305 if (!timestamp_should_run())
306 return;
307
308 if (N == 0 || M == 0)
309 return;
310
311 ts_table = timestamp_table_get();
312
313 /* No timestamp table found */
314 if (ts_table == NULL) {
315 printk(BIOS_ERR, "ERROR: No timestamp table found\n");
316 return;
317 }
318
319 ts_table->base_time /= M;
320 ts_table->base_time *= N;
321 for (i = 0; i < ts_table->num_entries; i++) {
322 struct timestamp_entry *tse = &ts_table->entries[i];
323 tse->entry_stamp /= M;
324 tse->entry_stamp *= N;
325 }
326}
327
Werner Zeh35cceb82017-09-12 07:42:54 +0200328/*
329 * Get the time in microseconds since boot (or more precise: since timestamp
330 * table was initialized).
331 */
332uint32_t get_us_since_boot(void)
333{
334 struct timestamp_table *ts = timestamp_table_get();
335
336 if (ts == NULL || ts->tick_freq_mhz == 0)
337 return 0;
338 return (timestamp_get() - ts->base_time) / ts->tick_freq_mhz;
339}
340
Kyösti Mälkki72e634f2019-09-05 18:16:25 +0300341ROMSTAGE_CBMEM_INIT_HOOK(timestamp_reinit)
342POSTCAR_CBMEM_INIT_HOOK(timestamp_reinit)
343RAMSTAGE_CBMEM_INIT_HOOK(timestamp_reinit)
Aaron Durbin9e80e272015-05-01 16:48:54 -0500344
345/* Provide default timestamp implementation using monotonic timer. */
Aaron Durbin64031672018-04-21 14:45:32 -0600346uint64_t __weak timestamp_get(void)
Aaron Durbin9e80e272015-05-01 16:48:54 -0500347{
348 struct mono_time t1, t2;
349
Julius Wernercd49cce2019-03-05 16:53:33 -0800350 if (!CONFIG(HAVE_MONOTONIC_TIMER))
Aaron Durbin7aafe532015-05-07 11:32:30 -0500351 return 0;
352
Aaron Durbin9e80e272015-05-01 16:48:54 -0500353 mono_time_set_usecs(&t1, 0);
354 timer_monotonic_get(&t2);
355
356 return mono_time_diff_microseconds(&t1, &t2);
357}
Aaron Durbinc49014e2015-08-30 21:19:55 -0500358
359/* Like timestamp_get() above this matches up with microsecond granularity. */
Aaron Durbin64031672018-04-21 14:45:32 -0600360int __weak timestamp_tick_freq_mhz(void)
Aaron Durbinc49014e2015-08-30 21:19:55 -0500361{
362 return 1;
363}