]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Core/Dxe/Event/timer.c
8d7932f8375adbb45658102865959462a2756168
[mirror_edk2.git] / EdkModulePkg / Core / Dxe / Event / timer.c
1 /*++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 timer.c
15
16 Abstract:
17
18 EFI Event support
19
20 Revision History
21
22 --*/
23
24
25 #include <DxeMain.h>
26
27 //
28 // Internal prototypes
29 //
30 STATIC
31 UINT64
32 CoreCurrentSystemTime (
33 VOID
34 );
35
36 VOID
37 EFIAPI
38 CoreCheckTimers (
39 IN EFI_EVENT Event,
40 IN VOID *Context
41 );
42
43 STATIC
44 VOID
45 CoreInsertEventTimer (
46 IN IEVENT *Event
47 );
48
49 //
50 // Internal data
51 //
52
53 static LIST_ENTRY mEfiTimerList = INITIALIZE_LIST_HEAD_VARIABLE (mEfiTimerList);
54 static EFI_LOCK mEfiTimerLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_HIGH_LEVEL - 1);
55 static EFI_EVENT mEfiCheckTimerEvent;
56
57 static EFI_LOCK mEfiSystemTimeLock = EFI_INITIALIZE_LOCK_VARIABLE (EFI_TPL_HIGH_LEVEL);
58 static UINT64 mEfiSystemTime = 0;
59
60 //
61 // Timer functions
62 //
63
64 VOID
65 CoreInitializeTimer (
66 VOID
67 )
68 /*++
69
70 Routine Description:
71
72 Initializes timer support
73
74 Arguments:
75
76 None
77
78 Returns:
79
80 None
81
82 --*/
83 {
84 EFI_STATUS Status;
85
86 Status = CoreCreateEvent (
87 EFI_EVENT_NOTIFY_SIGNAL,
88 EFI_TPL_HIGH_LEVEL - 1,
89 CoreCheckTimers,
90 NULL,
91 &mEfiCheckTimerEvent
92 );
93 ASSERT_EFI_ERROR (Status);
94 }
95
96 STATIC
97 UINT64
98 CoreCurrentSystemTime (
99 VOID
100 )
101 /*++
102
103 Routine Description:
104
105 Returns the current system time
106
107 Arguments:
108
109 None
110
111 Returns:
112
113 Returns the current system time
114
115 --*/
116 {
117 UINT64 SystemTime;
118
119 CoreAcquireLock (&mEfiSystemTimeLock);
120 SystemTime = mEfiSystemTime;
121 CoreReleaseLock (&mEfiSystemTimeLock);
122 return SystemTime;
123 }
124
125 VOID
126 EFIAPI
127 CoreTimerTick (
128 IN UINT64 Duration
129 )
130 /*++
131
132 Routine Description:
133
134 Called by the platform code to process a tick.
135
136 Arguments:
137
138 Duration - The number of 100ns elasped since the last call to TimerTick
139
140 Returns:
141
142 None
143
144 --*/
145 {
146 IEVENT *Event;
147
148 //
149 // Check runtiem flag in case there are ticks while exiting boot services
150 //
151
152 CoreAcquireLock (&mEfiSystemTimeLock);
153
154 //
155 // Update the system time
156 //
157
158 mEfiSystemTime += Duration;
159
160 //
161 // If the head of the list is expired, fire the timer event
162 // to process it
163 //
164
165 if (!IsListEmpty (&mEfiTimerList)) {
166 Event = CR (mEfiTimerList.ForwardLink, IEVENT, u.Timer.Link, EVENT_SIGNATURE);
167
168 if (Event->u.Timer.TriggerTime <= mEfiSystemTime) {
169 CoreSignalEvent (mEfiCheckTimerEvent);
170 }
171 }
172
173 CoreReleaseLock (&mEfiSystemTimeLock);
174 }
175
176 VOID
177 EFIAPI
178 CoreCheckTimers (
179 IN EFI_EVENT CheckEvent,
180 IN VOID *Context
181 )
182 /*++
183
184 Routine Description:
185
186 Checks the sorted timer list against the current system time.
187 Signals any expired event timer.
188
189 Arguments:
190
191 CheckEvent - Not used
192
193 Context - Not used
194
195 Returns:
196
197 None
198
199 --*/
200 {
201 UINT64 SystemTime;
202 IEVENT *Event;
203
204 //
205 // Check the timer database for expired timers
206 //
207
208 CoreAcquireLock (&mEfiTimerLock);
209 SystemTime = CoreCurrentSystemTime ();
210
211 while (!IsListEmpty (&mEfiTimerList)) {
212 Event = CR (mEfiTimerList.ForwardLink, IEVENT, u.Timer.Link, EVENT_SIGNATURE);
213
214 //
215 // If this timer is not expired, then we're done
216 //
217
218 if (Event->u.Timer.TriggerTime > SystemTime) {
219 break;
220 }
221
222 //
223 // Remove this timer from the timer queue
224 //
225
226 RemoveEntryList (&Event->u.Timer.Link);
227 Event->u.Timer.Link.ForwardLink = NULL;
228
229 //
230 // Signal it
231 //
232 CoreSignalEvent (Event);
233
234 //
235 // If this is a periodic timer, set it
236 //
237 if (Event->u.Timer.Period) {
238
239 //
240 // Compute the timers new trigger time
241 //
242
243 Event->u.Timer.TriggerTime = Event->u.Timer.TriggerTime + Event->u.Timer.Period;
244
245 //
246 // If that's before now, then reset the timer to start from now
247 //
248 if (Event->u.Timer.TriggerTime <= SystemTime) {
249 Event->u.Timer.TriggerTime = SystemTime;
250 CoreSignalEvent (mEfiCheckTimerEvent);
251 }
252
253 //
254 // Add the timer
255 //
256
257 CoreInsertEventTimer (Event);
258 }
259 }
260
261 CoreReleaseLock (&mEfiTimerLock);
262 }
263
264 STATIC
265 VOID
266 CoreInsertEventTimer (
267 IN IEVENT *Event
268 )
269 /*++
270
271 Routine Description:
272
273 Inserts the timer event
274
275 Arguments:
276
277 Event - Points to the internal structure of timer event to be installed
278
279 Returns:
280
281 None
282
283 --*/
284 {
285 UINT64 TriggerTime;
286 LIST_ENTRY *Link;
287 IEVENT *Event2;
288
289 ASSERT_LOCKED (&mEfiTimerLock);
290
291 //
292 // Get the timer's trigger time
293 //
294
295 TriggerTime = Event->u.Timer.TriggerTime;
296
297 //
298 // Insert the timer into the timer database in assending sorted order
299 //
300
301 for (Link = mEfiTimerList.ForwardLink; Link != &mEfiTimerList; Link = Link->ForwardLink) {
302 Event2 = CR (Link, IEVENT, u.Timer.Link, EVENT_SIGNATURE);
303
304 if (Event2->u.Timer.TriggerTime > TriggerTime) {
305 break;
306 }
307 }
308
309 InsertTailList (Link, &Event->u.Timer.Link);
310 }
311
312
313
314 EFI_STATUS
315 EFIAPI
316 CoreSetTimer (
317 IN EFI_EVENT UserEvent,
318 IN EFI_TIMER_DELAY Type,
319 IN UINT64 TriggerTime
320 )
321 /*++
322
323 Routine Description:
324
325 Sets the type of timer and the trigger time for a timer event.
326
327 Arguments:
328
329 UserEvent - The timer event that is to be signaled at the specified time
330 Type - The type of time that is specified in TriggerTime
331 TriggerTime - The number of 100ns units until the timer expires
332
333 Returns:
334
335 EFI_SUCCESS - The event has been set to be signaled at the requested time
336 EFI_INVALID_PARAMETER - Event or Type is not valid
337
338 --*/
339 {
340 IEVENT *Event;
341
342 Event = UserEvent;
343
344 if (Event == NULL) {
345 return EFI_INVALID_PARAMETER;
346 }
347
348 if (Event->Signature != EVENT_SIGNATURE) {
349 return EFI_INVALID_PARAMETER;
350 }
351
352 if (Type < 0 || Type > TimerRelative || !(Event->Type & EFI_EVENT_TIMER)) {
353 return EFI_INVALID_PARAMETER;
354 }
355
356 CoreAcquireLock (&mEfiTimerLock);
357
358 //
359 // If the timer is queued to the timer database, remove it
360 //
361
362 if (Event->u.Timer.Link.ForwardLink != NULL) {
363 RemoveEntryList (&Event->u.Timer.Link);
364 Event->u.Timer.Link.ForwardLink = NULL;
365 }
366
367 Event->u.Timer.TriggerTime = 0;
368 Event->u.Timer.Period = 0;
369
370 if (Type != TimerCancel) {
371
372 if (Type == TimerPeriodic) {
373 Event->u.Timer.Period = TriggerTime;
374 }
375
376 Event->u.Timer.TriggerTime = CoreCurrentSystemTime () + TriggerTime;
377 CoreInsertEventTimer (Event);
378
379 if (TriggerTime == 0) {
380 CoreSignalEvent (mEfiCheckTimerEvent);
381 }
382 }
383
384 CoreReleaseLock (&mEfiTimerLock);
385 return EFI_SUCCESS;
386 }