\r
Copyright (C) 2016, Red Hat, Inc.\r
\r
- This program and the accompanying materials are licensed and made available\r
- under the terms and conditions of the BSD License which accompanies this\r
- distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
- WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
**/\r
\r
#include <IndustryStandard/Acpi10.h>\r
+#include <IndustryStandard/Q35MchIch9.h>\r
+#include <IndustryStandard/QemuPciBridgeCapabilities.h>\r
\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
#include <Library/DebugLib.h>\r
#include <Library/DevicePathLib.h>\r
#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PciCapLib.h>\r
+#include <Library/PciCapPciSegmentLib.h>\r
+#include <Library/PciLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
\r
#include <Protocol/PciHotPlugInit.h>\r
#include <Protocol/PciRootBridgeIo.h>\r
\r
+//\r
+// TRUE if the PCI platform supports extended config space, FALSE otherwise.\r
+//\r
+STATIC BOOLEAN mPciExtConfSpaceSupported;\r
+\r
//\r
// The protocol interface this driver produces.\r
//\r
// Refer to 12.6 "PCI Hot Plug PCI Initialization Protocol" in the Platform\r
// Init 1.4a Spec, Volume 5.\r
//\r
-STATIC EFI_PCI_HOT_PLUG_INIT_PROTOCOL mPciHotPlugInit;\r
-\r
+STATIC EFI_PCI_HOT_PLUG_INIT_PROTOCOL mPciHotPlugInit;\r
\r
//\r
// Resource padding template for the GetResourcePadding() protocol member\r
// This structure is interpreted by the ApplyResourcePadding() function in the\r
// edk2 PCI Bus UEFI_DRIVER.\r
//\r
+// We can request padding for at most four resource types, each of which is\r
+// optional, independently of the others:\r
+// (a) bus numbers,\r
+// (b) IO space,\r
+// (c) non-prefetchable MMIO space (32-bit only),\r
+// (d) prefetchable MMIO space (either 32-bit or 64-bit, never both).\r
+//\r
#pragma pack (1)\r
typedef struct {\r
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR MmioPadding;\r
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR IoPadding;\r
- EFI_ACPI_END_TAG_DESCRIPTOR EndDesc;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR Padding[4];\r
+ EFI_ACPI_END_TAG_DESCRIPTOR EndDesc;\r
} RESOURCE_PADDING;\r
#pragma pack ()\r
\r
-STATIC CONST RESOURCE_PADDING mPadding = {\r
+/**\r
+ Initialize a RESOURCE_PADDING object.\r
+\r
+ @param[out] ResourcePadding The caller-allocated RESOURCE_PADDING object to\r
+ initialize.\r
+**/\r
+STATIC\r
+VOID\r
+InitializeResourcePadding (\r
+ OUT RESOURCE_PADDING *ResourcePadding\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ ZeroMem (ResourcePadding, sizeof *ResourcePadding);\r
+\r
+ //\r
+ // Fill in the Padding fields that don't vary across resource types.\r
+ //\r
+ for (Index = 0; Index < ARRAY_SIZE (ResourcePadding->Padding); ++Index) {\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
+\r
+ Descriptor = ResourcePadding->Padding + Index;\r
+ Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
+ Descriptor->Len = (UINT16)(\r
+ sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -\r
+ OFFSET_OF (\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,\r
+ ResType\r
+ )\r
+ );\r
+ }\r
+\r
+ //\r
+ // Fill in the End Tag.\r
+ //\r
+ ResourcePadding->EndDesc.Desc = ACPI_END_TAG_DESCRIPTOR;\r
+}\r
+\r
+/**\r
+ Set up a descriptor entry for reserving IO space.\r
+\r
+ @param[in,out] Descriptor The descriptor to configure. The caller shall have\r
+ initialized Descriptor earlier, with\r
+ InitializeResourcePadding().\r
+\r
+ @param[in] SizeExponent The size and natural alignment of the reservation\r
+ are determined by raising two to this power.\r
+**/\r
+STATIC\r
+VOID\r
+SetIoPadding (\r
+ IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor,\r
+ IN UINTN SizeExponent\r
+ )\r
+{\r
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;\r
+ Descriptor->AddrLen = LShiftU64 (1, SizeExponent);\r
+ Descriptor->AddrRangeMax = Descriptor->AddrLen - 1;\r
+}\r
+\r
+/**\r
+ Set up a descriptor entry for reserving MMIO space.\r
+\r
+ @param[in,out] Descriptor The descriptor to configure. The caller shall\r
+ have initialized Descriptor earlier, with\r
+ InitializeResourcePadding().\r
+\r
+ @param[in] Prefetchable TRUE if the descriptor should reserve\r
+ prefetchable MMIO space. Pass FALSE for\r
+ reserving non-prefetchable MMIO space.\r
+\r
+ @param[in] ThirtyTwoBitOnly TRUE if the reservation should be limited to\r
+ 32-bit address space. FALSE if the reservation\r
+ can be satisfied from 64-bit address space.\r
+ ThirtyTwoBitOnly is ignored if Prefetchable is\r
+ FALSE; in that case ThirtyTwoBitOnly is always\r
+ considered TRUE.\r
+\r
+ @param[in] SizeExponent The size and natural alignment of the\r
+ reservation are determined by raising two to\r
+ this power.\r
+**/\r
+STATIC\r
+VOID\r
+SetMmioPadding (\r
+ IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor,\r
+ IN BOOLEAN Prefetchable,\r
+ IN BOOLEAN ThirtyTwoBitOnly,\r
+ IN UINTN SizeExponent\r
+ )\r
+{\r
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
+ if (Prefetchable) {\r
+ Descriptor->SpecificFlag =\r
+ EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
+ Descriptor->AddrSpaceGranularity = ThirtyTwoBitOnly ? 32 : 64;\r
+ } else {\r
+ Descriptor->SpecificFlag =\r
+ EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_NON_CACHEABLE;\r
+ Descriptor->AddrSpaceGranularity = 32;\r
+ }\r
+\r
+ Descriptor->AddrLen = LShiftU64 (1, SizeExponent);\r
+ Descriptor->AddrRangeMax = Descriptor->AddrLen - 1;\r
+}\r
+\r
+/**\r
+ Round up a positive 32-bit value to the next whole power of two, and return\r
+ the bit position of the highest bit set in the result. Equivalent to\r
+ ceil(log2(x)).\r
+\r
+ @param[in] Operand The 32-bit operand to evaluate.\r
+\r
+ @retval -1 Operand is zero.\r
+\r
+ @retval -1 Operand is positive, not a whole power of two, and rounding it\r
+ up to the next power of two does not fit into 32 bits.\r
+\r
+ @retval 0..31 Otherwise, return ceil(log2(Value)).\r
+**/\r
+STATIC\r
+INTN\r
+HighBitSetRoundUp32 (\r
+ IN UINT32 Operand\r
+ )\r
+{\r
+ INTN HighBit;\r
+\r
+ HighBit = HighBitSet32 (Operand);\r
+ if (HighBit == -1) {\r
+ //\r
+ // Operand is zero.\r
+ //\r
+ return HighBit;\r
+ }\r
+\r
+ if ((Operand & (Operand - 1)) != 0) {\r
+ //\r
+ // Operand is not a whole power of two.\r
+ //\r
+ ++HighBit;\r
+ }\r
+\r
+ return (HighBit < 32) ? HighBit : -1;\r
+}\r
+\r
+/**\r
+ Round up a positive 64-bit value to the next whole power of two, and return\r
+ the bit position of the highest bit set in the result. Equivalent to\r
+ ceil(log2(x)).\r
+\r
+ @param[in] Operand The 64-bit operand to evaluate.\r
+\r
+ @retval -1 Operand is zero.\r
+\r
+ @retval -1 Operand is positive, not a whole power of two, and rounding it\r
+ up to the next power of two does not fit into 64 bits.\r
+\r
+ @retval 0..63 Otherwise, return ceil(log2(Value)).\r
+**/\r
+STATIC\r
+INTN\r
+HighBitSetRoundUp64 (\r
+ IN UINT64 Operand\r
+ )\r
+{\r
+ INTN HighBit;\r
+\r
+ HighBit = HighBitSet64 (Operand);\r
+ if (HighBit == -1) {\r
+ //\r
+ // Operand is zero.\r
+ //\r
+ return HighBit;\r
+ }\r
+\r
+ if ((Operand & (Operand - 1)) != 0) {\r
+ //\r
+ // Operand is not a whole power of two.\r
+ //\r
+ ++HighBit;\r
+ }\r
+\r
+ return (HighBit < 64) ? HighBit : -1;\r
+}\r
+\r
+/**\r
+ Look up the QEMU-specific Resource Reservation capability in the conventional\r
+ config space of a Hotplug Controller (that is, PCI Bridge).\r
+\r
+ On error, the contents of ReservationHint are indeterminate.\r
+\r
+ @param[in] HpcPciAddress The address of the PCI Bridge -- Bus, Device,\r
+ Function -- in UEFI (not PciLib) encoding.\r
+\r
+ @param[out] ReservationHint The caller-allocated capability structure to\r
+ populate from the PCI Bridge's config space.\r
+\r
+ @retval EFI_SUCCESS The capability has been found, ReservationHint has\r
+ been populated.\r
+\r
+ @retval EFI_NOT_FOUND The capability is missing.\r
+\r
+ @return Error codes from PciCapPciSegmentLib and PciCapLib.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+QueryReservationHint (\r
+ IN CONST EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *HpcPciAddress,\r
+ OUT QEMU_PCI_BRIDGE_CAPABILITY_RESOURCE_RESERVATION *ReservationHint\r
+ )\r
+{\r
+ UINT16 PciVendorId;\r
+ EFI_STATUS Status;\r
+ PCI_CAP_DEV *PciDevice;\r
+ PCI_CAP_LIST *CapList;\r
+ UINT16 VendorInstance;\r
+ PCI_CAP *VendorCap;\r
+\r
//\r
- // MmioPadding\r
+ // Check the vendor identifier.\r
//\r
- {\r
- ACPI_ADDRESS_SPACE_DESCRIPTOR, // Desc\r
- (UINT16)( // Len\r
- sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -\r
- OFFSET_OF (\r
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,\r
- ResType\r
- )\r
- ),\r
- ACPI_ADDRESS_SPACE_TYPE_MEM, // ResType\r
- 0, // GenFlag:\r
- // ignored\r
- 0, // SpecificFlag:\r
- // non-prefetchable\r
- 32, // AddrSpaceGranularity:\r
- // reserve 32-bit aperture\r
- 0, // AddrRangeMin:\r
- // ignored\r
- SIZE_2MB - 1, // AddrRangeMax:\r
- // align at 2MB\r
- 0, // AddrTranslationOffset:\r
- // ignored\r
- SIZE_2MB // AddrLen:\r
- // 2MB padding\r
- },\r
+ PciVendorId = PciRead16 (\r
+ PCI_LIB_ADDRESS (\r
+ HpcPciAddress->Bus,\r
+ HpcPciAddress->Device,\r
+ HpcPciAddress->Function,\r
+ PCI_VENDOR_ID_OFFSET\r
+ )\r
+ );\r
+ if (PciVendorId != QEMU_PCI_BRIDGE_VENDOR_ID_REDHAT) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
\r
//\r
- // IoPadding\r
+ // Parse the capabilities lists.\r
//\r
- {\r
- ACPI_ADDRESS_SPACE_DESCRIPTOR, // Desc\r
- (UINT16)( // Len\r
- sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -\r
- OFFSET_OF (\r
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,\r
- ResType\r
- )\r
- ),\r
- ACPI_ADDRESS_SPACE_TYPE_IO,// ResType\r
- 0, // GenFlag:\r
- // ignored\r
- 0, // SpecificFlag:\r
- // ignored\r
- 0, // AddrSpaceGranularity:\r
- // ignored\r
- 0, // AddrRangeMin:\r
- // ignored\r
- 512 - 1, // AddrRangeMax:\r
- // align at 512 IO ports\r
- 0, // AddrTranslationOffset:\r
- // ignored\r
- 512 // AddrLen:\r
- // 512 IO ports\r
- },\r
+ Status = PciCapPciSegmentDeviceInit (\r
+ mPciExtConfSpaceSupported ? PciCapExtended : PciCapNormal,\r
+ 0, // Segment\r
+ HpcPciAddress->Bus,\r
+ HpcPciAddress->Device,\r
+ HpcPciAddress->Function,\r
+ &PciDevice\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = PciCapListInit (PciDevice, &CapList);\r
+ if (EFI_ERROR (Status)) {\r
+ goto UninitPciDevice;\r
+ }\r
\r
//\r
- // EndDesc\r
+ // Scan the vendor capability instances for the Resource Reservation\r
+ // capability.\r
//\r
- {\r
- ACPI_END_TAG_DESCRIPTOR, // Desc\r
- 0 // Checksum: to be ignored\r
+ VendorInstance = 0;\r
+ for ( ; ;) {\r
+ UINT8 VendorLength;\r
+ UINT8 BridgeCapType;\r
+\r
+ Status = PciCapListFindCap (\r
+ CapList,\r
+ PciCapNormal,\r
+ EFI_PCI_CAPABILITY_ID_VENDOR,\r
+ VendorInstance++,\r
+ &VendorCap\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto UninitCapList;\r
+ }\r
+\r
+ //\r
+ // Check the vendor capability length.\r
+ //\r
+ Status = PciCapRead (\r
+ PciDevice,\r
+ VendorCap,\r
+ OFFSET_OF (EFI_PCI_CAPABILITY_VENDOR_HDR, Length),\r
+ &VendorLength,\r
+ sizeof VendorLength\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto UninitCapList;\r
+ }\r
+\r
+ if (VendorLength != sizeof *ReservationHint) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Check the vendor bridge capability type.\r
+ //\r
+ Status = PciCapRead (\r
+ PciDevice,\r
+ VendorCap,\r
+ OFFSET_OF (QEMU_PCI_BRIDGE_CAPABILITY_HDR, Type),\r
+ &BridgeCapType,\r
+ sizeof BridgeCapType\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto UninitCapList;\r
+ }\r
+\r
+ if (BridgeCapType ==\r
+ QEMU_PCI_BRIDGE_CAPABILITY_TYPE_RESOURCE_RESERVATION)\r
+ {\r
+ //\r
+ // We have a match.\r
+ //\r
+ break;\r
+ }\r
}\r
-};\r
\r
+ //\r
+ // Populate ReservationHint.\r
+ //\r
+ Status = PciCapRead (\r
+ PciDevice,\r
+ VendorCap,\r
+ 0, // SourceOffsetInCap\r
+ ReservationHint,\r
+ sizeof *ReservationHint\r
+ );\r
+\r
+UninitCapList:\r
+ PciCapListUninit (CapList);\r
+\r
+UninitPciDevice:\r
+ PciCapPciSegmentDeviceUninit (PciDevice);\r
+\r
+ return Status;\r
+}\r
\r
/**\r
Returns a list of root Hot Plug Controllers (HPCs) that require\r
EFI_STATUS\r
EFIAPI\r
GetRootHpcList (\r
- IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,\r
- OUT UINTN *HpcCount,\r
- OUT EFI_HPC_LOCATION **HpcList\r
+ IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,\r
+ OUT UINTN *HpcCount,\r
+ OUT EFI_HPC_LOCATION **HpcList\r
)\r
{\r
- if (HpcCount == NULL || HpcList == NULL) {\r
+ if ((HpcCount == NULL) || (HpcList == NULL)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
// that would require special initialization.\r
//\r
*HpcCount = 0;\r
- *HpcList = NULL;\r
+ *HpcList = NULL;\r
return EFI_SUCCESS;\r
}\r
\r
-\r
/**\r
Initializes one root Hot Plug Controller (HPC). This process may causes\r
initialization of its subordinate buses.\r
EFI_STATUS\r
EFIAPI\r
InitializeRootHpc (\r
- IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,\r
- IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,\r
- IN UINT64 HpcPciAddress,\r
- IN EFI_EVENT Event, OPTIONAL\r
- OUT EFI_HPC_STATE *HpcState\r
+ IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,\r
+ IN UINT64 HpcPciAddress,\r
+ IN EFI_EVENT Event OPTIONAL,\r
+ OUT EFI_HPC_STATE *HpcState\r
)\r
{\r
//\r
if (HpcState == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
+\r
return EFI_UNSUPPORTED;\r
}\r
\r
-\r
/**\r
Returns the resource padding that is required by the PCI bus that is\r
controlled by the specified Hot Plug Controller (HPC).\r
EFI_STATUS\r
EFIAPI\r
GetResourcePadding (\r
- IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,\r
- IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,\r
- IN UINT64 HpcPciAddress,\r
- OUT EFI_HPC_STATE *HpcState,\r
- OUT VOID **Padding,\r
- OUT EFI_HPC_PADDING_ATTRIBUTES *Attributes\r
+ IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,\r
+ IN UINT64 HpcPciAddress,\r
+ OUT EFI_HPC_STATE *HpcState,\r
+ OUT VOID **Padding,\r
+ OUT EFI_HPC_PADDING_ATTRIBUTES *Attributes\r
)\r
{\r
- DEBUG_CODE (\r
- EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *Address;\r
- CHAR16 *DevicePathString;\r
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *Address;\r
+ BOOLEAN DefaultIo;\r
+ BOOLEAN DefaultMmio;\r
+ RESOURCE_PADDING ReservationRequest;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FirstResource;\r
+ EFI_STATUS ReservationHintStatus;\r
+ QEMU_PCI_BRIDGE_CAPABILITY_RESOURCE_RESERVATION ReservationHint;\r
+\r
+ Address = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&HpcPciAddress;\r
+\r
+ DEBUG_CODE_BEGIN ();\r
+ CHAR16 *DevicePathString;\r
+\r
+ DevicePathString = ConvertDevicePathToText (HpcDevicePath, FALSE, FALSE);\r
+\r
+ DEBUG ((\r
+ DEBUG_VERBOSE,\r
+ "%a: Address=%02x:%02x.%x DevicePath=%s\n",\r
+ __FUNCTION__,\r
+ Address->Bus,\r
+ Address->Device,\r
+ Address->Function,\r
+ (DevicePathString == NULL) ? L"<unavailable>" : DevicePathString\r
+ ));\r
+\r
+ if (DevicePathString != NULL) {\r
+ FreePool (DevicePathString);\r
+ }\r
+\r
+ DEBUG_CODE_END ();\r
+\r
+ if ((HpcState == NULL) || (Padding == NULL) || (Attributes == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DefaultIo = TRUE;\r
+ DefaultMmio = TRUE;\r
\r
- Address = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&HpcPciAddress;\r
- DevicePathString = ConvertDevicePathToText (HpcDevicePath, FALSE, FALSE);\r
+ //\r
+ // Init ReservationRequest, and point FirstResource one past the last\r
+ // descriptor entry. We're going to build the entries backwards from\r
+ // ReservationRequest.EndDesc.\r
+ //\r
+ InitializeResourcePadding (&ReservationRequest);\r
+ FirstResource = ReservationRequest.Padding +\r
+ ARRAY_SIZE (ReservationRequest.Padding);\r
+\r
+ //\r
+ // Try to get the QEMU-specific Resource Reservation capability.\r
+ //\r
+ ReservationHintStatus = QueryReservationHint (Address, &ReservationHint);\r
+ if (!EFI_ERROR (ReservationHintStatus)) {\r
+ INTN HighBit;\r
+\r
+ DEBUG ((\r
+ DEBUG_VERBOSE,\r
+ "%a: BusNumbers=0x%x Io=0x%Lx NonPrefetchable32BitMmio=0x%x\n"\r
+ "%a: Prefetchable32BitMmio=0x%x Prefetchable64BitMmio=0x%Lx\n",\r
+ __FUNCTION__,\r
+ ReservationHint.BusNumbers,\r
+ ReservationHint.Io,\r
+ ReservationHint.NonPrefetchable32BitMmio,\r
+ __FUNCTION__,\r
+ ReservationHint.Prefetchable32BitMmio,\r
+ ReservationHint.Prefetchable64BitMmio\r
+ ));\r
+\r
+ //\r
+ // (a) Reserve bus numbers.\r
+ //\r
+ switch (ReservationHint.BusNumbers) {\r
+ case 0:\r
+ //\r
+ // No reservation needed.\r
+ //\r
+ break;\r
+ case MAX_UINT32:\r
+ //\r
+ // Firmware default (unspecified). Treat it as "no reservation needed".\r
+ //\r
+ break;\r
+ default:\r
+ //\r
+ // Request the specified amount.\r
+ //\r
+ --FirstResource;\r
+ FirstResource->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;\r
+ FirstResource->AddrLen = ReservationHint.BusNumbers;\r
+ break;\r
+ }\r
\r
- DEBUG ((EFI_D_VERBOSE, "%a: Address=%02x:%02x.%x DevicePath=%s\n",\r
- __FUNCTION__, Address->Bus, Address->Device, Address->Function,\r
- (DevicePathString == NULL) ? L"<unavailable>" : DevicePathString));\r
+ //\r
+ // (b) Reserve IO space.\r
+ //\r
+ switch (ReservationHint.Io) {\r
+ case 0:\r
+ //\r
+ // No reservation needed, disable our built-in.\r
+ //\r
+ DefaultIo = FALSE;\r
+ break;\r
+ case MAX_UINT64:\r
+ //\r
+ // Firmware default (unspecified). Stick with our built-in.\r
+ //\r
+ break;\r
+ default:\r
+ //\r
+ // Round the specified amount up to the next power of two. If rounding is\r
+ // successful, reserve the rounded value. Fall back to the default\r
+ // otherwise.\r
+ //\r
+ HighBit = HighBitSetRoundUp64 (ReservationHint.Io);\r
+ if (HighBit != -1) {\r
+ SetIoPadding (--FirstResource, (UINTN)HighBit);\r
+ DefaultIo = FALSE;\r
+ }\r
+\r
+ break;\r
+ }\r
\r
- if (DevicePathString != NULL) {\r
- FreePool (DevicePathString);\r
+ //\r
+ // (c) Reserve non-prefetchable MMIO space (32-bit only).\r
+ //\r
+ switch (ReservationHint.NonPrefetchable32BitMmio) {\r
+ case 0:\r
+ //\r
+ // No reservation needed, disable our built-in.\r
+ //\r
+ DefaultMmio = FALSE;\r
+ break;\r
+ case MAX_UINT32:\r
+ //\r
+ // Firmware default (unspecified). Stick with our built-in.\r
+ //\r
+ break;\r
+ default:\r
+ //\r
+ // Round the specified amount up to the next power of two. If rounding is\r
+ // successful, reserve the rounded value. Fall back to the default\r
+ // otherwise.\r
+ //\r
+ HighBit = HighBitSetRoundUp32 (ReservationHint.NonPrefetchable32BitMmio);\r
+ if (HighBit != -1) {\r
+ SetMmioPadding (--FirstResource, FALSE, TRUE, (UINTN)HighBit);\r
+ DefaultMmio = FALSE;\r
+ }\r
+\r
+ break;\r
}\r
- );\r
\r
- if (HpcState == NULL || Padding == NULL || Attributes == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
+ //\r
+ // (d) Reserve prefetchable MMIO space (either 32-bit or 64-bit, never\r
+ // both).\r
+ //\r
+ // For either space, we treat 0 as "no reservation needed", and the maximum\r
+ // value as "firmware default". The latter is unspecified, and we interpret\r
+ // it as the former.\r
+ //\r
+ // Otherwise, round the specified amount up to the next power of two. If\r
+ // rounding is successful, reserve the rounded value. Do not reserve\r
+ // prefetchable MMIO space otherwise.\r
+ //\r
+ if ((ReservationHint.Prefetchable32BitMmio > 0) &&\r
+ (ReservationHint.Prefetchable32BitMmio < MAX_UINT32))\r
+ {\r
+ HighBit = HighBitSetRoundUp32 (ReservationHint.Prefetchable32BitMmio);\r
+ if (HighBit != -1) {\r
+ SetMmioPadding (--FirstResource, TRUE, TRUE, (UINTN)HighBit);\r
+ }\r
+ } else if ((ReservationHint.Prefetchable64BitMmio > 0) &&\r
+ (ReservationHint.Prefetchable64BitMmio < MAX_UINT64))\r
+ {\r
+ HighBit = HighBitSetRoundUp64 (ReservationHint.Prefetchable64BitMmio);\r
+ if (HighBit != -1) {\r
+ SetMmioPadding (--FirstResource, TRUE, FALSE, (UINTN)HighBit);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (DefaultIo) {\r
+ //\r
+ // Request defaults.\r
+ //\r
+ SetIoPadding (--FirstResource, (UINTN)HighBitSetRoundUp64 (512));\r
+ }\r
+\r
+ if (DefaultMmio) {\r
+ //\r
+ // Request defaults.\r
+ //\r
+ SetMmioPadding (\r
+ --FirstResource,\r
+ FALSE,\r
+ TRUE,\r
+ (UINTN)HighBitSetRoundUp32 (SIZE_2MB)\r
+ );\r
}\r
\r
- *Padding = AllocateCopyPool (sizeof mPadding, &mPadding);\r
+ //\r
+ // Output a copy of ReservationRequest from the lowest-address populated\r
+ // entry until the end of the structure (including\r
+ // ReservationRequest.EndDesc). If no reservations are necessary, we'll only\r
+ // output the End Tag.\r
+ //\r
+ *Padding = AllocateCopyPool (\r
+ (UINT8 *)(&ReservationRequest + 1) - (UINT8 *)FirstResource,\r
+ FirstResource\r
+ );\r
if (*Padding == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
return EFI_SUCCESS;\r
}\r
\r
-\r
/**\r
Entry point for this driver.\r
\r
EFI_STATUS\r
EFIAPI\r
DriverInitialize (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
)\r
{\r
- EFI_STATUS Status;\r
+ EFI_STATUS Status;\r
\r
- mPciHotPlugInit.GetRootHpcList = GetRootHpcList;\r
- mPciHotPlugInit.InitializeRootHpc = InitializeRootHpc;\r
+ mPciExtConfSpaceSupported = (PcdGet16 (PcdOvmfHostBridgePciDevId) ==\r
+ INTEL_Q35_MCH_DEVICE_ID);\r
+ mPciHotPlugInit.GetRootHpcList = GetRootHpcList;\r
+ mPciHotPlugInit.InitializeRootHpc = InitializeRootHpc;\r
mPciHotPlugInit.GetResourcePadding = GetResourcePadding;\r
- Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,\r
- &gEfiPciHotPlugInitProtocolGuid, &mPciHotPlugInit, NULL);\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &ImageHandle,\r
+ &gEfiPciHotPlugInitProtocolGuid,\r
+ &mPciHotPlugInit,\r
+ NULL\r
+ );\r
return Status;\r
}\r