~ubuntu-branches/ubuntu/trusty/virtualbox-lts-xenial/trusty-updates

« back to all changes in this revision

Viewing changes to src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Network/DpcDxe/Dpc.c

  • Committer: Package Import Robot
  • Author(s): Gianfranco Costamagna
  • Date: 2016-02-23 14:28:26 UTC
  • Revision ID: package-import@ubuntu.com-20160223142826-bdu69el2z6wa2a44
Tags: upstream-4.3.36-dfsg
ImportĀ upstreamĀ versionĀ 4.3.36-dfsg

Show diffs side-by-side

added added

removed removed

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