ArmVirtPkg/FdtPciHostBridgeLib: Relocate FdtPciHostBridgeLib to OvmfPkg/Fdt
Relocate FdtPciHostBridgeLib to OvmfPkg/Fdt, this library is leverage by both ARM and RISC-V archs. Also use PcdPciMmio32Translation and PcdPciMmio64Translation PCDs provided by MdePkg instead of ArmPkg. Signed-off-by: Abner Chang <abner.chang@hpe.com> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Sami Mujawar <sami.mujawar@arm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: Daniel Schaefer <daniel.schaefer@hpe.com> Cc: Sunil V L <sunilvl@ventanamicro.com> Reviewed-by: Daniel Schaefer <daniel.schaefer@hpe.com> Reviewed-by: Sunil V L <sunilvl@ventanamicro.com> Acked-by: Gerd Hoffmann <kraxel@redhat.com> Acked-by: Jiewen Yao <jiewen.yao@intel.com>
This commit is contained in:
committed by
mergify[bot]
parent
c6770f4b88
commit
9a7509e465
417
OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.c
Normal file
417
OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.c
Normal file
@@ -0,0 +1,417 @@
|
||||
/** @file
|
||||
PCI Host Bridge Library instance for pci-ecam-generic DT nodes
|
||||
|
||||
Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
#include <PiDxe.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/DxeServicesTableLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/PcdLib.h>
|
||||
#include <Library/PciHostBridgeLib.h>
|
||||
#include <Library/PciHostBridgeUtilityLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
|
||||
#include <Protocol/FdtClient.h>
|
||||
#include <Protocol/PciRootBridgeIo.h>
|
||||
#include <Protocol/PciHostBridgeResourceAllocation.h>
|
||||
|
||||
//
|
||||
// We expect the "ranges" property of "pci-host-ecam-generic" to consist of
|
||||
// records like this.
|
||||
//
|
||||
#pragma pack (1)
|
||||
typedef struct {
|
||||
UINT32 Type;
|
||||
UINT64 ChildBase;
|
||||
UINT64 CpuBase;
|
||||
UINT64 Size;
|
||||
} DTB_PCI_HOST_RANGE_RECORD;
|
||||
#pragma pack ()
|
||||
|
||||
#define DTB_PCI_HOST_RANGE_RELOCATABLE BIT31
|
||||
#define DTB_PCI_HOST_RANGE_PREFETCHABLE BIT30
|
||||
#define DTB_PCI_HOST_RANGE_ALIASED BIT29
|
||||
#define DTB_PCI_HOST_RANGE_MMIO32 BIT25
|
||||
#define DTB_PCI_HOST_RANGE_MMIO64 (BIT25 | BIT24)
|
||||
#define DTB_PCI_HOST_RANGE_IO BIT24
|
||||
#define DTB_PCI_HOST_RANGE_TYPEMASK (BIT31 | BIT30 | BIT29 | BIT25 | BIT24)
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
MapGcdMmioSpace (
|
||||
IN UINT64 Base,
|
||||
IN UINT64 Size
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo, Base, Size,
|
||||
EFI_MEMORY_UC);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR,
|
||||
"%a: failed to add GCD memory space for region [0x%Lx+0x%Lx)\n",
|
||||
__FUNCTION__, Base, Size));
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gDS->SetMemorySpaceAttributes (Base, Size, EFI_MEMORY_UC);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR,
|
||||
"%a: failed to set memory space attributes for region [0x%Lx+0x%Lx)\n",
|
||||
__FUNCTION__, Base, Size));
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
ProcessPciHost (
|
||||
OUT UINT64 *IoBase,
|
||||
OUT UINT64 *IoSize,
|
||||
OUT UINT64 *Mmio32Base,
|
||||
OUT UINT64 *Mmio32Size,
|
||||
OUT UINT64 *Mmio64Base,
|
||||
OUT UINT64 *Mmio64Size,
|
||||
OUT UINT32 *BusMin,
|
||||
OUT UINT32 *BusMax
|
||||
)
|
||||
{
|
||||
FDT_CLIENT_PROTOCOL *FdtClient;
|
||||
INT32 Node;
|
||||
UINT64 ConfigBase, ConfigSize;
|
||||
CONST VOID *Prop;
|
||||
UINT32 Len;
|
||||
UINT32 RecordIdx;
|
||||
EFI_STATUS Status;
|
||||
UINT64 IoTranslation;
|
||||
UINT64 Mmio32Translation;
|
||||
UINT64 Mmio64Translation;
|
||||
|
||||
//
|
||||
// The following output arguments are initialized only in
|
||||
// order to suppress '-Werror=maybe-uninitialized' warnings
|
||||
// *incorrectly* emitted by some gcc versions.
|
||||
//
|
||||
*IoBase = 0;
|
||||
*Mmio32Base = 0;
|
||||
*Mmio64Base = MAX_UINT64;
|
||||
*BusMin = 0;
|
||||
*BusMax = 0;
|
||||
|
||||
//
|
||||
// *IoSize, *Mmio##Size and IoTranslation are initialized to zero because the
|
||||
// logic below requires it. However, since they are also affected by the issue
|
||||
// reported above, they are initialized early.
|
||||
//
|
||||
*IoSize = 0;
|
||||
*Mmio32Size = 0;
|
||||
*Mmio64Size = 0;
|
||||
IoTranslation = 0;
|
||||
|
||||
Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL,
|
||||
(VOID **)&FdtClient);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
Status = FdtClient->FindCompatibleNode (FdtClient, "pci-host-ecam-generic",
|
||||
&Node);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_INFO,
|
||||
"%a: No 'pci-host-ecam-generic' compatible DT node found\n",
|
||||
__FUNCTION__));
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
DEBUG_CODE (
|
||||
INT32 Tmp;
|
||||
|
||||
//
|
||||
// A DT can legally describe multiple PCI host bridges, but we are not
|
||||
// equipped to deal with that. So assert that there is only one.
|
||||
//
|
||||
Status = FdtClient->FindNextCompatibleNode (FdtClient,
|
||||
"pci-host-ecam-generic", Node, &Tmp);
|
||||
ASSERT (Status == EFI_NOT_FOUND);
|
||||
);
|
||||
|
||||
Status = FdtClient->GetNodeProperty (FdtClient, Node, "reg", &Prop, &Len);
|
||||
if (EFI_ERROR (Status) || Len != 2 * sizeof (UINT64)) {
|
||||
DEBUG ((EFI_D_ERROR, "%a: 'reg' property not found or invalid\n",
|
||||
__FUNCTION__));
|
||||
return EFI_PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Fetch the ECAM window.
|
||||
//
|
||||
ConfigBase = SwapBytes64 (((CONST UINT64 *)Prop)[0]);
|
||||
ConfigSize = SwapBytes64 (((CONST UINT64 *)Prop)[1]);
|
||||
|
||||
//
|
||||
// Fetch the bus range (note: inclusive).
|
||||
//
|
||||
Status = FdtClient->GetNodeProperty (FdtClient, Node, "bus-range", &Prop,
|
||||
&Len);
|
||||
if (EFI_ERROR (Status) || Len != 2 * sizeof (UINT32)) {
|
||||
DEBUG ((EFI_D_ERROR, "%a: 'bus-range' not found or invalid\n",
|
||||
__FUNCTION__));
|
||||
return EFI_PROTOCOL_ERROR;
|
||||
}
|
||||
*BusMin = SwapBytes32 (((CONST UINT32 *)Prop)[0]);
|
||||
*BusMax = SwapBytes32 (((CONST UINT32 *)Prop)[1]);
|
||||
|
||||
//
|
||||
// Sanity check: the config space must accommodate all 4K register bytes of
|
||||
// all 8 functions of all 32 devices of all buses.
|
||||
//
|
||||
if (*BusMax < *BusMin || *BusMax - *BusMin == MAX_UINT32 ||
|
||||
DivU64x32 (ConfigSize, SIZE_4KB * 8 * 32) < *BusMax - *BusMin + 1) {
|
||||
DEBUG ((EFI_D_ERROR, "%a: invalid 'bus-range' and/or 'reg'\n",
|
||||
__FUNCTION__));
|
||||
return EFI_PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Iterate over "ranges".
|
||||
//
|
||||
Status = FdtClient->GetNodeProperty (FdtClient, Node, "ranges", &Prop, &Len);
|
||||
if (EFI_ERROR (Status) || Len == 0 ||
|
||||
Len % sizeof (DTB_PCI_HOST_RANGE_RECORD) != 0) {
|
||||
DEBUG ((EFI_D_ERROR, "%a: 'ranges' not found or invalid\n", __FUNCTION__));
|
||||
return EFI_PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
for (RecordIdx = 0; RecordIdx < Len / sizeof (DTB_PCI_HOST_RANGE_RECORD);
|
||||
++RecordIdx) {
|
||||
CONST DTB_PCI_HOST_RANGE_RECORD *Record;
|
||||
|
||||
Record = (CONST DTB_PCI_HOST_RANGE_RECORD *)Prop + RecordIdx;
|
||||
switch (SwapBytes32 (Record->Type) & DTB_PCI_HOST_RANGE_TYPEMASK) {
|
||||
case DTB_PCI_HOST_RANGE_IO:
|
||||
*IoBase = SwapBytes64 (Record->ChildBase);
|
||||
*IoSize = SwapBytes64 (Record->Size);
|
||||
IoTranslation = SwapBytes64 (Record->CpuBase) - *IoBase;
|
||||
|
||||
ASSERT (PcdGet64 (PcdPciIoTranslation) == IoTranslation);
|
||||
break;
|
||||
|
||||
case DTB_PCI_HOST_RANGE_MMIO32:
|
||||
*Mmio32Base = SwapBytes64 (Record->ChildBase);
|
||||
*Mmio32Size = SwapBytes64 (Record->Size);
|
||||
Mmio32Translation = SwapBytes64 (Record->CpuBase) - *Mmio32Base;
|
||||
|
||||
if (*Mmio32Base > MAX_UINT32 || *Mmio32Size > MAX_UINT32 ||
|
||||
*Mmio32Base + *Mmio32Size > SIZE_4GB) {
|
||||
DEBUG ((EFI_D_ERROR, "%a: MMIO32 space invalid\n", __FUNCTION__));
|
||||
return EFI_PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
ASSERT (PcdGet64 (PcdPciMmio32Translation) == Mmio32Translation);
|
||||
|
||||
if (Mmio32Translation != 0) {
|
||||
DEBUG ((EFI_D_ERROR, "%a: unsupported nonzero MMIO32 translation "
|
||||
"0x%Lx\n", __FUNCTION__, Mmio32Translation));
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DTB_PCI_HOST_RANGE_MMIO64:
|
||||
*Mmio64Base = SwapBytes64 (Record->ChildBase);
|
||||
*Mmio64Size = SwapBytes64 (Record->Size);
|
||||
Mmio64Translation = SwapBytes64 (Record->CpuBase) - *Mmio64Base;
|
||||
|
||||
ASSERT (PcdGet64 (PcdPciMmio64Translation) == Mmio64Translation);
|
||||
|
||||
if (Mmio64Translation != 0) {
|
||||
DEBUG ((EFI_D_ERROR, "%a: unsupported nonzero MMIO64 translation "
|
||||
"0x%Lx\n", __FUNCTION__, Mmio64Translation));
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*IoSize == 0 || *Mmio32Size == 0) {
|
||||
DEBUG ((EFI_D_ERROR, "%a: %a space empty\n", __FUNCTION__,
|
||||
(*IoSize == 0) ? "IO" : "MMIO32"));
|
||||
return EFI_PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// The dynamic PCD PcdPciExpressBaseAddress should have already been set,
|
||||
// and should match the value we found in the DT node.
|
||||
//
|
||||
ASSERT (PcdGet64 (PcdPciExpressBaseAddress) == ConfigBase);
|
||||
|
||||
DEBUG ((EFI_D_INFO, "%a: Config[0x%Lx+0x%Lx) Bus[0x%x..0x%x] "
|
||||
"Io[0x%Lx+0x%Lx)@0x%Lx Mem32[0x%Lx+0x%Lx)@0x0 Mem64[0x%Lx+0x%Lx)@0x0\n",
|
||||
__FUNCTION__, ConfigBase, ConfigSize, *BusMin, *BusMax, *IoBase, *IoSize,
|
||||
IoTranslation, *Mmio32Base, *Mmio32Size, *Mmio64Base, *Mmio64Size));
|
||||
|
||||
// Map the ECAM space in the GCD memory map
|
||||
Status = MapGcdMmioSpace (ConfigBase, ConfigSize);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Map the MMIO window that provides I/O access - the PCI host bridge code
|
||||
// is not aware of this translation and so it will only map the I/O view
|
||||
// in the GCD I/O map.
|
||||
//
|
||||
Status = MapGcdMmioSpace (*IoBase + IoTranslation, *IoSize);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
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
|
||||
)
|
||||
{
|
||||
UINT64 IoBase, IoSize;
|
||||
UINT64 Mmio32Base, Mmio32Size;
|
||||
UINT64 Mmio64Base, Mmio64Size;
|
||||
UINT32 BusMin, BusMax;
|
||||
EFI_STATUS Status;
|
||||
UINT64 Attributes;
|
||||
UINT64 AllocationAttributes;
|
||||
PCI_ROOT_BRIDGE_APERTURE Io;
|
||||
PCI_ROOT_BRIDGE_APERTURE Mem;
|
||||
PCI_ROOT_BRIDGE_APERTURE MemAbove4G;
|
||||
PCI_ROOT_BRIDGE_APERTURE PMem;
|
||||
PCI_ROOT_BRIDGE_APERTURE PMemAbove4G;
|
||||
|
||||
if (PcdGet64 (PcdPciExpressBaseAddress) == 0) {
|
||||
DEBUG ((EFI_D_INFO, "%a: PCI host bridge not present\n", __FUNCTION__));
|
||||
|
||||
*Count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Status = ProcessPciHost (&IoBase, &IoSize, &Mmio32Base, &Mmio32Size,
|
||||
&Mmio64Base, &Mmio64Size, &BusMin, &BusMax);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "%a: failed to discover PCI host bridge: %r\n",
|
||||
__FUNCTION__, Status));
|
||||
*Count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ZeroMem (&Io, sizeof (Io));
|
||||
ZeroMem (&Mem, sizeof (Mem));
|
||||
ZeroMem (&MemAbove4G, sizeof (MemAbove4G));
|
||||
ZeroMem (&PMem, sizeof (PMem));
|
||||
ZeroMem (&PMemAbove4G, sizeof (PMemAbove4G));
|
||||
|
||||
Attributes = EFI_PCI_ATTRIBUTE_ISA_IO_16 |
|
||||
EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO |
|
||||
EFI_PCI_ATTRIBUTE_VGA_IO_16 |
|
||||
EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16;
|
||||
|
||||
AllocationAttributes = EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM;
|
||||
|
||||
Io.Base = IoBase;
|
||||
Io.Limit = IoBase + IoSize - 1;
|
||||
Mem.Base = Mmio32Base;
|
||||
Mem.Limit = Mmio32Base + Mmio32Size - 1;
|
||||
|
||||
if (sizeof (UINTN) == sizeof (UINT64)) {
|
||||
MemAbove4G.Base = Mmio64Base;
|
||||
MemAbove4G.Limit = Mmio64Base + Mmio64Size - 1;
|
||||
if (Mmio64Size > 0) {
|
||||
AllocationAttributes |= EFI_PCI_HOST_BRIDGE_MEM64_DECODE;
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// UEFI mandates a 1:1 virtual-to-physical mapping, so on a 32-bit
|
||||
// architecture such as ARM, we will not be able to access 64-bit MMIO
|
||||
// BARs unless they are allocated below 4 GB. So ignore the range above
|
||||
// 4 GB in this case.
|
||||
//
|
||||
MemAbove4G.Base = MAX_UINT64;
|
||||
MemAbove4G.Limit = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// No separate ranges for prefetchable and non-prefetchable BARs
|
||||
//
|
||||
PMem.Base = MAX_UINT64;
|
||||
PMem.Limit = 0;
|
||||
PMemAbove4G.Base = MAX_UINT64;
|
||||
PMemAbove4G.Limit = 0;
|
||||
|
||||
return PciHostBridgeUtilityGetRootBridges (
|
||||
Count,
|
||||
Attributes,
|
||||
AllocationAttributes,
|
||||
TRUE,
|
||||
FALSE,
|
||||
BusMin,
|
||||
BusMax,
|
||||
&Io,
|
||||
&Mem,
|
||||
&MemAbove4G,
|
||||
&PMem,
|
||||
&PMemAbove4G
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
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
|
||||
)
|
||||
{
|
||||
PciHostBridgeUtilityFreeRootBridges (Bridges, Count);
|
||||
}
|
||||
|
||||
/**
|
||||
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
|
||||
)
|
||||
{
|
||||
PciHostBridgeUtilityResourceConflict (Configuration);
|
||||
}
|
53
OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf
Normal file
53
OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf
Normal file
@@ -0,0 +1,53 @@
|
||||
## @file
|
||||
# PCI Host Bridge Library instance for pci-ecam-generic DT nodes
|
||||
#
|
||||
# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = FdtPciHostBridgeLib
|
||||
FILE_GUID = 59fcb139-2558-4cf0-8d7c-ebac499da727
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = PciHostBridgeLib
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build
|
||||
# tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = AARCH64 ARM
|
||||
#
|
||||
|
||||
[Sources]
|
||||
FdtPciHostBridgeLib.c
|
||||
|
||||
[Packages]
|
||||
EmbeddedPkg/EmbeddedPkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
MdePkg/MdePkg.dec
|
||||
OvmfPkg/OvmfPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
BaseMemoryLib
|
||||
DebugLib
|
||||
DevicePathLib
|
||||
DxeServicesTableLib
|
||||
MemoryAllocationLib
|
||||
PciHostBridgeUtilityLib
|
||||
PciPcdProducerLib
|
||||
|
||||
[FixedPcd]
|
||||
gEfiMdePkgTokenSpaceGuid.PcdPciMmio32Translation
|
||||
gEfiMdePkgTokenSpaceGuid.PcdPciMmio64Translation
|
||||
|
||||
[Pcd]
|
||||
gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation
|
||||
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
|
||||
|
||||
[Depex]
|
||||
gFdtClientProtocolGuid
|
Reference in New Issue
Block a user