| /** @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; | |
| } |