[PATCH v3 14/28] Ampere: PCIe: Add PciHostBridgeLib library instance


Nhi Pham
 

From: Vu Nguyen <vunguyen@os.amperecomputing.com>

Provides the number of supported RootBridges and the resource allocated
for each RootBridge. These information are essential to the HostBridge
driver to initialize the PCIe subsystem.

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
---
Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc | 1 +
Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf | 48 +++
Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c | 378 ++++++++++++++++++++
3 files changed, 427 insertions(+)

diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
index d4e1b84c0276..dc66b711aba8 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
@@ -228,6 +228,7 @@ [LibraryClasses.common.DXE_DRIVER]
PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
+ PciHostBridgeLib|Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf

[LibraryClasses.common.UEFI_APPLICATION]
UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiTianoCustomDecompressLib.inf
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
new file mode 100644
index 000000000000..a8ee0c2b9278
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
@@ -0,0 +1,48 @@
+## @file
+#
+# Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = PciHostBridgeLib
+ FILE_GUID = 9D0522E5-B5FD-4E3F-9D10-52AE221FA314
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciHostBridgeLib|DXE_DRIVER
+ CONSTRUCTOR = HostBridgeConstructor
+
+[Sources]
+ PciHostBridgeLib.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+ Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+ Ac01PcieLib
+ AcpiLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ IoLib
+ MemoryAllocationLib
+ PrintLib
+ UefiBootServicesTableLib
+
+[Guids]
+ gEfiEventReadyToBootGuid
+
+[Protocols]
+ gEfiCpuIo2ProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiCpuIo2ProtocolGuid
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
new file mode 100644
index 000000000000..281f20b4bb63
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
@@ -0,0 +1,378 @@
+/** @file
+ PCI Host Bridge Library instance for Ampere Altra-based platforms.
+
+ Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Guid/EventGroup.h>
+#include <IndustryStandard/Acpi.h>
+#include <Library/Ac01PcieLib.h>
+#include <Library/AcpiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+#include <Protocol/PciRootBridgeIo.h>
+
+#include <Ac01PcieCommon.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+STATIC CHAR16 CONST * CONST mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {
+ L"Mem", L"I/O", L"Bus"
+};
+
+#pragma pack(1)
+typedef struct {
+ ACPI_HID_DEVICE_PATH AcpiDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
+#pragma pack ()
+
+STATIC EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath = {
+ {
+ {
+ ACPI_DEVICE_PATH,
+ ACPI_DP,
+ {
+ (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
+ (UINT8)((sizeof (ACPI_HID_DEVICE_PATH)) >> 8)
+ }
+ },
+ EISA_PNP_ID (0x0A08), // PCIe
+ 0
+ }, {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+STATIC PCI_ROOT_BRIDGE mRootBridgeTemplate = {
+ 0, // Segment
+ 0, // Supports
+ 0, // Attributes
+ TRUE, // DmaAbove4G
+ FALSE, // NoExtendedConfigSpace
+ FALSE, // ResourceAssigned
+ EFI_PCI_HOST_BRIDGE_MEM64_DECODE,
+ {
+ // Bus
+ 0,
+ 0
+ }, {
+ // Io
+ 0,
+ 0,
+ 0
+ }, {
+ // Mem
+ MAX_UINT64,
+ 0,
+ 0
+ }, {
+ // MemAbove4G
+ MAX_UINT64,
+ 0,
+ 0
+ }, {
+ // PMem
+ MAX_UINT64,
+ 0,
+ 0
+ }, {
+ // PMemAbove4G
+ MAX_UINT64,
+ 0,
+ 0
+ },
+ (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath
+};
+
+UINT8 mRootBridgeCount = 0;
+PCI_ROOT_BRIDGE *mRootBridges = NULL;
+
+EFI_STATUS
+UpdateStatusMethodObject (
+ EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
+ EFI_ACPI_HANDLE TableHandle,
+ CHAR8 *AsciiObjectPath,
+ CHAR8 ReturnValue
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_HANDLE ObjectHandle;
+ EFI_ACPI_DATA_TYPE DataType;
+ CHAR8 *Buffer;
+ UINTN DataSize;
+
+ Status = AcpiSdtProtocol->FindPath (TableHandle, AsciiObjectPath, &ObjectHandle);
+ if (EFI_ERROR (Status) || ObjectHandle == NULL) {
+ return EFI_SUCCESS;
+ }
+ ASSERT (ObjectHandle != NULL);
+
+ Status = AcpiSdtProtocol->GetOption (ObjectHandle, 2, &DataType, (VOID *)&Buffer, &DataSize);
+ if (!EFI_ERROR (Status) && Buffer[2] == AML_BYTE_PREFIX) {
+ //
+ // Only patch when the initial value is byte object.
+ //
+ Buffer[3] = ReturnValue;
+ }
+
+ AcpiSdtProtocol->Close (ObjectHandle);
+ return Status;
+}
+
+/**
+ This function will be called when ReadyToBoot event is signaled.
+
+ @param Event signaled event
+ @param Context calling context
+
+ @retval VOID
+**/
+VOID
+EFIAPI
+PciHostBridgeReadyToBootEvent (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol;
+ EFI_ACPI_DESCRIPTION_HEADER *Table;
+ UINTN TableKey;
+ UINTN TableIndex;
+ EFI_ACPI_HANDLE TableHandle;
+ CHAR8 NodePath[256];
+ UINTN Count;
+ UINTN Idx1;
+ UINTN Idx2;
+
+ Count = 0;
+
+ Status = gBS->LocateProtocol (
+ &gEfiAcpiSdtProtocolGuid,
+ NULL,
+ (VOID **)&AcpiSdtProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Unable to locate ACPI table protocol\n"));
+ return;
+ }
+
+ TableIndex = 0;
+ Status = AcpiLocateTableBySignature (
+ AcpiSdtProtocol,
+ EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
+ &TableIndex,
+ &Table,
+ &TableKey
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a %d Status = %r \n", __FUNCTION__, __LINE__, Status));
+ ASSERT_EFI_ERROR (Status);
+ return;
+ }
+
+ Status = AcpiSdtProtocol->OpenSdt (TableKey, &TableHandle);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ AcpiSdtProtocol->Close (TableHandle);
+ return;
+ }
+
+ for (Idx1 = 0; Idx1 < Ac01PcieGetTotalHBs (); Idx1++) {
+ for (Idx2 = 0; Idx2 < Ac01PcieGetTotalRBsPerHB (Idx1); Idx2++) {
+ AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.PCI%X._STA", Count);
+ if (Ac01PcieCheckRootBridgeDisabled (Idx1, Idx2)) {
+ UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
+ } else {
+ UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0xf);
+ }
+ Count++;
+ }
+ }
+
+ AcpiSdtProtocol->Close (TableHandle);
+ AcpiUpdateChecksum ((UINT8 *)Table, Table->Length);
+
+ //
+ // Close the event, so it will not be signalled again.
+ //
+ gBS->CloseEvent (Event);
+}
+
+EFI_STATUS
+HostBridgeConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Index;
+ EFI_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath;
+ EFI_EVENT EvtReadyToBoot;
+
+ mRootBridges = AllocatePool (Ac01PcieGetTotalHBs () * sizeof (PCI_ROOT_BRIDGE));
+ if (mRootBridges == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Ac01PcieSetup ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < Ac01PcieGetTotalHBs (); Index++) {
+ CopyMem (&mRootBridges[mRootBridgeCount], &mRootBridgeTemplate, sizeof (PCI_ROOT_BRIDGE));
+
+ Status = Ac01PcieSetupRootBridge (Index, 0, (VOID *)&mRootBridges[mRootBridgeCount]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ mRootBridges[mRootBridgeCount].Segment = Ac01PcieGetRootBridgeSegmentNumber (Index, 0);
+
+ DevicePath = AllocateCopyPool (
+ sizeof (EFI_PCI_ROOT_BRIDGE_DEVICE_PATH),
+ (VOID *)&mEfiPciRootBridgeDevicePath
+ );
+ if (DevicePath == NULL) {
+ continue;
+ }
+
+ //
+ // Embedded RC Index to the DevicePath
+ // This will be used later by the platform NotifyPhase()
+ //
+ DevicePath->AcpiDevicePath.UID = Index;
+
+ mRootBridges[mRootBridgeCount].DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
+ mRootBridgeCount++;
+ }
+
+ Ac01PcieEnd ();
+
+ //
+ // Register event to fixup ACPI table
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL, // Type,
+ TPL_NOTIFY, // NotifyTpl
+ PciHostBridgeReadyToBootEvent, // NotifyFunction
+ NULL, // NotifyContext
+ &gEfiEventReadyToBootGuid, // EventGroup
+ &EvtReadyToBoot // Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return all the root bridge instances in an array.
+
+ @param Count Return the count of root bridge instances.
+
+ @return All the root bridge instances in an array.
+ The array should be passed into PciHostBridgeFreeRootBridges()
+ when it's not used.
+**/
+PCI_ROOT_BRIDGE *
+EFIAPI
+PciHostBridgeGetRootBridges (
+ UINTN *Count
+ )
+{
+ *Count = mRootBridgeCount;
+ return mRootBridges;
+}
+
+/**
+ Free the root bridge instances array returned from PciHostBridgeGetRootBridges().
+
+ @param Bridges The root bridge instances array.
+ @param Count The count of the array.
+**/
+VOID
+EFIAPI
+PciHostBridgeFreeRootBridges (
+ PCI_ROOT_BRIDGE *Bridges,
+ UINTN Count
+ )
+{
+ //
+ // Unsupported
+ //
+}
+
+/**
+ Inform the platform that the resource conflict happens.
+
+ @param HostBridgeHandle Handle of the Host Bridge.
+ @param Configuration Pointer to PCI I/O and PCI memory resource
+ descriptors. The Configuration contains the resources
+ for all the root bridges. The resource for each root
+ bridge is terminated with END descriptor and an
+ additional END is appended indicating the end of the
+ entire resources. The resource descriptor field
+ values follow the description in
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ .SubmitResources().
+**/
+VOID
+EFIAPI
+PciHostBridgeResourceConflict (
+ EFI_HANDLE HostBridgeHandle,
+ VOID *Configuration
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ UINTN RootBridgeIndex;
+ DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n"));
+
+ RootBridgeIndex = 0;
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;
+ while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+ DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));
+ for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
+ ASSERT (Descriptor->ResType <
+ (sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr) /
+ sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr[0])
+ )
+ );
+ DEBUG ((DEBUG_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n",
+ mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],
+ Descriptor->AddrLen, Descriptor->AddrRangeMax
+ ));
+ if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+ DEBUG ((DEBUG_ERROR, " Granularity/SpecificFlag = %ld / %02x%s\n",
+ Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
+ ((Descriptor->SpecificFlag &
+ EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
+ ) != 0) ? L" (Prefetchable)" : L""
+ ));
+ }
+ }
+ //
+ // Skip the END descriptor for root bridge
+ //
+ ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(
+ (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1
+ );
+ }
+}
--
2.17.1


