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