123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830 |
- /** @file
- This driver implements EFI_PCI_HOT_PLUG_INIT_PROTOCOL, providing the PCI bus
- driver with resource padding information, for PCIe hotplug purposes.
- Copyright (C) 2016, Red Hat, Inc.
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <IndustryStandard/Acpi10.h>
- #include <IndustryStandard/Q35MchIch9.h>
- #include <IndustryStandard/QemuPciBridgeCapabilities.h>
- #include <Library/BaseLib.h>
- #include <Library/BaseMemoryLib.h>
- #include <Library/DebugLib.h>
- #include <Library/DevicePathLib.h>
- #include <Library/MemoryAllocationLib.h>
- #include <Library/PciCapLib.h>
- #include <Library/PciCapPciSegmentLib.h>
- #include <Library/PciLib.h>
- #include <Library/UefiBootServicesTableLib.h>
- #include <Protocol/PciHotPlugInit.h>
- #include <Protocol/PciRootBridgeIo.h>
- //
- // TRUE if the PCI platform supports extended config space, FALSE otherwise.
- //
- STATIC BOOLEAN mPciExtConfSpaceSupported;
- //
- // The protocol interface this driver produces.
- //
- // Refer to 12.6 "PCI Hot Plug PCI Initialization Protocol" in the Platform
- // Init 1.4a Spec, Volume 5.
- //
- STATIC EFI_PCI_HOT_PLUG_INIT_PROTOCOL mPciHotPlugInit;
- //
- // Resource padding template for the GetResourcePadding() protocol member
- // function.
- //
- // Refer to Table 8 "ACPI 2.0 & 3.0 QWORD Address Space Descriptor Usage" in
- // the Platform Init 1.4a Spec, Volume 5.
- //
- // This structure is interpreted by the ApplyResourcePadding() function in the
- // edk2 PCI Bus UEFI_DRIVER.
- //
- // We can request padding for at most four resource types, each of which is
- // optional, independently of the others:
- // (a) bus numbers,
- // (b) IO space,
- // (c) non-prefetchable MMIO space (32-bit only),
- // (d) prefetchable MMIO space (either 32-bit or 64-bit, never both).
- //
- #pragma pack (1)
- typedef struct {
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR Padding[4];
- EFI_ACPI_END_TAG_DESCRIPTOR EndDesc;
- } RESOURCE_PADDING;
- #pragma pack ()
- /**
- Initialize a RESOURCE_PADDING object.
- @param[out] ResourcePadding The caller-allocated RESOURCE_PADDING object to
- initialize.
- **/
- STATIC
- VOID
- InitializeResourcePadding (
- OUT RESOURCE_PADDING *ResourcePadding
- )
- {
- UINTN Index;
- ZeroMem (ResourcePadding, sizeof *ResourcePadding);
- //
- // Fill in the Padding fields that don't vary across resource types.
- //
- for (Index = 0; Index < ARRAY_SIZE (ResourcePadding->Padding); ++Index) {
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
- Descriptor = ResourcePadding->Padding + Index;
- Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
- Descriptor->Len = (UINT16)(
- sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -
- OFFSET_OF (
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,
- ResType
- )
- );
- }
- //
- // Fill in the End Tag.
- //
- ResourcePadding->EndDesc.Desc = ACPI_END_TAG_DESCRIPTOR;
- }
- /**
- Set up a descriptor entry for reserving IO space.
- @param[in,out] Descriptor The descriptor to configure. The caller shall have
- initialized Descriptor earlier, with
- InitializeResourcePadding().
- @param[in] SizeExponent The size and natural alignment of the reservation
- are determined by raising two to this power.
- **/
- STATIC
- VOID
- SetIoPadding (
- IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor,
- IN UINTN SizeExponent
- )
- {
- Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
- Descriptor->AddrLen = LShiftU64 (1, SizeExponent);
- Descriptor->AddrRangeMax = Descriptor->AddrLen - 1;
- }
- /**
- Set up a descriptor entry for reserving MMIO space.
- @param[in,out] Descriptor The descriptor to configure. The caller shall
- have initialized Descriptor earlier, with
- InitializeResourcePadding().
- @param[in] Prefetchable TRUE if the descriptor should reserve
- prefetchable MMIO space. Pass FALSE for
- reserving non-prefetchable MMIO space.
- @param[in] ThirtyTwoBitOnly TRUE if the reservation should be limited to
- 32-bit address space. FALSE if the reservation
- can be satisfied from 64-bit address space.
- ThirtyTwoBitOnly is ignored if Prefetchable is
- FALSE; in that case ThirtyTwoBitOnly is always
- considered TRUE.
- @param[in] SizeExponent The size and natural alignment of the
- reservation are determined by raising two to
- this power.
- **/
- STATIC
- VOID
- SetMmioPadding (
- IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor,
- IN BOOLEAN Prefetchable,
- IN BOOLEAN ThirtyTwoBitOnly,
- IN UINTN SizeExponent
- )
- {
- Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
- if (Prefetchable) {
- Descriptor->SpecificFlag =
- EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
- Descriptor->AddrSpaceGranularity = ThirtyTwoBitOnly ? 32 : 64;
- } else {
- Descriptor->SpecificFlag =
- EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_NON_CACHEABLE;
- Descriptor->AddrSpaceGranularity = 32;
- }
- Descriptor->AddrLen = LShiftU64 (1, SizeExponent);
- Descriptor->AddrRangeMax = Descriptor->AddrLen - 1;
- }
- /**
- Round up a positive 32-bit value to the next whole power of two, and return
- the bit position of the highest bit set in the result. Equivalent to
- ceil(log2(x)).
- @param[in] Operand The 32-bit operand to evaluate.
- @retval -1 Operand is zero.
- @retval -1 Operand is positive, not a whole power of two, and rounding it
- up to the next power of two does not fit into 32 bits.
- @retval 0..31 Otherwise, return ceil(log2(Value)).
- **/
- STATIC
- INTN
- HighBitSetRoundUp32 (
- IN UINT32 Operand
- )
- {
- INTN HighBit;
- HighBit = HighBitSet32 (Operand);
- if (HighBit == -1) {
- //
- // Operand is zero.
- //
- return HighBit;
- }
- if ((Operand & (Operand - 1)) != 0) {
- //
- // Operand is not a whole power of two.
- //
- ++HighBit;
- }
- return (HighBit < 32) ? HighBit : -1;
- }
- /**
- Round up a positive 64-bit value to the next whole power of two, and return
- the bit position of the highest bit set in the result. Equivalent to
- ceil(log2(x)).
- @param[in] Operand The 64-bit operand to evaluate.
- @retval -1 Operand is zero.
- @retval -1 Operand is positive, not a whole power of two, and rounding it
- up to the next power of two does not fit into 64 bits.
- @retval 0..63 Otherwise, return ceil(log2(Value)).
- **/
- STATIC
- INTN
- HighBitSetRoundUp64 (
- IN UINT64 Operand
- )
- {
- INTN HighBit;
- HighBit = HighBitSet64 (Operand);
- if (HighBit == -1) {
- //
- // Operand is zero.
- //
- return HighBit;
- }
- if ((Operand & (Operand - 1)) != 0) {
- //
- // Operand is not a whole power of two.
- //
- ++HighBit;
- }
- return (HighBit < 64) ? HighBit : -1;
- }
- /**
- Look up the QEMU-specific Resource Reservation capability in the conventional
- config space of a Hotplug Controller (that is, PCI Bridge).
- On error, the contents of ReservationHint are indeterminate.
- @param[in] HpcPciAddress The address of the PCI Bridge -- Bus, Device,
- Function -- in UEFI (not PciLib) encoding.
- @param[out] ReservationHint The caller-allocated capability structure to
- populate from the PCI Bridge's config space.
- @retval EFI_SUCCESS The capability has been found, ReservationHint has
- been populated.
- @retval EFI_NOT_FOUND The capability is missing.
- @return Error codes from PciCapPciSegmentLib and PciCapLib.
- **/
- STATIC
- EFI_STATUS
- QueryReservationHint (
- IN CONST EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *HpcPciAddress,
- OUT QEMU_PCI_BRIDGE_CAPABILITY_RESOURCE_RESERVATION *ReservationHint
- )
- {
- UINT16 PciVendorId;
- EFI_STATUS Status;
- PCI_CAP_DEV *PciDevice;
- PCI_CAP_LIST *CapList;
- UINT16 VendorInstance;
- PCI_CAP *VendorCap;
- //
- // Check the vendor identifier.
- //
- PciVendorId = PciRead16 (
- PCI_LIB_ADDRESS (
- HpcPciAddress->Bus,
- HpcPciAddress->Device,
- HpcPciAddress->Function,
- PCI_VENDOR_ID_OFFSET
- )
- );
- if (PciVendorId != QEMU_PCI_BRIDGE_VENDOR_ID_REDHAT) {
- return EFI_NOT_FOUND;
- }
- //
- // Parse the capabilities lists.
- //
- Status = PciCapPciSegmentDeviceInit (
- mPciExtConfSpaceSupported ? PciCapExtended : PciCapNormal,
- 0, // Segment
- HpcPciAddress->Bus,
- HpcPciAddress->Device,
- HpcPciAddress->Function,
- &PciDevice
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = PciCapListInit (PciDevice, &CapList);
- if (EFI_ERROR (Status)) {
- goto UninitPciDevice;
- }
- //
- // Scan the vendor capability instances for the Resource Reservation
- // capability.
- //
- VendorInstance = 0;
- for ( ; ;) {
- UINT8 VendorLength;
- UINT8 BridgeCapType;
- Status = PciCapListFindCap (
- CapList,
- PciCapNormal,
- EFI_PCI_CAPABILITY_ID_VENDOR,
- VendorInstance++,
- &VendorCap
- );
- if (EFI_ERROR (Status)) {
- goto UninitCapList;
- }
- //
- // Check the vendor capability length.
- //
- Status = PciCapRead (
- PciDevice,
- VendorCap,
- OFFSET_OF (EFI_PCI_CAPABILITY_VENDOR_HDR, Length),
- &VendorLength,
- sizeof VendorLength
- );
- if (EFI_ERROR (Status)) {
- goto UninitCapList;
- }
- if (VendorLength != sizeof *ReservationHint) {
- continue;
- }
- //
- // Check the vendor bridge capability type.
- //
- Status = PciCapRead (
- PciDevice,
- VendorCap,
- OFFSET_OF (QEMU_PCI_BRIDGE_CAPABILITY_HDR, Type),
- &BridgeCapType,
- sizeof BridgeCapType
- );
- if (EFI_ERROR (Status)) {
- goto UninitCapList;
- }
- if (BridgeCapType ==
- QEMU_PCI_BRIDGE_CAPABILITY_TYPE_RESOURCE_RESERVATION)
- {
- //
- // We have a match.
- //
- break;
- }
- }
- //
- // Populate ReservationHint.
- //
- Status = PciCapRead (
- PciDevice,
- VendorCap,
- 0, // SourceOffsetInCap
- ReservationHint,
- sizeof *ReservationHint
- );
- UninitCapList:
- PciCapListUninit (CapList);
- UninitPciDevice:
- PciCapPciSegmentDeviceUninit (PciDevice);
- return Status;
- }
- /**
- Returns a list of root Hot Plug Controllers (HPCs) that require
- initialization during the boot process.
- This procedure returns a list of root HPCs. The PCI bus driver must
- initialize these controllers during the boot process. The PCI bus driver may
- or may not be able to detect these HPCs. If the platform includes a
- PCI-to-CardBus bridge, it can be included in this list if it requires
- initialization. The HpcList must be self consistent. An HPC cannot control
- any of its parent buses. Only one HPC can control a PCI bus. Because this
- list includes only root HPCs, no HPC in the list can be a child of another
- HPC. This policy must be enforced by the EFI_PCI_HOT_PLUG_INIT_PROTOCOL.
- The PCI bus driver may not check for such invalid conditions. The callee
- allocates the buffer HpcList
- @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
- instance.
- @param[out] HpcCount The number of root HPCs that were returned.
- @param[out] HpcList The list of root HPCs. HpcCount defines the number of
- elements in this list.
- @retval EFI_SUCCESS HpcList was returned.
- @retval EFI_OUT_OF_RESOURCES HpcList was not returned due to insufficient
- resources.
- @retval EFI_INVALID_PARAMETER HpcCount is NULL or HpcList is NULL.
- **/
- STATIC
- EFI_STATUS
- EFIAPI
- GetRootHpcList (
- IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,
- OUT UINTN *HpcCount,
- OUT EFI_HPC_LOCATION **HpcList
- )
- {
- if ((HpcCount == NULL) || (HpcList == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // There are no top-level (i.e., un-enumerable) hot-plug controllers in QEMU
- // that would require special initialization.
- //
- *HpcCount = 0;
- *HpcList = NULL;
- return EFI_SUCCESS;
- }
- /**
- Initializes one root Hot Plug Controller (HPC). This process may causes
- initialization of its subordinate buses.
- This function initializes the specified HPC. At the end of initialization,
- the hot-plug slots or sockets (controlled by this HPC) are powered and are
- connected to the bus. All the necessary registers in the HPC are set up. For
- a Standard (PCI) Hot Plug Controller (SHPC), the registers that must be set
- up are defined in the PCI Standard Hot Plug Controller and Subsystem
- Specification.
- @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
- instance.
- @param[in] HpcDevicePath The device path to the HPC that is being
- initialized.
- @param[in] HpcPciAddress The address of the HPC function on the PCI bus.
- @param[in] Event The event that should be signaled when the HPC
- initialization is complete. Set to NULL if the
- caller wants to wait until the entire
- initialization process is complete.
- @param[out] HpcState The state of the HPC hardware. The state is
- EFI_HPC_STATE_INITIALIZED or
- EFI_HPC_STATE_ENABLED.
- @retval EFI_SUCCESS If Event is NULL, the specific HPC was
- successfully initialized. If Event is not
- NULL, Event will be signaled at a later time
- when initialization is complete.
- @retval EFI_UNSUPPORTED This instance of
- EFI_PCI_HOT_PLUG_INIT_PROTOCOL does not
- support the specified HPC.
- @retval EFI_OUT_OF_RESOURCES Initialization failed due to insufficient
- resources.
- @retval EFI_INVALID_PARAMETER HpcState is NULL.
- **/
- STATIC
- EFI_STATUS
- EFIAPI
- InitializeRootHpc (
- IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,
- IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
- IN UINT64 HpcPciAddress,
- IN EFI_EVENT Event OPTIONAL,
- OUT EFI_HPC_STATE *HpcState
- )
- {
- //
- // This function should never be called, due to the information returned by
- // GetRootHpcList().
- //
- ASSERT (FALSE);
- if (HpcState == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- return EFI_UNSUPPORTED;
- }
- /**
- Returns the resource padding that is required by the PCI bus that is
- controlled by the specified Hot Plug Controller (HPC).
- This function returns the resource padding that is required by the PCI bus
- that is controlled by the specified HPC. This member function is called for
- all the root HPCs and nonroot HPCs that are detected by the PCI bus
- enumerator. This function will be called before PCI resource allocation is
- completed. This function must be called after all the root HPCs, with the
- possible exception of a PCI-to-CardBus bridge, have completed
- initialization.
- @param[in] This Pointer to the EFI_PCI_HOT_PLUG_INIT_PROTOCOL
- instance.
- @param[in] HpcDevicePath The device path to the HPC.
- @param[in] HpcPciAddress The address of the HPC function on the PCI bus.
- @param[in] HpcState The state of the HPC hardware.
- @param[out] Padding The amount of resource padding that is required
- by the PCI bus under the control of the specified
- HPC.
- @param[out] Attributes Describes how padding is accounted for. The
- padding is returned in the form of ACPI 2.0
- resource descriptors.
- @retval EFI_SUCCESS The resource padding was successfully
- returned.
- @retval EFI_UNSUPPORTED This instance of the
- EFI_PCI_HOT_PLUG_INIT_PROTOCOL does not
- support the specified HPC.
- @retval EFI_NOT_READY This function was called before HPC
- initialization is complete.
- @retval EFI_INVALID_PARAMETER HpcState or Padding or Attributes is NULL.
- @retval EFI_OUT_OF_RESOURCES ACPI 2.0 resource descriptors for Padding
- cannot be allocated due to insufficient
- resources.
- **/
- STATIC
- EFI_STATUS
- EFIAPI
- GetResourcePadding (
- IN EFI_PCI_HOT_PLUG_INIT_PROTOCOL *This,
- IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
- IN UINT64 HpcPciAddress,
- OUT EFI_HPC_STATE *HpcState,
- OUT VOID **Padding,
- OUT EFI_HPC_PADDING_ATTRIBUTES *Attributes
- )
- {
- EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *Address;
- BOOLEAN DefaultIo;
- BOOLEAN DefaultMmio;
- BOOLEAN DefaultPrefMmio;
- RESOURCE_PADDING ReservationRequest;
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FirstResource;
- EFI_STATUS ReservationHintStatus;
- QEMU_PCI_BRIDGE_CAPABILITY_RESOURCE_RESERVATION ReservationHint;
- Address = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&HpcPciAddress;
- DEBUG_CODE_BEGIN ();
- CHAR16 *DevicePathString;
- DevicePathString = ConvertDevicePathToText (HpcDevicePath, FALSE, FALSE);
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: Address=%02x:%02x.%x DevicePath=%s\n",
- __FUNCTION__,
- Address->Bus,
- Address->Device,
- Address->Function,
- (DevicePathString == NULL) ? L"<unavailable>" : DevicePathString
- ));
- if (DevicePathString != NULL) {
- FreePool (DevicePathString);
- }
- DEBUG_CODE_END ();
- if ((HpcState == NULL) || (Padding == NULL) || (Attributes == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- DefaultIo = TRUE;
- DefaultMmio = TRUE;
- DefaultPrefMmio = TRUE;
- //
- // Init ReservationRequest, and point FirstResource one past the last
- // descriptor entry. We're going to build the entries backwards from
- // ReservationRequest.EndDesc.
- //
- InitializeResourcePadding (&ReservationRequest);
- FirstResource = ReservationRequest.Padding +
- ARRAY_SIZE (ReservationRequest.Padding);
- //
- // Try to get the QEMU-specific Resource Reservation capability.
- //
- ReservationHintStatus = QueryReservationHint (Address, &ReservationHint);
- if (!EFI_ERROR (ReservationHintStatus)) {
- INTN HighBit;
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: BusNumbers=0x%x Io=0x%Lx NonPrefetchable32BitMmio=0x%x\n"
- "%a: Prefetchable32BitMmio=0x%x Prefetchable64BitMmio=0x%Lx\n",
- __FUNCTION__,
- ReservationHint.BusNumbers,
- ReservationHint.Io,
- ReservationHint.NonPrefetchable32BitMmio,
- __FUNCTION__,
- ReservationHint.Prefetchable32BitMmio,
- ReservationHint.Prefetchable64BitMmio
- ));
- //
- // (a) Reserve bus numbers.
- //
- switch (ReservationHint.BusNumbers) {
- case 0:
- //
- // No reservation needed.
- //
- break;
- case MAX_UINT32:
- //
- // Firmware default (unspecified). Treat it as "no reservation needed".
- //
- break;
- default:
- //
- // Request the specified amount.
- //
- --FirstResource;
- FirstResource->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
- FirstResource->AddrLen = ReservationHint.BusNumbers;
- break;
- }
- //
- // (b) Reserve IO space.
- //
- switch (ReservationHint.Io) {
- case 0:
- //
- // No reservation needed, disable our built-in.
- //
- DefaultIo = FALSE;
- break;
- case MAX_UINT64:
- //
- // Firmware default (unspecified). Stick with our built-in.
- //
- break;
- default:
- //
- // Round the specified amount up to the next power of two. If rounding is
- // successful, reserve the rounded value. Fall back to the default
- // otherwise.
- //
- HighBit = HighBitSetRoundUp64 (ReservationHint.Io);
- if (HighBit != -1) {
- SetIoPadding (--FirstResource, (UINTN)HighBit);
- DefaultIo = FALSE;
- }
- break;
- }
- //
- // (c) Reserve non-prefetchable MMIO space (32-bit only).
- //
- switch (ReservationHint.NonPrefetchable32BitMmio) {
- case 0:
- //
- // No reservation needed, disable our built-in.
- //
- DefaultMmio = FALSE;
- break;
- case MAX_UINT32:
- //
- // Firmware default (unspecified). Stick with our built-in.
- //
- break;
- default:
- //
- // Round the specified amount up to the next power of two. If rounding is
- // successful, reserve the rounded value. Fall back to the default
- // otherwise.
- //
- HighBit = HighBitSetRoundUp32 (ReservationHint.NonPrefetchable32BitMmio);
- if (HighBit != -1) {
- SetMmioPadding (--FirstResource, FALSE, TRUE, (UINTN)HighBit);
- DefaultMmio = FALSE;
- }
- break;
- }
- //
- // (d) Reserve prefetchable MMIO space (either 32-bit or 64-bit, never
- // both).
- //
- // For either space, we treat 0 as "no reservation needed", and the maximum
- // value as "firmware default". The latter is unspecified, and we interpret
- // it as the former.
- //
- // Otherwise, round the specified amount up to the next power of two. If
- // rounding is successful, reserve the rounded value. Do not reserve
- // prefetchable MMIO space otherwise.
- //
- if ((ReservationHint.Prefetchable32BitMmio > 0) &&
- (ReservationHint.Prefetchable32BitMmio < MAX_UINT32))
- {
- HighBit = HighBitSetRoundUp32 (ReservationHint.Prefetchable32BitMmio);
- if (HighBit != -1) {
- SetMmioPadding (--FirstResource, TRUE, TRUE, (UINTN)HighBit);
- DefaultPrefMmio = FALSE;
- }
- } else if ((ReservationHint.Prefetchable64BitMmio > 0) &&
- (ReservationHint.Prefetchable64BitMmio < MAX_UINT64))
- {
- HighBit = HighBitSetRoundUp64 (ReservationHint.Prefetchable64BitMmio);
- if (HighBit != -1) {
- SetMmioPadding (--FirstResource, TRUE, FALSE, (UINTN)HighBit);
- DefaultPrefMmio = FALSE;
- }
- }
- }
- if (DefaultIo) {
- //
- // Request defaults.
- //
- SetIoPadding (--FirstResource, (UINTN)HighBitSetRoundUp64 (512));
- }
- if (DefaultMmio) {
- //
- // Request defaults.
- //
- SetMmioPadding (
- --FirstResource,
- FALSE,
- TRUE,
- (UINTN)HighBitSetRoundUp32 (SIZE_2MB)
- );
- }
- if (DefaultPrefMmio) {
- UINT64 Pci64Size = PcdGet64 (PcdPciMmio64Size);
- if (Pci64Size > SIZE_32GB) {
- SetMmioPadding (
- --FirstResource,
- TRUE,
- FALSE,
- (UINTN)HighBitSetRoundUp64 (RShiftU64 (Pci64Size, 8))
- );
- }
- }
- //
- // Output a copy of ReservationRequest from the lowest-address populated
- // entry until the end of the structure (including
- // ReservationRequest.EndDesc). If no reservations are necessary, we'll only
- // output the End Tag.
- //
- *Padding = AllocateCopyPool (
- (UINT8 *)(&ReservationRequest + 1) - (UINT8 *)FirstResource,
- FirstResource
- );
- if (*Padding == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Resource padding is required.
- //
- *HpcState = EFI_HPC_STATE_INITIALIZED | EFI_HPC_STATE_ENABLED;
- //
- // The padding should be applied at PCI bus level, and considered by upstream
- // bridges, recursively.
- //
- *Attributes = EfiPaddingPciBus;
- return EFI_SUCCESS;
- }
- /**
- Entry point for this driver.
- @param[in] ImageHandle Image handle of this driver.
- @param[in] SystemTable Pointer to SystemTable.
- @retval EFI_SUCESS Driver has loaded successfully.
- @return Error codes from lower level functions.
- **/
- EFI_STATUS
- EFIAPI
- DriverInitialize (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- EFI_STATUS Status;
- mPciExtConfSpaceSupported = (PcdGet16 (PcdOvmfHostBridgePciDevId) ==
- INTEL_Q35_MCH_DEVICE_ID);
- mPciHotPlugInit.GetRootHpcList = GetRootHpcList;
- mPciHotPlugInit.InitializeRootHpc = InitializeRootHpc;
- mPciHotPlugInit.GetResourcePadding = GetResourcePadding;
- Status = gBS->InstallMultipleProtocolInterfaces (
- &ImageHandle,
- &gEfiPciHotPlugInitProtocolGuid,
- &mPciHotPlugInit,
- NULL
- );
- return Status;
- }
|