summaryrefslogtreecommitdiffstats
path: root/MdePkg/Library
diff options
context:
space:
mode:
authorRuiyu Ni <ruiyu.ni@intel.com>2017-08-04 13:18:37 +0800
committerRuiyu Ni <ruiyu.ni@intel.com>2017-08-28 16:47:04 +0800
commit5c9bb86f171c9a3a89ac4b5b00518cb00bf32132 (patch)
tree514905ebfcae4b62430bbd6f522d8a807c2e71a7 /MdePkg/Library
parente457c1f65d187f58272c1dc98ae338b4f221ee41 (diff)
downloadedk2-5c9bb86f171c9a3a89ac4b5b00518cb00bf32132.tar.gz
edk2-5c9bb86f171c9a3a89ac4b5b00518cb00bf32132.tar.bz2
edk2-5c9bb86f171c9a3a89ac4b5b00518cb00bf32132.zip
MdePkg/PciSegmentLib: Add instances that consumes PciSegmentInfoLib
The patch adds two PciSegmentLib instances that consumes PciSegmentInfoLib to provide multiple segments PCI configuration access. BasePciSegmentLibSegmentInfo instance is a BASE library. DxeRuntimePciSegmentLibSegmentInfo instance is to be linked with runtime drivers to provide not only boot time but also runtime PCI configuration access. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com>
Diffstat (limited to 'MdePkg/Library')
-rw-r--r--MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c71
-rw-r--r--MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf46
-rw-r--r--MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni21
-rw-r--r--MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c321
-rw-r--r--MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf55
-rw-r--r--MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni21
-rw-r--r--MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c1375
-rw-r--r--MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h57
8 files changed, 1967 insertions, 0 deletions
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c b/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c
new file mode 100644
index 0000000000..e71624d4ba
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c
@@ -0,0 +1,71 @@
+/** @file
+ Instance of Base PCI Segment Library that support multi-segment PCI configuration access.
+
+ PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to
+ support multi-segment PCI configuration access through enhanced configuration access mechanism.
+
+ Copyright (c) 2017, 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.
+
+**/
+
+#include "PciSegmentLibCommon.h"
+
+/**
+ Return the virtual address for the physical address.
+
+ @param Address The physical address.
+
+ @retval The virtual address.
+**/
+UINTN
+PciSegmentLibVirtualAddress (
+ IN UINTN Address
+ )
+{
+ return Address;
+}
+
+/**
+ Register a PCI device so PCI configuration registers may be accessed after
+ SetVirtualAddressMap().
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+
+ @retval RETURN_SUCCESS The PCI device was registered for runtime access.
+ @retval RETURN_UNSUPPORTED An attempt was made to call this function
+ after ExitBootServices().
+ @retval RETURN_UNSUPPORTED The resources required to access the PCI device
+ at runtime could not be mapped.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
+ complete the registration.
+
+**/
+RETURN_STATUS
+EFIAPI
+PciSegmentRegisterForRuntimeAccess (
+ IN UINTN Address
+ )
+{
+ //
+ // Use PciSegmentLibGetEcamAddress() to validate the Address.
+ //
+ DEBUG_CODE (
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count);
+ );
+ return RETURN_SUCCESS;
+}
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf b/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf
new file mode 100644
index 0000000000..9cd60764dc
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf
@@ -0,0 +1,46 @@
+## @file
+# Instance of Base PCI Segment Library that support multi-segment PCI configuration access.
+#
+# PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to
+# support multi-segment PCI configuration access through enhanced configuration access mechanism.
+#
+# Copyright (c) 2017, 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 = BasePciSegmentLibSegmentInfo
+ MODULE_UNI_FILE = BasePciSegmentLibSegmentInfo.uni
+ FILE_GUID = 3427D883-E093-4CC9-BE85-6BD4058E96E2
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciSegmentLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ PciSegmentLibCommon.h
+ PciSegmentLibCommon.c
+ BasePciSegmentLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ IoLib
+ DebugLib
+ PciSegmentInfoLib
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni b/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni
new file mode 100644
index 0000000000..ad33a5fdad
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Instance of Base PCI Segment Library that support multi-segment PCI configuration access.
+
+// PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to
+// support multi-segment PCI configuration access through enhanced configuration access mechanism.
+//
+// Copyright (c) 2017, 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Instance of Base PCI Segment Library that support multi-segment PCI configuration access."
+
+#string STR_MODULE_DESCRIPTION #language en-US "PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to support multi-segment PCI configuration access through enhanced configuration access mechanism."
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c
new file mode 100644
index 0000000000..9c86608677
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c
@@ -0,0 +1,321 @@
+/** @file
+ Instance of Runtime PCI Segment Library that support multi-segment PCI configuration access.
+
+ PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to
+ support multi-segment PCI configuration access through enhanced configuration access mechanism.
+
+ Copyright (c) 2017, 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.
+
+**/
+
+#include "PciSegmentLibCommon.h"
+#include <PiDxe.h>
+#include <Guid/EventGroup.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PciSegmentInfoLib.h>
+
+///
+/// Define table for mapping PCI Segment MMIO physical addresses to virtual addresses at OS runtime
+///
+typedef struct {
+ UINTN PhysicalAddress;
+ UINTN VirtualAddress;
+} PCI_SEGMENT_RUNTIME_REGISTRATION_TABLE;
+
+///
+/// Set Virtual Address Map Event
+///
+EFI_EVENT mDxeRuntimePciSegmentLibVirtualNotifyEvent = NULL;
+
+///
+/// The number of PCI devices that have been registered for runtime access.
+///
+UINTN mDxeRuntimePciSegmentLibNumberOfRuntimeRanges = 0;
+
+///
+/// The table of PCI devices that have been registered for runtime access.
+///
+PCI_SEGMENT_RUNTIME_REGISTRATION_TABLE *mDxeRuntimePciSegmentLibRegistrationTable = NULL;
+
+///
+/// The table index of the most recent virtual address lookup.
+///
+UINTN mDxeRuntimePciSegmentLibLastRuntimeRange = 0;
+
+/**
+ Convert the physical PCI Express MMIO addresses for all registered PCI devices
+ to virtual addresses.
+
+ @param[in] Event The event that is being processed.
+ @param[in] Context The Event Context.
+**/
+VOID
+EFIAPI
+DxeRuntimePciSegmentLibVirtualNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+
+ //
+ // If there have been no runtime registrations, then just return
+ //
+ if (mDxeRuntimePciSegmentLibRegistrationTable == NULL) {
+ return;
+ }
+
+ //
+ // Convert physical addresses associated with the set of registered PCI devices to
+ // virtual addresses.
+ //
+ for (Index = 0; Index < mDxeRuntimePciSegmentLibNumberOfRuntimeRanges; Index++) {
+ Status = EfiConvertPointer (0, (VOID **) &(mDxeRuntimePciSegmentLibRegistrationTable[Index].VirtualAddress));
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Convert table pointer that is allocated from EfiRuntimeServicesData to a virtual address.
+ //
+ Status = EfiConvertPointer (0, (VOID **) &mDxeRuntimePciSegmentLibRegistrationTable);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ The constructor function caches the PCI Express Base Address and creates a
+ Set Virtual Address Map event to convert physical address to virtual addresses.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor completed successfully.
+ @retval Other value The constructor did not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeRuntimePciSegmentLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Register SetVirtualAddressMap () notify function
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ DxeRuntimePciSegmentLibVirtualNotify,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mDxeRuntimePciSegmentLibVirtualNotifyEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ The destructor function frees any allocated buffers and closes the Set Virtual
+ Address Map event.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The destructor completed successfully.
+ @retval Other value The destructor did not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeRuntimePciSegmentLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // If one or more PCI devices have been registered for runtime access, then
+ // free the registration table.
+ //
+ if (mDxeRuntimePciSegmentLibRegistrationTable != NULL) {
+ FreePool (mDxeRuntimePciSegmentLibRegistrationTable);
+ }
+
+ //
+ // Close the Set Virtual Address Map event
+ //
+ Status = gBS->CloseEvent (mDxeRuntimePciSegmentLibVirtualNotifyEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Register a PCI device so PCI configuration registers may be accessed after
+ SetVirtualAddressMap().
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+
+ @retval RETURN_SUCCESS The PCI device was registered for runtime access.
+ @retval RETURN_UNSUPPORTED An attempt was made to call this function
+ after ExitBootServices().
+ @retval RETURN_UNSUPPORTED The resources required to access the PCI device
+ at runtime could not be mapped.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
+ complete the registration.
+
+**/
+RETURN_STATUS
+EFIAPI
+PciSegmentRegisterForRuntimeAccess (
+ IN UINTN Address
+ )
+{
+ RETURN_STATUS Status;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+ UINTN Index;
+ VOID *NewTable;
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+ UINT64 EcamAddress;
+
+ //
+ // Convert Address to a ECAM address at the beginning of the PCI Configuration
+ // header for the specified PCI Bus/Dev/Func
+ //
+ Address &= ~(UINTN)EFI_PAGE_MASK;
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ EcamAddress = PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count);
+
+ //
+ // Return an error if this function is called after ExitBootServices().
+ //
+ if (EfiAtRuntime ()) {
+ return RETURN_UNSUPPORTED;
+ }
+ if (sizeof (UINTN) == sizeof (UINT32)) {
+ ASSERT (EcamAddress < BASE_4GB);
+ }
+ Address = (UINTN)EcamAddress;
+
+ //
+ // See if Address has already been registerd for runtime access
+ //
+ for (Index = 0; Index < mDxeRuntimePciSegmentLibNumberOfRuntimeRanges; Index++) {
+ if (mDxeRuntimePciSegmentLibRegistrationTable[Index].PhysicalAddress == Address) {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ //
+ // Get the GCD Memory Descriptor for the ECAM Address
+ //
+ Status = gDS->GetMemorySpaceDescriptor (Address, &Descriptor);
+ if (EFI_ERROR (Status)) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Mark the 4KB region for the PCI Express Bus/Dev/Func as EFI_RUNTIME_MEMORY so the OS
+ // will allocate a virtual address range for the 4KB PCI Configuration Header.
+ //
+ Status = gDS->SetMemorySpaceAttributes (Address, EFI_PAGE_SIZE, Descriptor.Attributes | EFI_MEMORY_RUNTIME);
+ if (EFI_ERROR (Status)) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Grow the size of the registration table
+ //
+ NewTable = ReallocateRuntimePool (
+ (mDxeRuntimePciSegmentLibNumberOfRuntimeRanges + 0) * sizeof (PCI_SEGMENT_RUNTIME_REGISTRATION_TABLE),
+ (mDxeRuntimePciSegmentLibNumberOfRuntimeRanges + 1) * sizeof (PCI_SEGMENT_RUNTIME_REGISTRATION_TABLE),
+ mDxeRuntimePciSegmentLibRegistrationTable
+ );
+ if (NewTable == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ mDxeRuntimePciSegmentLibRegistrationTable = NewTable;
+ mDxeRuntimePciSegmentLibRegistrationTable[mDxeRuntimePciSegmentLibNumberOfRuntimeRanges].PhysicalAddress = Address;
+ mDxeRuntimePciSegmentLibRegistrationTable[mDxeRuntimePciSegmentLibNumberOfRuntimeRanges].VirtualAddress = Address;
+ mDxeRuntimePciSegmentLibNumberOfRuntimeRanges++;
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Return the linear address for the physical address.
+
+ @param Address The physical address.
+
+ @retval The linear address.
+**/
+UINTN
+PciSegmentLibVirtualAddress (
+ IN UINTN Address
+ )
+{
+ UINTN Index;
+ //
+ // If SetVirtualAddressMap() has not been called, then just return the physical address
+ //
+ if (!EfiGoneVirtual ()) {
+ return Address;
+ }
+
+ //
+ // See if there is a physical address match at the exact same index as the last address match
+ //
+ if (mDxeRuntimePciSegmentLibRegistrationTable[mDxeRuntimePciSegmentLibLastRuntimeRange].PhysicalAddress == (Address & (~(UINTN)EFI_PAGE_MASK))) {
+ //
+ // Convert the physical address to a virtual address and return the virtual address
+ //
+ return (Address & EFI_PAGE_MASK) + mDxeRuntimePciSegmentLibRegistrationTable[mDxeRuntimePciSegmentLibLastRuntimeRange].VirtualAddress;
+ }
+
+ //
+ // Search the entire table for a physical address match
+ //
+ for (Index = 0; Index < mDxeRuntimePciSegmentLibNumberOfRuntimeRanges; Index++) {
+ if (mDxeRuntimePciSegmentLibRegistrationTable[Index].PhysicalAddress == (Address & (~(UINTN)EFI_PAGE_MASK))) {
+ //
+ // Cache the matching index value
+ //
+ mDxeRuntimePciSegmentLibLastRuntimeRange = Index;
+ //
+ // Convert the physical address to a virtual address and return the virtual address
+ //
+ return (Address & EFI_PAGE_MASK) + mDxeRuntimePciSegmentLibRegistrationTable[Index].VirtualAddress;
+ }
+ }
+
+ //
+ // No match was found. This is a critical error at OS runtime, so ASSERT() and force a breakpoint.
+ //
+ ASSERT (FALSE);
+ CpuBreakpoint ();
+
+ //
+ // Return the physical address
+ //
+ return Address;
+}
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf
new file mode 100644
index 0000000000..e484af5b06
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf
@@ -0,0 +1,55 @@
+## @file
+# Instance of Runtime PCI Segment Library that support multi-segment PCI configuration access.
+#
+# PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to
+# support multi-segment PCI configuration access through enhanced configuration access mechanism.
+#
+# Copyright (c) 2017, 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 = DxeRuntimePciSegmentLibSegmentInfo
+ MODULE_UNI_FILE = DxeRuntimePciSegmentLibSegmentInfo.uni
+ FILE_GUID = F73EB3DE-F4E3-47CB-9F18-97796AE06314
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciSegmentLib|DXE_RUNTIME_DRIVER
+ CONSTRUCTOR = DxeRuntimePciSegmentLibConstructor
+ DESTRUCTOR = DxeRuntimePciSegmentLibDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ PciSegmentLibCommon.h
+ PciSegmentLibCommon.c
+ DxeRuntimePciSegmentLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ IoLib
+ DebugLib
+ PciSegmentInfoLib
+ UefiRuntimeLib
+ MemoryAllocationLib
+ DxeServicesTableLib
+ UefiBootServicesTableLib
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni
new file mode 100644
index 0000000000..171fc7d16c
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Instance of Runtime PCI Segment Library that support multi-segment PCI configuration access.
+
+// PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to
+// support multi-segment PCI configuration access through enhanced configuration access mechanism.
+//
+// Copyright (c) 2017, 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.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Instance of Runtime PCI Segment Library that support multi-segment PCI configuration access."
+
+#string STR_MODULE_DESCRIPTION #language en-US "PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to support multi-segment PCI configuration access through enhanced configuration access mechanism."
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c b/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
new file mode 100644
index 0000000000..7b7324d673
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
@@ -0,0 +1,1375 @@
+/** @file
+ Provide common routines used by BasePciSegmentLibSegmentInfo and
+ DxeRuntimePciSegmentLibSegmentInfo libraries.
+
+ Copyright (c) 2017, 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.
+
+**/
+
+#include "PciSegmentLibCommon.h"
+
+typedef struct {
+ UINT64 Register : 12;
+ UINT64 Function : 3;
+ UINT64 Device : 5;
+ UINT64 Bus : 8;
+ UINT64 Reserved1 : 4;
+ UINT64 Segment : 16;
+ UINT64 Reserved2 : 16;
+} PCI_SEGMENT_LIB_ADDRESS_STRUCTURE;
+
+/**
+ Internal function that converts PciSegmentLib format address that encodes the PCI Bus, Device,
+ Function and Register to ECAM (Enhanced Configuration Access Mechanism) address.
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+ @param SegmentInfo An array of PCI_SEGMENT_INFO holding the segment information.
+ @param Count Number of segments.
+
+ @retval ECAM address.
+**/
+UINTN
+PciSegmentLibGetEcamAddress (
+ IN UINT64 Address,
+ IN CONST PCI_SEGMENT_INFO *SegmentInfo,
+ IN UINTN Count
+ )
+{
+ while (Count != 0) {
+ if (SegmentInfo->SegmentNumber == ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Segment) {
+ break;
+ }
+ SegmentInfo++;
+ Count--;
+ }
+ ASSERT (Count != 0);
+ ASSERT (
+ (((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Reserved1 == 0) &&
+ (((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Reserved2 == 0)
+ );
+ ASSERT (((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Bus >= SegmentInfo->StartBusNumber);
+ ASSERT (((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Bus <= SegmentInfo->EndBusNumber);
+
+ Address = SegmentInfo->BaseAddress + PCI_ECAM_ADDRESS (
+ ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Bus,
+ ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Device,
+ ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Function,
+ ((PCI_SEGMENT_LIB_ADDRESS_STRUCTURE *)&Address)->Register);
+
+ if (sizeof (UINTN) == sizeof (UINT32)) {
+ ASSERT (Address < BASE_4GB);
+ }
+
+ return PciSegmentLibVirtualAddress ((UINTN)Address);
+}
+
+/**
+ Reads an 8-bit PCI configuration register.
+
+ Reads and returns the 8-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+
+ @return The 8-bit PCI configuration register specified by Address.
+
+**/
+UINT8
+EFIAPI
+PciSegmentRead8 (
+ IN UINT64 Address
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioRead8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count));
+}
+
+/**
+ Writes an 8-bit PCI configuration register.
+
+ Writes the 8-bit PCI configuration register specified by Address with the value specified by Value.
+ Value is returned. This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param Value The value to write.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentWrite8 (
+ IN UINT64 Address,
+ IN UINT8 Value
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioWrite8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), Value);
+}
+
+/**
+ Performs a bitwise OR of an 8-bit PCI configuration register with an 8-bit value.
+
+ Reads the 8-bit PCI configuration register specified by Address,
+ performs a bitwise OR between the read result and the value specified by OrData,
+ and writes the result to the 8-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentOr8 (
+ IN UINT64 Address,
+ IN UINT8 OrData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), OrData);
+}
+
+/**
+ Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value.
+
+ Reads the 8-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ and writes the result to the 8-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentAnd8 (
+ IN UINT64 Address,
+ IN UINT8 AndData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioAnd8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData);
+}
+
+/**
+ Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value,
+ followed a bitwise OR with another 8-bit value.
+
+ Reads the 8-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+ and writes the result to the 8-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentAndThenOr8 (
+ IN UINT64 Address,
+ IN UINT8 AndData,
+ IN UINT8 OrData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioAndThenOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData, OrData);
+}
+
+/**
+ Reads a bit field of a PCI configuration register.
+
+ Reads the bit field in an 8-bit PCI configuration register. The bit field is
+ specified by the StartBit and the EndBit. The value of the bit field is
+ returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+
+ @param Address PCI configuration register to read.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+
+ @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldRead8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldRead8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit);
+}
+
+/**
+ Writes a bit field to a PCI configuration register.
+
+ Writes Value to the bit field of the PCI configuration register. The bit
+ field is specified by the StartBit and the EndBit. All other bits in the
+ destination PCI configuration register are preserved. The new value of the
+ 8-bit register is returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param Value New value of the bit field.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldWrite8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 Value
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldWrite8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, Value);
+}
+
+/**
+ Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and
+ writes the result back to the bit field in the 8-bit port.
+
+ Reads the 8-bit PCI configuration register specified by Address, performs a
+ bitwise OR between the read result and the value specified by
+ OrData, and writes the result to the 8-bit PCI configuration register
+ specified by Address. The value written to the PCI configuration register is
+ returned. This function must guarantee that all PCI read and write operations
+ are serialized. Extra left bits in OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldOr8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 OrData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, OrData);
+}
+
+/**
+ Reads a bit field in an 8-bit PCI configuration register, performs a bitwise
+ AND, and writes the result back to the bit field in the 8-bit register.
+
+ Reads the 8-bit PCI configuration register specified by Address, performs a
+ bitwise AND between the read result and the value specified by AndData, and
+ writes the result to the 8-bit PCI configuration register specified by
+ Address. The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are
+ serialized. Extra left bits in AndData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldAnd8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 AndData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData);
+}
+
+/**
+ Reads a bit field in an 8-bit port, performs a bitwise AND followed by a
+ bitwise OR, and writes the result back to the bit field in the 8-bit port.
+
+ Reads the 8-bit PCI configuration register specified by Address, performs a
+ bitwise AND followed by a bitwise OR between the read result and
+ the value specified by AndData, and writes the result to the 8-bit PCI
+ configuration register specified by Address. The value written to the PCI
+ configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in both AndData and
+ OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 7, then ASSERT().
+ If EndBit is greater than 7, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..7.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..7.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the result of the AND operation.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciSegmentBitFieldAndThenOr8 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT8 AndData,
+ IN UINT8 OrData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldAndThenOr8 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData, OrData);
+}
+
+/**
+ Reads a 16-bit PCI configuration register.
+
+ Reads and returns the 16-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+
+ @return The 16-bit PCI configuration register specified by Address.
+
+**/
+UINT16
+EFIAPI
+PciSegmentRead16 (
+ IN UINT64 Address
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioRead16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count));
+}
+
+/**
+ Writes a 16-bit PCI configuration register.
+
+ Writes the 16-bit PCI configuration register specified by Address with the value specified by Value.
+ Value is returned. This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param Value The value to write.
+
+ @return The parameter of Value.
+
+**/
+UINT16
+EFIAPI
+PciSegmentWrite16 (
+ IN UINT64 Address,
+ IN UINT16 Value
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioWrite16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), Value);
+}
+
+/**
+ Performs a bitwise OR of a 16-bit PCI configuration register with
+ a 16-bit value.
+
+ Reads the 16-bit PCI configuration register specified by Address, performs a
+ bitwise OR between the read result and the value specified by OrData, and
+ writes the result to the 16-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned. This function
+ must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function and
+ Register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentOr16 (
+ IN UINT64 Address,
+ IN UINT16 OrData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), OrData);
+}
+
+/**
+ Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value.
+
+ Reads the 16-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ and writes the result to the 16-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentAnd16 (
+ IN UINT64 Address,
+ IN UINT16 AndData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioAnd16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData);
+}
+
+/**
+ Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value,
+ followed a bitwise OR with another 16-bit value.
+
+ Reads the 16-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+ and writes the result to the 16-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentAndThenOr16 (
+ IN UINT64 Address,
+ IN UINT16 AndData,
+ IN UINT16 OrData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioAndThenOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData, OrData);
+}
+
+/**
+ Reads a bit field of a PCI configuration register.
+
+ Reads the bit field in a 16-bit PCI configuration register. The bit field is
+ specified by the StartBit and the EndBit. The value of the bit field is
+ returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+
+ @param Address PCI configuration register to read.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+
+ @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldRead16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldRead16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit);
+}
+
+/**
+ Writes a bit field to a PCI configuration register.
+
+ Writes Value to the bit field of the PCI configuration register. The bit
+ field is specified by the StartBit and the EndBit. All other bits in the
+ destination PCI configuration register are preserved. The new value of the
+ 16-bit register is returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+ @param Value New value of the bit field.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldWrite16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 Value
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldWrite16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, Value);
+}
+
+/**
+ Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR, writes
+ the result back to the bit field in the 16-bit port.
+
+ Reads the 16-bit PCI configuration register specified by Address, performs a
+ bitwise OR between the read result and the value specified by
+ OrData, and writes the result to the 16-bit PCI configuration register
+ specified by Address. The value written to the PCI configuration register is
+ returned. This function must guarantee that all PCI read and write operations
+ are serialized. Extra left bits in OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldOr16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 OrData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, OrData);
+}
+
+/**
+ Reads a bit field in a 16-bit PCI configuration register, performs a bitwise
+ AND, writes the result back to the bit field in the 16-bit register.
+
+ Reads the 16-bit PCI configuration register specified by Address, performs a
+ bitwise AND between the read result and the value specified by AndData, and
+ writes the result to the 16-bit PCI configuration register specified by
+ Address. The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are
+ serialized. Extra left bits in AndData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 16-bit boundary, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldAnd16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 AndData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData);
+}
+
+/**
+ Reads a bit field in a 16-bit port, performs a bitwise AND followed by a
+ bitwise OR, and writes the result back to the bit field in the
+ 16-bit port.
+
+ Reads the 16-bit PCI configuration register specified by Address, performs a
+ bitwise AND followed by a bitwise OR between the read result and
+ the value specified by AndData, and writes the result to the 16-bit PCI
+ configuration register specified by Address. The value written to the PCI
+ configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in both AndData and
+ OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 15, then ASSERT().
+ If EndBit is greater than 15, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..15.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..15.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the result of the AND operation.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciSegmentBitFieldAndThenOr16 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT16 AndData,
+ IN UINT16 OrData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldAndThenOr16 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData, OrData);
+}
+
+/**
+ Reads a 32-bit PCI configuration register.
+
+ Reads and returns the 32-bit PCI configuration register specified by Address.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+
+ @return The 32-bit PCI configuration register specified by Address.
+
+**/
+UINT32
+EFIAPI
+PciSegmentRead32 (
+ IN UINT64 Address
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioRead32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count));
+}
+
+/**
+ Writes a 32-bit PCI configuration register.
+
+ Writes the 32-bit PCI configuration register specified by Address with the value specified by Value.
+ Value is returned. This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param Value The value to write.
+
+ @return The parameter of Value.
+
+**/
+UINT32
+EFIAPI
+PciSegmentWrite32 (
+ IN UINT64 Address,
+ IN UINT32 Value
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioWrite32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), Value);
+}
+
+/**
+ Performs a bitwise OR of a 32-bit PCI configuration register with a 32-bit value.
+
+ Reads the 32-bit PCI configuration register specified by Address,
+ performs a bitwise OR between the read result and the value specified by OrData,
+ and writes the result to the 32-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentOr32 (
+ IN UINT64 Address,
+ IN UINT32 OrData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioOr32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), OrData);
+}
+
+/**
+ Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value.
+
+ Reads the 32-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ and writes the result to the 32-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentAnd32 (
+ IN UINT64 Address,
+ IN UINT32 AndData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioAnd32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData);
+}
+
+/**
+ Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value,
+ followed a bitwise OR with another 32-bit value.
+
+ Reads the 32-bit PCI configuration register specified by Address,
+ performs a bitwise AND between the read result and the value specified by AndData,
+ performs a bitwise OR between the result of the AND operation and the value specified by OrData,
+ and writes the result to the 32-bit PCI configuration register specified by Address.
+ The value written to the PCI configuration register is returned.
+ This function must guarantee that all PCI read and write operations are serialized.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentAndThenOr32 (
+ IN UINT64 Address,
+ IN UINT32 AndData,
+ IN UINT32 OrData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioAndThenOr32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), AndData, OrData);
+}
+
+/**
+ Reads a bit field of a PCI configuration register.
+
+ Reads the bit field in a 32-bit PCI configuration register. The bit field is
+ specified by the StartBit and the EndBit. The value of the bit field is
+ returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+
+ @param Address PCI configuration register to read.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+
+ @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldRead32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldRead32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit);
+}
+
+/**
+ Writes a bit field to a PCI configuration register.
+
+ Writes Value to the bit field of the PCI configuration register. The bit
+ field is specified by the StartBit and the EndBit. All other bits in the
+ destination PCI configuration register are preserved. The new value of the
+ 32-bit register is returned.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param Value New value of the bit field.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldWrite32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 Value
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldWrite32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, Value);
+}
+
+/**
+ Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and
+ writes the result back to the bit field in the 32-bit port.
+
+ Reads the 32-bit PCI configuration register specified by Address, performs a
+ bitwise OR between the read result and the value specified by
+ OrData, and writes the result to the 32-bit PCI configuration register
+ specified by Address. The value written to the PCI configuration register is
+ returned. This function must guarantee that all PCI read and write operations
+ are serialized. Extra left bits in OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param OrData The value to OR with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldOr32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 OrData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldOr32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, OrData);
+}
+
+/**
+ Reads a bit field in a 32-bit PCI configuration register, performs a bitwise
+ AND, and writes the result back to the bit field in the 32-bit register.
+
+
+ Reads the 32-bit PCI configuration register specified by Address, performs a bitwise
+ AND between the read result and the value specified by AndData, and writes the result
+ to the 32-bit PCI configuration register specified by Address. The value written to
+ the PCI configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in AndData are stripped.
+ If any reserved bits in Address are set, then ASSERT().
+ If Address is not aligned on a 32-bit boundary, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address Address that encodes the PCI Segment, Bus, Device, Function, and Register.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param AndData The value to AND with the PCI configuration register.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldAnd32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 AndData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldOr32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData);
+}
+
+/**
+ Reads a bit field in a 32-bit port, performs a bitwise AND followed by a
+ bitwise OR, and writes the result back to the bit field in the
+ 32-bit port.
+
+ Reads the 32-bit PCI configuration register specified by Address, performs a
+ bitwise AND followed by a bitwise OR between the read result and
+ the value specified by AndData, and writes the result to the 32-bit PCI
+ configuration register specified by Address. The value written to the PCI
+ configuration register is returned. This function must guarantee that all PCI
+ read and write operations are serialized. Extra left bits in both AndData and
+ OrData are stripped.
+
+ If any reserved bits in Address are set, then ASSERT().
+ If StartBit is greater than 31, then ASSERT().
+ If EndBit is greater than 31, then ASSERT().
+ If EndBit is less than StartBit, then ASSERT().
+ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+ @param Address PCI configuration register to write.
+ @param StartBit The ordinal of the least significant bit in the bit field.
+ Range 0..31.
+ @param EndBit The ordinal of the most significant bit in the bit field.
+ Range 0..31.
+ @param AndData The value to AND with the PCI configuration register.
+ @param OrData The value to OR with the result of the AND operation.
+
+ @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciSegmentBitFieldAndThenOr32 (
+ IN UINT64 Address,
+ IN UINTN StartBit,
+ IN UINTN EndBit,
+ IN UINT32 AndData,
+ IN UINT32 OrData
+ )
+{
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ return MmioBitFieldAndThenOr32 (PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count), StartBit, EndBit, AndData, OrData);
+}
+
+/**
+ Reads a range of PCI configuration registers into a caller supplied buffer.
+
+ Reads the range of PCI configuration registers specified by StartAddress and
+ Size into the buffer specified by Buffer. This function only allows the PCI
+ configuration registers from a single PCI function to be read. Size is
+ returned. When possible 32-bit PCI configuration read cycles are used to read
+ from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit
+ and 16-bit PCI configuration read cycles may be used at the beginning and the
+ end of the range.
+
+ If any reserved bits in StartAddress are set, then ASSERT().
+ If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
+ If Size > 0 and Buffer is NULL, then ASSERT().
+
+ @param StartAddress Starting address that encodes the PCI Segment, Bus, Device,
+ Function and Register.
+ @param Size Size in bytes of the transfer.
+ @param Buffer Pointer to a buffer receiving the data read.
+
+ @return Size
+
+**/
+UINTN
+EFIAPI
+PciSegmentReadBuffer (
+ IN UINT64 StartAddress,
+ IN UINTN Size,
+ OUT VOID *Buffer
+ )
+{
+ UINTN ReturnValue;
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+ UINTN Address;
+
+ ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ Address = PciSegmentLibGetEcamAddress (StartAddress, SegmentInfo, Count);
+
+ if (Size == 0) {
+ return 0;
+ }
+
+ ASSERT (Buffer != NULL);
+
+ //
+ // Save Size for return
+ //
+ ReturnValue = Size;
+
+ if ((Address & BIT0) != 0) {
+ //
+ // Read a byte if StartAddress is byte aligned
+ //
+ *(volatile UINT8 *)Buffer = MmioRead8 (Address);
+ Address += sizeof (UINT8);
+ Size -= sizeof (UINT8);
+ Buffer = (UINT8*)Buffer + 1;
+ }
+
+ if (Size >= sizeof (UINT16) && (Address & BIT1) != 0) {
+ //
+ // Read a word if StartAddress is word aligned
+ //
+ WriteUnaligned16 (Buffer, MmioRead16 (Address));
+ Address += sizeof (UINT16);
+ Size -= sizeof (UINT16);
+ Buffer = (UINT16*)Buffer + 1;
+ }
+
+ while (Size >= sizeof (UINT32)) {
+ //
+ // Read as many double words as possible
+ //
+ WriteUnaligned32 (Buffer, MmioRead32 (Address));
+ Address += sizeof (UINT32);
+ Size -= sizeof (UINT32);
+ Buffer = (UINT32*)Buffer + 1;
+ }
+
+ if (Size >= sizeof (UINT16)) {
+ //
+ // Read the last remaining word if exist
+ //
+ WriteUnaligned16 (Buffer, MmioRead16 (Address));
+ Address += sizeof (UINT16);
+ Size -= sizeof (UINT16);
+ Buffer = (UINT16*)Buffer + 1;
+ }
+
+ if (Size >= sizeof (UINT8)) {
+ //
+ // Read the last remaining byte if exist
+ //
+ *(volatile UINT8 *)Buffer = MmioRead8 (Address);
+ }
+
+ return ReturnValue;
+}
+
+/**
+ Copies the data in a caller supplied buffer to a specified range of PCI
+ configuration space.
+
+ Writes the range of PCI configuration registers specified by StartAddress and
+ Size from the buffer specified by Buffer. This function only allows the PCI
+ configuration registers from a single PCI function to be written. Size is
+ returned. When possible 32-bit PCI configuration write cycles are used to
+ write from StartAdress to StartAddress + Size. Due to alignment restrictions,
+ 8-bit and 16-bit PCI configuration write cycles may be used at the beginning
+ and the end of the range.
+
+ If any reserved bits in StartAddress are set, then ASSERT().
+ If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
+ If Size > 0 and Buffer is NULL, then ASSERT().
+
+ @param StartAddress Starting address that encodes the PCI Segment, Bus, Device,
+ Function and Register.
+ @param Size Size in bytes of the transfer.
+ @param Buffer Pointer to a buffer containing the data to write.
+
+ @return The parameter of Size.
+
+**/
+UINTN
+EFIAPI
+PciSegmentWriteBuffer (
+ IN UINT64 StartAddress,
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ UINTN ReturnValue;
+ UINTN Count;
+ PCI_SEGMENT_INFO *SegmentInfo;
+ UINTN Address;
+
+ ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
+
+ SegmentInfo = GetPciSegmentInfo (&Count);
+ Address = PciSegmentLibGetEcamAddress (StartAddress, SegmentInfo, Count);
+
+ if (Size == 0) {
+ return 0;
+ }
+
+ ASSERT (Buffer != NULL);
+
+ //
+ // Save Size for return
+ //
+ ReturnValue = Size;
+
+ if ((Address & BIT0) != 0) {
+ //
+ // Write a byte if StartAddress is byte aligned
+ //
+ MmioWrite8 (Address, *(UINT8*)Buffer);
+ Address += sizeof (UINT8);
+ Size -= sizeof (UINT8);
+ Buffer = (UINT8*)Buffer + 1;
+ }
+
+ if (Size >= sizeof (UINT16) && (Address & BIT1) != 0) {
+ //
+ // Write a word if StartAddress is word aligned
+ //
+ MmioWrite16 (Address, ReadUnaligned16 (Buffer));
+ Address += sizeof (UINT16);
+ Size -= sizeof (UINT16);
+ Buffer = (UINT16*)Buffer + 1;
+ }
+
+ while (Size >= sizeof (UINT32)) {
+ //
+ // Write as many double words as possible
+ //
+ MmioWrite32 (Address, ReadUnaligned32 (Buffer));
+ Address += sizeof (UINT32);
+ Size -= sizeof (UINT32);
+ Buffer = (UINT32*)Buffer + 1;
+ }
+
+ if (Size >= sizeof (UINT16)) {
+ //
+ // Write the last remaining word if exist
+ //
+ MmioWrite16 (Address, ReadUnaligned16 (Buffer));
+ Address += sizeof (UINT16);
+ Size -= sizeof (UINT16);
+ Buffer = (UINT16*)Buffer + 1;
+ }
+
+ if (Size >= sizeof (UINT8)) {
+ //
+ // Write the last remaining byte if exist
+ //
+ MmioWrite8 (Address, *(UINT8*)Buffer);
+ }
+
+ return ReturnValue;
+}
diff --git a/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h b/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h
new file mode 100644
index 0000000000..4e1f523098
--- /dev/null
+++ b/MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h
@@ -0,0 +1,57 @@
+/** @file
+ Provide common routines used by BasePciSegmentLibSegmentInfo and
+ DxeRuntimePciSegmentLibSegmentInfo libraries.
+
+ Copyright (c) 2017, 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.
+
+**/
+
+#ifndef _PCI_SEGMENT_LIB_COMMON_H_
+#define _PCI_SEGMENT_LIB_COMMON_H_
+
+#include <Base.h>
+#include <IndustryStandard/PciExpress21.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciSegmentLib.h>
+#include <Library/PciSegmentInfoLib.h>
+
+/**
+ Return the linear address for the physical address.
+
+ @param Address The physical address.
+
+ @retval The linear address.
+**/
+UINTN
+PciSegmentLibVirtualAddress (
+ IN UINTN Address
+ );
+
+/**
+ Internal function that converts PciSegmentLib format address that encodes the PCI Bus, Device,
+ Function and Register to ECAM (Enhanced Configuration Access Mechanism) address.
+
+ @param Address The address that encodes the PCI Bus, Device, Function and
+ Register.
+ @param SegmentInfo An array of PCI_SEGMENT_INFO holding the segment information.
+ @param Count Number of segments.
+
+ @retval ECAM address.
+**/
+UINTN
+PciSegmentLibGetEcamAddress (
+ IN UINT64 Address,
+ IN CONST PCI_SEGMENT_INFO *SegmentInfo,
+ IN UINTN Count
+ );
+
+#endif