blob: 98ab24321659795473d9c8c68b206081075fae82 [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
45 if (!tst) {
Paul Menzel2edf77c2013-01-22 11:46:34 +010046 printk(BIOS_ERR, "ERROR: failed to allocate timestamp table\n");
Vadim Bendebury6f72d692011-09-21 16:12:39 -070047 return;
48 }
49
Stefan Reinauer3a6550d2013-08-01 13:31:44 -070050 tst->base_time = base;
Vadim Bendebury6f72d692011-09-21 16:12:39 -070051 tst->max_entries = MAX_TIMESTAMPS;
52 tst->num_entries = 0;
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +030053
Kyösti Mälkki29e9c222013-10-13 13:27:56 +030054 car_set_var(ts_table_p, tst);
Vadim Bendebury6f72d692011-09-21 16:12:39 -070055}
56
Aaron Durbin2daadf82015-05-01 16:48:54 -050057/* Determine if one should proceed into timestamp code. This is for protecting
58 * systems that have multiple processors running in romstage -- namely AMD
59 * based x86 platforms. */
60static int timestamp_should_run(void)
61{
62 /* Only check boot_cpu() in other stages than ramstage on x86. */
63 if ((!ENV_RAMSTAGE && IS_ENABLED(CONFIG_ARCH_X86)) && !boot_cpu())
64 return 0;
65
66 return 1;
67}
68
Stefan Reinauer3a6550d2013-08-01 13:31:44 -070069void timestamp_add(enum timestamp_id id, uint64_t ts_time)
Vadim Bendebury6f72d692011-09-21 16:12:39 -070070{
71 struct timestamp_entry *tse;
Kyösti Mälkki29e9c222013-10-13 13:27:56 +030072 struct timestamp_table *ts_table = NULL;
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +030073
Aaron Durbin2daadf82015-05-01 16:48:54 -050074 if (!timestamp_should_run())
Kyösti Mälkkif56ff902013-09-08 13:10:28 +030075 return;
76
Kyösti Mälkki29e9c222013-10-13 13:27:56 +030077 ts_table = car_get_var(ts_table_p);
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +030078 if (!ts_table) {
79 timestamp_stash(id, ts_time);
80 return;
81 }
82 if (ts_table->num_entries == ts_table->max_entries)
Vadim Bendebury6f72d692011-09-21 16:12:39 -070083 return;
84
85 tse = &ts_table->entries[ts_table->num_entries++];
86 tse->entry_id = id;
Stefan Reinauer3a6550d2013-08-01 13:31:44 -070087 tse->entry_stamp = ts_time - ts_table->base_time;
Vadim Bendebury6f72d692011-09-21 16:12:39 -070088}
89
90void timestamp_add_now(enum timestamp_id id)
91{
Stefan Reinauer3a6550d2013-08-01 13:31:44 -070092 timestamp_add(id, timestamp_get());
Vadim Bendebury6f72d692011-09-21 16:12:39 -070093}
Stefan Reinauer4221a192012-10-15 15:23:20 -070094
Stefan Reinauer4221a192012-10-15 15:23:20 -070095#define MAX_TIMESTAMP_CACHE 8
96struct timestamp_cache {
97 enum timestamp_id id;
Stefan Reinauer3a6550d2013-08-01 13:31:44 -070098 uint64_t time;
Stefan Reinauer4221a192012-10-15 15:23:20 -070099} timestamp_cache[MAX_TIMESTAMP_CACHE] CAR_GLOBAL;
100
101static int timestamp_entries CAR_GLOBAL = 0;
102
103/**
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300104 * timestamp_stash() allows to temporarily cache timestamps.
105 * This is needed when timestamping before the CBMEM area
106 * is initialized. The function timestamp_do_sync() is used to
107 * write the timestamps to the CBMEM area and this is done as
108 * part of CAR migration for romstage, and in ramstage main().
Stefan Reinauer4221a192012-10-15 15:23:20 -0700109 */
110
Stefan Reinauer3a6550d2013-08-01 13:31:44 -0700111static void timestamp_stash(enum timestamp_id id, uint64_t ts_time)
Stefan Reinauer4221a192012-10-15 15:23:20 -0700112{
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300113 struct timestamp_cache *ts_cache = car_get_var(timestamp_cache);
114 int ts_entries = car_get_var(timestamp_entries);
115
116 if (ts_entries >= MAX_TIMESTAMP_CACHE) {
Stefan Reinauer4221a192012-10-15 15:23:20 -0700117 printk(BIOS_ERR, "ERROR: failed to add timestamp to cache\n");
118 return;
119 }
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300120 ts_cache[ts_entries].id = id;
121 ts_cache[ts_entries].time = ts_time;
122 car_set_var(timestamp_entries, ++ts_entries);
Stefan Reinauer4221a192012-10-15 15:23:20 -0700123}
124
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300125static void timestamp_do_sync(void)
Stefan Reinauer4221a192012-10-15 15:23:20 -0700126{
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300127 struct timestamp_cache *ts_cache = car_get_var(timestamp_cache);
128 int ts_entries = car_get_var(timestamp_entries);
129
Stefan Reinauer4221a192012-10-15 15:23:20 -0700130 int i;
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300131 for (i = 0; i < ts_entries; i++)
132 timestamp_add(ts_cache[i].id, ts_cache[i].time);
133 car_set_var(timestamp_entries, 0);
Stefan Reinauer4221a192012-10-15 15:23:20 -0700134}
135
Stefan Reinauer3a6550d2013-08-01 13:31:44 -0700136void timestamp_init(uint64_t base)
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300137{
Aaron Durbin2daadf82015-05-01 16:48:54 -0500138 if (!timestamp_should_run())
Kyösti Mälkkif56ff902013-09-08 13:10:28 +0300139 return;
140
Kyösti Mälkki3d45c402013-09-07 20:26:36 +0300141#ifdef __PRE_RAM__
142 /* Copy of basetime, it is too early for CBMEM. */
Kyösti Mälkki29e9c222013-10-13 13:27:56 +0300143 car_set_var(ts_basetime, base);
Kyösti Mälkki3d45c402013-09-07 20:26:36 +0300144#else
Kyösti Mälkkib766b1c2013-09-07 17:26:08 +0300145 struct timestamp_table* tst;
146
147 /* Locate and use an already existing table. */
148 tst = cbmem_find(CBMEM_ID_TIMESTAMP);
149 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}