blob: 8c82649863eb9cef1c4c688ca6c9642e7566eb23 [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.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
Patrick Georgib890a122015-03-26 15:17:45 +010017 * Foundation, Inc.
Vadim Bendebury6f72d692011-09-21 16:12:39 -070018 */
19
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +030020#include <stddef.h>
Vadim Bendebury6f72d692011-09-21 16:12:39 -070021#include <stdint.h>
22#include <console/console.h>
23#include <cbmem.h>
Aaron Durbin2daadf82015-05-01 16:48:54 -050024#include <timer.h>
Vadim Bendebury6f72d692011-09-21 16:12:39 -070025#include <timestamp.h>
Stefan Reinauerfd4f4132013-06-19 12:25:44 -070026#include <arch/early_variables.h>
Aaron Durbin2daadf82015-05-01 16:48:54 -050027#include <rules.h>
Kyösti Mälkki5a5c8862014-01-26 14:41:54 +020028#include <smp/node.h>
Vadim Bendebury6f72d692011-09-21 16:12:39 -070029
Julius Wernera7d92442014-12-02 20:51:19 -080030#define MAX_TIMESTAMPS 60
Vadim Bendebury6f72d692011-09-21 16:12:39 -070031
Kyösti Mälkki29e9c222013-10-13 13:27:56 +030032static struct timestamp_table* ts_table_p CAR_GLOBAL = NULL;
Stefan Reinauer3a6550d2013-08-01 13:31:44 -070033static uint64_t ts_basetime CAR_GLOBAL = 0;
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +030034
Stefan Reinauer3a6550d2013-08-01 13:31:44 -070035static void timestamp_stash(enum timestamp_id id, uint64_t ts_time);
Vadim Bendebury6f72d692011-09-21 16:12:39 -070036
Stefan Reinauer3a6550d2013-08-01 13:31:44 -070037static void timestamp_real_init(uint64_t base)
Vadim Bendebury6f72d692011-09-21 16:12:39 -070038{
39 struct timestamp_table* tst;
40
41 tst = cbmem_add(CBMEM_ID_TIMESTAMP,
42 sizeof(struct timestamp_table) +
43 MAX_TIMESTAMPS * sizeof(struct timestamp_entry));
44
Kyösti Mälkkie0344172015-05-26 06:23:02 +030045 if (!tst)
Vadim Bendebury6f72d692011-09-21 16:12:39 -070046 return;
Vadim Bendebury6f72d692011-09-21 16:12:39 -070047
Stefan Reinauer3a6550d2013-08-01 13:31:44 -070048 tst->base_time = base;
Vadim Bendebury6f72d692011-09-21 16:12:39 -070049 tst->max_entries = MAX_TIMESTAMPS;
50 tst->num_entries = 0;
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +030051
Kyösti Mälkki29e9c222013-10-13 13:27:56 +030052 car_set_var(ts_table_p, tst);
Vadim Bendebury6f72d692011-09-21 16:12:39 -070053}
54
Aaron Durbin2daadf82015-05-01 16:48:54 -050055/* Determine if one should proceed into timestamp code. This is for protecting
56 * systems that have multiple processors running in romstage -- namely AMD
57 * based x86 platforms. */
58static int timestamp_should_run(void)
59{
60 /* Only check boot_cpu() in other stages than ramstage on x86. */
61 if ((!ENV_RAMSTAGE && IS_ENABLED(CONFIG_ARCH_X86)) && !boot_cpu())
62 return 0;
63
64 return 1;
65}
66
Stefan Reinauer3a6550d2013-08-01 13:31:44 -070067void timestamp_add(enum timestamp_id id, uint64_t ts_time)
Vadim Bendebury6f72d692011-09-21 16:12:39 -070068{
69 struct timestamp_entry *tse;
Kyösti Mälkki29e9c222013-10-13 13:27:56 +030070 struct timestamp_table *ts_table = NULL;
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +030071
Aaron Durbin2daadf82015-05-01 16:48:54 -050072 if (!timestamp_should_run())
Kyösti Mälkkif56ff902013-09-08 13:10:28 +030073 return;
74
Kyösti Mälkki29e9c222013-10-13 13:27:56 +030075 ts_table = car_get_var(ts_table_p);
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +030076 if (!ts_table) {
77 timestamp_stash(id, ts_time);
78 return;
79 }
80 if (ts_table->num_entries == ts_table->max_entries)
Vadim Bendebury6f72d692011-09-21 16:12:39 -070081 return;
82
83 tse = &ts_table->entries[ts_table->num_entries++];
84 tse->entry_id = id;
Stefan Reinauer3a6550d2013-08-01 13:31:44 -070085 tse->entry_stamp = ts_time - ts_table->base_time;
Vadim Bendebury6f72d692011-09-21 16:12:39 -070086}
87
88void timestamp_add_now(enum timestamp_id id)
89{
Stefan Reinauer3a6550d2013-08-01 13:31:44 -070090 timestamp_add(id, timestamp_get());
Vadim Bendebury6f72d692011-09-21 16:12:39 -070091}
Stefan Reinauer4221a192012-10-15 15:23:20 -070092
Stefan Reinauer4221a192012-10-15 15:23:20 -070093#define MAX_TIMESTAMP_CACHE 8
94struct timestamp_cache {
95 enum timestamp_id id;
Stefan Reinauer3a6550d2013-08-01 13:31:44 -070096 uint64_t time;
Stefan Reinauer4221a192012-10-15 15:23:20 -070097} timestamp_cache[MAX_TIMESTAMP_CACHE] CAR_GLOBAL;
98
99static int timestamp_entries CAR_GLOBAL = 0;
100
101/**
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300102 * timestamp_stash() allows to temporarily cache timestamps.
103 * This is needed when timestamping before the CBMEM area
104 * is initialized. The function timestamp_do_sync() is used to
105 * write the timestamps to the CBMEM area and this is done as
106 * part of CAR migration for romstage, and in ramstage main().
Stefan Reinauer4221a192012-10-15 15:23:20 -0700107 */
108
Stefan Reinauer3a6550d2013-08-01 13:31:44 -0700109static void timestamp_stash(enum timestamp_id id, uint64_t ts_time)
Stefan Reinauer4221a192012-10-15 15:23:20 -0700110{
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300111 struct timestamp_cache *ts_cache = car_get_var(timestamp_cache);
112 int ts_entries = car_get_var(timestamp_entries);
113
114 if (ts_entries >= MAX_TIMESTAMP_CACHE) {
Stefan Reinauer4221a192012-10-15 15:23:20 -0700115 printk(BIOS_ERR, "ERROR: failed to add timestamp to cache\n");
116 return;
117 }
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300118 ts_cache[ts_entries].id = id;
119 ts_cache[ts_entries].time = ts_time;
120 car_set_var(timestamp_entries, ++ts_entries);
Stefan Reinauer4221a192012-10-15 15:23:20 -0700121}
122
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300123static void timestamp_do_sync(void)
Stefan Reinauer4221a192012-10-15 15:23:20 -0700124{
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300125 struct timestamp_cache *ts_cache = car_get_var(timestamp_cache);
126 int ts_entries = car_get_var(timestamp_entries);
127
Stefan Reinauer4221a192012-10-15 15:23:20 -0700128 int i;
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300129 for (i = 0; i < ts_entries; i++)
130 timestamp_add(ts_cache[i].id, ts_cache[i].time);
131 car_set_var(timestamp_entries, 0);
Stefan Reinauer4221a192012-10-15 15:23:20 -0700132}
133
Stefan Reinauer3a6550d2013-08-01 13:31:44 -0700134void timestamp_init(uint64_t base)
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300135{
Aaron Durbin2daadf82015-05-01 16:48:54 -0500136 if (!timestamp_should_run())
Kyösti Mälkkif56ff902013-09-08 13:10:28 +0300137 return;
138
Kyösti Mälkki3d45c402013-09-07 20:26:36 +0300139#ifdef __PRE_RAM__
140 /* Copy of basetime, it is too early for CBMEM. */
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300141 car_set_var(ts_basetime, base);
Kyösti Mälkki3d45c402013-09-07 20:26:36 +0300142#else
Kyösti Mälkkie0344172015-05-26 06:23:02 +0300143 struct timestamp_table *tst = NULL;
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300144
145 /* Locate and use an already existing table. */
Kyösti Mälkkie0344172015-05-26 06:23:02 +0300146 if (!IS_ENABLED(CONFIG_LATE_CBMEM_INIT))
147 tst = cbmem_find(CBMEM_ID_TIMESTAMP);
148
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300149 if (tst) {
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300150 car_set_var(ts_table_p, tst);
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300151 return;
152 }
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300153
Kyösti Mälkki3d45c402013-09-07 20:26:36 +0300154 /* Copy of basetime, may be too early for CBMEM. */
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300155 car_set_var(ts_basetime, base);
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300156 timestamp_real_init(base);
Kyösti Mälkki3d45c402013-09-07 20:26:36 +0300157#endif
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300158}
159
Kyösti Mälkkicbf5bdf2013-09-10 00:07:21 +0300160void timestamp_reinit(void)
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300161{
Aaron Durbin2daadf82015-05-01 16:48:54 -0500162 if (!timestamp_should_run())
Kyösti Mälkkif56ff902013-09-08 13:10:28 +0300163 return;
164
Kyösti Mälkki3d45c402013-09-07 20:26:36 +0300165#ifdef __PRE_RAM__
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300166 timestamp_real_init(car_get_var(ts_basetime));
Kyösti Mälkki3d45c402013-09-07 20:26:36 +0300167#else
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300168 if (!car_get_var(ts_table_p))
169 timestamp_init(car_get_var(ts_basetime));
Stefan Reinauer4221a192012-10-15 15:23:20 -0700170#endif
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300171 if (car_get_var(ts_table_p))
Kyösti Mälkki3d45c402013-09-07 20:26:36 +0300172 timestamp_do_sync();
173}
Kyösti Mälkkicbf5bdf2013-09-10 00:07:21 +0300174
175/* Call timestamp_reinit at CAR migration time. */
176CAR_MIGRATE(timestamp_reinit)
Aaron Durbin9e80e272015-05-01 16:48:54 -0500177
178/* Provide default timestamp implementation using monotonic timer. */
179uint64_t __attribute__((weak)) timestamp_get(void)
180{
181 struct mono_time t1, t2;
182
Aaron Durbin7aafe532015-05-07 11:32:30 -0500183 if (!IS_ENABLED(CONFIG_HAVE_MONOTONIC_TIMER))
184 return 0;
185
Aaron Durbin9e80e272015-05-01 16:48:54 -0500186 mono_time_set_usecs(&t1, 0);
187 timer_monotonic_get(&t2);
188
189 return mono_time_diff_microseconds(&t1, &t2);
190}