\r
#include <IndustryStandard/Acpi10.h>\r
#include <IndustryStandard/Pci.h>\r
+#include <Library/BaseLib.h>\r
#include <Library/BaseMemoryLib.h>\r
#include <Library/DebugLib.h>\r
#include <Library/DevicePathLib.h>\r
+#include <Library/HardwareInfoLib.h>\r
#include <Library/MemoryAllocationLib.h>\r
#include <Library/PciHostBridgeUtilityLib.h>\r
#include <Library/PciLib.h>\r
#include <Library/QemuFwCfgLib.h>\r
+#include <Protocol/PciHostBridgeResourceAllocation.h>\r
\r
#pragma pack(1)\r
typedef struct {\r
}\r
\r
/**\r
- Utility function to return all the root bridge instances in an array.\r
+ Utility function to scan PCI root bridges and create instances for those\r
+ that are found not empty. Populate their resources from the default\r
+ provided parameters and return all the root bridge instances in an array.\r
\r
@param[out] Count The number of root bridge instances.\r
\r
\r
@return All the root bridge instances in an array.\r
**/\r
+STATIC\r
PCI_ROOT_BRIDGE *\r
-EFIAPI\r
-PciHostBridgeUtilityGetRootBridges (\r
+PciHostBridgeUtilityGetRootBridgesBusScan (\r
OUT UINTN *Count,\r
IN UINT64 Attributes,\r
IN UINT64 AllocationAttributes,\r
UINTN LastRootBridgeNumber;\r
UINTN RootBridgeNumber;\r
\r
- *Count = 0;\r
-\r
if ((BusMin > BusMax) || (BusMax > PCI_MAX_BUS)) {\r
DEBUG ((\r
DEBUG_ERROR,\r
return NULL;\r
}\r
\r
+/**\r
+ Utility function to read root bridges information from host-provided fw-cfg\r
+ file and return them in an array.\r
+\r
+ @param[out] Count The number of root bridge instances.\r
+\r
+ @return All the root bridge instances in an array parsed from\r
+ host-provided fw-cfg file (hardware-info).\r
+**/\r
+STATIC\r
+PCI_ROOT_BRIDGE *\r
+PciHostBridgeUtilityGetRootBridgesHostProvided (\r
+ OUT UINTN *Count\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ FIRMWARE_CONFIG_ITEM FwCfgItem;\r
+ UINTN FwCfgSize;\r
+ PCI_ROOT_BRIDGE *Bridges;\r
+ UINTN Initialized;\r
+ UINTN LastRootBridgeNumber;\r
+ UINTN RootBridgeNumber;\r
+ UINTN PciHostBridgeCount;\r
+ UINT8 *HardwareInfoBlob;\r
+ LIST_ENTRY HwInfoList;\r
+ LIST_ENTRY *HwLink;\r
+ HARDWARE_INFO *HwInfo;\r
+ UINT64 Attributes;\r
+ UINT64 AllocationAttributes;\r
+ BOOLEAN DmaAbove4G;\r
+ BOOLEAN NoExtendedConfigSpace;\r
+ BOOLEAN CombineMemPMem;\r
+ PCI_ROOT_BRIDGE_APERTURE Io;\r
+ PCI_ROOT_BRIDGE_APERTURE Mem;\r
+ PCI_ROOT_BRIDGE_APERTURE MemAbove4G;\r
+ PCI_ROOT_BRIDGE_APERTURE PMem;\r
+ PCI_ROOT_BRIDGE_APERTURE PMemAbove4G;\r
+\r
+ //\r
+ // Initialize the Hardware Info list head to start with an empty but valid\r
+ // list head.\r
+ //\r
+ InitializeListHead (&HwInfoList);\r
+ HardwareInfoBlob = NULL;\r
+ Initialized = 0;\r
+ Bridges = NULL;\r
+ PciHostBridgeCount = 0;\r
+\r
+ //\r
+ // Hypervisor can provide the specifications (resources) for one or more\r
+ // PCI host bridges. Such information comes through fw-cfg as part of\r
+ // the hardware-info file.\r
+ //\r
+ Status = QemuFwCfgFindFile ("etc/hardware-info", &FwCfgItem, &FwCfgSize);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ HardwareInfoBlob = AllocatePool (FwCfgSize);\r
+\r
+ if (HardwareInfoBlob == NULL) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "%a: Failed to allocate memory for hardware resources info\n",\r
+ __FUNCTION__\r
+ ));\r
+ return NULL;\r
+ }\r
+\r
+ QemuFwCfgSelectItem (FwCfgItem);\r
+ QemuFwCfgReadBytes (FwCfgSize, HardwareInfoBlob);\r
+\r
+ //\r
+ // Create the list of hardware info devices filtering for PCI host\r
+ // bridges\r
+ //\r
+ Status = CreateHardwareInfoList (\r
+ HardwareInfoBlob,\r
+ FwCfgSize,\r
+ HardwareInfoTypeHostBridge,\r
+ &HwInfoList\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "%a: Failed to create hardware info list to retrieve host "\r
+ "bridges information from fw-cfg\n",\r
+ __FUNCTION__\r
+ ));\r
+\r
+ goto FreeBridges;\r
+ }\r
+\r
+ PciHostBridgeCount = GetHardwareInfoCountByType (\r
+ &HwInfoList,\r
+ HardwareInfoTypeHostBridge,\r
+ sizeof (HOST_BRIDGE_INFO)\r
+ );\r
+\r
+ if (PciHostBridgeCount == 0) {\r
+ goto FreeBridges;\r
+ }\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "%a: Host provided description for %Lu root bridges\n",\r
+ __FUNCTION__,\r
+ PciHostBridgeCount\r
+ ));\r
+\r
+ //\r
+ // Allocate the root bridges\r
+ //\r
+ Bridges = AllocatePool (((UINTN)PciHostBridgeCount) * sizeof *Bridges);\r
+ if (Bridges == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r
+ goto FreeBridges;\r
+ }\r
+\r
+ //\r
+ // If Host Bridges' specification was obtained from fw-cfg, the list\r
+ // contains information to populate all root bridges in the system\r
+ // including resources and attributes.\r
+ //\r
+ HwLink = GetFirstHardwareInfoByType (\r
+ &HwInfoList,\r
+ HardwareInfoTypeHostBridge,\r
+ sizeof (HOST_BRIDGE_INFO)\r
+ );\r
+\r
+ while (!EndOfHardwareInfoList (&HwInfoList, HwLink)) {\r
+ HwInfo = HARDWARE_INFO_FROM_LINK (HwLink);\r
+\r
+ Status = HardwareInfoPciHostBridgeGet (\r
+ HwInfo->Data.PciHostBridge,\r
+ (UINTN)HwInfo->Header.Size,\r
+ &RootBridgeNumber,\r
+ &LastRootBridgeNumber,\r
+ &Attributes,\r
+ &DmaAbove4G,\r
+ &NoExtendedConfigSpace,\r
+ &CombineMemPMem,\r
+ &Io,\r
+ &Mem,\r
+ &MemAbove4G,\r
+ &PMem,\r
+ &PMemAbove4G,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeBridges;\r
+ }\r
+\r
+ if ((RootBridgeNumber > LastRootBridgeNumber) || (LastRootBridgeNumber > PCI_MAX_BUS)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "%a: invalid bus range with BusMin %Lu and BusMax "\r
+ "%Lu\n",\r
+ __FUNCTION__,\r
+ (UINT64)RootBridgeNumber,\r
+ (UINT64)LastRootBridgeNumber\r
+ ));\r
+ goto FreeBridges;\r
+ }\r
+\r
+ AllocationAttributes = 0;\r
+ if (CombineMemPMem) {\r
+ AllocationAttributes |= EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM;\r
+ }\r
+\r
+ if ((MemAbove4G.Limit > MemAbove4G.Base) ||\r
+ (PMemAbove4G.Limit > PMemAbove4G.Base))\r
+ {\r
+ AllocationAttributes |= EFI_PCI_HOST_BRIDGE_MEM64_DECODE;\r
+ }\r
+\r
+ Status = PciHostBridgeUtilityInitRootBridge (\r
+ Attributes,\r
+ Attributes,\r
+ AllocationAttributes,\r
+ DmaAbove4G,\r
+ NoExtendedConfigSpace,\r
+ (UINT8)RootBridgeNumber,\r
+ (UINT8)LastRootBridgeNumber,\r
+ &Io,\r
+ &Mem,\r
+ &MemAbove4G,\r
+ &PMem,\r
+ &PMemAbove4G,\r
+ &Bridges[Initialized]\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeBridges;\r
+ }\r
+\r
+ ++Initialized;\r
+\r
+ HwLink = GetNextHardwareInfoByType (\r
+ &HwInfoList,\r
+ HwLink,\r
+ HardwareInfoTypeHostBridge,\r
+ sizeof (HOST_BRIDGE_INFO)\r
+ );\r
+ }\r
+\r
+ *Count = Initialized;\r
+\r
+ //\r
+ // If resources were allocated for host bridges info, release them\r
+ //\r
+ if (HardwareInfoBlob) {\r
+ FreePool (HardwareInfoBlob);\r
+ }\r
+\r
+ FreeHardwareInfoList (&HwInfoList);\r
+ return Bridges;\r
+\r
+FreeBridges:\r
+ while (Initialized > 0) {\r
+ --Initialized;\r
+ PciHostBridgeUtilityUninitRootBridge (&Bridges[Initialized]);\r
+ }\r
+\r
+ if (Bridges) {\r
+ FreePool (Bridges);\r
+ }\r
+\r
+ if (HardwareInfoBlob) {\r
+ FreePool (HardwareInfoBlob);\r
+ }\r
+\r
+ FreeHardwareInfoList (&HwInfoList);\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Utility function to return all the root bridge instances in an array.\r
+\r
+ @param[out] Count The number of root bridge instances.\r
+\r
+ @param[in] Attributes Initial attributes.\r
+\r
+ @param[in] AllocAttributes Allocation attributes.\r
+\r
+ @param[in] DmaAbove4G DMA above 4GB memory.\r
+\r
+ @param[in] NoExtendedConfigSpace No Extended Config Space.\r
+\r
+ @param[in] BusMin Minimum Bus number, inclusive.\r
+\r
+ @param[in] BusMax Maximum Bus number, inclusive.\r
+\r
+ @param[in] Io IO aperture.\r
+\r
+ @param[in] Mem MMIO aperture.\r
+\r
+ @param[in] MemAbove4G MMIO aperture above 4G.\r
+\r
+ @param[in] PMem Prefetchable MMIO aperture.\r
+\r
+ @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.\r
+\r
+ @return All the root bridge instances in an array.\r
+**/\r
+PCI_ROOT_BRIDGE *\r
+EFIAPI\r
+PciHostBridgeUtilityGetRootBridges (\r
+ OUT UINTN *Count,\r
+ IN UINT64 Attributes,\r
+ IN UINT64 AllocationAttributes,\r
+ IN BOOLEAN DmaAbove4G,\r
+ IN BOOLEAN NoExtendedConfigSpace,\r
+ IN UINTN BusMin,\r
+ IN UINTN BusMax,\r
+ IN PCI_ROOT_BRIDGE_APERTURE *Io,\r
+ IN PCI_ROOT_BRIDGE_APERTURE *Mem,\r
+ IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,\r
+ IN PCI_ROOT_BRIDGE_APERTURE *PMem,\r
+ IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G\r
+ )\r
+{\r
+ PCI_ROOT_BRIDGE *Bridges;\r
+\r
+ *Count = 0;\r
+\r
+ //\r
+ // First attempt to get the host provided descriptions of the Root Bridges\r
+ // if available.\r
+ //\r
+ Bridges = PciHostBridgeUtilityGetRootBridgesHostProvided (Count);\r
+\r
+ //\r
+ // If host did not provide Root Bridge information, scan the buses and\r
+ // auto populate them with default resources.\r
+ //\r
+ if (Bridges == NULL) {\r
+ Bridges = PciHostBridgeUtilityGetRootBridgesBusScan (\r
+ Count,\r
+ Attributes,\r
+ AllocationAttributes,\r
+ DmaAbove4G,\r
+ NoExtendedConfigSpace,\r
+ BusMin,\r
+ BusMax,\r
+ Io,\r
+ Mem,\r
+ MemAbove4G,\r
+ PMem,\r
+ PMemAbove4G\r
+ );\r
+ }\r
+\r
+ return Bridges;\r
+}\r
+\r
/**\r
Utility function to free root bridge instances array from\r
PciHostBridgeUtilityGetRootBridges().\r