]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/DpcDxe/Dpc.c
MdeModulePkg: Clean up source files
[mirror_edk2.git] / MdeModulePkg / Universal / Network / DpcDxe / Dpc.c
CommitLineData
36ee91ca 1/** @file\r
2\r
d1102dba 3Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 4This program and the accompanying materials\r
36ee91ca 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 Dpc.c\r
15\r
16Abstract:\r
17\r
18\r
19**/\r
20\r
21#include "Dpc.h"\r
22\r
23//\r
24// Handle for the EFI_DPC_PROTOCOL instance\r
25//\r
26EFI_HANDLE mDpcHandle = NULL;\r
27\r
28//\r
29// The EFI_DPC_PROTOCOL instances that is installed onto mDpcHandle\r
30//\r
31EFI_DPC_PROTOCOL mDpc = {\r
32 DpcQueueDpc,\r
33 DpcDispatchDpc\r
34};\r
35\r
36//\r
37// Global variables used to meaasure the DPC Queue Depths\r
38//\r
39UINTN mDpcQueueDepth = 0;\r
40UINTN mMaxDpcQueueDepth = 0;\r
41\r
42//\r
43// Free list of DPC entries. As DPCs are queued, entries are removed from this\r
44// free list. As DPC entries are dispatched, DPC entries are added to the free list.\r
45// If the free list is empty and a DPC is queued, the free list is grown by allocating\r
46// an additional set of DPC entries.\r
47//\r
e48e37fc 48LIST_ENTRY mDpcEntryFreeList = INITIALIZE_LIST_HEAD_VARIABLE(mDpcEntryFreeList);\r
36ee91ca 49\r
50//\r
51// An array of DPC queues. A DPC queue is allocated for every leval EFI_TPL value.\r
52// As DPCs are queued, they are added to the end of the linked list.\r
53// As DPCs are dispatched, they are removed from the beginning of the linked list.\r
54//\r
e48e37fc 55LIST_ENTRY mDpcQueue[TPL_HIGH_LEVEL + 1];\r
36ee91ca 56\r
57/**\r
58 Add a Deferred Procedure Call to the end of the DPC queue.\r
59\r
60 @param This Protocol instance pointer.\r
61 @param DpcTpl The EFI_TPL that the DPC should be invoked.\r
62 @param DpcProcedure Pointer to the DPC's function.\r
63 @param DpcContext Pointer to the DPC's context. Passed to DpcProcedure\r
64 when DpcProcedure is invoked.\r
65\r
66 @retval EFI_SUCCESS The DPC was queued.\r
67 @retval EFI_INVALID_PARAMETER DpcTpl is not a valid EFI_TPL.\r
68 @retval EFI_INVALID_PARAMETER DpcProcedure is NULL.\r
69 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to\r
70 add the DPC to the queue.\r
71\r
72**/\r
73EFI_STATUS\r
74EFIAPI\r
75DpcQueueDpc (\r
76 IN EFI_DPC_PROTOCOL *This,\r
77 IN EFI_TPL DpcTpl,\r
78 IN EFI_DPC_PROCEDURE DpcProcedure,\r
79 IN VOID *DpcContext OPTIONAL\r
80 )\r
81{\r
82 EFI_STATUS ReturnStatus;\r
83 EFI_TPL OriginalTpl;\r
84 DPC_ENTRY *DpcEntry;\r
85 UINTN Index;\r
86\r
87 //\r
88 // Make sure DpcTpl is valid\r
89 //\r
90 if (DpcTpl < TPL_APPLICATION || DpcTpl > TPL_HIGH_LEVEL) {\r
91 return EFI_INVALID_PARAMETER;\r
92 }\r
93\r
94 //\r
95 // Make sure DpcProcedure is valid\r
96 //\r
97 if (DpcProcedure == NULL) {\r
98 return EFI_INVALID_PARAMETER;\r
99 }\r
100\r
101 //\r
102 // Assume this function will succeed\r
103 //\r
104 ReturnStatus = EFI_SUCCESS;\r
105\r
106 //\r
107 // Raise the TPL level to TPL_HIGH_LEVEL for DPC list operation and save the\r
108 // current TPL value so it can be restored when this function returns.\r
109 //\r
110 OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
111\r
112 //\r
113 // Check to see if there are any entries in the DPC free list\r
114 //\r
115 if (IsListEmpty (&mDpcEntryFreeList)) {\r
116 //\r
117 // If the current TPL is greater than TPL_NOTIFY, then memory allocations\r
118 // can not be performed, so the free list can not be expanded. In this case\r
119 // return EFI_OUT_OF_RESOURCES.\r
120 //\r
121 if (OriginalTpl > TPL_NOTIFY) {\r
122 ReturnStatus = EFI_OUT_OF_RESOURCES;\r
123 goto Done;\r
124 }\r
125\r
126 //\r
127 // Add 64 DPC entries to the free list\r
128 //\r
129 for (Index = 0; Index < 64; Index++) {\r
130 //\r
131 // Lower the TPL level to perform a memory allocation\r
132 //\r
133 gBS->RestoreTPL (OriginalTpl);\r
134\r
135 //\r
136 // Allocate a new DPC entry\r
137 //\r
138 DpcEntry = AllocatePool (sizeof (DPC_ENTRY));\r
139\r
140 //\r
141 // Raise the TPL level back to TPL_HIGH_LEVEL for DPC list operations\r
142 //\r
143 gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
144\r
145 //\r
146 // If the allocation of a DPC entry fails, and the free list is empty,\r
147 // then return EFI_OUT_OF_RESOURCES.\r
148 //\r
149 if (DpcEntry == NULL) {\r
150 if (IsListEmpty (&mDpcEntryFreeList)) {\r
151 ReturnStatus = EFI_OUT_OF_RESOURCES;\r
152 goto Done;\r
153 }\r
154 }\r
155\r
156 //\r
157 // Add the newly allocated DPC entry to the DPC free list\r
158 //\r
159 InsertTailList (&mDpcEntryFreeList, &DpcEntry->ListEntry);\r
160 }\r
161 }\r
162\r
163 //\r
164 // Retrieve the first node from the free list of DPCs\r
165 //\r
166 DpcEntry = (DPC_ENTRY *)(GetFirstNode (&mDpcEntryFreeList));\r
167\r
168 //\r
169 // Remove the first node from the free list of DPCs\r
170 //\r
171 RemoveEntryList (&DpcEntry->ListEntry);\r
172\r
173 //\r
174 // Fill in the DPC entry with the DpcProcedure and DpcContext\r
175 //\r
176 DpcEntry->DpcProcedure = DpcProcedure;\r
177 DpcEntry->DpcContext = DpcContext;\r
178\r
179 //\r
180 // Add the DPC entry to the end of the list for the specified DplTpl.\r
181 //\r
182 InsertTailList (&mDpcQueue[DpcTpl], &DpcEntry->ListEntry);\r
183\r
184 //\r
185 // Increment the measured DPC queue depth across all TPLs\r
186 //\r
187 mDpcQueueDepth++;\r
188\r
189 //\r
190 // Measure the maximum DPC queue depth across all TPLs\r
191 //\r
192 if (mDpcQueueDepth > mMaxDpcQueueDepth) {\r
193 mMaxDpcQueueDepth = mDpcQueueDepth;\r
194 }\r
195\r
196Done:\r
197 //\r
198 // Restore the original TPL level when this function was called\r
199 //\r
200 gBS->RestoreTPL (OriginalTpl);\r
201\r
202 return ReturnStatus;\r
203}\r
204\r
205/**\r
206 Dispatch the queue of DPCs. ALL DPCs that have been queued with a DpcTpl\r
207 value greater than or equal to the current TPL are invoked in the order that\r
208 they were queued. DPCs with higher DpcTpl values are invoked before DPCs with\r
209 lower DpcTpl values.\r
210\r
211 @param This Protocol instance pointer.\r
212\r
213 @retval EFI_SUCCESS One or more DPCs were invoked.\r
214 @retval EFI_NOT_FOUND No DPCs were invoked.\r
215\r
216**/\r
217EFI_STATUS\r
218EFIAPI\r
219DpcDispatchDpc (\r
220 IN EFI_DPC_PROTOCOL *This\r
221 )\r
222{\r
223 EFI_STATUS ReturnStatus;\r
224 EFI_TPL OriginalTpl;\r
225 EFI_TPL Tpl;\r
226 DPC_ENTRY *DpcEntry;\r
227\r
228 //\r
229 // Assume that no DPCs will be invoked\r
230 //\r
231 ReturnStatus = EFI_NOT_FOUND;\r
232\r
233 //\r
234 // Raise the TPL level to TPL_HIGH_LEVEL for DPC list operation and save the\r
235 // current TPL value so it can be restored when this function returns.\r
236 //\r
237 OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
238\r
239 //\r
240 // Check to see if there are 1 or more DPCs currently queued\r
241 //\r
242 if (mDpcQueueDepth > 0) {\r
243 //\r
244 // Loop from TPL_HIGH_LEVEL down to the current TPL value\r
245 //\r
246 for (Tpl = TPL_HIGH_LEVEL; Tpl >= OriginalTpl; Tpl--) {\r
247 //\r
248 // Check to see if the DPC queue is empty\r
249 //\r
250 while (!IsListEmpty (&mDpcQueue[Tpl])) {\r
251 //\r
252 // Retrieve the first DPC entry from the DPC queue specified by Tpl\r
253 //\r
254 DpcEntry = (DPC_ENTRY *)(GetFirstNode (&mDpcQueue[Tpl]));\r
255\r
256 //\r
257 // Remove the first DPC entry from the DPC queue specified by Tpl\r
258 //\r
259 RemoveEntryList (&DpcEntry->ListEntry);\r
260\r
261 //\r
262 // Decrement the measured DPC Queue Depth across all TPLs\r
263 //\r
264 mDpcQueueDepth--;\r
265\r
266 //\r
267 // Lower the TPL to TPL value of the current DPC queue\r
268 //\r
269 gBS->RestoreTPL (Tpl);\r
270\r
271 //\r
272 // Invoke the DPC passing in its context\r
273 //\r
274 (DpcEntry->DpcProcedure) (DpcEntry->DpcContext);\r
275\r
276 //\r
277 // At least one DPC has been invoked, so set the return status to EFI_SUCCESS\r
278 //\r
279 ReturnStatus = EFI_SUCCESS;\r
280\r
281 //\r
282 // Raise the TPL level back to TPL_HIGH_LEVEL for DPC list operations\r
283 //\r
284 gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
285\r
286 //\r
287 // Add the invoked DPC entry to the DPC free list\r
288 //\r
289 InsertTailList (&mDpcEntryFreeList, &DpcEntry->ListEntry);\r
290 }\r
291 }\r
292 }\r
293\r
294 //\r
295 // Restore the original TPL level when this function was called\r
296 //\r
297 gBS->RestoreTPL (OriginalTpl);\r
298\r
299 return ReturnStatus;\r
300}\r
301\r
7bce0c5a 302/**\r
303 The entry point for DPC driver which installs the EFI_DPC_PROTOCOL onto a new handle.\r
304\r
305 @param ImageHandle The image handle of the driver.\r
306 @param SystemTable The system table.\r
307\r
308 @retval EFI_SUCCES The DPC queues were initialized and the EFI_DPC_PROTOCOL was\r
309 installed onto a new handle.\r
310 @retval Others Failed to install EFI_DPC_PROTOCOL.\r
311\r
312**/\r
36ee91ca 313EFI_STATUS\r
314EFIAPI\r
315DpcDriverEntryPoint (\r
316 IN EFI_HANDLE ImageHandle,\r
317 IN EFI_SYSTEM_TABLE *SystemTable\r
318 )\r
36ee91ca 319{\r
320 EFI_STATUS Status;\r
321 UINTN Index;\r
322\r
323 //\r
324 // ASSERT() if the EFI_DPC_PROTOCOL is already present in the handle database\r
325 //\r
326 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiDpcProtocolGuid);\r
327\r
328 //\r
329 // Initialize the DPC queue for all possible TPL values\r
330 //\r
331 for (Index = 0; Index <= TPL_HIGH_LEVEL; Index++) {\r
332 InitializeListHead (&mDpcQueue[Index]);\r
333 }\r
334\r
335 //\r
336 // Install the EFI_DPC_PROTOCOL instance onto a new handle\r
337 //\r
338 Status = gBS->InstallMultipleProtocolInterfaces (\r
339 &mDpcHandle,\r
d1102dba 340 &gEfiDpcProtocolGuid,\r
c4a62a12 341 &mDpc,\r
36ee91ca 342 NULL\r
343 );\r
344 ASSERT_EFI_ERROR (Status);\r
345\r
346 return Status;\r
347}\r