2 * This file is part of the coreboot project.
4 * Copyright (C) 2013 Google, Inc.
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.
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.
18 #define NSECS_PER_SEC 1000000000
19 #define USECS_PER_SEC 1000000
20 #define MSECS_PER_SEC 1000
21 #define USECS_PER_MSEC (USECS_PER_SEC / MSECS_PER_SEC)
23 /* The time structures are defined to be a representation of the time since
24 * coreboot started executing one of its stages. The reason for using structures
25 * is to allow for changes in the future. The structures' details are exposed
26 * so that the compiler can allocate space on the stack and use in other
27 * structures. In other words, accessing any field within this structure
28 * outside of the core timer code is not supported. */
34 /* A timeout_callback structure is used for the book keeping for scheduling
35 * work in the future. When a callback is called the structure can be
36 * re-used for scheduling as it is not being tracked by the core timer
37 * library any more. */
38 struct timeout_callback
{
40 void (*callback
)(struct timeout_callback
*tocb
);
41 /* Not for public use. The timer library uses the fields below. */
42 struct mono_time expiration
;
45 /* Obtain the current monotonic time. The assumption is that the time counts
46 * up from the value 0 with value 0 being the point when the timer was
47 * initialized. Additionally, the timer is assumed to only be valid for the
48 * duration of the boot.
50 * Note that any implementations of timer_monotonic_get()
51 * need to ensure its timesource does not roll over within 10 secs. The reason
52 * is that the time between calls to timer_monotonic_get() may be on order
54 void timer_monotonic_get(struct mono_time
*mt
);
56 /* Returns 1 if callbacks still present in the queue. 0 if no timers left. */
59 /* Schedule a callback to be ran microseconds from time of invocation.
60 * 0 returned on success, < 0 on error. */
61 int timer_sched_callback(struct timeout_callback
*tocb
, unsigned long us
);
63 /* Set an absolute time to a number of microseconds. */
64 static inline void mono_time_set_usecs(struct mono_time
*mt
, long us
)
66 mt
->microseconds
= us
;
69 /* Set an absolute time to a number of milliseconds. */
70 static inline void mono_time_set_msecs(struct mono_time
*mt
, long ms
)
72 mt
->microseconds
= ms
* USECS_PER_MSEC
;
75 /* Add microseconds to an absolute time. */
76 static inline void mono_time_add_usecs(struct mono_time
*mt
, long us
)
78 mt
->microseconds
+= us
;
81 /* Add milliseconds to an absolute time. */
82 static inline void mono_time_add_msecs(struct mono_time
*mt
, long ms
)
84 mono_time_add_usecs(mt
, ms
* USECS_PER_MSEC
);
87 /* Compare two absolute times: Return -1, 0, or 1 if t1 is <, =, or > t2,
89 static inline int mono_time_cmp(const struct mono_time
*t1
,
90 const struct mono_time
*t2
)
92 if (t1
->microseconds
== t2
->microseconds
)
95 if (t1
->microseconds
< t2
->microseconds
)
101 /* Return true if t1 after t2 */
102 static inline int mono_time_after(const struct mono_time
*t1
,
103 const struct mono_time
*t2
)
105 return mono_time_cmp(t1
, t2
) > 0;
108 /* Return true if t1 before t2. */
109 static inline int mono_time_before(const struct mono_time
*t1
,
110 const struct mono_time
*t2
)
112 return mono_time_cmp(t1
, t2
) < 0;
115 /* Return time difference between t1 and t2. i.e. t2 - t1. */
116 static inline long mono_time_diff_microseconds(const struct mono_time
*t1
,
117 const struct mono_time
*t2
)
119 return t2
->microseconds
- t1
->microseconds
;
123 struct mono_time start
;
124 struct mono_time current
;
125 struct mono_time expires
;
128 static inline void stopwatch_init(struct stopwatch
*sw
)
130 if (IS_ENABLED(CONFIG_HAVE_MONOTONIC_TIMER
))
131 timer_monotonic_get(&sw
->start
);
133 sw
->start
.microseconds
= 0;
135 sw
->current
= sw
->expires
= sw
->start
;
138 static inline void stopwatch_init_usecs_expire(struct stopwatch
*sw
, long us
)
141 mono_time_add_usecs(&sw
->expires
, us
);
144 static inline void stopwatch_init_msecs_expire(struct stopwatch
*sw
, long ms
)
146 stopwatch_init_usecs_expire(sw
, USECS_PER_MSEC
* ms
);
150 * Tick the stopwatch to collect the current time.
152 static inline void stopwatch_tick(struct stopwatch
*sw
)
154 if (IS_ENABLED(CONFIG_HAVE_MONOTONIC_TIMER
))
155 timer_monotonic_get(&sw
->current
);
157 sw
->current
.microseconds
= 0;
161 * Tick and check the stopwatch for expiration. Returns non-zero on exipration.
163 static inline int stopwatch_expired(struct stopwatch
*sw
)
166 return !mono_time_before(&sw
->current
, &sw
->expires
);
170 * Tick and check the stopwatch as long as it has not expired.
172 static inline void stopwatch_wait_until_expired(struct stopwatch
*sw
)
174 while (!stopwatch_expired(sw
))
179 * Return number of microseconds since starting the stopwatch.
181 static inline long stopwatch_duration_usecs(struct stopwatch
*sw
)
184 * If the stopwatch hasn't been ticked (current == start) tick
185 * the stopwatch to gather the accumulated time.
187 if (!mono_time_cmp(&sw
->start
, &sw
->current
))
190 return mono_time_diff_microseconds(&sw
->start
, &sw
->current
);
193 static inline long stopwatch_duration_msecs(struct stopwatch
*sw
)
195 return stopwatch_duration_usecs(sw
) / USECS_PER_MSEC
;