]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Event/Timer.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Event / Timer.c
CommitLineData
23c98c94 1/** @file\r
504214c4
LG
2 Core Timer Services\r
3\r
d1edec0a 4Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
9d510e61 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
28a00297 6\r
504214c4 7**/\r
28a00297 8\r
9\r
9c4ac31c 10#include "DxeMain.h"\r
ec90508b 11#include "Event.h"\r
28a00297 12\r
28a00297 13//\r
14// Internal data\r
15//\r
16\r
e94a9ff7 17LIST_ENTRY mEfiTimerList = INITIALIZE_LIST_HEAD_VARIABLE (mEfiTimerList);\r
18EFI_LOCK mEfiTimerLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL - 1);\r
19EFI_EVENT mEfiCheckTimerEvent = NULL;\r
28a00297 20\r
e94a9ff7 21EFI_LOCK mEfiSystemTimeLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);\r
22UINT64 mEfiSystemTime = 0;\r
28a00297 23\r
24//\r
25// Timer functions\r
26//\r
162ed594 27/**\r
f94b9be3 28 Inserts the timer event.\r
29\r
30 @param Event Points to the internal structure of timer event\r
31 to be installed\r
162ed594 32\r
33**/\r
28a00297 34VOID\r
f94b9be3 35CoreInsertEventTimer (\r
36 IN IEVENT *Event\r
28a00297 37 )\r
28a00297 38{\r
f94b9be3 39 UINT64 TriggerTime;\r
40 LIST_ENTRY *Link;\r
41 IEVENT *Event2;\r
28a00297 42\r
f94b9be3 43 ASSERT_LOCKED (&mEfiTimerLock);\r
44\r
45 //\r
46 // Get the timer's trigger time\r
47 //\r
1ccdbf2a 48 TriggerTime = Event->Timer.TriggerTime;\r
f94b9be3 49\r
50 //\r
51 // Insert the timer into the timer database in assending sorted order\r
52 //\r
53 for (Link = mEfiTimerList.ForwardLink; Link != &mEfiTimerList; Link = Link->ForwardLink) {\r
1ccdbf2a 54 Event2 = CR (Link, IEVENT, Timer.Link, EVENT_SIGNATURE);\r
28a00297 55\r
1ccdbf2a 56 if (Event2->Timer.TriggerTime > TriggerTime) {\r
f94b9be3 57 break;\r
58 }\r
59 }\r
60\r
1ccdbf2a 61 InsertTailList (Link, &Event->Timer.Link);\r
f94b9be3 62}\r
162ed594 63\r
64/**\r
65 Returns the current system time.\r
66\r
67 @return The current system time\r
68\r
69**/\r
28a00297 70UINT64\r
71CoreCurrentSystemTime (\r
72 VOID\r
73 )\r
28a00297 74{\r
75 UINT64 SystemTime;\r
76\r
77 CoreAcquireLock (&mEfiSystemTimeLock);\r
78 SystemTime = mEfiSystemTime;\r
79 CoreReleaseLock (&mEfiSystemTimeLock);\r
022c6d45 80\r
28a00297 81 return SystemTime;\r
82}\r
83\r
162ed594 84/**\r
85 Checks the sorted timer list against the current system time.\r
86 Signals any expired event timer.\r
87\r
022c6d45 88 @param CheckEvent Not used\r
162ed594 89 @param Context Not used\r
90\r
91**/\r
28a00297 92VOID\r
93EFIAPI\r
94CoreCheckTimers (\r
95 IN EFI_EVENT CheckEvent,\r
96 IN VOID *Context\r
97 )\r
28a00297 98{\r
99 UINT64 SystemTime;\r
100 IEVENT *Event;\r
101\r
102 //\r
103 // Check the timer database for expired timers\r
104 //\r
28a00297 105 CoreAcquireLock (&mEfiTimerLock);\r
106 SystemTime = CoreCurrentSystemTime ();\r
107\r
108 while (!IsListEmpty (&mEfiTimerList)) {\r
1ccdbf2a 109 Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);\r
28a00297 110\r
111 //\r
112 // If this timer is not expired, then we're done\r
113 //\r
1ccdbf2a 114 if (Event->Timer.TriggerTime > SystemTime) {\r
28a00297 115 break;\r
116 }\r
117\r
118 //\r
119 // Remove this timer from the timer queue\r
120 //\r
121\r
1ccdbf2a 122 RemoveEntryList (&Event->Timer.Link);\r
123 Event->Timer.Link.ForwardLink = NULL;\r
28a00297 124\r
125 //\r
126 // Signal it\r
127 //\r
128 CoreSignalEvent (Event);\r
129\r
130 //\r
131 // If this is a periodic timer, set it\r
132 //\r
1ccdbf2a 133 if (Event->Timer.Period != 0) {\r
28a00297 134 //\r
135 // Compute the timers new trigger time\r
136 //\r
1ccdbf2a 137 Event->Timer.TriggerTime = Event->Timer.TriggerTime + Event->Timer.Period;\r
28a00297 138\r
139 //\r
140 // If that's before now, then reset the timer to start from now\r
141 //\r
1ccdbf2a 142 if (Event->Timer.TriggerTime <= SystemTime) {\r
143 Event->Timer.TriggerTime = SystemTime;\r
28a00297 144 CoreSignalEvent (mEfiCheckTimerEvent);\r
145 }\r
146\r
147 //\r
148 // Add the timer\r
149 //\r
28a00297 150 CoreInsertEventTimer (Event);\r
151 }\r
152 }\r
153\r
154 CoreReleaseLock (&mEfiTimerLock);\r
155}\r
156\r
162ed594 157\r
158/**\r
f94b9be3 159 Initializes timer support.\r
162ed594 160\r
f94b9be3 161**/\r
162VOID\r
163CoreInitializeTimer (\r
164 VOID\r
165 )\r
166{\r
167 EFI_STATUS Status;\r
168\r
670d4d88 169 Status = CoreCreateEventInternal (\r
f94b9be3 170 EVT_NOTIFY_SIGNAL,\r
171 TPL_HIGH_LEVEL - 1,\r
172 CoreCheckTimers,\r
173 NULL,\r
670d4d88 174 NULL,\r
f94b9be3 175 &mEfiCheckTimerEvent\r
176 );\r
177 ASSERT_EFI_ERROR (Status);\r
178}\r
179\r
180\r
181/**\r
182 Called by the platform code to process a tick.\r
183\r
6393d9c8 184 @param Duration The number of 100ns elapsed since the last call\r
f94b9be3 185 to TimerTick\r
162ed594 186\r
187**/\r
28a00297 188VOID\r
f94b9be3 189EFIAPI\r
190CoreTimerTick (\r
191 IN UINT64 Duration\r
28a00297 192 )\r
28a00297 193{\r
f94b9be3 194 IEVENT *Event;\r
28a00297 195\r
f94b9be3 196 //\r
197 // Check runtiem flag in case there are ticks while exiting boot services\r
198 //\r
199 CoreAcquireLock (&mEfiSystemTimeLock);\r
28a00297 200\r
201 //\r
f94b9be3 202 // Update the system time\r
28a00297 203 //\r
f94b9be3 204 mEfiSystemTime += Duration;\r
28a00297 205\r
206 //\r
f94b9be3 207 // If the head of the list is expired, fire the timer event\r
208 // to process it\r
28a00297 209 //\r
f94b9be3 210 if (!IsListEmpty (&mEfiTimerList)) {\r
1ccdbf2a 211 Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);\r
28a00297 212\r
1ccdbf2a 213 if (Event->Timer.TriggerTime <= mEfiSystemTime) {\r
f94b9be3 214 CoreSignalEvent (mEfiCheckTimerEvent);\r
28a00297 215 }\r
216 }\r
217\r
f94b9be3 218 CoreReleaseLock (&mEfiSystemTimeLock);\r
28a00297 219}\r
220\r
221\r
222\r
162ed594 223/**\r
224 Sets the type of timer and the trigger time for a timer event.\r
225\r
022c6d45 226 @param UserEvent The timer event that is to be signaled at the\r
227 specified time\r
228 @param Type The type of time that is specified in\r
229 TriggerTime\r
230 @param TriggerTime The number of 100ns units until the timer\r
231 expires\r
162ed594 232\r
022c6d45 233 @retval EFI_SUCCESS The event has been set to be signaled at the\r
234 requested time\r
162ed594 235 @retval EFI_INVALID_PARAMETER Event or Type is not valid\r
236\r
237**/\r
28a00297 238EFI_STATUS\r
239EFIAPI\r
240CoreSetTimer (\r
241 IN EFI_EVENT UserEvent,\r
242 IN EFI_TIMER_DELAY Type,\r
243 IN UINT64 TriggerTime\r
244 )\r
28a00297 245{\r
246 IEVENT *Event;\r
247\r
248 Event = UserEvent;\r
249\r
250 if (Event == NULL) {\r
251 return EFI_INVALID_PARAMETER;\r
252 }\r
253\r
254 if (Event->Signature != EVENT_SIGNATURE) {\r
255 return EFI_INVALID_PARAMETER;\r
256 }\r
257\r
3d78c020 258 if ((UINT32)Type > TimerRelative || (Event->Type & EVT_TIMER) == 0) {\r
28a00297 259 return EFI_INVALID_PARAMETER;\r
260 }\r
261\r
262 CoreAcquireLock (&mEfiTimerLock);\r
263\r
264 //\r
265 // If the timer is queued to the timer database, remove it\r
266 //\r
1ccdbf2a 267 if (Event->Timer.Link.ForwardLink != NULL) {\r
268 RemoveEntryList (&Event->Timer.Link);\r
269 Event->Timer.Link.ForwardLink = NULL;\r
28a00297 270 }\r
271\r
1ccdbf2a 272 Event->Timer.TriggerTime = 0;\r
273 Event->Timer.Period = 0;\r
28a00297 274\r
275 if (Type != TimerCancel) {\r
276\r
277 if (Type == TimerPeriodic) {\r
d1edec0a
EL
278 if (TriggerTime == 0) {\r
279 gTimer->GetTimerPeriod (gTimer, &TriggerTime);\r
280 }\r
1ccdbf2a 281 Event->Timer.Period = TriggerTime;\r
28a00297 282 }\r
283\r
1ccdbf2a 284 Event->Timer.TriggerTime = CoreCurrentSystemTime () + TriggerTime;\r
28a00297 285 CoreInsertEventTimer (Event);\r
286\r
287 if (TriggerTime == 0) {\r
288 CoreSignalEvent (mEfiCheckTimerEvent);\r
289 }\r
290 }\r
291\r
292 CoreReleaseLock (&mEfiTimerLock);\r
e94a9ff7 293\r
28a00297 294 return EFI_SUCCESS;\r
295}\r