2 The NvmExpressPei driver is used to manage non-volatile memory subsystem
3 which follows NVM Express specification at PEI phase.
5 Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "NvmExpressPei.h"
13 EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIoPpiListTemplate
= {
14 EFI_PEI_PPI_DESCRIPTOR_PPI
,
15 &gEfiPeiVirtualBlockIoPpiGuid
,
19 EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIo2PpiListTemplate
= {
20 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
21 &gEfiPeiVirtualBlockIo2PpiGuid
,
25 EFI_PEI_PPI_DESCRIPTOR mNvmeStorageSecurityPpiListTemplate
= {
26 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
27 &gEdkiiPeiStorageSecurityCommandPpiGuid
,
31 EFI_PEI_PPI_DESCRIPTOR mNvmePassThruPpiListTemplate
= {
32 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
33 &gEdkiiPeiNvmExpressPassThruPpiGuid
,
37 EFI_PEI_NOTIFY_DESCRIPTOR mNvmeEndOfPeiNotifyListTemplate
= {
38 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
39 &gEfiEndOfPeiSignalPpiGuid
,
44 Check if the specified Nvm Express device namespace is active, and then get the Identify
47 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
48 @param[in] NamespaceId The specified namespace identifier.
50 @retval EFI_SUCCESS The specified namespace in the device is successfully enumerated.
51 @return Others Error occurs when enumerating the namespace.
55 EnumerateNvmeDevNamespace (
56 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
,
61 NVME_ADMIN_NAMESPACE_DATA
*NamespaceData
;
62 PEI_NVME_NAMESPACE_INFO
*NamespaceInfo
;
68 NamespaceData
= (NVME_ADMIN_NAMESPACE_DATA
*)AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA
));
69 if (NamespaceData
== NULL
) {
70 return EFI_OUT_OF_RESOURCES
;
76 Status
= NvmeIdentifyNamespace (
81 if (EFI_ERROR (Status
)) {
82 DEBUG ((DEBUG_ERROR
, "%a: NvmeIdentifyNamespace fail, Status - %r\n", __FUNCTION__
, Status
));
89 if (NamespaceData
->Ncap
== 0) {
90 DEBUG ((DEBUG_INFO
, "%a: Namespace ID %d is an inactive one.\n", __FUNCTION__
, NamespaceId
));
91 Status
= EFI_DEVICE_ERROR
;
95 DeviceIndex
= Private
->ActiveNamespaceNum
;
96 NamespaceInfo
= &Private
->NamespaceInfo
[DeviceIndex
];
97 NamespaceInfo
->NamespaceId
= NamespaceId
;
98 NamespaceInfo
->NamespaceUuid
= NamespaceData
->Eui64
;
99 NamespaceInfo
->Controller
= Private
;
100 Private
->ActiveNamespaceNum
++;
103 // Build BlockIo media structure
105 Flbas
= NamespaceData
->Flbas
;
106 LbaFmtIdx
= Flbas
& 0xF;
109 // Currently this NVME driver only suport Metadata Size == 0
111 if (NamespaceData
->LbaFormat
[LbaFmtIdx
].Ms
!= 0) {
114 "NVME IDENTIFY NAMESPACE [%d] Ms(%d) is not supported.\n",
116 NamespaceData
->LbaFormat
[LbaFmtIdx
].Ms
118 Status
= EFI_UNSUPPORTED
;
122 Lbads
= NamespaceData
->LbaFormat
[LbaFmtIdx
].Lbads
;
124 NamespaceInfo
->Media
.InterfaceType
= MSG_NVME_NAMESPACE_DP
;
125 NamespaceInfo
->Media
.RemovableMedia
= FALSE
;
126 NamespaceInfo
->Media
.MediaPresent
= TRUE
;
127 NamespaceInfo
->Media
.ReadOnly
= FALSE
;
128 NamespaceInfo
->Media
.BlockSize
= (UINT32
)1 << Lbads
;
129 NamespaceInfo
->Media
.LastBlock
= (EFI_PEI_LBA
)NamespaceData
->Nsze
- 1;
132 "%a: Namespace ID %d - BlockSize = 0x%x, LastBlock = 0x%lx\n",
135 NamespaceInfo
->Media
.BlockSize
,
136 NamespaceInfo
->Media
.LastBlock
140 if (NamespaceData
!= NULL
) {
141 FreePool (NamespaceData
);
148 Discover all Nvm Express device active namespaces.
150 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
152 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.
153 @return EFI_NOT_FOUND No active namespaces can be found.
157 NvmeDiscoverNamespaces (
158 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
163 Private
->ActiveNamespaceNum
= 0;
164 Private
->NamespaceInfo
= AllocateZeroPool (Private
->ControllerData
->Nn
* sizeof (PEI_NVME_NAMESPACE_INFO
));
167 // According to Nvm Express 1.1 spec Figure 82, the field 'Nn' of the identify
168 // controller data defines the number of valid namespaces present for the
169 // controller. Namespaces shall be allocated in order (starting with 1) and
170 // packed sequentially.
172 for (NamespaceId
= 1; NamespaceId
<= Private
->ControllerData
->Nn
; NamespaceId
++) {
174 // For now, we do not care the return status. Since if a valid namespace is inactive,
175 // error status will be returned. But we continue to enumerate other valid namespaces.
177 EnumerateNvmeDevNamespace (Private
, NamespaceId
);
180 if (Private
->ActiveNamespaceNum
== 0) {
181 return EFI_NOT_FOUND
;
188 One notified function to cleanup the allocated resources at the end of PEI.
190 @param[in] PeiServices Pointer to PEI Services Table.
191 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
192 event that caused this function to execute.
193 @param[in] Ppi Pointer to the PPI data associated with this function.
195 @retval EFI_SUCCESS The function completes successfully
201 IN EFI_PEI_SERVICES
**PeiServices
,
202 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
206 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
208 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor
);
209 NvmeFreeDmaResource (Private
);
215 Entry point of the PEIM.
217 @param[in] FileHandle Handle of the file being invoked.
218 @param[in] PeiServices Describes the list of possible PEI Services.
220 @retval EFI_SUCCESS PPI successfully installed.
225 NvmExpressPeimEntry (
226 IN EFI_PEI_FILE_HANDLE FileHandle
,
227 IN CONST EFI_PEI_SERVICES
**PeiServices
231 EFI_BOOT_MODE BootMode
;
232 EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI
*NvmeHcPpi
;
235 UINTN DevicePathLength
;
236 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
237 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
238 EFI_PHYSICAL_ADDRESS DeviceAddress
;
240 DEBUG ((DEBUG_INFO
, "%a: Enters.\n", __FUNCTION__
));
243 // Get the current boot mode.
245 Status
= PeiServicesGetBootMode (&BootMode
);
246 if (EFI_ERROR (Status
)) {
247 DEBUG ((DEBUG_ERROR
, "%a: Fail to get the current boot mode.\n", __FUNCTION__
));
252 // Locate the NVME host controller PPI
254 Status
= PeiServicesLocatePpi (
255 &gEdkiiPeiNvmExpressHostControllerPpiGuid
,
260 if (EFI_ERROR (Status
)) {
261 DEBUG ((DEBUG_ERROR
, "%a: Fail to locate NvmeHostControllerPpi.\n", __FUNCTION__
));
262 return EFI_UNSUPPORTED
;
268 Status
= NvmeHcPpi
->GetNvmeHcMmioBar (
274 // When status is error, meant no controller is found
276 if (EFI_ERROR (Status
)) {
280 Status
= NvmeHcPpi
->GetNvmeHcDevicePath (
286 if (EFI_ERROR (Status
)) {
289 "%a: Fail to allocate get the device path for Controller %d.\n",
297 // Check validity of the device path of the NVM Express controller.
299 Status
= NvmeIsHcDevicePathValid (DevicePath
, DevicePathLength
);
300 if (EFI_ERROR (Status
)) {
303 "%a: The device path is invalid for Controller %d.\n",
312 // For S3 resume performance consideration, not all NVM Express controllers
313 // will be initialized. The driver consumes the content within
314 // S3StorageDeviceInitList LockBox to see if a controller will be skipped
317 if ((BootMode
== BOOT_ON_S3_RESUME
) &&
318 (NvmeS3SkipThisController (DevicePath
, DevicePathLength
)))
322 "%a: Controller %d is skipped during S3.\n",
331 // Memory allocation for controller private data
333 Private
= AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA
));
334 if (Private
== NULL
) {
337 "%a: Fail to allocate private data for Controller %d.\n",
341 return EFI_OUT_OF_RESOURCES
;
345 // Memory allocation for transfer-related data
347 Status
= IoMmuAllocateBuffer (
351 &Private
->BufferMapping
353 if (EFI_ERROR (Status
)) {
356 "%a: Fail to allocate DMA buffers for Controller %d.\n",
363 ASSERT (DeviceAddress
== ((EFI_PHYSICAL_ADDRESS
)(UINTN
)Private
->Buffer
));
364 DEBUG ((DEBUG_INFO
, "%a: DMA buffer base at 0x%x\n", __FUNCTION__
, Private
->Buffer
));
367 // Initialize controller private data
369 Private
->Signature
= NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE
;
370 Private
->MmioBase
= MmioBase
;
371 Private
->DevicePathLength
= DevicePathLength
;
372 Private
->DevicePath
= DevicePath
;
375 // Initialize the NVME controller
377 Status
= NvmeControllerInit (Private
);
378 if (EFI_ERROR (Status
)) {
381 "%a: Controller initialization fail for Controller %d with Status - %r.\n",
386 NvmeFreeDmaResource (Private
);
392 // Enumerate the NVME namespaces on the controller
394 Status
= NvmeDiscoverNamespaces (Private
);
395 if (EFI_ERROR (Status
)) {
397 // No active namespace was found on the controller
401 "%a: Namespaces discovery fail for Controller %d with Status - %r.\n",
406 NvmeFreeDmaResource (Private
);
412 // Nvm Express Pass Thru PPI
414 Private
->PassThruMode
.Attributes
= EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL
|
415 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL
|
416 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVM
;
417 Private
->PassThruMode
.IoAlign
= sizeof (UINTN
);
418 Private
->PassThruMode
.NvmeVersion
= EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI_REVISION
;
419 Private
->NvmePassThruPpi
.Mode
= &Private
->PassThruMode
;
420 Private
->NvmePassThruPpi
.GetDevicePath
= NvmePassThruGetDevicePath
;
421 Private
->NvmePassThruPpi
.GetNextNameSpace
= NvmePassThruGetNextNameSpace
;
422 Private
->NvmePassThruPpi
.PassThru
= NvmePassThru
;
424 &Private
->NvmePassThruPpiList
,
425 &mNvmePassThruPpiListTemplate
,
426 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
428 Private
->NvmePassThruPpiList
.Ppi
= &Private
->NvmePassThruPpi
;
429 PeiServicesInstallPpi (&Private
->NvmePassThruPpiList
);
434 Private
->BlkIoPpi
.GetNumberOfBlockDevices
= NvmeBlockIoPeimGetDeviceNo
;
435 Private
->BlkIoPpi
.GetBlockDeviceMediaInfo
= NvmeBlockIoPeimGetMediaInfo
;
436 Private
->BlkIoPpi
.ReadBlocks
= NvmeBlockIoPeimReadBlocks
;
438 &Private
->BlkIoPpiList
,
439 &mNvmeBlkIoPpiListTemplate
,
440 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
442 Private
->BlkIoPpiList
.Ppi
= &Private
->BlkIoPpi
;
444 Private
->BlkIo2Ppi
.Revision
= EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION
;
445 Private
->BlkIo2Ppi
.GetNumberOfBlockDevices
= NvmeBlockIoPeimGetDeviceNo2
;
446 Private
->BlkIo2Ppi
.GetBlockDeviceMediaInfo
= NvmeBlockIoPeimGetMediaInfo2
;
447 Private
->BlkIo2Ppi
.ReadBlocks
= NvmeBlockIoPeimReadBlocks2
;
449 &Private
->BlkIo2PpiList
,
450 &mNvmeBlkIo2PpiListTemplate
,
451 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
453 Private
->BlkIo2PpiList
.Ppi
= &Private
->BlkIo2Ppi
;
454 PeiServicesInstallPpi (&Private
->BlkIoPpiList
);
457 // Check if the NVME controller supports the Security Receive/Send commands
459 if ((Private
->ControllerData
->Oacs
& SECURITY_SEND_RECEIVE_SUPPORTED
) != 0) {
462 "%a: Security Security Command PPI will be produced for Controller %d.\n",
466 Private
->StorageSecurityPpi
.Revision
= EDKII_STORAGE_SECURITY_PPI_REVISION
;
467 Private
->StorageSecurityPpi
.GetNumberofDevices
= NvmeStorageSecurityGetDeviceNo
;
468 Private
->StorageSecurityPpi
.GetDevicePath
= NvmeStorageSecurityGetDevicePath
;
469 Private
->StorageSecurityPpi
.ReceiveData
= NvmeStorageSecurityReceiveData
;
470 Private
->StorageSecurityPpi
.SendData
= NvmeStorageSecuritySendData
;
472 &Private
->StorageSecurityPpiList
,
473 &mNvmeStorageSecurityPpiListTemplate
,
474 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
476 Private
->StorageSecurityPpiList
.Ppi
= &Private
->StorageSecurityPpi
;
477 PeiServicesInstallPpi (&Private
->StorageSecurityPpiList
);
481 &Private
->EndOfPeiNotifyList
,
482 &mNvmeEndOfPeiNotifyListTemplate
,
483 sizeof (EFI_PEI_NOTIFY_DESCRIPTOR
)
485 PeiServicesNotifyPpi (&Private
->EndOfPeiNotifyList
);
489 "%a: Controller %d has been successfully initialized.\n",