/** @file
Copyright (c) 2016, Linaro, Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/**
Get Guid form the type of non-discoverable device.
@param[in] Type The type of non-discoverable device.
@retval Return the Guid.
**/
STATIC
CONST EFI_GUID *
GetGuidFromType (
IN NON_DISCOVERABLE_DEVICE_TYPE Type
)
{
switch (Type) {
case NonDiscoverableDeviceTypeAhci:
return &gEdkiiNonDiscoverableAhciDeviceGuid;
case NonDiscoverableDeviceTypeAmba:
return &gEdkiiNonDiscoverableAmbaDeviceGuid;
case NonDiscoverableDeviceTypeEhci:
return &gEdkiiNonDiscoverableEhciDeviceGuid;
case NonDiscoverableDeviceTypeNvme:
return &gEdkiiNonDiscoverableNvmeDeviceGuid;
case NonDiscoverableDeviceTypeOhci:
return &gEdkiiNonDiscoverableOhciDeviceGuid;
case NonDiscoverableDeviceTypeSdhci:
return &gEdkiiNonDiscoverableSdhciDeviceGuid;
case NonDiscoverableDeviceTypeUfs:
return &gEdkiiNonDiscoverableUfsDeviceGuid;
case NonDiscoverableDeviceTypeUhci:
return &gEdkiiNonDiscoverableUhciDeviceGuid;
case NonDiscoverableDeviceTypeXhci:
return &gEdkiiNonDiscoverableXhciDeviceGuid;
default:
return NULL;
}
}
#pragma pack (1)
typedef struct {
VENDOR_DEVICE_PATH Vendor;
UINT64 BaseAddress;
UINT8 ResourceType;
EFI_DEVICE_PATH_PROTOCOL End;
} NON_DISCOVERABLE_DEVICE_PATH;
#pragma pack ()
/**
Register a non-discoverable MMIO device.
@param[in] Type The type of non-discoverable device
@param[in] DmaType Whether the device is DMA coherent
@param[in] InitFunc Initialization routine to be invoked when
the device is enabled
@param[in,out] Handle The handle onto which to install the
non-discoverable device protocol.
If Handle is NULL or *Handle is NULL, a
new handle will be allocated.
@param[in] NumMmioResources The number of UINTN base/size pairs that
follow, each describing an MMIO region
owned by the device
@param[in] ... The variable argument list which contains the
info about MmioResources.
@retval EFI_SUCCESS The registration succeeded.
@retval EFI_INVALID_PARAMETER An invalid argument was given
@retval Other The registration failed.
**/
EFI_STATUS
EFIAPI
RegisterNonDiscoverableMmioDevice (
IN NON_DISCOVERABLE_DEVICE_TYPE Type,
IN NON_DISCOVERABLE_DEVICE_DMA_TYPE DmaType,
IN NON_DISCOVERABLE_DEVICE_INIT InitFunc,
IN OUT EFI_HANDLE *Handle OPTIONAL,
IN UINTN NumMmioResources,
...
)
{
NON_DISCOVERABLE_DEVICE *Device;
NON_DISCOVERABLE_DEVICE_PATH *DevicePath;
EFI_HANDLE LocalHandle;
EFI_STATUS Status;
UINTN AllocSize;
UINTN Index;
VA_LIST Args;
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
EFI_ACPI_END_TAG_DESCRIPTOR *End;
UINTN Base, Size;
if ((Type >= NonDiscoverableDeviceTypeMax) ||
(DmaType >= NonDiscoverableDeviceDmaTypeMax) ||
(NumMmioResources == 0))
{
return EFI_INVALID_PARAMETER;
}
if (Handle == NULL) {
Handle = &LocalHandle;
LocalHandle = NULL;
}
AllocSize = sizeof *Device +
NumMmioResources * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +
sizeof (EFI_ACPI_END_TAG_DESCRIPTOR);
Device = (NON_DISCOVERABLE_DEVICE *)AllocateZeroPool (AllocSize);
if (Device == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Device->Type = GetGuidFromType (Type);
ASSERT (Device->Type != NULL);
Device->DmaType = DmaType;
Device->Initialize = InitFunc;
Device->Resources = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(Device + 1);
VA_START (Args, NumMmioResources);
for (Index = 0; Index < NumMmioResources; Index++) {
Desc = &Device->Resources[Index];
Base = VA_ARG (Args, UINTN);
Size = VA_ARG (Args, UINTN);
Desc->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
Desc->Len = sizeof *Desc - 3;
Desc->AddrRangeMin = Base;
Desc->AddrLen = Size;
Desc->AddrRangeMax = Base + Size - 1;
Desc->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
Desc->AddrSpaceGranularity = ((EFI_PHYSICAL_ADDRESS)Base + Size > SIZE_4GB) ? 64 : 32;
Desc->AddrTranslationOffset = 0;
}
VA_END (Args);
End = (EFI_ACPI_END_TAG_DESCRIPTOR *)&Device->Resources[NumMmioResources];
End->Desc = ACPI_END_TAG_DESCRIPTOR;
End->Checksum = 0;
DevicePath = (NON_DISCOVERABLE_DEVICE_PATH *)CreateDeviceNode (
HARDWARE_DEVICE_PATH,
HW_VENDOR_DP,
sizeof (*DevicePath)
);
if (DevicePath == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto FreeDevice;
}
CopyGuid (&DevicePath->Vendor.Guid, &gEdkiiNonDiscoverableDeviceProtocolGuid);
//
// Use the base address and type of the first region to
// make the device path unique
//
DevicePath->BaseAddress = Device->Resources[0].AddrRangeMin;
DevicePath->ResourceType = Device->Resources[0].ResType;
SetDevicePathNodeLength (
&DevicePath->Vendor,
sizeof (*DevicePath) - sizeof (DevicePath->End)
);
SetDevicePathEndNode (&DevicePath->End);
Status = gBS->InstallMultipleProtocolInterfaces (
Handle,
&gEdkiiNonDiscoverableDeviceProtocolGuid,
Device,
&gEfiDevicePathProtocolGuid,
DevicePath,
NULL
);
if (EFI_ERROR (Status)) {
goto FreeDevicePath;
}
return EFI_SUCCESS;
FreeDevicePath:
FreePool (DevicePath);
FreeDevice:
FreePool (Device);
return Status;
}