/** @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 | |
**/ | |
#include "NvmExpressPei.h" | |
EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIoPpiListTemplate = { | |
EFI_PEI_PPI_DESCRIPTOR_PPI, | |
&gEfiPeiVirtualBlockIoPpiGuid, | |
NULL | |
}; | |
EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIo2PpiListTemplate = { | |
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), | |
&gEfiPeiVirtualBlockIo2PpiGuid, | |
NULL | |
}; | |
EFI_PEI_PPI_DESCRIPTOR mNvmeStorageSecurityPpiListTemplate = { | |
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), | |
&gEdkiiPeiStorageSecurityCommandPpiGuid, | |
NULL | |
}; | |
EFI_PEI_PPI_DESCRIPTOR mNvmePassThruPpiListTemplate = { | |
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), | |
&gEdkiiPeiNvmExpressPassThruPpiGuid, | |
NULL | |
}; | |
EFI_PEI_NOTIFY_DESCRIPTOR mNvmeEndOfPeiNotifyListTemplate = { | |
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), | |
&gEfiEndOfPeiSignalPpiGuid, | |
NvmePeimEndOfPei | |
}; | |
EFI_PEI_NOTIFY_DESCRIPTOR mNvmeHostControllerNotify = { | |
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), | |
&gEdkiiPeiNvmExpressHostControllerPpiGuid, | |
NvmeHostControllerPpiInstallationCallback | |
}; | |
EFI_PEI_NOTIFY_DESCRIPTOR mPciDevicePpiNotify = { | |
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), | |
&gEdkiiPeiPciDevicePpiGuid, | |
NvmePciDevicePpiInstallationCallback | |
}; | |
/** | |
Check if the specified Nvm Express device namespace is active, and then get the Identify | |
Namespace data. | |
@param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure. | |
@param[in] NamespaceId The specified namespace identifier. | |
@retval EFI_SUCCESS The specified namespace in the device is successfully enumerated. | |
@return Others Error occurs when enumerating the namespace. | |
**/ | |
EFI_STATUS | |
EnumerateNvmeDevNamespace ( | |
IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA *Private, | |
IN UINT32 NamespaceId | |
) | |
{ | |
EFI_STATUS Status; | |
NVME_ADMIN_NAMESPACE_DATA *NamespaceData; | |
PEI_NVME_NAMESPACE_INFO *NamespaceInfo; | |
UINT32 DeviceIndex; | |
UINT32 Lbads; | |
UINT32 Flbas; | |
UINT32 LbaFmtIdx; | |
NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA)); | |
if (NamespaceData == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Identify Namespace | |
// | |
Status = NvmeIdentifyNamespace ( | |
Private, | |
NamespaceId, | |
NamespaceData | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: NvmeIdentifyNamespace fail, Status - %r\n", __func__, Status)); | |
goto Exit; | |
} | |
// | |
// Validate Namespace | |
// | |
if (NamespaceData->Ncap == 0) { | |
DEBUG ((DEBUG_INFO, "%a: Namespace ID %d is an inactive one.\n", __func__, NamespaceId)); | |
Status = EFI_DEVICE_ERROR; | |
goto Exit; | |
} | |
DeviceIndex = Private->ActiveNamespaceNum; | |
NamespaceInfo = &Private->NamespaceInfo[DeviceIndex]; | |
NamespaceInfo->NamespaceId = NamespaceId; | |
NamespaceInfo->NamespaceUuid = NamespaceData->Eui64; | |
NamespaceInfo->Controller = Private; | |
Private->ActiveNamespaceNum++; | |
// | |
// Build BlockIo media structure | |
// | |
Flbas = NamespaceData->Flbas; | |
LbaFmtIdx = Flbas & 0xF; | |
// | |
// Currently this NVME driver only suport Metadata Size == 0 | |
// | |
if (NamespaceData->LbaFormat[LbaFmtIdx].Ms != 0) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"NVME IDENTIFY NAMESPACE [%d] Ms(%d) is not supported.\n", | |
NamespaceId, | |
NamespaceData->LbaFormat[LbaFmtIdx].Ms | |
)); | |
Status = EFI_UNSUPPORTED; | |
goto Exit; | |
} | |
Lbads = NamespaceData->LbaFormat[LbaFmtIdx].Lbads; | |
NamespaceInfo->Media.InterfaceType = MSG_NVME_NAMESPACE_DP; | |
NamespaceInfo->Media.RemovableMedia = FALSE; | |
NamespaceInfo->Media.MediaPresent = TRUE; | |
NamespaceInfo->Media.ReadOnly = FALSE; | |
NamespaceInfo->Media.BlockSize = (UINT32)1 << Lbads; | |
NamespaceInfo->Media.LastBlock = (EFI_PEI_LBA)NamespaceData->Nsze - 1; | |
DEBUG (( | |
DEBUG_INFO, | |
"%a: Namespace ID %d - BlockSize = 0x%x, LastBlock = 0x%lx\n", | |
__func__, | |
NamespaceId, | |
NamespaceInfo->Media.BlockSize, | |
NamespaceInfo->Media.LastBlock | |
)); | |
Exit: | |
if (NamespaceData != NULL) { | |
FreePool (NamespaceData); | |
} | |
return Status; | |
} | |
/** | |
Discover all Nvm Express device active namespaces. | |
@param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure. | |
@retval EFI_SUCCESS All the namespaces in the device are successfully enumerated. | |
@return EFI_NOT_FOUND No active namespaces can be found. | |
**/ | |
EFI_STATUS | |
NvmeDiscoverNamespaces ( | |
IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA *Private | |
) | |
{ | |
UINT32 NamespaceId; | |
Private->ActiveNamespaceNum = 0; | |
Private->NamespaceInfo = AllocateZeroPool (Private->ControllerData->Nn * sizeof (PEI_NVME_NAMESPACE_INFO)); | |
// | |
// According to Nvm Express 1.1 spec Figure 82, the field 'Nn' of the identify | |
// controller data defines the number of valid namespaces present for the | |
// controller. Namespaces shall be allocated in order (starting with 1) and | |
// packed sequentially. | |
// | |
for (NamespaceId = 1; NamespaceId <= Private->ControllerData->Nn; NamespaceId++) { | |
// | |
// For now, we do not care the return status. Since if a valid namespace is inactive, | |
// error status will be returned. But we continue to enumerate other valid namespaces. | |
// | |
EnumerateNvmeDevNamespace (Private, NamespaceId); | |
} | |
if (Private->ActiveNamespaceNum == 0) { | |
return EFI_NOT_FOUND; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
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 | |
) | |
{ | |
PEI_NVME_CONTROLLER_PRIVATE_DATA *Private; | |
Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor); | |
NvmeFreeDmaResource (Private); | |
return EFI_SUCCESS; | |
} | |
/** | |
Initialize and install PrivateData PPIs. | |
@param[in] MmioBase MMIO base address of specific Nvme controller | |
@param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL | |
structure. | |
@param[in] DevicePathLength Length of the device path. | |
@retval EFI_SUCCESS Nvme controller initialized and PPIs installed | |
@retval others Failed to initialize Nvme controller | |
**/ | |
EFI_STATUS | |
NvmeInitPrivateData ( | |
IN UINTN MmioBase, | |
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
IN UINTN DevicePathLength | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_BOOT_MODE BootMode; | |
PEI_NVME_CONTROLLER_PRIVATE_DATA *Private; | |
EFI_PHYSICAL_ADDRESS DeviceAddress; | |
DEBUG ((DEBUG_INFO, "%a: Enters.\n", __func__)); | |
// | |
// Get the current boot mode. | |
// | |
Status = PeiServicesGetBootMode (&BootMode); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __func__)); | |
return Status; | |
} | |
// | |
// Check validity of the device path of the NVM Express controller. | |
// | |
Status = NvmeIsHcDevicePathValid (DevicePath, DevicePathLength); | |
if (EFI_ERROR (Status)) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: The device path is invalid.\n", | |
__func__ | |
)); | |
return Status; | |
} | |
// | |
// For S3 resume performance consideration, not all NVM Express controllers | |
// will be initialized. The driver consumes the content within | |
// S3StorageDeviceInitList LockBox to see if a controller will be skipped | |
// during S3 resume. | |
// | |
if ((BootMode == BOOT_ON_S3_RESUME) && | |
(NvmeS3SkipThisController (DevicePath, DevicePathLength))) | |
{ | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: skipped during S3.\n", | |
__func__ | |
)); | |
return EFI_SUCCESS; | |
} | |
// | |
// Memory allocation for controller private data | |
// | |
Private = AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA)); | |
if (Private == NULL) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Fail to allocate private data.\n", | |
__func__ | |
)); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Memory allocation for transfer-related data | |
// | |
Status = IoMmuAllocateBuffer ( | |
NVME_MEM_MAX_PAGES, | |
&Private->Buffer, | |
&DeviceAddress, | |
&Private->BufferMapping | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Fail to allocate DMA buffers.\n", | |
__func__ | |
)); | |
return Status; | |
} | |
ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS)(UINTN)Private->Buffer)); | |
DEBUG ((DEBUG_INFO, "%a: DMA buffer base at 0x%x\n", __func__, Private->Buffer)); | |
// | |
// Initialize controller private data | |
// | |
Private->Signature = NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE; | |
Private->MmioBase = MmioBase; | |
Private->DevicePathLength = DevicePathLength; | |
Private->DevicePath = DevicePath; | |
// | |
// Initialize the NVME controller | |
// | |
Status = NvmeControllerInit (Private); | |
if (EFI_ERROR (Status)) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Controller initialization fail with Status - %r.\n", | |
__func__, | |
Status | |
)); | |
NvmeFreeDmaResource (Private); | |
return Status; | |
} | |
// | |
// Enumerate the NVME namespaces on the controller | |
// | |
Status = NvmeDiscoverNamespaces (Private); | |
if (EFI_ERROR (Status)) { | |
// | |
// No active namespace was found on the controller | |
// | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Namespaces discovery fail with Status - %r.\n", | |
__func__, | |
Status | |
)); | |
NvmeFreeDmaResource (Private); | |
return Status; | |
} | |
// | |
// Nvm Express Pass Thru PPI | |
// | |
Private->PassThruMode.Attributes = EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL | | |
EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL | | |
EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVM; | |
Private->PassThruMode.IoAlign = sizeof (UINTN); | |
Private->PassThruMode.NvmeVersion = EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI_REVISION; | |
Private->NvmePassThruPpi.Mode = &Private->PassThruMode; | |
Private->NvmePassThruPpi.GetDevicePath = NvmePassThruGetDevicePath; | |
Private->NvmePassThruPpi.GetNextNameSpace = NvmePassThruGetNextNameSpace; | |
Private->NvmePassThruPpi.PassThru = NvmePassThru; | |
CopyMem ( | |
&Private->NvmePassThruPpiList, | |
&mNvmePassThruPpiListTemplate, | |
sizeof (EFI_PEI_PPI_DESCRIPTOR) | |
); | |
Private->NvmePassThruPpiList.Ppi = &Private->NvmePassThruPpi; | |
PeiServicesInstallPpi (&Private->NvmePassThruPpiList); | |
// | |
// Block Io PPI | |
// | |
Private->BlkIoPpi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo; | |
Private->BlkIoPpi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo; | |
Private->BlkIoPpi.ReadBlocks = NvmeBlockIoPeimReadBlocks; | |
CopyMem ( | |
&Private->BlkIoPpiList, | |
&mNvmeBlkIoPpiListTemplate, | |
sizeof (EFI_PEI_PPI_DESCRIPTOR) | |
); | |
Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi; | |
Private->BlkIo2Ppi.Revision = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION; | |
Private->BlkIo2Ppi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo2; | |
Private->BlkIo2Ppi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo2; | |
Private->BlkIo2Ppi.ReadBlocks = NvmeBlockIoPeimReadBlocks2; | |
CopyMem ( | |
&Private->BlkIo2PpiList, | |
&mNvmeBlkIo2PpiListTemplate, | |
sizeof (EFI_PEI_PPI_DESCRIPTOR) | |
); | |
Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi; | |
PeiServicesInstallPpi (&Private->BlkIoPpiList); | |
// | |
// Check if the NVME controller supports the Security Receive/Send commands | |
// | |
if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) { | |
DEBUG (( | |
DEBUG_INFO, | |
"%a: Security Security Command PPI will be produced.\n", | |
__func__ | |
)); | |
Private->StorageSecurityPpi.Revision = EDKII_STORAGE_SECURITY_PPI_REVISION; | |
Private->StorageSecurityPpi.GetNumberofDevices = NvmeStorageSecurityGetDeviceNo; | |
Private->StorageSecurityPpi.GetDevicePath = NvmeStorageSecurityGetDevicePath; | |
Private->StorageSecurityPpi.ReceiveData = NvmeStorageSecurityReceiveData; | |
Private->StorageSecurityPpi.SendData = NvmeStorageSecuritySendData; | |
CopyMem ( | |
&Private->StorageSecurityPpiList, | |
&mNvmeStorageSecurityPpiListTemplate, | |
sizeof (EFI_PEI_PPI_DESCRIPTOR) | |
); | |
Private->StorageSecurityPpiList.Ppi = &Private->StorageSecurityPpi; | |
PeiServicesInstallPpi (&Private->StorageSecurityPpiList); | |
} | |
CopyMem ( | |
&Private->EndOfPeiNotifyList, | |
&mNvmeEndOfPeiNotifyListTemplate, | |
sizeof (EFI_PEI_NOTIFY_DESCRIPTOR) | |
); | |
PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList); | |
return EFI_SUCCESS; | |
} | |
/** | |
Initialize Nvme controller from fiven PCI_DEVICE_PPI. | |
@param[in] PciDevice Pointer to the PCI Device PPI instance. | |
@retval EFI_SUCCESS The function completes successfully | |
@retval Others Cannot initialize Nvme controller for given device | |
**/ | |
EFI_STATUS | |
NvmeInitControllerDataFromPciDevice ( | |
EDKII_PCI_DEVICE_PPI *PciDevice | |
) | |
{ | |
EFI_STATUS Status; | |
PCI_TYPE00 PciData; | |
UINTN MmioBase; | |
EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
UINTN DevicePathLength; | |
UINT64 EnabledPciAttributes; | |
UINT32 MmioBaseH; | |
// | |
// Now further check the PCI header: Base Class (offset 0x0B), Sub Class (offset 0x0A) and | |
// Programming Interface (offset 0x09). This controller should be an Nvme controller | |
// | |
Status = PciDevice->PciIo.Pci.Read ( | |
&PciDevice->PciIo, | |
EfiPciIoWidthUint8, | |
PCI_CLASSCODE_OFFSET, | |
sizeof (PciData.Hdr.ClassCode), | |
PciData.Hdr.ClassCode | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_UNSUPPORTED; | |
} | |
if (!IS_PCI_NVMHCI (&PciData)) { | |
return EFI_UNSUPPORTED; | |
} | |
Status = PciDevice->PciIo.Attributes ( | |
&PciDevice->PciIo, | |
EfiPciIoAttributeOperationSupported, | |
0, | |
&EnabledPciAttributes | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_UNSUPPORTED; | |
} else { | |
EnabledPciAttributes &= (UINT64)EFI_PCI_DEVICE_ENABLE; | |
Status = PciDevice->PciIo.Attributes ( | |
&PciDevice->PciIo, | |
EfiPciIoAttributeOperationEnable, | |
EnabledPciAttributes, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_UNSUPPORTED; | |
} | |
} | |
Status = PciDevice->PciIo.Pci.Read ( | |
&PciDevice->PciIo, | |
EfiPciIoWidthUint32, | |
PCI_BASE_ADDRESSREG_OFFSET, | |
1, | |
&MmioBase | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_UNSUPPORTED; | |
} | |
switch (MmioBase & 0x07) { | |
case 0x0: | |
// | |
// Memory space for 32 bit bar address | |
// | |
MmioBase = MmioBase & 0xFFFFFFF0; | |
break; | |
case 0x4: | |
// | |
// For 64 bit bar address, read the high 32bits of this 64 bit bar | |
// | |
Status = PciDevice->PciIo.Pci.Read ( | |
&PciDevice->PciIo, | |
EfiPciIoWidthUint32, | |
PCI_BASE_ADDRESSREG_OFFSET + 4, | |
1, | |
&MmioBaseH | |
); | |
// | |
// For 32 bit environment, high 32bits of the bar should be zero. | |
// | |
if ( EFI_ERROR (Status) | |
|| ((MmioBaseH != 0) && (sizeof (UINTN) == sizeof (UINT32)))) | |
{ | |
return EFI_UNSUPPORTED; | |
} | |
MmioBase = MmioBase & 0xFFFFFFF0; | |
MmioBase |= LShiftU64 ((UINT64)MmioBaseH, 32); | |
break; | |
default: | |
// | |
// Unknown bar type | |
// | |
return EFI_UNSUPPORTED; | |
} | |
DevicePathLength = GetDevicePathSize (PciDevice->DevicePath); | |
DevicePath = PciDevice->DevicePath; | |
Status = NvmeInitPrivateData (MmioBase, DevicePath, DevicePathLength); | |
if (EFI_ERROR (Status)) { | |
DEBUG (( | |
DEBUG_INFO, | |
"%a: Failed to init controller, with Status - %r\n", | |
__func__, | |
Status | |
)); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
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 | |
) | |
{ | |
EDKII_PCI_DEVICE_PPI *PciDevice; | |
PciDevice = (EDKII_PCI_DEVICE_PPI *)Ppi; | |
return NvmeInitControllerDataFromPciDevice (PciDevice); | |
} | |
/** | |
Initialize Nvme controller from EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI instance. | |
@param[in] NvmeHcPpi Pointer to the Nvme Host Controller PPI instance. | |
@retval EFI_SUCCESS PPI successfully installed. | |
**/ | |
EFI_STATUS | |
NvmeInitControllerFromHostControllerPpi ( | |
IN EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *NvmeHcPpi | |
) | |
{ | |
UINT8 Controller; | |
UINTN MmioBase; | |
UINTN DevicePathLength; | |
EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
EFI_STATUS Status; | |
Controller = 0; | |
MmioBase = 0; | |
while (TRUE) { | |
Status = NvmeHcPpi->GetNvmeHcMmioBar ( | |
NvmeHcPpi, | |
Controller, | |
&MmioBase | |
); | |
// | |
// When status is error, meant no controller is found | |
// | |
if (EFI_ERROR (Status)) { | |
break; | |
} | |
Status = NvmeHcPpi->GetNvmeHcDevicePath ( | |
NvmeHcPpi, | |
Controller, | |
&DevicePathLength, | |
&DevicePath | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Fail to allocate get the device path for Controller %d.\n", | |
__func__, | |
Controller | |
)); | |
return Status; | |
} | |
Status = NvmeInitPrivateData (MmioBase, DevicePath, DevicePathLength); | |
if (EFI_ERROR (Status)) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Controller initialization fail for Controller %d with Status - %r.\n", | |
__func__, | |
Controller, | |
Status | |
)); | |
} else { | |
DEBUG (( | |
DEBUG_INFO, | |
"%a: Controller %d has been successfully initialized.\n", | |
__func__, | |
Controller | |
)); | |
} | |
Controller++; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
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 | |
) | |
{ | |
EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *NvmeHcPpi; | |
if (Ppi == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
NvmeHcPpi = (EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *)Ppi; | |
return NvmeInitControllerFromHostControllerPpi (NvmeHcPpi); | |
} | |
/** | |
Entry point of the PEIM. | |
@param[in] FileHandle Handle of the file being invoked. | |
@param[in] PeiServices Describes the list of possible PEI Services. | |
@retval EFI_SUCCESS PPI successfully installed. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
NvmExpressPeimEntry ( | |
IN EFI_PEI_FILE_HANDLE FileHandle, | |
IN CONST EFI_PEI_SERVICES **PeiServices | |
) | |
{ | |
DEBUG ((DEBUG_INFO, "%a: Enters.\n", __func__)); | |
PeiServicesNotifyPpi (&mNvmeHostControllerNotify); | |
PeiServicesNotifyPpi (&mPciDevicePpiNotify); | |
return EFI_SUCCESS; | |
} |