summaryrefslogtreecommitdiff
path: root/Core/MdeModulePkg/Universal/Network/DpcDxe
diff options
context:
space:
mode:
Diffstat (limited to 'Core/MdeModulePkg/Universal/Network/DpcDxe')
-rw-r--r--Core/MdeModulePkg/Universal/Network/DpcDxe/Dpc.c347
-rw-r--r--Core/MdeModulePkg/Universal/Network/DpcDxe/Dpc.h86
-rw-r--r--Core/MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf52
-rw-r--r--Core/MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.unibin0 -> 1776 bytes
-rw-r--r--Core/MdeModulePkg/Universal/Network/DpcDxe/DpcDxeExtra.unibin0 -> 1364 bytes
5 files changed, 485 insertions, 0 deletions
diff --git a/Core/MdeModulePkg/Universal/Network/DpcDxe/Dpc.c b/Core/MdeModulePkg/Universal/Network/DpcDxe/Dpc.c
new file mode 100644
index 0000000000..c605f721eb
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Network/DpcDxe/Dpc.c
@@ -0,0 +1,347 @@
+/** @file
+
+Copyright (c) 2007 - 2008, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Dpc.c
+
+Abstract:
+
+
+**/
+
+#include "Dpc.h"
+
+//
+// Handle for the EFI_DPC_PROTOCOL instance
+//
+EFI_HANDLE mDpcHandle = NULL;
+
+//
+// The EFI_DPC_PROTOCOL instances that is installed onto mDpcHandle
+//
+EFI_DPC_PROTOCOL mDpc = {
+ DpcQueueDpc,
+ DpcDispatchDpc
+};
+
+//
+// Global variables used to meaasure the DPC Queue Depths
+//
+UINTN mDpcQueueDepth = 0;
+UINTN mMaxDpcQueueDepth = 0;
+
+//
+// Free list of DPC entries. As DPCs are queued, entries are removed from this
+// free list. As DPC entries are dispatched, DPC entries are added to the free list.
+// If the free list is empty and a DPC is queued, the free list is grown by allocating
+// an additional set of DPC entries.
+//
+LIST_ENTRY mDpcEntryFreeList = INITIALIZE_LIST_HEAD_VARIABLE(mDpcEntryFreeList);
+
+//
+// An array of DPC queues. A DPC queue is allocated for every leval EFI_TPL value.
+// As DPCs are queued, they are added to the end of the linked list.
+// As DPCs are dispatched, they are removed from the beginning of the linked list.
+//
+LIST_ENTRY mDpcQueue[TPL_HIGH_LEVEL + 1];
+
+/**
+ Add a Deferred Procedure Call to the end of the DPC queue.
+
+ @param This Protocol instance pointer.
+ @param DpcTpl The EFI_TPL that the DPC should be invoked.
+ @param DpcProcedure Pointer to the DPC's function.
+ @param DpcContext Pointer to the DPC's context. Passed to DpcProcedure
+ when DpcProcedure is invoked.
+
+ @retval EFI_SUCCESS The DPC was queued.
+ @retval EFI_INVALID_PARAMETER DpcTpl is not a valid EFI_TPL.
+ @retval EFI_INVALID_PARAMETER DpcProcedure is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
+ add the DPC to the queue.
+
+**/
+EFI_STATUS
+EFIAPI
+DpcQueueDpc (
+ IN EFI_DPC_PROTOCOL *This,
+ IN EFI_TPL DpcTpl,
+ IN EFI_DPC_PROCEDURE DpcProcedure,
+ IN VOID *DpcContext OPTIONAL
+ )
+{
+ EFI_STATUS ReturnStatus;
+ EFI_TPL OriginalTpl;
+ DPC_ENTRY *DpcEntry;
+ UINTN Index;
+
+ //
+ // Make sure DpcTpl is valid
+ //
+ if (DpcTpl < TPL_APPLICATION || DpcTpl > TPL_HIGH_LEVEL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Make sure DpcProcedure is valid
+ //
+ if (DpcProcedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Assume this function will succeed
+ //
+ ReturnStatus = EFI_SUCCESS;
+
+ //
+ // Raise the TPL level to TPL_HIGH_LEVEL for DPC list operation and save the
+ // current TPL value so it can be restored when this function returns.
+ //
+ OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ //
+ // Check to see if there are any entries in the DPC free list
+ //
+ if (IsListEmpty (&mDpcEntryFreeList)) {
+ //
+ // If the current TPL is greater than TPL_NOTIFY, then memory allocations
+ // can not be performed, so the free list can not be expanded. In this case
+ // return EFI_OUT_OF_RESOURCES.
+ //
+ if (OriginalTpl > TPL_NOTIFY) {
+ ReturnStatus = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Add 64 DPC entries to the free list
+ //
+ for (Index = 0; Index < 64; Index++) {
+ //
+ // Lower the TPL level to perform a memory allocation
+ //
+ gBS->RestoreTPL (OriginalTpl);
+
+ //
+ // Allocate a new DPC entry
+ //
+ DpcEntry = AllocatePool (sizeof (DPC_ENTRY));
+
+ //
+ // Raise the TPL level back to TPL_HIGH_LEVEL for DPC list operations
+ //
+ gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ //
+ // If the allocation of a DPC entry fails, and the free list is empty,
+ // then return EFI_OUT_OF_RESOURCES.
+ //
+ if (DpcEntry == NULL) {
+ if (IsListEmpty (&mDpcEntryFreeList)) {
+ ReturnStatus = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+
+ //
+ // Add the newly allocated DPC entry to the DPC free list
+ //
+ InsertTailList (&mDpcEntryFreeList, &DpcEntry->ListEntry);
+ }
+ }
+
+ //
+ // Retrieve the first node from the free list of DPCs
+ //
+ DpcEntry = (DPC_ENTRY *)(GetFirstNode (&mDpcEntryFreeList));
+
+ //
+ // Remove the first node from the free list of DPCs
+ //
+ RemoveEntryList (&DpcEntry->ListEntry);
+
+ //
+ // Fill in the DPC entry with the DpcProcedure and DpcContext
+ //
+ DpcEntry->DpcProcedure = DpcProcedure;
+ DpcEntry->DpcContext = DpcContext;
+
+ //
+ // Add the DPC entry to the end of the list for the specified DplTpl.
+ //
+ InsertTailList (&mDpcQueue[DpcTpl], &DpcEntry->ListEntry);
+
+ //
+ // Increment the measured DPC queue depth across all TPLs
+ //
+ mDpcQueueDepth++;
+
+ //
+ // Measure the maximum DPC queue depth across all TPLs
+ //
+ if (mDpcQueueDepth > mMaxDpcQueueDepth) {
+ mMaxDpcQueueDepth = mDpcQueueDepth;
+ }
+
+Done:
+ //
+ // Restore the original TPL level when this function was called
+ //
+ gBS->RestoreTPL (OriginalTpl);
+
+ return ReturnStatus;
+}
+
+/**
+ Dispatch the queue of DPCs. ALL DPCs that have been queued with a DpcTpl
+ value greater than or equal to the current TPL are invoked in the order that
+ they were queued. DPCs with higher DpcTpl values are invoked before DPCs with
+ lower DpcTpl values.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS One or more DPCs were invoked.
+ @retval EFI_NOT_FOUND No DPCs were invoked.
+
+**/
+EFI_STATUS
+EFIAPI
+DpcDispatchDpc (
+ IN EFI_DPC_PROTOCOL *This
+ )
+{
+ EFI_STATUS ReturnStatus;
+ EFI_TPL OriginalTpl;
+ EFI_TPL Tpl;
+ DPC_ENTRY *DpcEntry;
+
+ //
+ // Assume that no DPCs will be invoked
+ //
+ ReturnStatus = EFI_NOT_FOUND;
+
+ //
+ // Raise the TPL level to TPL_HIGH_LEVEL for DPC list operation and save the
+ // current TPL value so it can be restored when this function returns.
+ //
+ OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ //
+ // Check to see if there are 1 or more DPCs currently queued
+ //
+ if (mDpcQueueDepth > 0) {
+ //
+ // Loop from TPL_HIGH_LEVEL down to the current TPL value
+ //
+ for (Tpl = TPL_HIGH_LEVEL; Tpl >= OriginalTpl; Tpl--) {
+ //
+ // Check to see if the DPC queue is empty
+ //
+ while (!IsListEmpty (&mDpcQueue[Tpl])) {
+ //
+ // Retrieve the first DPC entry from the DPC queue specified by Tpl
+ //
+ DpcEntry = (DPC_ENTRY *)(GetFirstNode (&mDpcQueue[Tpl]));
+
+ //
+ // Remove the first DPC entry from the DPC queue specified by Tpl
+ //
+ RemoveEntryList (&DpcEntry->ListEntry);
+
+ //
+ // Decrement the measured DPC Queue Depth across all TPLs
+ //
+ mDpcQueueDepth--;
+
+ //
+ // Lower the TPL to TPL value of the current DPC queue
+ //
+ gBS->RestoreTPL (Tpl);
+
+ //
+ // Invoke the DPC passing in its context
+ //
+ (DpcEntry->DpcProcedure) (DpcEntry->DpcContext);
+
+ //
+ // At least one DPC has been invoked, so set the return status to EFI_SUCCESS
+ //
+ ReturnStatus = EFI_SUCCESS;
+
+ //
+ // Raise the TPL level back to TPL_HIGH_LEVEL for DPC list operations
+ //
+ gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ //
+ // Add the invoked DPC entry to the DPC free list
+ //
+ InsertTailList (&mDpcEntryFreeList, &DpcEntry->ListEntry);
+ }
+ }
+ }
+
+ //
+ // Restore the original TPL level when this function was called
+ //
+ gBS->RestoreTPL (OriginalTpl);
+
+ return ReturnStatus;
+}
+
+/**
+ The entry point for DPC driver which installs the EFI_DPC_PROTOCOL onto a new handle.
+
+ @param ImageHandle The image handle of the driver.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCES The DPC queues were initialized and the EFI_DPC_PROTOCOL was
+ installed onto a new handle.
+ @retval Others Failed to install EFI_DPC_PROTOCOL.
+
+**/
+EFI_STATUS
+EFIAPI
+DpcDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ //
+ // ASSERT() if the EFI_DPC_PROTOCOL is already present in the handle database
+ //
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiDpcProtocolGuid);
+
+ //
+ // Initialize the DPC queue for all possible TPL values
+ //
+ for (Index = 0; Index <= TPL_HIGH_LEVEL; Index++) {
+ InitializeListHead (&mDpcQueue[Index]);
+ }
+
+ //
+ // Install the EFI_DPC_PROTOCOL instance onto a new handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mDpcHandle,
+ &gEfiDpcProtocolGuid,
+ &mDpc,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/Core/MdeModulePkg/Universal/Network/DpcDxe/Dpc.h b/Core/MdeModulePkg/Universal/Network/DpcDxe/Dpc.h
new file mode 100644
index 0000000000..443bc3904e
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Network/DpcDxe/Dpc.h
@@ -0,0 +1,86 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Dpc.h
+
+Abstract:
+
+
+**/
+
+#ifndef _DPC_H_
+#define _DPC_H_
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/Dpc.h>
+
+//
+// Internal data struture for managing DPCs. A DPC entry is either on the free
+// list or on a DPC queue at a specific EFI_TPL.
+//
+typedef struct {
+ LIST_ENTRY ListEntry;
+ EFI_DPC_PROCEDURE DpcProcedure;
+ VOID *DpcContext;
+} DPC_ENTRY;
+
+/**
+ Add a Deferred Procedure Call to the end of the DPC queue.
+
+ @param This Protocol instance pointer.
+ @param DpcTpl The EFI_TPL that the DPC should be invoked.
+ @param DpcProcedure Pointer to the DPC's function.
+ @param DpcContext Pointer to the DPC's context. Passed to DpcProcedure
+ when DpcProcedure is invoked.
+
+ @retval EFI_SUCCESS The DPC was queued.
+ @retval EFI_INVALID_PARAMETER DpcTpl is not a valid EFI_TPL.
+ @retval EFI_INVALID_PARAMETER DpcProcedure is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
+ add the DPC to the queue.
+
+**/
+EFI_STATUS
+EFIAPI
+DpcQueueDpc (
+ IN EFI_DPC_PROTOCOL *This,
+ IN EFI_TPL DpcTpl,
+ IN EFI_DPC_PROCEDURE DpcProcedure,
+ IN VOID *DpcContext OPTIONAL
+ );
+
+/**
+ Dispatch the queue of DPCs. ALL DPCs that have been queued with a DpcTpl
+ value greater than or equal to the current TPL are invoked in the order that
+ they were queued. DPCs with higher DpcTpl values are invoked before DPCs with
+ lower DpcTpl values.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS One or more DPCs were invoked.
+ @retval EFI_NOT_FOUND No DPCs were invoked.
+
+**/
+EFI_STATUS
+EFIAPI
+DpcDispatchDpc (
+ IN EFI_DPC_PROTOCOL *This
+ );
+
+#endif
+
diff --git a/Core/MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf b/Core/MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf
new file mode 100644
index 0000000000..8a1f8baf79
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf
@@ -0,0 +1,52 @@
+## @file
+# This module produces Deferred Procedure Call Protocol.
+#
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DpcDxe
+ MODULE_UNI_FILE = DpcDxe.uni
+ FILE_GUID = A210F973-229D-4f4d-AA37-9895E6C9EABA
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DpcDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ Dpc.c
+ Dpc.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ BaseLib
+ DebugLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+
+[Protocols]
+ gEfiDpcProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+[UserExtensions.TianoCore."ExtraFiles"]
+ DpcDxeExtra.uni
diff --git a/Core/MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.uni b/Core/MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.uni
new file mode 100644
index 0000000000..82e3e7985c
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Universal/Network/DpcDxe/DpcDxeExtra.uni b/Core/MdeModulePkg/Universal/Network/DpcDxe/DpcDxeExtra.uni
new file mode 100644
index 0000000000..ca47539550
--- /dev/null
+++ b/Core/MdeModulePkg/Universal/Network/DpcDxe/DpcDxeExtra.uni
Binary files differ