Ard Biesheuvel
 

On Wed, 15 Sept 2021 at 18:00, Nhi Pham <nhi@os.amperecomputing.com> wrote:

From: Vu Nguyen <vunguyen@os.amperecomputing.com>

Provides the number of supported RootBridges and the resource allocated
for each RootBridge. These information are essential to the HostBridge
driver to initialize the PCIe subsystem.

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
This looks ok to me, although I will note the code that patches the
_STA methods in the DSDT according to which host bridges actually
exist in the system should not typically live in a library. However,
this particular library is designed to be incorporated only by
PciHostBridgeDxe so in this case, I can live with it.

Reviewed-by: Ard Biesheuvel <ardb@kernel.org>

---
Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc | 1 +
Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf | 48 +++
Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c | 378 ++++++++++++++++++++
3 files changed, 427 insertions(+)

diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
index d4e1b84c0276..dc66b711aba8 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
@@ -228,6 +228,7 @@ [LibraryClasses.common.DXE_DRIVER]
PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
+ PciHostBridgeLib|Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf

[LibraryClasses.common.UEFI_APPLICATION]
UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiTianoCustomDecompressLib.inf
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
new file mode 100644
index 000000000000..a8ee0c2b9278
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
@@ -0,0 +1,48 @@
+## @file
+#
+# Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = PciHostBridgeLib
+ FILE_GUID = 9D0522E5-B5FD-4E3F-9D10-52AE221FA314
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciHostBridgeLib|DXE_DRIVER
+ CONSTRUCTOR = HostBridgeConstructor
+
+[Sources]
+ PciHostBridgeLib.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+ Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+ Ac01PcieLib
+ AcpiLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ IoLib
+ MemoryAllocationLib
+ PrintLib
+ UefiBootServicesTableLib
+
+[Guids]
+ gEfiEventReadyToBootGuid
+
+[Protocols]
+ gEfiCpuIo2ProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiCpuIo2ProtocolGuid
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
new file mode 100644
index 000000000000..281f20b4bb63
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PciHostBridgeLib/PciHostBridgeLib.c
@@ -0,0 +1,378 @@
+/** @file
+ PCI Host Bridge Library instance for Ampere Altra-based platforms.
+
+ Copyright (c) 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Guid/EventGroup.h>
+#include <IndustryStandard/Acpi.h>
+#include <Library/Ac01PcieLib.h>
+#include <Library/AcpiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+#include <Protocol/PciRootBridgeIo.h>
+
+#include <Ac01PcieCommon.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+STATIC CHAR16 CONST * CONST mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {
+ L"Mem", L"I/O", L"Bus"
+};
+
+#pragma pack(1)
+typedef struct {
+ ACPI_HID_DEVICE_PATH AcpiDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
+#pragma pack ()
+
+STATIC EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath = {
+ {
+ {
+ ACPI_DEVICE_PATH,
+ ACPI_DP,
+ {
+ (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)),
+ (UINT8)((sizeof (ACPI_HID_DEVICE_PATH)) >> 8)
+ }
+ },
+ EISA_PNP_ID (0x0A08), // PCIe
+ 0
+ }, {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+STATIC PCI_ROOT_BRIDGE mRootBridgeTemplate = {
+ 0, // Segment
+ 0, // Supports
+ 0, // Attributes
+ TRUE, // DmaAbove4G
+ FALSE, // NoExtendedConfigSpace
+ FALSE, // ResourceAssigned
+ EFI_PCI_HOST_BRIDGE_MEM64_DECODE,
+ {
+ // Bus
+ 0,
+ 0
+ }, {
+ // Io
+ 0,
+ 0,
+ 0
+ }, {
+ // Mem
+ MAX_UINT64,
+ 0,
+ 0
+ }, {
+ // MemAbove4G
+ MAX_UINT64,
+ 0,
+ 0
+ }, {
+ // PMem
+ MAX_UINT64,
+ 0,
+ 0
+ }, {
+ // PMemAbove4G
+ MAX_UINT64,
+ 0,
+ 0
+ },
+ (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath
+};
+
+UINT8 mRootBridgeCount = 0;
+PCI_ROOT_BRIDGE *mRootBridges = NULL;
+
+EFI_STATUS
+UpdateStatusMethodObject (
+ EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
+ EFI_ACPI_HANDLE TableHandle,
+ CHAR8 *AsciiObjectPath,
+ CHAR8 ReturnValue
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_HANDLE ObjectHandle;
+ EFI_ACPI_DATA_TYPE DataType;
+ CHAR8 *Buffer;
+ UINTN DataSize;
+
+ Status = AcpiSdtProtocol->FindPath (TableHandle, AsciiObjectPath, &ObjectHandle);
+ if (EFI_ERROR (Status) || ObjectHandle == NULL) {
+ return EFI_SUCCESS;
+ }
+ ASSERT (ObjectHandle != NULL);
+
+ Status = AcpiSdtProtocol->GetOption (ObjectHandle, 2, &DataType, (VOID *)&Buffer, &DataSize);
+ if (!EFI_ERROR (Status) && Buffer[2] == AML_BYTE_PREFIX) {
+ //
+ // Only patch when the initial value is byte object.
+ //
+ Buffer[3] = ReturnValue;
+ }
+
+ AcpiSdtProtocol->Close (ObjectHandle);
+ return Status;
+}
+
+/**
+ This function will be called when ReadyToBoot event is signaled.
+
+ @param Event signaled event
+ @param Context calling context
+
+ @retval VOID
+**/
+VOID
+EFIAPI
+PciHostBridgeReadyToBootEvent (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol;
+ EFI_ACPI_DESCRIPTION_HEADER *Table;
+ UINTN TableKey;
+ UINTN TableIndex;
+ EFI_ACPI_HANDLE TableHandle;
+ CHAR8 NodePath[256];
+ UINTN Count;
+ UINTN Idx1;
+ UINTN Idx2;
+
+ Count = 0;
+
+ Status = gBS->LocateProtocol (
+ &gEfiAcpiSdtProtocolGuid,
+ NULL,
+ (VOID **)&AcpiSdtProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Unable to locate ACPI table protocol\n"));
+ return;
+ }
+
+ TableIndex = 0;
+ Status = AcpiLocateTableBySignature (
+ AcpiSdtProtocol,
+ EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
+ &TableIndex,
+ &Table,
+ &TableKey
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a %d Status = %r \n", __FUNCTION__, __LINE__, Status));
+ ASSERT_EFI_ERROR (Status);
+ return;
+ }
+
+ Status = AcpiSdtProtocol->OpenSdt (TableKey, &TableHandle);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ AcpiSdtProtocol->Close (TableHandle);
+ return;
+ }
+
+ for (Idx1 = 0; Idx1 < Ac01PcieGetTotalHBs (); Idx1++) {
+ for (Idx2 = 0; Idx2 < Ac01PcieGetTotalRBsPerHB (Idx1); Idx2++) {
+ AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.PCI%X._STA", Count);
+ if (Ac01PcieCheckRootBridgeDisabled (Idx1, Idx2)) {
+ UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
+ } else {
+ UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0xf);
+ }
+ Count++;
+ }
+ }
+
+ AcpiSdtProtocol->Close (TableHandle);
+ AcpiUpdateChecksum ((UINT8 *)Table, Table->Length);
+
+ //
+ // Close the event, so it will not be signalled again.
+ //
+ gBS->CloseEvent (Event);
+}
+
+EFI_STATUS
+HostBridgeConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Index;
+ EFI_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath;
+ EFI_EVENT EvtReadyToBoot;
+
+ mRootBridges = AllocatePool (Ac01PcieGetTotalHBs () * sizeof (PCI_ROOT_BRIDGE));
+ if (mRootBridges == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Ac01PcieSetup ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < Ac01PcieGetTotalHBs (); Index++) {
+ CopyMem (&mRootBridges[mRootBridgeCount], &mRootBridgeTemplate, sizeof (PCI_ROOT_BRIDGE));
+
+ Status = Ac01PcieSetupRootBridge (Index, 0, (VOID *)&mRootBridges[mRootBridgeCount]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ mRootBridges[mRootBridgeCount].Segment = Ac01PcieGetRootBridgeSegmentNumber (Index, 0);
+
+ DevicePath = AllocateCopyPool (
+ sizeof (EFI_PCI_ROOT_BRIDGE_DEVICE_PATH),
+ (VOID *)&mEfiPciRootBridgeDevicePath
+ );
+ if (DevicePath == NULL) {
+ continue;
+ }
+
+ //
+ // Embedded RC Index to the DevicePath
+ // This will be used later by the platform NotifyPhase()
+ //
+ DevicePath->AcpiDevicePath.UID = Index;
+
+ mRootBridges[mRootBridgeCount].DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
+ mRootBridgeCount++;
+ }
+
+ Ac01PcieEnd ();
+
+ //
+ // Register event to fixup ACPI table
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL, // Type,
+ TPL_NOTIFY, // NotifyTpl
+ PciHostBridgeReadyToBootEvent, // NotifyFunction
+ NULL, // NotifyContext
+ &gEfiEventReadyToBootGuid, // EventGroup
+ &EvtReadyToBoot // Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return all the root bridge instances in an array.
+
+ @param Count Return the count of root bridge instances.
+
+ @return All the root bridge instances in an array.
+ The array should be passed into PciHostBridgeFreeRootBridges()
+ when it's not used.
+**/
+PCI_ROOT_BRIDGE *
+EFIAPI
+PciHostBridgeGetRootBridges (
+ UINTN *Count
+ )
+{
+ *Count = mRootBridgeCount;
+ return mRootBridges;
+}
+
+/**
+ Free the root bridge instances array returned from PciHostBridgeGetRootBridges().
+
+ @param Bridges The root bridge instances array.
+ @param Count The count of the array.
+**/
+VOID
+EFIAPI
+PciHostBridgeFreeRootBridges (
+ PCI_ROOT_BRIDGE *Bridges,
+ UINTN Count
+ )
+{
+ //
+ // Unsupported
+ //
+}
+
+/**
+ Inform the platform that the resource conflict happens.
+
+ @param HostBridgeHandle Handle of the Host Bridge.
+ @param Configuration Pointer to PCI I/O and PCI memory resource
+ descriptors. The Configuration contains the resources
+ for all the root bridges. The resource for each root
+ bridge is terminated with END descriptor and an
+ additional END is appended indicating the end of the
+ entire resources. The resource descriptor field
+ values follow the description in
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ .SubmitResources().
+**/
+VOID
+EFIAPI
+PciHostBridgeResourceConflict (
+ EFI_HANDLE HostBridgeHandle,
+ VOID *Configuration
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ UINTN RootBridgeIndex;
+ DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n"));
+
+ RootBridgeIndex = 0;
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;
+ while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+ DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));
+ for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
+ ASSERT (Descriptor->ResType <
+ (sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr) /
+ sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr[0])
+ )
+ );
+ DEBUG ((DEBUG_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n",
+ mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],
+ Descriptor->AddrLen, Descriptor->AddrRangeMax
+ ));
+ if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+ DEBUG ((DEBUG_ERROR, " Granularity/SpecificFlag = %ld / %02x%s\n",
+ Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
+ ((Descriptor->SpecificFlag &
+ EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
+ ) != 0) ? L" (Prefetchable)" : L""
+ ));
+ }
+ }
+ //
+ // Skip the END descriptor for root bridge
+ //
+ ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(
+ (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1
+ );
+ }
+}
--
2.17.1