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
,
43 EFI_PEI_NOTIFY_DESCRIPTOR mNvmeHostControllerNotify
= {
44 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
45 &gEdkiiPeiNvmExpressHostControllerPpiGuid
,
46 NvmeHostControllerPpiInstallationCallback
49 EFI_PEI_NOTIFY_DESCRIPTOR mPciDevicePpiNotify
= {
50 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
51 &gEdkiiPeiPciDevicePpiGuid
,
52 NvmePciDevicePpiInstallationCallback
56 Check if the specified Nvm Express device namespace is active, and then get the Identify
59 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
60 @param[in] NamespaceId The specified namespace identifier.
62 @retval EFI_SUCCESS The specified namespace in the device is successfully enumerated.
63 @return Others Error occurs when enumerating the namespace.
67 EnumerateNvmeDevNamespace (
68 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
,
73 NVME_ADMIN_NAMESPACE_DATA
*NamespaceData
;
74 PEI_NVME_NAMESPACE_INFO
*NamespaceInfo
;
80 NamespaceData
= (NVME_ADMIN_NAMESPACE_DATA
*)AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA
));
81 if (NamespaceData
== NULL
) {
82 return EFI_OUT_OF_RESOURCES
;
88 Status
= NvmeIdentifyNamespace (
93 if (EFI_ERROR (Status
)) {
94 DEBUG ((DEBUG_ERROR
, "%a: NvmeIdentifyNamespace fail, Status - %r\n", __FUNCTION__
, Status
));
101 if (NamespaceData
->Ncap
== 0) {
102 DEBUG ((DEBUG_INFO
, "%a: Namespace ID %d is an inactive one.\n", __FUNCTION__
, NamespaceId
));
103 Status
= EFI_DEVICE_ERROR
;
107 DeviceIndex
= Private
->ActiveNamespaceNum
;
108 NamespaceInfo
= &Private
->NamespaceInfo
[DeviceIndex
];
109 NamespaceInfo
->NamespaceId
= NamespaceId
;
110 NamespaceInfo
->NamespaceUuid
= NamespaceData
->Eui64
;
111 NamespaceInfo
->Controller
= Private
;
112 Private
->ActiveNamespaceNum
++;
115 // Build BlockIo media structure
117 Flbas
= NamespaceData
->Flbas
;
118 LbaFmtIdx
= Flbas
& 0xF;
121 // Currently this NVME driver only suport Metadata Size == 0
123 if (NamespaceData
->LbaFormat
[LbaFmtIdx
].Ms
!= 0) {
126 "NVME IDENTIFY NAMESPACE [%d] Ms(%d) is not supported.\n",
128 NamespaceData
->LbaFormat
[LbaFmtIdx
].Ms
130 Status
= EFI_UNSUPPORTED
;
134 Lbads
= NamespaceData
->LbaFormat
[LbaFmtIdx
].Lbads
;
136 NamespaceInfo
->Media
.InterfaceType
= MSG_NVME_NAMESPACE_DP
;
137 NamespaceInfo
->Media
.RemovableMedia
= FALSE
;
138 NamespaceInfo
->Media
.MediaPresent
= TRUE
;
139 NamespaceInfo
->Media
.ReadOnly
= FALSE
;
140 NamespaceInfo
->Media
.BlockSize
= (UINT32
)1 << Lbads
;
141 NamespaceInfo
->Media
.LastBlock
= (EFI_PEI_LBA
)NamespaceData
->Nsze
- 1;
144 "%a: Namespace ID %d - BlockSize = 0x%x, LastBlock = 0x%lx\n",
147 NamespaceInfo
->Media
.BlockSize
,
148 NamespaceInfo
->Media
.LastBlock
152 if (NamespaceData
!= NULL
) {
153 FreePool (NamespaceData
);
160 Discover all Nvm Express device active namespaces.
162 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
164 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.
165 @return EFI_NOT_FOUND No active namespaces can be found.
169 NvmeDiscoverNamespaces (
170 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
175 Private
->ActiveNamespaceNum
= 0;
176 Private
->NamespaceInfo
= AllocateZeroPool (Private
->ControllerData
->Nn
* sizeof (PEI_NVME_NAMESPACE_INFO
));
179 // According to Nvm Express 1.1 spec Figure 82, the field 'Nn' of the identify
180 // controller data defines the number of valid namespaces present for the
181 // controller. Namespaces shall be allocated in order (starting with 1) and
182 // packed sequentially.
184 for (NamespaceId
= 1; NamespaceId
<= Private
->ControllerData
->Nn
; NamespaceId
++) {
186 // For now, we do not care the return status. Since if a valid namespace is inactive,
187 // error status will be returned. But we continue to enumerate other valid namespaces.
189 EnumerateNvmeDevNamespace (Private
, NamespaceId
);
192 if (Private
->ActiveNamespaceNum
== 0) {
193 return EFI_NOT_FOUND
;
200 One notified function to cleanup the allocated resources at the end of PEI.
202 @param[in] PeiServices Pointer to PEI Services Table.
203 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
204 event that caused this function to execute.
205 @param[in] Ppi Pointer to the PPI data associated with this function.
207 @retval EFI_SUCCESS The function completes successfully
213 IN EFI_PEI_SERVICES
**PeiServices
,
214 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
218 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
220 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor
);
221 NvmeFreeDmaResource (Private
);
227 Initialize and install PrivateData PPIs.
229 @param[in] MmioBase MMIO base address of specific Nvme controller
230 @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
232 @param[in] DevicePathLength Length of the device path.
234 @retval EFI_SUCCESS Nvme controller initialized and PPIs installed
235 @retval others Failed to initialize Nvme controller
238 NvmeInitPrivateData (
240 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
241 IN UINTN DevicePathLength
245 EFI_BOOT_MODE BootMode
;
246 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
247 EFI_PHYSICAL_ADDRESS DeviceAddress
;
249 DEBUG ((DEBUG_INFO
, "%a: Enters.\n", __FUNCTION__
));
252 // Get the current boot mode.
254 Status
= PeiServicesGetBootMode (&BootMode
);
255 if (EFI_ERROR (Status
)) {
256 DEBUG ((DEBUG_ERROR
, "%a: Fail to get the current boot mode.\n", __FUNCTION__
));
261 // Check validity of the device path of the NVM Express controller.
263 Status
= NvmeIsHcDevicePathValid (DevicePath
, DevicePathLength
);
264 if (EFI_ERROR (Status
)) {
267 "%a: The device path is invalid for Controller %d.\n",
274 // For S3 resume performance consideration, not all NVM Express controllers
275 // will be initialized. The driver consumes the content within
276 // S3StorageDeviceInitList LockBox to see if a controller will be skipped
279 if ((BootMode
== BOOT_ON_S3_RESUME
) &&
280 (NvmeS3SkipThisController (DevicePath
, DevicePathLength
)))
284 "%a: skipped during S3.\n",
291 // Memory allocation for controller private data
293 Private
= AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA
));
294 if (Private
== NULL
) {
297 "%a: Fail to allocate private data.\n",
300 return EFI_OUT_OF_RESOURCES
;
304 // Memory allocation for transfer-related data
306 Status
= IoMmuAllocateBuffer (
310 &Private
->BufferMapping
312 if (EFI_ERROR (Status
)) {
315 "%a: Fail to allocate DMA buffers.\n",
321 ASSERT (DeviceAddress
== ((EFI_PHYSICAL_ADDRESS
)(UINTN
)Private
->Buffer
));
322 DEBUG ((DEBUG_INFO
, "%a: DMA buffer base at 0x%x\n", __FUNCTION__
, Private
->Buffer
));
325 // Initialize controller private data
327 Private
->Signature
= NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE
;
328 Private
->MmioBase
= MmioBase
;
329 Private
->DevicePathLength
= DevicePathLength
;
330 Private
->DevicePath
= DevicePath
;
333 // Initialize the NVME controller
335 Status
= NvmeControllerInit (Private
);
336 if (EFI_ERROR (Status
)) {
339 "%a: Controller initialization fail with Status - %r.\n",
343 NvmeFreeDmaResource (Private
);
348 // Enumerate the NVME namespaces on the controller
350 Status
= NvmeDiscoverNamespaces (Private
);
351 if (EFI_ERROR (Status
)) {
353 // No active namespace was found on the controller
357 "%a: Namespaces discovery fail with Status - %r.\n",
361 NvmeFreeDmaResource (Private
);
366 // Nvm Express Pass Thru PPI
368 Private
->PassThruMode
.Attributes
= EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL
|
369 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL
|
370 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVM
;
371 Private
->PassThruMode
.IoAlign
= sizeof (UINTN
);
372 Private
->PassThruMode
.NvmeVersion
= EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI_REVISION
;
373 Private
->NvmePassThruPpi
.Mode
= &Private
->PassThruMode
;
374 Private
->NvmePassThruPpi
.GetDevicePath
= NvmePassThruGetDevicePath
;
375 Private
->NvmePassThruPpi
.GetNextNameSpace
= NvmePassThruGetNextNameSpace
;
376 Private
->NvmePassThruPpi
.PassThru
= NvmePassThru
;
378 &Private
->NvmePassThruPpiList
,
379 &mNvmePassThruPpiListTemplate
,
380 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
382 Private
->NvmePassThruPpiList
.Ppi
= &Private
->NvmePassThruPpi
;
383 PeiServicesInstallPpi (&Private
->NvmePassThruPpiList
);
388 Private
->BlkIoPpi
.GetNumberOfBlockDevices
= NvmeBlockIoPeimGetDeviceNo
;
389 Private
->BlkIoPpi
.GetBlockDeviceMediaInfo
= NvmeBlockIoPeimGetMediaInfo
;
390 Private
->BlkIoPpi
.ReadBlocks
= NvmeBlockIoPeimReadBlocks
;
392 &Private
->BlkIoPpiList
,
393 &mNvmeBlkIoPpiListTemplate
,
394 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
396 Private
->BlkIoPpiList
.Ppi
= &Private
->BlkIoPpi
;
398 Private
->BlkIo2Ppi
.Revision
= EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION
;
399 Private
->BlkIo2Ppi
.GetNumberOfBlockDevices
= NvmeBlockIoPeimGetDeviceNo2
;
400 Private
->BlkIo2Ppi
.GetBlockDeviceMediaInfo
= NvmeBlockIoPeimGetMediaInfo2
;
401 Private
->BlkIo2Ppi
.ReadBlocks
= NvmeBlockIoPeimReadBlocks2
;
403 &Private
->BlkIo2PpiList
,
404 &mNvmeBlkIo2PpiListTemplate
,
405 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
407 Private
->BlkIo2PpiList
.Ppi
= &Private
->BlkIo2Ppi
;
408 PeiServicesInstallPpi (&Private
->BlkIoPpiList
);
411 // Check if the NVME controller supports the Security Receive/Send commands
413 if ((Private
->ControllerData
->Oacs
& SECURITY_SEND_RECEIVE_SUPPORTED
) != 0) {
416 "%a: Security Security Command PPI will be produced.\n",
419 Private
->StorageSecurityPpi
.Revision
= EDKII_STORAGE_SECURITY_PPI_REVISION
;
420 Private
->StorageSecurityPpi
.GetNumberofDevices
= NvmeStorageSecurityGetDeviceNo
;
421 Private
->StorageSecurityPpi
.GetDevicePath
= NvmeStorageSecurityGetDevicePath
;
422 Private
->StorageSecurityPpi
.ReceiveData
= NvmeStorageSecurityReceiveData
;
423 Private
->StorageSecurityPpi
.SendData
= NvmeStorageSecuritySendData
;
425 &Private
->StorageSecurityPpiList
,
426 &mNvmeStorageSecurityPpiListTemplate
,
427 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
429 Private
->StorageSecurityPpiList
.Ppi
= &Private
->StorageSecurityPpi
;
430 PeiServicesInstallPpi (&Private
->StorageSecurityPpiList
);
434 &Private
->EndOfPeiNotifyList
,
435 &mNvmeEndOfPeiNotifyListTemplate
,
436 sizeof (EFI_PEI_NOTIFY_DESCRIPTOR
)
438 PeiServicesNotifyPpi (&Private
->EndOfPeiNotifyList
);
444 Initialize Nvme controller from fiven PCI_DEVICE_PPI.
446 @param[in] PciDevice Pointer to the PCI Device PPI instance.
448 @retval EFI_SUCCESS The function completes successfully
449 @retval Others Cannot initialize Nvme controller for given device
452 NvmeInitControllerDataFromPciDevice (
453 EDKII_PCI_DEVICE_PPI
*PciDevice
459 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
460 UINTN DevicePathLength
;
461 UINT64 EnabledPciAttributes
;
465 // Now further check the PCI header: Base Class (offset 0x0B), Sub Class (offset 0x0A) and
466 // Programming Interface (offset 0x09). This controller should be an Nvme controller
468 Status
= PciDevice
->PciIo
.Pci
.Read (
471 PCI_CLASSCODE_OFFSET
,
472 sizeof (PciData
.Hdr
.ClassCode
),
473 PciData
.Hdr
.ClassCode
475 if (EFI_ERROR (Status
)) {
476 return EFI_UNSUPPORTED
;
479 if (!IS_PCI_NVMHCI (&PciData
)) {
480 return EFI_UNSUPPORTED
;
483 Status
= PciDevice
->PciIo
.Attributes (
485 EfiPciIoAttributeOperationSupported
,
487 &EnabledPciAttributes
489 if (EFI_ERROR (Status
)) {
490 return EFI_UNSUPPORTED
;
492 EnabledPciAttributes
&= (UINT64
)EFI_PCI_DEVICE_ENABLE
;
493 Status
= PciDevice
->PciIo
.Attributes (
495 EfiPciIoAttributeOperationEnable
,
496 EnabledPciAttributes
,
499 if (EFI_ERROR (Status
)) {
500 return EFI_UNSUPPORTED
;
504 Status
= PciDevice
->PciIo
.Pci
.Read (
507 PCI_BASE_ADDRESSREG_OFFSET
,
511 if (EFI_ERROR (Status
)) {
512 return EFI_UNSUPPORTED
;
515 switch (MmioBase
& 0x07) {
518 // Memory space for 32 bit bar address
520 MmioBase
= MmioBase
& 0xFFFFFFF0;
524 // For 64 bit bar address, read the high 32bits of this 64 bit bar
526 Status
= PciDevice
->PciIo
.Pci
.Read (
529 PCI_BASE_ADDRESSREG_OFFSET
+ 4,
534 // For 32 bit environment, high 32bits of the bar should be zero.
536 if ( EFI_ERROR (Status
)
537 || ((MmioBaseH
!= 0) && (sizeof (UINTN
) == sizeof (UINT32
))))
539 return EFI_UNSUPPORTED
;
542 MmioBase
= MmioBase
& 0xFFFFFFF0;
543 MmioBase
|= LShiftU64 ((UINT64
)MmioBaseH
, 32);
549 return EFI_UNSUPPORTED
;
552 DevicePathLength
= GetDevicePathSize (PciDevice
->DevicePath
);
553 DevicePath
= PciDevice
->DevicePath
;
555 Status
= NvmeInitPrivateData (MmioBase
, DevicePath
, DevicePathLength
);
556 if (EFI_ERROR (Status
)) {
559 "%a: Failed to init controller, with Status - %r\n",
569 Callback for EDKII_PCI_DEVICE_PPI installation.
571 @param[in] PeiServices Pointer to PEI Services Table.
572 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
573 event that caused this function to execute.
574 @param[in] Ppi Pointer to the PPI data associated with this function.
576 @retval EFI_SUCCESS The function completes successfully
577 @retval Others Cannot initialize Nvme controller from given PCI_DEVICE_PPI
582 NvmePciDevicePpiInstallationCallback (
583 IN EFI_PEI_SERVICES
**PeiServices
,
584 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
588 EDKII_PCI_DEVICE_PPI
*PciDevice
;
590 PciDevice
= (EDKII_PCI_DEVICE_PPI
*)Ppi
;
592 return NvmeInitControllerDataFromPciDevice (PciDevice
);
596 Initialize Nvme controller from EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI instance.
598 @param[in] NvmeHcPpi Pointer to the Nvme Host Controller PPI instance.
600 @retval EFI_SUCCESS PPI successfully installed.
603 NvmeInitControllerFromHostControllerPpi (
604 IN EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI
*NvmeHcPpi
609 UINTN DevicePathLength
;
610 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
616 Status
= NvmeHcPpi
->GetNvmeHcMmioBar (
622 // When status is error, meant no controller is found
624 if (EFI_ERROR (Status
)) {
628 Status
= NvmeHcPpi
->GetNvmeHcDevicePath (
634 if (EFI_ERROR (Status
)) {
637 "%a: Fail to allocate get the device path for Controller %d.\n",
644 Status
= NvmeInitPrivateData (MmioBase
, DevicePath
, DevicePathLength
);
645 if (EFI_ERROR (Status
)) {
648 "%a: Controller initialization fail for Controller %d with Status - %r.\n",
656 "%a: Controller %d has been successfully initialized.\n",
669 Callback for EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI installation.
671 @param[in] PeiServices Pointer to PEI Services Table.
672 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
673 event that caused this function to execute.
674 @param[in] Ppi Pointer to the PPI data associated with this function.
676 @retval EFI_SUCCESS The function completes successfully
677 @retval Others Cannot initialize Nvme controller from given EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI
682 NvmeHostControllerPpiInstallationCallback (
683 IN EFI_PEI_SERVICES
**PeiServices
,
684 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
688 EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI
*NvmeHcPpi
;
691 return EFI_INVALID_PARAMETER
;
694 NvmeHcPpi
= (EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI
*)Ppi
;
696 return NvmeInitControllerFromHostControllerPpi (NvmeHcPpi
);
700 Entry point of the PEIM.
702 @param[in] FileHandle Handle of the file being invoked.
703 @param[in] PeiServices Describes the list of possible PEI Services.
705 @retval EFI_SUCCESS PPI successfully installed.
710 NvmExpressPeimEntry (
711 IN EFI_PEI_FILE_HANDLE FileHandle
,
712 IN CONST EFI_PEI_SERVICES
**PeiServices
715 DEBUG ((DEBUG_INFO
, "%a: Enters.\n", __FUNCTION__
));
717 PeiServicesNotifyPpi (&mNvmeHostControllerNotify
);
719 PeiServicesNotifyPpi (&mPciDevicePpiNotify
);