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_NOTIFY_DESCRIPTOR mNvmeEndOfPeiNotifyListTemplate
= {
32 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
33 &gEfiEndOfPeiSignalPpiGuid
,
38 Check if the specified Nvm Express device namespace is active, and then get the Identify
41 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
42 @param[in] NamespaceId The specified namespace identifier.
44 @retval EFI_SUCCESS The specified namespace in the device is successfully enumerated.
45 @return Others Error occurs when enumerating the namespace.
49 EnumerateNvmeDevNamespace (
50 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
,
55 NVME_ADMIN_NAMESPACE_DATA
*NamespaceData
;
56 PEI_NVME_NAMESPACE_INFO
*NamespaceInfo
;
62 NamespaceData
= (NVME_ADMIN_NAMESPACE_DATA
*) AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA
));
63 if (NamespaceData
== NULL
) {
64 return EFI_OUT_OF_RESOURCES
;
70 Status
= NvmeIdentifyNamespace (
75 if (EFI_ERROR (Status
)) {
76 DEBUG ((DEBUG_ERROR
, "%a: NvmeIdentifyNamespace fail, Status - %r\n", __FUNCTION__
, Status
));
83 if (NamespaceData
->Ncap
== 0) {
84 DEBUG ((DEBUG_INFO
, "%a: Namespace ID %d is an inactive one.\n", __FUNCTION__
, NamespaceId
));
85 Status
= EFI_DEVICE_ERROR
;
89 DeviceIndex
= Private
->ActiveNamespaceNum
;
90 NamespaceInfo
= &Private
->NamespaceInfo
[DeviceIndex
];
91 NamespaceInfo
->NamespaceId
= NamespaceId
;
92 NamespaceInfo
->NamespaceUuid
= NamespaceData
->Eui64
;
93 NamespaceInfo
->Controller
= Private
;
94 Private
->ActiveNamespaceNum
++;
97 // Build BlockIo media structure
99 Flbas
= NamespaceData
->Flbas
;
100 LbaFmtIdx
= Flbas
& 0xF;
101 Lbads
= NamespaceData
->LbaFormat
[LbaFmtIdx
].Lbads
;
103 NamespaceInfo
->Media
.InterfaceType
= MSG_NVME_NAMESPACE_DP
;
104 NamespaceInfo
->Media
.RemovableMedia
= FALSE
;
105 NamespaceInfo
->Media
.MediaPresent
= TRUE
;
106 NamespaceInfo
->Media
.ReadOnly
= FALSE
;
107 NamespaceInfo
->Media
.BlockSize
= (UINT32
) 1 << Lbads
;
108 NamespaceInfo
->Media
.LastBlock
= (EFI_PEI_LBA
) NamespaceData
->Nsze
- 1;
111 "%a: Namespace ID %d - BlockSize = 0x%x, LastBlock = 0x%lx\n",
114 NamespaceInfo
->Media
.BlockSize
,
115 NamespaceInfo
->Media
.LastBlock
119 if (NamespaceData
!= NULL
) {
120 FreePool (NamespaceData
);
127 Discover all Nvm Express device active namespaces.
129 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
131 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.
132 @return EFI_NOT_FOUND No active namespaces can be found.
136 NvmeDiscoverNamespaces (
137 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
142 Private
->ActiveNamespaceNum
= 0;
143 Private
->NamespaceInfo
= AllocateZeroPool (Private
->ControllerData
->Nn
* sizeof (PEI_NVME_NAMESPACE_INFO
));
146 // According to Nvm Express 1.1 spec Figure 82, the field 'Nn' of the identify
147 // controller data defines the number of valid namespaces present for the
148 // controller. Namespaces shall be allocated in order (starting with 1) and
149 // packed sequentially.
151 for (NamespaceId
= 1; NamespaceId
<= Private
->ControllerData
->Nn
; NamespaceId
++) {
153 // For now, we do not care the return status. Since if a valid namespace is inactive,
154 // error status will be returned. But we continue to enumerate other valid namespaces.
156 EnumerateNvmeDevNamespace (Private
, NamespaceId
);
158 if (Private
->ActiveNamespaceNum
== 0) {
159 return EFI_NOT_FOUND
;
166 One notified function to cleanup the allocated resources at the end of PEI.
168 @param[in] PeiServices Pointer to PEI Services Table.
169 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
170 event that caused this function to execute.
171 @param[in] Ppi Pointer to the PPI data associated with this function.
173 @retval EFI_SUCCESS The function completes successfully
179 IN EFI_PEI_SERVICES
**PeiServices
,
180 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
184 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
186 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor
);
187 NvmeFreeDmaResource (Private
);
193 Entry point of the PEIM.
195 @param[in] FileHandle Handle of the file being invoked.
196 @param[in] PeiServices Describes the list of possible PEI Services.
198 @retval EFI_SUCCESS PPI successfully installed.
203 NvmExpressPeimEntry (
204 IN EFI_PEI_FILE_HANDLE FileHandle
,
205 IN CONST EFI_PEI_SERVICES
**PeiServices
209 EFI_BOOT_MODE BootMode
;
210 EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI
*NvmeHcPpi
;
213 UINTN DevicePathLength
;
214 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
215 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
216 EFI_PHYSICAL_ADDRESS DeviceAddress
;
218 DEBUG ((DEBUG_INFO
, "%a: Enters.\n", __FUNCTION__
));
221 // Get the current boot mode.
223 Status
= PeiServicesGetBootMode (&BootMode
);
224 if (EFI_ERROR (Status
)) {
225 DEBUG ((DEBUG_ERROR
, "%a: Fail to get the current boot mode.\n", __FUNCTION__
));
230 // Locate the NVME host controller PPI
232 Status
= PeiServicesLocatePpi (
233 &gEdkiiPeiNvmExpressHostControllerPpiGuid
,
238 if (EFI_ERROR (Status
)) {
239 DEBUG ((DEBUG_ERROR
, "%a: Fail to locate NvmeHostControllerPpi.\n", __FUNCTION__
));
240 return EFI_UNSUPPORTED
;
246 Status
= NvmeHcPpi
->GetNvmeHcMmioBar (
252 // When status is error, meant no controller is found
254 if (EFI_ERROR (Status
)) {
258 Status
= NvmeHcPpi
->GetNvmeHcDevicePath (
264 if (EFI_ERROR (Status
)) {
266 DEBUG_ERROR
, "%a: Fail to allocate get the device path for Controller %d.\n",
267 __FUNCTION__
, Controller
273 // Check validity of the device path of the NVM Express controller.
275 Status
= NvmeIsHcDevicePathValid (DevicePath
, DevicePathLength
);
276 if (EFI_ERROR (Status
)) {
278 DEBUG_ERROR
, "%a: The device path is invalid for Controller %d.\n",
279 __FUNCTION__
, Controller
286 // For S3 resume performance consideration, not all NVM Express controllers
287 // will be initialized. The driver consumes the content within
288 // S3StorageDeviceInitList LockBox to see if a controller will be skipped
291 if ((BootMode
== BOOT_ON_S3_RESUME
) &&
292 (NvmeS3SkipThisController (DevicePath
, DevicePathLength
))) {
294 DEBUG_ERROR
, "%a: Controller %d is skipped during S3.\n",
295 __FUNCTION__
, Controller
302 // Memory allocation for controller private data
304 Private
= AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA
));
305 if (Private
== NULL
) {
307 DEBUG_ERROR
, "%a: Fail to allocate private data for Controller %d.\n",
308 __FUNCTION__
, Controller
310 return EFI_OUT_OF_RESOURCES
;
314 // Memory allocation for transfer-related data
316 Status
= IoMmuAllocateBuffer (
320 &Private
->BufferMapping
322 if (EFI_ERROR (Status
)) {
324 DEBUG_ERROR
, "%a: Fail to allocate DMA buffers for Controller %d.\n",
325 __FUNCTION__
, Controller
329 ASSERT (DeviceAddress
== ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Private
->Buffer
));
330 DEBUG ((DEBUG_INFO
, "%a: DMA buffer base at 0x%x\n", __FUNCTION__
, Private
->Buffer
));
333 // Initialize controller private data
335 Private
->Signature
= NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE
;
336 Private
->MmioBase
= MmioBase
;
337 Private
->DevicePathLength
= DevicePathLength
;
338 Private
->DevicePath
= DevicePath
;
341 // Initialize the NVME controller
343 Status
= NvmeControllerInit (Private
);
344 if (EFI_ERROR (Status
)) {
347 "%a: Controller initialization fail for Controller %d with Status - %r.\n",
348 __FUNCTION__
, Controller
, Status
350 NvmeFreeDmaResource (Private
);
356 // Enumerate the NVME namespaces on the controller
358 Status
= NvmeDiscoverNamespaces (Private
);
359 if (EFI_ERROR (Status
)) {
361 // No active namespace was found on the controller
365 "%a: Namespaces discovery fail for Controller %d with Status - %r.\n",
366 __FUNCTION__
, Controller
, Status
368 NvmeFreeDmaResource (Private
);
373 Private
->BlkIoPpi
.GetNumberOfBlockDevices
= NvmeBlockIoPeimGetDeviceNo
;
374 Private
->BlkIoPpi
.GetBlockDeviceMediaInfo
= NvmeBlockIoPeimGetMediaInfo
;
375 Private
->BlkIoPpi
.ReadBlocks
= NvmeBlockIoPeimReadBlocks
;
377 &Private
->BlkIoPpiList
,
378 &mNvmeBlkIoPpiListTemplate
,
379 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
381 Private
->BlkIoPpiList
.Ppi
= &Private
->BlkIoPpi
;
383 Private
->BlkIo2Ppi
.Revision
= EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION
;
384 Private
->BlkIo2Ppi
.GetNumberOfBlockDevices
= NvmeBlockIoPeimGetDeviceNo2
;
385 Private
->BlkIo2Ppi
.GetBlockDeviceMediaInfo
= NvmeBlockIoPeimGetMediaInfo2
;
386 Private
->BlkIo2Ppi
.ReadBlocks
= NvmeBlockIoPeimReadBlocks2
;
388 &Private
->BlkIo2PpiList
,
389 &mNvmeBlkIo2PpiListTemplate
,
390 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
392 Private
->BlkIo2PpiList
.Ppi
= &Private
->BlkIo2Ppi
;
393 PeiServicesInstallPpi (&Private
->BlkIoPpiList
);
396 // Check if the NVME controller supports the Security Receive/Send commands
398 if ((Private
->ControllerData
->Oacs
& SECURITY_SEND_RECEIVE_SUPPORTED
) != 0) {
401 "%a: Security Security Command PPI will be produced for Controller %d.\n",
402 __FUNCTION__
, Controller
404 Private
->StorageSecurityPpi
.Revision
= EDKII_STORAGE_SECURITY_PPI_REVISION
;
405 Private
->StorageSecurityPpi
.GetNumberofDevices
= NvmeStorageSecurityGetDeviceNo
;
406 Private
->StorageSecurityPpi
.GetDevicePath
= NvmeStorageSecurityGetDevicePath
;
407 Private
->StorageSecurityPpi
.ReceiveData
= NvmeStorageSecurityReceiveData
;
408 Private
->StorageSecurityPpi
.SendData
= NvmeStorageSecuritySendData
;
410 &Private
->StorageSecurityPpiList
,
411 &mNvmeStorageSecurityPpiListTemplate
,
412 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
414 Private
->StorageSecurityPpiList
.Ppi
= &Private
->StorageSecurityPpi
;
415 PeiServicesInstallPpi (&Private
->StorageSecurityPpiList
);
419 &Private
->EndOfPeiNotifyList
,
420 &mNvmeEndOfPeiNotifyListTemplate
,
421 sizeof (EFI_PEI_NOTIFY_DESCRIPTOR
)
423 PeiServicesNotifyPpi (&Private
->EndOfPeiNotifyList
);
426 DEBUG_INFO
, "%a: Controller %d has been successfully initialized.\n",
427 __FUNCTION__
, Controller