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 This program and the accompanying materials
8 are licensed and made available under the terms and conditions
9 of the BSD License which accompanies this distribution. The
10 full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include "NvmExpressPei.h"
20 EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIoPpiListTemplate
= {
21 EFI_PEI_PPI_DESCRIPTOR_PPI
,
22 &gEfiPeiVirtualBlockIoPpiGuid
,
26 EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIo2PpiListTemplate
= {
27 EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
28 &gEfiPeiVirtualBlockIo2PpiGuid
,
32 EFI_PEI_NOTIFY_DESCRIPTOR mNvmeEndOfPeiNotifyListTemplate
= {
33 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
34 &gEfiEndOfPeiSignalPpiGuid
,
39 Check if the specified Nvm Express device namespace is active, and then get the Identify
42 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
43 @param[in] NamespaceId The specified namespace identifier.
45 @retval EFI_SUCCESS The specified namespace in the device is successfully enumerated.
46 @return Others Error occurs when enumerating the namespace.
50 EnumerateNvmeDevNamespace (
51 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
,
56 NVME_ADMIN_NAMESPACE_DATA
*NamespaceData
;
57 PEI_NVME_NAMESPACE_INFO
*NamespaceInfo
;
63 NamespaceData
= (NVME_ADMIN_NAMESPACE_DATA
*) AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA
));
64 if (NamespaceData
== NULL
) {
65 return EFI_OUT_OF_RESOURCES
;
71 Status
= NvmeIdentifyNamespace (
76 if (EFI_ERROR (Status
)) {
77 DEBUG ((DEBUG_ERROR
, "%a: NvmeIdentifyNamespace fail, Status - %r\n", __FUNCTION__
, Status
));
84 if (NamespaceData
->Ncap
== 0) {
85 DEBUG ((DEBUG_INFO
, "%a: Namespace ID %d is an inactive one.\n", __FUNCTION__
, NamespaceId
));
86 Status
= EFI_DEVICE_ERROR
;
90 DeviceIndex
= Private
->ActiveNamespaceNum
;
91 NamespaceInfo
= &Private
->NamespaceInfo
[DeviceIndex
];
92 NamespaceInfo
->NamespaceId
= NamespaceId
;
93 NamespaceInfo
->NamespaceUuid
= NamespaceData
->Eui64
;
94 NamespaceInfo
->Controller
= Private
;
95 Private
->ActiveNamespaceNum
++;
98 // Build BlockIo media structure
100 Flbas
= NamespaceData
->Flbas
;
101 LbaFmtIdx
= Flbas
& 0xF;
102 Lbads
= NamespaceData
->LbaFormat
[LbaFmtIdx
].Lbads
;
104 NamespaceInfo
->Media
.InterfaceType
= MSG_NVME_NAMESPACE_DP
;
105 NamespaceInfo
->Media
.RemovableMedia
= FALSE
;
106 NamespaceInfo
->Media
.MediaPresent
= TRUE
;
107 NamespaceInfo
->Media
.ReadOnly
= FALSE
;
108 NamespaceInfo
->Media
.BlockSize
= (UINT32
) 1 << Lbads
;
109 NamespaceInfo
->Media
.LastBlock
= (EFI_PEI_LBA
) NamespaceData
->Nsze
- 1;
112 "%a: Namespace ID %d - BlockSize = 0x%x, LastBlock = 0x%lx\n",
115 NamespaceInfo
->Media
.BlockSize
,
116 NamespaceInfo
->Media
.LastBlock
120 if (NamespaceData
!= NULL
) {
121 FreePool (NamespaceData
);
128 Discover all Nvm Express device active namespaces.
130 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
132 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.
133 @return EFI_NOT_FOUND No active namespaces can be found.
137 NvmeDiscoverNamespaces (
138 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
143 Private
->ActiveNamespaceNum
= 0;
144 Private
->NamespaceInfo
= AllocateZeroPool (Private
->ControllerData
->Nn
* sizeof (PEI_NVME_NAMESPACE_INFO
));
147 // According to Nvm Express 1.1 spec Figure 82, the field 'Nn' of the identify
148 // controller data defines the number of valid namespaces present for the
149 // controller. Namespaces shall be allocated in order (starting with 1) and
150 // packed sequentially.
152 for (NamespaceId
= 1; NamespaceId
<= Private
->ControllerData
->Nn
; NamespaceId
++) {
154 // For now, we do not care the return status. Since if a valid namespace is inactive,
155 // error status will be returned. But we continue to enumerate other valid namespaces.
157 EnumerateNvmeDevNamespace (Private
, NamespaceId
);
159 if (Private
->ActiveNamespaceNum
== 0) {
160 return EFI_NOT_FOUND
;
167 One notified function to cleanup the allocated resources at the end of PEI.
169 @param[in] PeiServices Pointer to PEI Services Table.
170 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
171 event that caused this function to execute.
172 @param[in] Ppi Pointer to the PPI data associated with this function.
174 @retval EFI_SUCCESS The function completes successfully
180 IN EFI_PEI_SERVICES
**PeiServices
,
181 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
185 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
187 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor
);
188 NvmeDisableController (Private
);
189 NvmeFreeControllerResource (Private
);
195 Entry point of the PEIM.
197 @param[in] FileHandle Handle of the file being invoked.
198 @param[in] PeiServices Describes the list of possible PEI Services.
200 @retval EFI_SUCCESS PPI successfully installed.
205 NvmExpressPeimEntry (
206 IN EFI_PEI_FILE_HANDLE FileHandle
,
207 IN CONST EFI_PEI_SERVICES
**PeiServices
211 EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI
*NvmeHcPpi
;
214 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
215 EFI_PHYSICAL_ADDRESS DeviceAddress
;
218 // Locate the NVME host controller PPI
220 Status
= PeiServicesLocatePpi (
221 &gEdkiiPeiNvmExpressHostControllerPpiGuid
,
226 if (EFI_ERROR (Status
)) {
227 DEBUG ((DEBUG_ERROR
, "%a: Fail to locate NvmeHostControllerPpi.\n", __FUNCTION__
));
228 return EFI_UNSUPPORTED
;
234 Status
= NvmeHcPpi
->GetNvmeHcMmioBar (
240 // When status is error, meant no controller is found
242 if (EFI_ERROR (Status
)) {
247 // Memory allocation for controller private data
249 Private
= AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA
));
250 if (Private
== NULL
) {
253 "%a: Fail to allocate private data for Controller %d.\n",
257 return EFI_OUT_OF_RESOURCES
;
261 // Memory allocation for transfer-related data
263 Status
= IoMmuAllocateBuffer (
267 &Private
->BufferMapping
269 if (EFI_ERROR (Status
)) {
272 "%a: Fail to allocate DMA buffers for Controller %d.\n",
276 NvmeFreeControllerResource (Private
);
279 ASSERT (DeviceAddress
== ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Private
->Buffer
));
280 DEBUG ((DEBUG_INFO
, "%a: DMA buffer base at 0x%x\n", __FUNCTION__
, Private
->Buffer
));
283 // Initialize controller private data
285 Private
->Signature
= NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE
;
286 Private
->MmioBase
= MmioBase
;
287 Private
->BlkIoPpi
.GetNumberOfBlockDevices
= NvmeBlockIoPeimGetDeviceNo
;
288 Private
->BlkIoPpi
.GetBlockDeviceMediaInfo
= NvmeBlockIoPeimGetMediaInfo
;
289 Private
->BlkIoPpi
.ReadBlocks
= NvmeBlockIoPeimReadBlocks
;
290 Private
->BlkIo2Ppi
.Revision
= EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION
;
291 Private
->BlkIo2Ppi
.GetNumberOfBlockDevices
= NvmeBlockIoPeimGetDeviceNo2
;
292 Private
->BlkIo2Ppi
.GetBlockDeviceMediaInfo
= NvmeBlockIoPeimGetMediaInfo2
;
293 Private
->BlkIo2Ppi
.ReadBlocks
= NvmeBlockIoPeimReadBlocks2
;
294 CopyMem (&Private
->BlkIoPpiList
, &mNvmeBlkIoPpiListTemplate
, sizeof (EFI_PEI_PPI_DESCRIPTOR
));
295 CopyMem (&Private
->BlkIo2PpiList
, &mNvmeBlkIo2PpiListTemplate
, sizeof (EFI_PEI_PPI_DESCRIPTOR
));
296 CopyMem (&Private
->EndOfPeiNotifyList
, &mNvmeEndOfPeiNotifyListTemplate
, sizeof (EFI_PEI_NOTIFY_DESCRIPTOR
));
297 Private
->BlkIoPpiList
.Ppi
= &Private
->BlkIoPpi
;
298 Private
->BlkIo2PpiList
.Ppi
= &Private
->BlkIo2Ppi
;
301 // Initialize the NVME controller
303 Status
= NvmeControllerInit (Private
);
304 if (EFI_ERROR (Status
)) {
307 "%a: Controller initialization fail for Controller %d with Status - %r.\n",
312 NvmeFreeControllerResource (Private
);
318 // Enumerate the NVME namespaces on the controller
320 Status
= NvmeDiscoverNamespaces (Private
);
321 if (EFI_ERROR (Status
)) {
323 // No active namespace was found on the controller
327 "%a: Namespaces discovery fail for Controller %d with Status - %r.\n",
332 NvmeFreeControllerResource (Private
);
337 PeiServicesInstallPpi (&Private
->BlkIoPpiList
);
338 PeiServicesNotifyPpi (&Private
->EndOfPeiNotifyList
);
341 "%a: BlockIO PPI has been installed on Controller %d.\n",