mirror of https://github.com/acidanthera/audk.git
343 lines
12 KiB
C
343 lines
12 KiB
C
|
/** @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.
|
||
|
|
||
|
This program and the accompanying materials are licensed and made available
|
||
|
under the terms and conditions of the BSD License which accompanies this
|
||
|
distribution. The full text of the license may be found at
|
||
|
http://opensource.org/licenses/bsd-license.php
|
||
|
|
||
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
|
||
|
WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||
|
**/
|
||
|
|
||
|
#include <IndustryStandard/Acpi10.h>
|
||
|
|
||
|
#include <Library/DebugLib.h>
|
||
|
#include <Library/DevicePathLib.h>
|
||
|
#include <Library/MemoryAllocationLib.h>
|
||
|
#include <Library/UefiBootServicesTableLib.h>
|
||
|
|
||
|
#include <Protocol/PciHotPlugInit.h>
|
||
|
#include <Protocol/PciRootBridgeIo.h>
|
||
|
|
||
|
//
|
||
|
// 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.
|
||
|
//
|
||
|
#pragma pack (1)
|
||
|
typedef struct {
|
||
|
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR MmioPadding;
|
||
|
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR IoPadding;
|
||
|
EFI_ACPI_END_TAG_DESCRIPTOR EndDesc;
|
||
|
} RESOURCE_PADDING;
|
||
|
#pragma pack ()
|
||
|
|
||
|
STATIC CONST RESOURCE_PADDING mPadding = {
|
||
|
//
|
||
|
// MmioPadding
|
||
|
//
|
||
|
{
|
||
|
ACPI_ADDRESS_SPACE_DESCRIPTOR, // Desc
|
||
|
(UINT16)( // Len
|
||
|
sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -
|
||
|
OFFSET_OF (
|
||
|
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,
|
||
|
ResType
|
||
|
)
|
||
|
),
|
||
|
ACPI_ADDRESS_SPACE_TYPE_MEM, // ResType
|
||
|
0, // GenFlag:
|
||
|
// ignored
|
||
|
0, // SpecificFlag:
|
||
|
// non-prefetchable
|
||
|
64, // AddrSpaceGranularity:
|
||
|
// reserve 64-bit aperture
|
||
|
0, // AddrRangeMin:
|
||
|
// ignored
|
||
|
SIZE_2MB - 1, // AddrRangeMax:
|
||
|
// align at 2MB
|
||
|
0, // AddrTranslationOffset:
|
||
|
// ignored
|
||
|
SIZE_2MB // AddrLen:
|
||
|
// 2MB padding
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// IoPadding
|
||
|
//
|
||
|
{
|
||
|
ACPI_ADDRESS_SPACE_DESCRIPTOR, // Desc
|
||
|
(UINT16)( // Len
|
||
|
sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) -
|
||
|
OFFSET_OF (
|
||
|
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR,
|
||
|
ResType
|
||
|
)
|
||
|
),
|
||
|
ACPI_ADDRESS_SPACE_TYPE_IO,// ResType
|
||
|
0, // GenFlag:
|
||
|
// ignored
|
||
|
0, // SpecificFlag:
|
||
|
// ignored
|
||
|
0, // AddrSpaceGranularity:
|
||
|
// ignored
|
||
|
0, // AddrRangeMin:
|
||
|
// ignored
|
||
|
512 - 1, // AddrRangeMax:
|
||
|
// align at 512 IO ports
|
||
|
0, // AddrTranslationOffset:
|
||
|
// ignored
|
||
|
512 // AddrLen:
|
||
|
// 512 IO ports
|
||
|
},
|
||
|
|
||
|
//
|
||
|
// EndDesc
|
||
|
//
|
||
|
{
|
||
|
ACPI_END_TAG_DESCRIPTOR, // Desc
|
||
|
0 // Checksum: to be ignored
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
/**
|
||
|
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
|
||
|
)
|
||
|
{
|
||
|
DEBUG_CODE (
|
||
|
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *Address;
|
||
|
CHAR16 *DevicePathString;
|
||
|
|
||
|
Address = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *)&HpcPciAddress;
|
||
|
DevicePathString = ConvertDevicePathToText (HpcDevicePath, FALSE, FALSE);
|
||
|
|
||
|
DEBUG ((EFI_D_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);
|
||
|
}
|
||
|
);
|
||
|
|
||
|
if (HpcState == NULL || Padding == NULL || Attributes == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
*Padding = AllocateCopyPool (sizeof mPadding, &mPadding);
|
||
|
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;
|
||
|
|
||
|
mPciHotPlugInit.GetRootHpcList = GetRootHpcList;
|
||
|
mPciHotPlugInit.InitializeRootHpc = InitializeRootHpc;
|
||
|
mPciHotPlugInit.GetResourcePadding = GetResourcePadding;
|
||
|
Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
|
||
|
&gEfiPciHotPlugInitProtocolGuid, &mPciHotPlugInit, NULL);
|
||
|
return Status;
|
||
|
}
|