blob: dcb3124567aa2d4aa4c7037ebcf1b934e38b2c21 [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 Werner8c093772016-02-09 16:09:15 -080030DECLARE_OPTIONAL_REGION(timestamp);
31
Kyösti Mälkki8b936892019-09-12 13:45:15 +030032/* This points to the active timestamp_table and can change within a stage
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +030033 as CBMEM comes available. */
34static struct timestamp_table *glob_ts_table CAR_GLOBAL;
Aaron Durbin1936f6c2015-07-03 17:04:21 -050035
Kyösti Mälkki3c559e72019-09-07 13:25:47 +030036static void timestamp_cache_init(struct timestamp_table *ts_cache,
Aaron Durbin1936f6c2015-07-03 17:04:21 -050037 uint64_t base)
38{
Kyösti Mälkki3c559e72019-09-07 13:25:47 +030039 ts_cache->num_entries = 0;
Kyösti Mälkki3c559e72019-09-07 13:25:47 +030040 ts_cache->base_time = base;
Kyösti Mälkki8b936892019-09-12 13:45:15 +030041 ts_cache->max_entries = (REGION_SIZE(timestamp) -
42 offsetof(struct timestamp_table, entries))
43 / sizeof(struct timestamp_entry);
Aaron Durbin1936f6c2015-07-03 17:04:21 -050044}
45
Kyösti Mälkki3c559e72019-09-07 13:25:47 +030046static struct timestamp_table *timestamp_cache_get(void)
Aaron Durbin1936f6c2015-07-03 17:04:21 -050047{
Kyösti Mälkki3c559e72019-09-07 13:25:47 +030048 struct timestamp_table *ts_cache = NULL;
Aaron Durbin1936f6c2015-07-03 17:04:21 -050049
Kyösti Mälkki8b936892019-09-12 13:45:15 +030050 if (!ENV_ROMSTAGE_OR_BEFORE)
51 return NULL;
52
53 if (REGION_SIZE(timestamp) < sizeof(*ts_cache)) {
54 BUG();
55 } else {
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +030056 ts_cache = (void *)_timestamp;
Aaron Durbin1936f6c2015-07-03 17:04:21 -050057 }
58
Aaron Durbin1936f6c2015-07-03 17:04:21 -050059 return ts_cache;
60}
61
62static struct timestamp_table *timestamp_alloc_cbmem_table(void)
Vadim Bendebury6f72d692011-09-21 16:12:39 -070063{
Lee Leahyb2d834a2017-03-08 16:52:22 -080064 struct timestamp_table *tst;
Vadim Bendebury6f72d692011-09-21 16:12:39 -070065
66 tst = cbmem_add(CBMEM_ID_TIMESTAMP,
67 sizeof(struct timestamp_table) +
68 MAX_TIMESTAMPS * sizeof(struct timestamp_entry));
69
Kyösti Mälkkie0344172015-05-26 06:23:02 +030070 if (!tst)
Aaron Durbin1936f6c2015-07-03 17:04:21 -050071 return NULL;
Vadim Bendebury6f72d692011-09-21 16:12:39 -070072
Aaron Durbin1936f6c2015-07-03 17:04:21 -050073 tst->base_time = 0;
Vadim Bendebury6f72d692011-09-21 16:12:39 -070074 tst->max_entries = MAX_TIMESTAMPS;
75 tst->num_entries = 0;
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +030076
Aaron Durbin1936f6c2015-07-03 17:04:21 -050077 return tst;
Vadim Bendebury6f72d692011-09-21 16:12:39 -070078}
79
Aaron Durbin2daadf82015-05-01 16:48:54 -050080/* Determine if one should proceed into timestamp code. This is for protecting
81 * systems that have multiple processors running in romstage -- namely AMD
82 * based x86 platforms. */
83static int timestamp_should_run(void)
84{
Subrata Banik42c44c22019-05-15 20:27:04 +053085 /*
86 * Only check boot_cpu() in other stages than
87 * ENV_PAYLOAD_LOADER on x86.
88 */
89 if ((!ENV_PAYLOAD_LOADER && CONFIG(ARCH_X86)) && !boot_cpu())
Aaron Durbin2daadf82015-05-01 16:48:54 -050090 return 0;
91
92 return 1;
93}
94
Aaron Durbin1936f6c2015-07-03 17:04:21 -050095static struct timestamp_table *timestamp_table_get(void)
Vadim Bendebury6f72d692011-09-21 16:12:39 -070096{
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +030097 struct timestamp_table *ts_table;
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +030098
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +030099 ts_table = car_get_ptr(glob_ts_table);
100 if (ts_table)
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500101 return ts_table;
102
Kyösti Mälkki3c559e72019-09-07 13:25:47 +0300103 ts_table = timestamp_cache_get();
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +0300104 car_set_ptr(glob_ts_table, ts_table);
Kyösti Mälkki3c559e72019-09-07 13:25:47 +0300105
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500106 return ts_table;
107}
108
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +0300109static void timestamp_table_set(struct timestamp_table *ts)
110{
111 car_set_ptr(glob_ts_table, ts);
112}
113
Martin Rothb22bbe22018-03-07 15:32:16 -0700114static const char *timestamp_name(enum timestamp_id id)
115{
116 int i;
117
118 for (i = 0; i < ARRAY_SIZE(timestamp_ids); i++) {
119 if (timestamp_ids[i].id == id)
120 return timestamp_ids[i].name;
121 }
122
123 return "Unknown timestamp ID";
124}
125
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500126static void timestamp_add_table_entry(struct timestamp_table *ts_table,
127 enum timestamp_id id, uint64_t ts_time)
128{
129 struct timestamp_entry *tse;
130
Ben Gardnerf5fd4c92015-11-20 13:25:25 -0600131 if (ts_table->num_entries >= ts_table->max_entries)
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300132 return;
Vadim Bendebury6f72d692011-09-21 16:12:39 -0700133
134 tse = &ts_table->entries[ts_table->num_entries++];
135 tse->entry_id = id;
Stefan Reinauer3a6550d2013-08-01 13:31:44 -0700136 tse->entry_stamp = ts_time - ts_table->base_time;
Ben Gardnerf5fd4c92015-11-20 13:25:25 -0600137
Julius Wernercd49cce2019-03-05 16:53:33 -0800138 if (CONFIG(TIMESTAMPS_ON_CONSOLE))
Jacob Garber3a323802019-08-07 19:10:52 -0600139 printk(BIOS_SPEW, "Timestamp - %s: %llu\n", timestamp_name(id), ts_time);
Martin Rothb22bbe22018-03-07 15:32:16 -0700140
Ben Gardnerf5fd4c92015-11-20 13:25:25 -0600141 if (ts_table->num_entries == ts_table->max_entries)
142 printk(BIOS_ERR, "ERROR: Timestamp table full\n");
Vadim Bendebury6f72d692011-09-21 16:12:39 -0700143}
144
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500145void timestamp_add(enum timestamp_id id, uint64_t ts_time)
146{
147 struct timestamp_table *ts_table;
148
Kyösti Mälkki187e4c42019-02-20 17:38:45 +0200149 if (!timestamp_should_run())
150 return;
151
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500152 ts_table = timestamp_table_get();
153
154 if (!ts_table) {
155 printk(BIOS_ERR, "ERROR: No timestamp table found\n");
156 return;
157 }
158
159 timestamp_add_table_entry(ts_table, id, ts_time);
160}
161
Vadim Bendebury6f72d692011-09-21 16:12:39 -0700162void timestamp_add_now(enum timestamp_id id)
163{
Stefan Reinauer3a6550d2013-08-01 13:31:44 -0700164 timestamp_add(id, timestamp_get());
Vadim Bendebury6f72d692011-09-21 16:12:39 -0700165}
Stefan Reinauer4221a192012-10-15 15:23:20 -0700166
Stefan Reinauer3a6550d2013-08-01 13:31:44 -0700167void timestamp_init(uint64_t base)
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300168{
Kyösti Mälkki3c559e72019-09-07 13:25:47 +0300169 struct timestamp_table *ts_cache;
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500170
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +0300171 assert(ENV_ROMSTAGE_OR_BEFORE);
172
Aaron Durbin2daadf82015-05-01 16:48:54 -0500173 if (!timestamp_should_run())
Kyösti Mälkkif56ff902013-09-08 13:10:28 +0300174 return;
175
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500176 ts_cache = timestamp_cache_get();
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300177
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500178 if (!ts_cache) {
179 printk(BIOS_ERR, "ERROR: No timestamp cache to init\n");
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300180 return;
181 }
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300182
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500183 timestamp_cache_init(ts_cache, base);
Kyösti Mälkki3c559e72019-09-07 13:25:47 +0300184 timestamp_table_set(ts_cache);
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300185}
186
Kyösti Mälkki72e634f2019-09-05 18:16:25 +0300187static void timestamp_sync_cache_to_cbmem(struct timestamp_table *ts_cbmem_table)
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300188{
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500189 uint32_t i;
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500190 struct timestamp_table *ts_cache_table;
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +0300191
192 ts_cache_table = timestamp_table_get();
193 if (!ts_cache_table) {
Kyösti Mälkki72e634f2019-09-05 18:16:25 +0300194 printk(BIOS_ERR, "ERROR: No timestamp cache found\n");
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500195 return;
196 }
197
198 /*
199 * There's no need to worry about the base_time fields being out of
Kyösti Mälkki513a1a82018-06-03 12:29:50 +0300200 * sync because only the following configuration is used/supported:
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500201 *
Kyösti Mälkki513a1a82018-06-03 12:29:50 +0300202 * Timestamps get initialized before ramstage, which implies
203 * CBMEM initialization in romstage.
Julius Werner8c093772016-02-09 16:09:15 -0800204 * This requires the board to define a TIMESTAMP() region in its
205 * memlayout.ld (default on x86). The base_time from timestamp_init()
206 * (usually called from bootblock.c on most non-x86 boards) persists
207 * in that region until it gets synced to CBMEM in romstage.
208 * In ramstage, the BSS cache's base_time will be 0 until the second
209 * sync, which will adjust the timestamps in there to the correct
210 * base_time (from CBMEM) with the timestamp_add_table_entry() below.
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500211 *
Julius Werner8c093772016-02-09 16:09:15 -0800212 * If you try to initialize timestamps before ramstage but don't define
213 * a TIMESTAMP region, all operations will fail (safely), and coreboot
214 * will behave as if timestamps only get initialized in ramstage.
215 *
Kyösti Mälkki513a1a82018-06-03 12:29:50 +0300216 * If timestamps only get initialized in ramstage, the base_time from
217 * timestamp_init() will get ignored and all timestamps will be 0-based.
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500218 */
Kyösti Mälkki3dd23a52019-08-22 15:06:50 +0300219
Aaron Durbin1936f6c2015-07-03 17:04:21 -0500220 for (i = 0; i < ts_cache_table->num_entries; i++) {
221 struct timestamp_entry *tse = &ts_cache_table->entries[i];
222 timestamp_add_table_entry(ts_cbmem_table, tse->entry_id,
223 tse->entry_stamp);
224 }
225
226 /* Freshly added cbmem table has base_time 0. Inherit cache base_time */
227 if (ts_cbmem_table->base_time == 0)
228 ts_cbmem_table->base_time = ts_cache_table->base_time;
229
230 /* Cache no longer required. */
231 ts_cache_table->num_entries = 0;
Kyösti Mälkki3d45c402013-09-07 20:26:36 +0300232}
Kyösti Mälkkicbf5bdf2013-09-10 00:07:21 +0300233
Kyösti Mälkki72e634f2019-09-05 18:16:25 +0300234static void timestamp_reinit(int is_recovery)
235{
236 struct timestamp_table *ts_cbmem_table;
237
238 if (!timestamp_should_run())
239 return;
240
Kyösti Mälkkib6b13c92019-09-12 12:58:50 +0300241 /* First time into romstage we make a clean new table. For platforms that travel
242 through this path on resume, ARCH_X86 S3, timestamps are also reset. */
243 if (ENV_ROMSTAGE) {
Kyösti Mälkki72e634f2019-09-05 18:16:25 +0300244 ts_cbmem_table = timestamp_alloc_cbmem_table();
Kyösti Mälkkib6b13c92019-09-12 12:58:50 +0300245 } else {
246 /* Find existing table in cbmem. */
247 ts_cbmem_table = cbmem_find(CBMEM_ID_TIMESTAMP);
248 }
Kyösti Mälkki72e634f2019-09-05 18:16:25 +0300249
250 if (ts_cbmem_table == NULL) {
251 printk(BIOS_ERR, "ERROR: No timestamp table allocated\n");
252 timestamp_table_set(NULL);
253 return;
254 }
255
256 if (ENV_ROMSTAGE)
257 timestamp_sync_cache_to_cbmem(ts_cbmem_table);
258
259 /* Seed the timestamp tick frequency in ENV_PAYLOAD_LOADER. */
260 if (ENV_PAYLOAD_LOADER)
261 ts_cbmem_table->tick_freq_mhz = timestamp_tick_freq_mhz();
262
263 timestamp_table_set(ts_cbmem_table);
264}
265
Kyösti Mälkki806ea08b2017-07-15 20:42:20 +0300266void timestamp_rescale_table(uint16_t N, uint16_t M)
267{
268 uint32_t i;
269 struct timestamp_table *ts_table;
270
271 if (!timestamp_should_run())
272 return;
273
274 if (N == 0 || M == 0)
275 return;
276
277 ts_table = timestamp_table_get();
278
279 /* No timestamp table found */
280 if (ts_table == NULL) {
281 printk(BIOS_ERR, "ERROR: No timestamp table found\n");
282 return;
283 }
284
285 ts_table->base_time /= M;
286 ts_table->base_time *= N;
287 for (i = 0; i < ts_table->num_entries; i++) {
288 struct timestamp_entry *tse = &ts_table->entries[i];
289 tse->entry_stamp /= M;
290 tse->entry_stamp *= N;
291 }
292}
293
Werner Zeh35cceb82017-09-12 07:42:54 +0200294/*
295 * Get the time in microseconds since boot (or more precise: since timestamp
296 * table was initialized).
297 */
298uint32_t get_us_since_boot(void)
299{
300 struct timestamp_table *ts = timestamp_table_get();
301
302 if (ts == NULL || ts->tick_freq_mhz == 0)
303 return 0;
304 return (timestamp_get() - ts->base_time) / ts->tick_freq_mhz;
305}
306
Kyösti Mälkki72e634f2019-09-05 18:16:25 +0300307ROMSTAGE_CBMEM_INIT_HOOK(timestamp_reinit)
308POSTCAR_CBMEM_INIT_HOOK(timestamp_reinit)
309RAMSTAGE_CBMEM_INIT_HOOK(timestamp_reinit)
Aaron Durbin9e80e272015-05-01 16:48:54 -0500310
311/* Provide default timestamp implementation using monotonic timer. */
Aaron Durbin64031672018-04-21 14:45:32 -0600312uint64_t __weak timestamp_get(void)
Aaron Durbin9e80e272015-05-01 16:48:54 -0500313{
314 struct mono_time t1, t2;
315
Julius Wernercd49cce2019-03-05 16:53:33 -0800316 if (!CONFIG(HAVE_MONOTONIC_TIMER))
Aaron Durbin7aafe532015-05-07 11:32:30 -0500317 return 0;
318
Aaron Durbin9e80e272015-05-01 16:48:54 -0500319 mono_time_set_usecs(&t1, 0);
320 timer_monotonic_get(&t2);
321
322 return mono_time_diff_microseconds(&t1, &t2);
323}
Aaron Durbinc49014e2015-08-30 21:19:55 -0500324
325/* Like timestamp_get() above this matches up with microsecond granularity. */
Aaron Durbin64031672018-04-21 14:45:32 -0600326int __weak timestamp_tick_freq_mhz(void)
Aaron Durbinc49014e2015-08-30 21:19:55 -0500327{
328 return 1;
329}