/** @file | |
The NvmExpressPei driver is used to manage non-volatile memory subsystem | |
which follows NVM Express specification at PEI phase. | |
Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#ifndef _NVM_EXPRESS_PEI_H_ | |
#define _NVM_EXPRESS_PEI_H_ | |
#include <PiPei.h> | |
#include <IndustryStandard/Nvme.h> | |
#include <IndustryStandard/Pci.h> | |
#include <Ppi/NvmExpressHostController.h> | |
#include <Ppi/BlockIo.h> | |
#include <Ppi/BlockIo2.h> | |
#include <Ppi/StorageSecurityCommand.h> | |
#include <Ppi/NvmExpressPassThru.h> | |
#include <Ppi/IoMmu.h> | |
#include <Ppi/EndOfPeiPhase.h> | |
#include <Ppi/PciDevice.h> | |
#include <Library/DebugLib.h> | |
#include <Library/PeiServicesLib.h> | |
#include <Library/MemoryAllocationLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/IoLib.h> | |
#include <Library/TimerLib.h> | |
#include <Library/DevicePathLib.h> | |
// | |
// Structure forward declarations | |
// | |
typedef struct _PEI_NVME_NAMESPACE_INFO PEI_NVME_NAMESPACE_INFO; | |
typedef struct _PEI_NVME_CONTROLLER_PRIVATE_DATA PEI_NVME_CONTROLLER_PRIVATE_DATA; | |
/** | |
Macro that checks whether device is a NVMHCI Interface. | |
@param _p Specified device. | |
@retval TRUE Device is a NVMHCI Interface. | |
@retval FALSE Device is not a NVMHCI Interface. | |
**/ | |
#define IS_PCI_NVMHCI(_p) IS_CLASS3 (_p, PCI_CLASS_MASS_STORAGE, PCI_CLASS_MASS_STORAGE_SOLID_STATE, PCI_IF_MASS_STORAGE_SOLID_STATE_ENTERPRISE_NVMHCI) | |
#include "NvmExpressPeiHci.h" | |
#include "NvmExpressPeiPassThru.h" | |
#include "NvmExpressPeiBlockIo.h" | |
#include "NvmExpressPeiStorageSecurity.h" | |
// | |
// NVME PEI driver implementation related definitions | |
// | |
#define NVME_MAX_QUEUES 2 // Number of I/O queues supported by the driver, 1 for AQ, 1 for CQ | |
#define NVME_ASQ_SIZE 1 // Number of admin submission queue entries, which is 0-based | |
#define NVME_ACQ_SIZE 1 // Number of admin completion queue entries, which is 0-based | |
#define NVME_CSQ_SIZE 63 // Number of I/O submission queue entries, which is 0-based | |
#define NVME_CCQ_SIZE 63 // Number of I/O completion queue entries, which is 0-based | |
#define NVME_PRP_SIZE (8) // Pages of PRP list | |
#define NVME_MEM_MAX_PAGES \ | |
( \ | |
1 /* ASQ */ + \ | |
1 /* ACQ */ + \ | |
1 /* SQs */ + \ | |
1 /* CQs */ + \ | |
NVME_PRP_SIZE) /* PRPs */ | |
#define NVME_ADMIN_QUEUE 0x00 | |
#define NVME_IO_QUEUE 0x01 | |
#define NVME_GENERIC_TIMEOUT 5000000 // Generic PassThru command timeout value, in us unit | |
#define NVME_POLL_INTERVAL 100 // Poll interval for PassThru command, in us unit | |
// | |
// Nvme namespace data structure. | |
// | |
struct _PEI_NVME_NAMESPACE_INFO { | |
UINT32 NamespaceId; | |
UINT64 NamespaceUuid; | |
EFI_PEI_BLOCK_IO2_MEDIA Media; | |
PEI_NVME_CONTROLLER_PRIVATE_DATA *Controller; | |
}; | |
#define NVME_CONTROLLER_NSID 0 | |
// | |
// Unique signature for private data structure. | |
// | |
#define NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('N','V','P','C') | |
// | |
// Nvme controller private data structure. | |
// | |
struct _PEI_NVME_CONTROLLER_PRIVATE_DATA { | |
UINT32 Signature; | |
UINTN MmioBase; | |
EFI_NVM_EXPRESS_PASS_THRU_MODE PassThruMode; | |
UINTN DevicePathLength; | |
EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi; | |
EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi; | |
EDKII_PEI_STORAGE_SECURITY_CMD_PPI StorageSecurityPpi; | |
EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI NvmePassThruPpi; | |
EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList; | |
EFI_PEI_PPI_DESCRIPTOR BlkIo2PpiList; | |
EFI_PEI_PPI_DESCRIPTOR StorageSecurityPpiList; | |
EFI_PEI_PPI_DESCRIPTOR NvmePassThruPpiList; | |
EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList; | |
// | |
// Pointer to identify controller data | |
// | |
NVME_ADMIN_CONTROLLER_DATA *ControllerData; | |
// | |
// (4 + NVME_PRP_SIZE) x 4kB aligned buffers will be carved out of this buffer | |
// 1st 4kB boundary is the start of the admin submission queue | |
// 2nd 4kB boundary is the start of the admin completion queue | |
// 3rd 4kB boundary is the start of I/O submission queue | |
// 4th 4kB boundary is the start of I/O completion queue | |
// 5th 4kB boundary is the start of PRP list buffers | |
// | |
VOID *Buffer; | |
VOID *BufferMapping; | |
// | |
// Pointers to 4kB aligned submission & completion queues | |
// | |
NVME_SQ *SqBuffer[NVME_MAX_QUEUES]; | |
NVME_CQ *CqBuffer[NVME_MAX_QUEUES]; | |
// | |
// Submission and completion queue indices | |
// | |
NVME_SQTDBL SqTdbl[NVME_MAX_QUEUES]; | |
NVME_CQHDBL CqHdbl[NVME_MAX_QUEUES]; | |
UINT8 Pt[NVME_MAX_QUEUES]; | |
UINT16 Cid[NVME_MAX_QUEUES]; | |
// | |
// Nvme controller capabilities | |
// | |
NVME_CAP Cap; | |
// | |
// Namespaces information on the controller | |
// | |
UINT32 ActiveNamespaceNum; | |
PEI_NVME_NAMESPACE_INFO *NamespaceInfo; | |
}; | |
#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO(a) \ | |
CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, BlkIoPpi, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE) | |
#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2(a) \ | |
CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, BlkIo2Ppi, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE) | |
#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_STROAGE_SECURITY(a) \ | |
CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, StorageSecurityPpi, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE) | |
#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NVME_PASSTHRU(a) \ | |
CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, NvmePassThruPpi, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE) | |
#define GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY(a) \ | |
CR (a, PEI_NVME_CONTROLLER_PRIVATE_DATA, EndOfPeiNotifyList, NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE) | |
// | |
// Internal functions | |
// | |
/** | |
Allocates pages that are suitable for an OperationBusMasterCommonBuffer or | |
OperationBusMasterCommonBuffer64 mapping. | |
@param Pages The number of pages to allocate. | |
@param HostAddress A pointer to store the base system memory address of the | |
allocated range. | |
@param DeviceAddress The resulting map address for the bus master PCI controller to use to | |
access the hosts HostAddress. | |
@param Mapping A resulting value to pass to Unmap(). | |
@retval EFI_SUCCESS The requested memory pages were allocated. | |
@retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are | |
MEMORY_WRITE_COMBINE and MEMORY_CACHED. | |
@retval EFI_INVALID_PARAMETER One or more parameters are invalid. | |
@retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. | |
**/ | |
EFI_STATUS | |
IoMmuAllocateBuffer ( | |
IN UINTN Pages, | |
OUT VOID **HostAddress, | |
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, | |
OUT VOID **Mapping | |
); | |
/** | |
Frees memory that was allocated with AllocateBuffer(). | |
@param Pages The number of pages to free. | |
@param HostAddress The base system memory address of the allocated range. | |
@param Mapping The mapping value returned from Map(). | |
@retval EFI_SUCCESS The requested memory pages were freed. | |
@retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages | |
was not allocated with AllocateBuffer(). | |
**/ | |
EFI_STATUS | |
IoMmuFreeBuffer ( | |
IN UINTN Pages, | |
IN VOID *HostAddress, | |
IN VOID *Mapping | |
); | |
/** | |
Provides the controller-specific addresses required to access system memory from a | |
DMA bus master. | |
@param Operation Indicates if the bus master is going to read or write to system memory. | |
@param HostAddress The system memory address to map to the PCI controller. | |
@param NumberOfBytes On input the number of bytes to map. On output the number of bytes | |
that were mapped. | |
@param DeviceAddress The resulting map address for the bus master PCI controller to use to | |
access the hosts HostAddress. | |
@param Mapping A resulting value to pass to Unmap(). | |
@retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. | |
@retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. | |
@retval EFI_INVALID_PARAMETER One or more parameters are invalid. | |
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. | |
@retval EFI_DEVICE_ERROR The system hardware could not map the requested address. | |
**/ | |
EFI_STATUS | |
IoMmuMap ( | |
IN EDKII_IOMMU_OPERATION Operation, | |
IN VOID *HostAddress, | |
IN OUT UINTN *NumberOfBytes, | |
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, | |
OUT VOID **Mapping | |
); | |
/** | |
Completes the Map() operation and releases any corresponding resources. | |
@param Mapping The mapping value returned from Map(). | |
@retval EFI_SUCCESS The range was unmapped. | |
@retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map(). | |
@retval EFI_DEVICE_ERROR The data was not committed to the target system memory. | |
**/ | |
EFI_STATUS | |
IoMmuUnmap ( | |
IN VOID *Mapping | |
); | |
/** | |
One notified function to cleanup the allocated resources at the end of PEI. | |
@param[in] PeiServices Pointer to PEI Services Table. | |
@param[in] NotifyDescriptor Pointer to the descriptor for the Notification | |
event that caused this function to execute. | |
@param[in] Ppi Pointer to the PPI data associated with this function. | |
@retval EFI_SUCCESS The function completes successfully | |
**/ | |
EFI_STATUS | |
EFIAPI | |
NvmePeimEndOfPei ( | |
IN EFI_PEI_SERVICES **PeiServices, | |
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, | |
IN VOID *Ppi | |
); | |
/** | |
Get the size of the current device path instance. | |
@param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL | |
structure. | |
@param[out] InstanceSize The size of the current device path instance. | |
@param[out] EntireDevicePathEnd Indicate whether the instance is the last | |
one in the device path strucure. | |
@retval EFI_SUCCESS The size of the current device path instance is fetched. | |
@retval Others Fails to get the size of the current device path instance. | |
**/ | |
EFI_STATUS | |
GetDevicePathInstanceSize ( | |
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
OUT UINTN *InstanceSize, | |
OUT BOOLEAN *EntireDevicePathEnd | |
); | |
/** | |
Check the validity of the device path of a NVM Express host controller. | |
@param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL | |
structure. | |
@param[in] DevicePathLength The length of the device path. | |
@retval EFI_SUCCESS The device path is valid. | |
@retval EFI_INVALID_PARAMETER The device path is invalid. | |
**/ | |
EFI_STATUS | |
NvmeIsHcDevicePathValid ( | |
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
IN UINTN DevicePathLength | |
); | |
/** | |
Build the device path for an Nvm Express device with given namespace identifier | |
and namespace extended unique identifier. | |
@param[in] Private A pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA | |
data structure. | |
@param[in] NamespaceId The given namespace identifier. | |
@param[in] NamespaceUuid The given namespace extended unique identifier. | |
@param[out] DevicePathLength The length of the device path in bytes specified | |
by DevicePath. | |
@param[out] DevicePath The device path of Nvm Express device. | |
@retval EFI_SUCCESS The operation succeeds. | |
@retval EFI_INVALID_PARAMETER The parameters are invalid. | |
@retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources. | |
**/ | |
EFI_STATUS | |
NvmeBuildDevicePath ( | |
IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private, | |
IN UINT32 NamespaceId, | |
IN UINT64 NamespaceUuid, | |
OUT UINTN *DevicePathLength, | |
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath | |
); | |
/** | |
Determine if a specific NVM Express controller can be skipped for S3 phase. | |
@param[in] HcDevicePath Device path of the controller. | |
@param[in] HcDevicePathLength Length of the device path specified by | |
HcDevicePath. | |
@retval The number of ports that need to be enumerated. | |
**/ | |
BOOLEAN | |
NvmeS3SkipThisController ( | |
IN EFI_DEVICE_PATH_PROTOCOL *HcDevicePath, | |
IN UINTN HcDevicePathLength | |
); | |
/** | |
Callback for EDKII_PCI_DEVICE_PPI installation. | |
@param[in] PeiServices Pointer to PEI Services Table. | |
@param[in] NotifyDescriptor Pointer to the descriptor for the Notification | |
event that caused this function to execute. | |
@param[in] Ppi Pointer to the PPI data associated with this function. | |
@retval EFI_SUCCESS The function completes successfully | |
@retval Others Cannot initialize Nvme controller from given PCI_DEVICE_PPI | |
**/ | |
EFI_STATUS | |
EFIAPI | |
NvmePciDevicePpiInstallationCallback ( | |
IN EFI_PEI_SERVICES **PeiServices, | |
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, | |
IN VOID *Ppi | |
); | |
/** | |
Callback for EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI installation. | |
@param[in] PeiServices Pointer to PEI Services Table. | |
@param[in] NotifyDescriptor Pointer to the descriptor for the Notification | |
event that caused this function to execute. | |
@param[in] Ppi Pointer to the PPI data associated with this function. | |
@retval EFI_SUCCESS The function completes successfully | |
@retval Others Cannot initialize Nvme controller from given EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI | |
**/ | |
EFI_STATUS | |
EFIAPI | |
NvmeHostControllerPpiInstallationCallback ( | |
IN EFI_PEI_SERVICES **PeiServices, | |
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, | |
IN VOID *Ppi | |
); | |
#endif |