blob: b034da2306ea6c146dd2253d2c2eb0518ded5b71 [file] [log] [blame]
Aaron Durbina4217912013-04-29 22:31:51 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Google, Inc.
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
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19#ifndef TIMER_H
20#define TIMER_H
21
22#define USECS_PER_SEC 1000000
23#define MSECS_PER_SEC 1000
24#define USECS_PER_MSEC (USECS_PER_SEC / MSECS_PER_SEC)
25
26/* The time structures are defined to be a representation of the time since
27 * coreboot started executing one of its stages. The reason for using structures
28 * is to allow for changes in the future. The structures' details are exposed
29 * so that the compiler can allocate space on the stack and use in other
30 * structures. In other words, accessing any field within this structure
31 * outside of the core timer code is not supported. */
32
33struct mono_time {
34 long microseconds;
35};
36
37struct rela_time {
38 long microseconds;
39};
40
Aaron Durbin340ca912013-04-30 09:58:12 -050041/* A timeout_callback structure is used for the book keeping for scheduling
42 * work in the future. When a callback is called the structure can be
43 * re-used for scheduling as it is not being tracked by the core timer
44 * library any more. */
45struct timeout_callback {
46 void *priv;
47 void (*callback)(struct timeout_callback *tocb);
48 /* Not for public use. The timer library uses the fields below. */
49 struct mono_time expiration;
50};
51
Aaron Durbina4217912013-04-29 22:31:51 -050052/* Obtain the current monotonic time. The assumption is that the time counts
53 * up from the value 0 with value 0 being the point when the timer was
54 * initialized. Additionally, the timer is assumed to only be valid for the
55 * duration of the boot.
56 *
57 * Note that any implementations of timer_monotonic_get()
58 * need to ensure its timesource does not roll over within 10 secs. The reason
59 * is that the time between calls to timer_monotonic_get() may be on order
60 * of 10 seconds. */
61void timer_monotonic_get(struct mono_time *mt);
62
Aaron Durbin340ca912013-04-30 09:58:12 -050063/* Returns 1 if callbacks still present in the queue. 0 if no timers left. */
64int timers_run(void);
65
66/* Schedule a callback to be ran microseconds from time of invocation.
67 * 0 returned on success, < 0 on error. */
68int timer_sched_callback(struct timeout_callback *tocb, unsigned long us);
69
Gabe Black6ccc45d2013-08-09 00:48:06 -070070/* Set an absolute time to a number of microseconds. */
71static inline void mono_time_set_usecs(struct mono_time *mt, long us)
72{
73 mt->microseconds = us;
74}
75
76/* Set an absolute time to a number of milliseconds. */
77static inline void mono_time_set_msecs(struct mono_time *mt, long ms)
78{
79 mt->microseconds = ms * USECS_PER_MSEC;
80}
81
Martin Roth0cb07e32013-07-09 21:46:01 -060082/* Add microseconds to an absolute time. */
Aaron Durbina4217912013-04-29 22:31:51 -050083static inline void mono_time_add_usecs(struct mono_time *mt, long us)
84{
85 mt->microseconds += us;
86}
87
Martin Roth0cb07e32013-07-09 21:46:01 -060088/* Add milliseconds to an absolute time. */
Aaron Durbina4217912013-04-29 22:31:51 -050089static inline void mono_time_add_msecs(struct mono_time *mt, long ms)
90{
91 mono_time_add_usecs(mt, ms * USECS_PER_MSEC);
92}
93
94static inline void mono_time_add_rela_time(struct mono_time *mt,
95 const struct rela_time *t)
96{
97 mono_time_add_usecs(mt, t->microseconds);
98}
99
Martin Roth0cb07e32013-07-09 21:46:01 -0600100/* Compare two absolute times: Return -1, 0, or 1 if t1 is <, =, or > t2,
Aaron Durbina4217912013-04-29 22:31:51 -0500101 * respectively. */
102static inline int mono_time_cmp(const struct mono_time *t1,
103 const struct mono_time *t2)
104{
105 if (t1->microseconds == t2->microseconds)
106 return 0;
107
108 if (t1->microseconds < t2->microseconds)
109 return -1;
110
111 return 1;
112}
113
114static inline int rela_time_cmp(const struct rela_time *t1,
115 const struct rela_time *t2)
116{
117 if (t1->microseconds == t2->microseconds)
118 return 0;
119
120 if (t1->microseconds < t2->microseconds)
121 return -1;
122
123 return 1;
124}
125
Paul Menzel87b9bf52013-05-13 23:59:20 +0200126/* Initialize a rela_time structure. */
Aaron Durbina4217912013-04-29 22:31:51 -0500127static inline struct rela_time rela_time_init_usecs(long us)
128{
129 struct rela_time t;
130 t.microseconds = us;
131 return t;
132}
133
134/* Return time difference between t1 and t2. i.e. t2 - t1. */
135static struct rela_time mono_time_diff(const struct mono_time *t1,
136 const struct mono_time *t2)
137{
138 return rela_time_init_usecs(t2->microseconds - t1->microseconds);
139}
140
141/* Return true if t1 after t2 */
142static inline int mono_time_after(const struct mono_time *t1,
143 const struct mono_time *t2)
144{
145 return mono_time_cmp(t1, t2) > 0;
146}
147
148/* Return true if t1 before t2. */
149static inline int mono_time_before(const struct mono_time *t1,
150 const struct mono_time *t2)
151{
152 return mono_time_cmp(t1, t2) < 0;
153}
154
155/* Return the difference between now and t. */
156static inline struct rela_time current_time_from(const struct mono_time *t)
157{
158 struct mono_time now;
159
160 timer_monotonic_get(&now);
161 return mono_time_diff(t, &now);
162
163}
164
165static inline long rela_time_in_microseconds(const struct rela_time *rt)
166{
167 return rt->microseconds;
168}
169
David Hendricks040f25b2013-05-03 12:28:11 -0700170static inline long mono_time_diff_microseconds(const struct mono_time *t1,
171 const struct mono_time *t2)
172{
173 struct rela_time rt;
174 rt = mono_time_diff(t1, t2);
175 return rela_time_in_microseconds(&rt);
176}
177
Aaron Durbinf65153e2014-09-23 16:28:43 -0500178struct stopwatch {
179 struct mono_time start;
180 struct mono_time current;
181 struct mono_time expires;
182};
183
184static inline void stopwatch_init(struct stopwatch *sw)
185{
186 timer_monotonic_get(&sw->start);
187 sw->current = sw->expires = sw->start;
188}
189
190static inline void stopwatch_init_usecs_expire(struct stopwatch *sw, long us)
191{
192 stopwatch_init(sw);
193 mono_time_add_usecs(&sw->expires, us);
194}
195
196static inline void stopwatch_init_msecs_expire(struct stopwatch *sw, long ms)
197{
198 stopwatch_init_usecs_expire(sw, USECS_PER_MSEC * ms);
199}
200
201/*
202 * Tick the stopwatch to collect the current time.
203 */
204static inline void stopwatch_tick(struct stopwatch *sw)
205{
206 timer_monotonic_get(&sw->current);
207}
208
209/*
210 * Tick and check the stopwatch for expiration. Returns non-zero on exipration.
211 */
212static inline int stopwatch_expired(struct stopwatch *sw)
213{
214 stopwatch_tick(sw);
215 return !mono_time_before(&sw->current, &sw->expires);
216}
217
218/*
219 * Return number of microseconds since starting the stopwatch.
220 */
221static inline long stopwatch_duration_usecs(struct stopwatch *sw)
222{
223 /*
224 * If the stopwatch hasn't been ticked (current == start) tick
225 * the stopwatch to gather the accumulated time.
226 */
227 if (!mono_time_cmp(&sw->start, &sw->current))
228 stopwatch_tick(sw);
229
230 return mono_time_diff_microseconds(&sw->start, &sw->current);
231}
232
233static inline long stopwatch_duration_msecs(struct stopwatch *sw)
234{
235 return stopwatch_duration_usecs(sw) / USECS_PER_MSEC;
236}
237
Aaron Durbina4217912013-04-29 22:31:51 -0500238#endif /* TIMER_H */