| /** @file | |
| Library instance of PciHostBridgeLib library class for coreboot. | |
| Copyright (C) 2016, Red Hat, Inc. | |
| Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <PiDxe.h> | |
| #include <IndustryStandard/Pci.h> | |
| #include <Protocol/PciHostBridgeResourceAllocation.h> | |
| #include <Protocol/PciRootBridgeIo.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/DevicePathLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/PciHostBridgeLib.h> | |
| #include <Library/PciLib.h> | |
| #include <Library/HobLib.h> | |
| #include "PciHostBridge.h" | |
| STATIC | |
| CONST | |
| CB_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate = { | |
| { | |
| { | |
| ACPI_DEVICE_PATH, | |
| ACPI_DP, | |
| { | |
| (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)), | |
| (UINT8)((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) | |
| } | |
| }, | |
| EISA_PNP_ID (0x0A03), // HID | |
| 0 // UID | |
| }, | |
| { | |
| END_DEVICE_PATH_TYPE, | |
| END_ENTIRE_DEVICE_PATH_SUBTYPE, | |
| { | |
| END_DEVICE_PATH_LENGTH, | |
| 0 | |
| } | |
| } | |
| }; | |
| /** | |
| Initialize a PCI_ROOT_BRIDGE structure. | |
| @param[in] Supports Supported attributes. | |
| @param[in] Attributes Initial attributes. | |
| @param[in] AllocAttributes Allocation attributes. | |
| @param[in] RootBusNumber The bus number to store in RootBus. | |
| @param[in] MaxSubBusNumber The inclusive maximum bus number that can be | |
| assigned to any subordinate bus found behind any | |
| PCI bridge hanging off this root bus. | |
| The caller is responsible for ensuring that | |
| RootBusNumber <= MaxSubBusNumber. If | |
| RootBusNumber equals MaxSubBusNumber, then the | |
| root bus has no room for subordinate buses. | |
| @param[in] Io IO aperture. | |
| @param[in] Mem MMIO aperture. | |
| @param[in] MemAbove4G MMIO aperture above 4G. | |
| @param[in] PMem Prefetchable MMIO aperture. | |
| @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G. | |
| @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated by the | |
| caller) that should be filled in by this | |
| function. | |
| @retval EFI_SUCCESS Initialization successful. A device path | |
| consisting of an ACPI device path node, with | |
| UID = RootBusNumber, has been allocated and | |
| linked into RootBus. | |
| @retval EFI_OUT_OF_RESOURCES Memory allocation failed. | |
| **/ | |
| EFI_STATUS | |
| InitRootBridge ( | |
| IN UINT64 Supports, | |
| IN UINT64 Attributes, | |
| IN UINT64 AllocAttributes, | |
| IN UINT8 RootBusNumber, | |
| IN UINT8 MaxSubBusNumber, | |
| IN PCI_ROOT_BRIDGE_APERTURE *Io, | |
| IN PCI_ROOT_BRIDGE_APERTURE *Mem, | |
| IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G, | |
| IN PCI_ROOT_BRIDGE_APERTURE *PMem, | |
| IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G, | |
| OUT PCI_ROOT_BRIDGE *RootBus | |
| ) | |
| { | |
| CB_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath; | |
| // | |
| // Be safe if other fields are added to PCI_ROOT_BRIDGE later. | |
| // | |
| ZeroMem (RootBus, sizeof *RootBus); | |
| RootBus->Segment = 0; | |
| RootBus->Supports = Supports; | |
| RootBus->Attributes = Attributes; | |
| RootBus->DmaAbove4G = FALSE; | |
| RootBus->AllocationAttributes = AllocAttributes; | |
| RootBus->Bus.Base = RootBusNumber; | |
| RootBus->Bus.Limit = MaxSubBusNumber; | |
| CopyMem (&RootBus->Io, Io, sizeof (*Io)); | |
| CopyMem (&RootBus->Mem, Mem, sizeof (*Mem)); | |
| CopyMem (&RootBus->MemAbove4G, MemAbove4G, sizeof (*MemAbove4G)); | |
| CopyMem (&RootBus->PMem, PMem, sizeof (*PMem)); | |
| CopyMem (&RootBus->PMemAbove4G, PMemAbove4G, sizeof (*PMemAbove4G)); | |
| RootBus->NoExtendedConfigSpace = FALSE; | |
| DevicePath = AllocateCopyPool ( | |
| sizeof (mRootBridgeDevicePathTemplate), | |
| &mRootBridgeDevicePathTemplate | |
| ); | |
| if (DevicePath == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: %r\n", __func__, EFI_OUT_OF_RESOURCES)); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| DevicePath->AcpiDevicePath.UID = RootBusNumber; | |
| RootBus->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "%a: populated root bus %d, with room for %d subordinate bus(es)\n", | |
| __func__, | |
| RootBusNumber, | |
| MaxSubBusNumber - RootBusNumber | |
| )); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Initialize DevicePath for a PCI_ROOT_BRIDGE. | |
| @param[in] HID HID for device path | |
| @param[in] UID UID for device path | |
| @retval A pointer to the new created device patch. | |
| **/ | |
| EFI_DEVICE_PATH_PROTOCOL * | |
| CreateRootBridgeDevicePath ( | |
| IN UINT32 HID, | |
| IN UINT32 UID | |
| ) | |
| { | |
| CB_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath; | |
| DevicePath = AllocateCopyPool ( | |
| sizeof (mRootBridgeDevicePathTemplate), | |
| &mRootBridgeDevicePathTemplate | |
| ); | |
| ASSERT (DevicePath != NULL); | |
| DevicePath->AcpiDevicePath.HID = HID; | |
| DevicePath->AcpiDevicePath.UID = UID; | |
| return (EFI_DEVICE_PATH_PROTOCOL *)DevicePath; | |
| } | |
| /** | |
| 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 | |
| ) | |
| { | |
| UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *PciRootBridgeInfo; | |
| EFI_HOB_GUID_TYPE *GuidHob; | |
| UNIVERSAL_PAYLOAD_GENERIC_HEADER *GenericHeader; | |
| // | |
| // Find Universal Payload PCI Root Bridge Info hob | |
| // | |
| GuidHob = GetFirstGuidHob (&gUniversalPayloadPciRootBridgeInfoGuid); | |
| if (GuidHob != NULL) { | |
| GenericHeader = (UNIVERSAL_PAYLOAD_GENERIC_HEADER *)GET_GUID_HOB_DATA (GuidHob); | |
| if ((sizeof (UNIVERSAL_PAYLOAD_GENERIC_HEADER) <= GET_GUID_HOB_DATA_SIZE (GuidHob)) && (GenericHeader->Length <= GET_GUID_HOB_DATA_SIZE (GuidHob))) { | |
| if ((GenericHeader->Revision == UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES_REVISION) && (GenericHeader->Length >= sizeof (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES))) { | |
| // | |
| // UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES structure is used when Revision equals to UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES_REVISION | |
| // | |
| PciRootBridgeInfo = (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *)GET_GUID_HOB_DATA (GuidHob); | |
| if (PciRootBridgeInfo->Count <= (GET_GUID_HOB_DATA_SIZE (GuidHob) - sizeof (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES)) / sizeof (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGE)) { | |
| return RetrieveRootBridgeInfoFromHob (PciRootBridgeInfo, Count); | |
| } | |
| } | |
| } | |
| } | |
| return ScanForRootBridges (Count); | |
| } | |
| /** | |
| 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 | |
| ) | |
| { | |
| if ((Bridges == NULL) || (Count == 0)) { | |
| return; | |
| } | |
| ASSERT (Bridges != NULL || Count > 0); | |
| do { | |
| --Count; | |
| FreePool (Bridges[Count].DevicePath); | |
| } while (Count > 0); | |
| FreePool (Bridges); | |
| } | |
| /** | |
| 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 | |
| ) | |
| { | |
| // | |
| // coreboot UEFI Payload does not do PCI enumeration and should not call this | |
| // library interface. | |
| // | |
| ASSERT (FALSE); | |
| } |