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>
Cc: Liming Gao <liming.gao@intel.com>
---
.../PciSegmentLibSegmentInfo/BasePciSegmentLib.c | 71 +
.../BasePciSegmentLibSegmentInfo.inf | 46 +
.../BasePciSegmentLibSegmentInfo.uni | 21 +
.../DxeRuntimePciSegmentLib.c | 321 +++++
.../DxeRuntimePciSegmentLibSegmentInfo.inf | 55 +
.../DxeRuntimePciSegmentLibSegmentInfo.uni | 21 +
.../PciSegmentLibSegmentInfo/PciSegmentLibCommon.c | 1375 ++++++++++++++++++++
.../PciSegmentLibSegmentInfo/PciSegmentLibCommon.h | 57 +
MdePkg/MdePkg.dsc | 2 +
9 files changed, 1969 insertions(+)
create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c
create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf
create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni
create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c
create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf
create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni
create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c
create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h
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
diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc
index e553a702a3..19545aa398 100644
--- a/MdePkg/MdePkg.dsc
+++ b/MdePkg/MdePkg.dsc
@@ -70,6 +70,8 @@ [Components]
MdePkg/Library/BasePciLibPciExpress/BasePciLibPciExpress.inf
MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
MdePkg/Library/BasePciSegmentInfoLibNull/BasePciSegmentInfoLibNull.inf
+ MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf
+ MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf
MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
--
2.12.2.windows.2
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Hi, Some comments below. On 25 August 2017 at 09:57, Ruiyu Ni <ruiyu.ni@intel.com> wrote: > 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> > Cc: Liming Gao <liming.gao@intel.com> > --- > .../PciSegmentLibSegmentInfo/BasePciSegmentLib.c | 71 + > .../BasePciSegmentLibSegmentInfo.inf | 46 + > .../BasePciSegmentLibSegmentInfo.uni | 21 + > .../DxeRuntimePciSegmentLib.c | 321 +++++ > .../DxeRuntimePciSegmentLibSegmentInfo.inf | 55 + > .../DxeRuntimePciSegmentLibSegmentInfo.uni | 21 + > .../PciSegmentLibSegmentInfo/PciSegmentLibCommon.c | 1375 ++++++++++++++++++++ > .../PciSegmentLibSegmentInfo/PciSegmentLibCommon.h | 57 + > MdePkg/MdePkg.dsc | 2 + > 9 files changed, 1969 insertions(+) > create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c > create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf > create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni > create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c > create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf > create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni > create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c > create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h > [...] > 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; > + Is this guaranteed to work as expected by the C spec? > +/** > + 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); > +} MmioBitFieldAnd8 > + > +/** > + 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); > +} MmioBitFieldAnd16 > + > +/** > + 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); > +} MmioBitFieldAnd32 -- Ard. _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
On 08/29/17 20:51, Ard Biesheuvel wrote: > Hi, > > Some comments below. > > On 25 August 2017 at 09:57, Ruiyu Ni <ruiyu.ni@intel.com> wrote: >> 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> >> Cc: Liming Gao <liming.gao@intel.com> >> --- >> .../PciSegmentLibSegmentInfo/BasePciSegmentLib.c | 71 + >> .../BasePciSegmentLibSegmentInfo.inf | 46 + >> .../BasePciSegmentLibSegmentInfo.uni | 21 + >> .../DxeRuntimePciSegmentLib.c | 321 +++++ >> .../DxeRuntimePciSegmentLibSegmentInfo.inf | 55 + >> .../DxeRuntimePciSegmentLibSegmentInfo.uni | 21 + >> .../PciSegmentLibSegmentInfo/PciSegmentLibCommon.c | 1375 ++++++++++++++++++++ >> .../PciSegmentLibSegmentInfo/PciSegmentLibCommon.h | 57 + >> MdePkg/MdePkg.dsc | 2 + >> 9 files changed, 1969 insertions(+) >> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c >> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf >> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni >> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c >> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf >> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni >> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c >> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h >> > [...] >> 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; >> + > > Is this guaranteed to work as expected by the C spec? From C99, "6.7.2.1 Structure and union specifiers", paragraph 10: "An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified." Due to the above, I consider bit-fields totally nonportable, and avoid introducing bit-fields in any code I write. However, "implementation-defined" means the compiler docs have to describe how bit-fields are laid out. If you know your toolchain (...all of your toolchains...), I guess you can make them work. FWIW, edk2 is chock-full of bit-fields. ... For example, the clang build options contain "-mms-bitfields": https://clang.llvm.org/docs/ClangCommandLineReference.html --> "Set the default structure layout to be compatible with the Microsoft compiler standard". The GCC docs are here: https://gcc.gnu.org/onlinedocs/gcc/Structures-unions-enumerations-and-bit-fields-implementation.html --> "Determined by ABI." These structures make me shudder, but if they work, I just close my eyes and move on. :/ Laszlo _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
> On Aug 29, 2017, at 1:39 PM, Laszlo Ersek <lersek@redhat.com> wrote: > > On 08/29/17 20:51, Ard Biesheuvel wrote: >> Hi, >> >> Some comments below. >> >> On 25 August 2017 at 09:57, Ruiyu Ni <ruiyu.ni@intel.com> wrote: >>> 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> >>> Cc: Liming Gao <liming.gao@intel.com> >>> --- >>> .../PciSegmentLibSegmentInfo/BasePciSegmentLib.c | 71 + >>> .../BasePciSegmentLibSegmentInfo.inf | 46 + >>> .../BasePciSegmentLibSegmentInfo.uni | 21 + >>> .../DxeRuntimePciSegmentLib.c | 321 +++++ >>> .../DxeRuntimePciSegmentLibSegmentInfo.inf | 55 + >>> .../DxeRuntimePciSegmentLibSegmentInfo.uni | 21 + >>> .../PciSegmentLibSegmentInfo/PciSegmentLibCommon.c | 1375 ++++++++++++++++++++ >>> .../PciSegmentLibSegmentInfo/PciSegmentLibCommon.h | 57 + >>> MdePkg/MdePkg.dsc | 2 + >>> 9 files changed, 1969 insertions(+) >>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLib.c >>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf >>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.uni >>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c >>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf >>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.uni >>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.c >>> create mode 100644 MdePkg/Library/PciSegmentLibSegmentInfo/PciSegmentLibCommon.h >>> >> [...] >>> 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; >>> + >> >> Is this guaranteed to work as expected by the C spec? > > From C99, "6.7.2.1 Structure and union specifiers", paragraph 10: > > "An implementation may allocate any addressable storage unit large > enough to hold a bit-field. If enough space remains, a bit-field that > immediately follows another bit-field in a structure shall be packed > into adjacent bits of the same unit. If insufficient space remains, > whether a bit-field that does not fit is put into the next unit or > overlaps adjacent units is implementation-defined. The order of > allocation of bit-fields within a unit (high-order to low-order or > low-order to high-order) is implementation-defined. The alignment of the > addressable storage unit is unspecified." > > Due to the above, I consider bit-fields totally nonportable, and avoid > introducing bit-fields in any code I write. > > However, "implementation-defined" means the compiler docs have to > describe how bit-fields are laid out. If you know your toolchain (...all > of your toolchains...), I guess you can make them work. FWIW, edk2 is > chock-full of bit-fields. > > ... For example, the clang build options contain "-mms-bitfields": > Laszlo, FYI -mms-bitfields was to force EFI ABI compatibility, not to enabled bit fields per say. I can't remember why we used ms-bitfields vs. ms-struct? Thanks, Andrew Fish > https://clang.llvm.org/docs/ClangCommandLineReference.html <https://clang.llvm.org/docs/ClangCommandLineReference.html> > > --> "Set the default structure layout to be compatible with the > Microsoft compiler standard". > > The GCC docs are here: > > https://gcc.gnu.org/onlinedocs/gcc/Structures-unions-enumerations-and-bit-fields-implementation.html <https://gcc.gnu.org/onlinedocs/gcc/Structures-unions-enumerations-and-bit-fields-implementation.html> > > --> "Determined by ABI." > > These structures make me shudder, but if they work, I just close my eyes > and move on. :/ > > Laszlo > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> > https://lists.01.org/mailman/listinfo/edk2-devel <https://lists.01.org/mailman/listinfo/edk2-devel> _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
© 2016 - 2024 Red Hat, Inc.