]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NvmExpressPei / NvmExpressPei.c
1 /** @file
2 The NvmExpressPei driver is used to manage non-volatile memory subsystem
3 which follows NVM Express specification at PEI phase.
4
5 Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "NvmExpressPei.h"
12
13 EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIoPpiListTemplate = {
14 EFI_PEI_PPI_DESCRIPTOR_PPI,
15 &gEfiPeiVirtualBlockIoPpiGuid,
16 NULL
17 };
18
19 EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIo2PpiListTemplate = {
20 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
21 &gEfiPeiVirtualBlockIo2PpiGuid,
22 NULL
23 };
24
25 EFI_PEI_PPI_DESCRIPTOR mNvmeStorageSecurityPpiListTemplate = {
26 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
27 &gEdkiiPeiStorageSecurityCommandPpiGuid,
28 NULL
29 };
30
31 EFI_PEI_NOTIFY_DESCRIPTOR mNvmeEndOfPeiNotifyListTemplate = {
32 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
33 &gEfiEndOfPeiSignalPpiGuid,
34 NvmePeimEndOfPei
35 };
36
37 /**
38 Check if the specified Nvm Express device namespace is active, and then get the Identify
39 Namespace data.
40
41 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
42 @param[in] NamespaceId The specified namespace identifier.
43
44 @retval EFI_SUCCESS The specified namespace in the device is successfully enumerated.
45 @return Others Error occurs when enumerating the namespace.
46
47 **/
48 EFI_STATUS
49 EnumerateNvmeDevNamespace (
50 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
51 IN UINT32 NamespaceId
52 )
53 {
54 EFI_STATUS Status;
55 NVME_ADMIN_NAMESPACE_DATA *NamespaceData;
56 PEI_NVME_NAMESPACE_INFO *NamespaceInfo;
57 UINT32 DeviceIndex;
58 UINT32 Lbads;
59 UINT32 Flbas;
60 UINT32 LbaFmtIdx;
61
62 NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *) AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));
63 if (NamespaceData == NULL) {
64 return EFI_OUT_OF_RESOURCES;
65 }
66
67 //
68 // Identify Namespace
69 //
70 Status = NvmeIdentifyNamespace (
71 Private,
72 NamespaceId,
73 NamespaceData
74 );
75 if (EFI_ERROR (Status)) {
76 DEBUG ((DEBUG_ERROR, "%a: NvmeIdentifyNamespace fail, Status - %r\n", __FUNCTION__, Status));
77 goto Exit;
78 }
79
80 //
81 // Validate Namespace
82 //
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;
86 goto Exit;
87 }
88
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++;
95
96 //
97 // Build BlockIo media structure
98 //
99 Flbas = NamespaceData->Flbas;
100 LbaFmtIdx = Flbas & 0xF;
101 Lbads = NamespaceData->LbaFormat[LbaFmtIdx].Lbads;
102
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;
109 DEBUG ((
110 DEBUG_INFO,
111 "%a: Namespace ID %d - BlockSize = 0x%x, LastBlock = 0x%lx\n",
112 __FUNCTION__,
113 NamespaceId,
114 NamespaceInfo->Media.BlockSize,
115 NamespaceInfo->Media.LastBlock
116 ));
117
118 Exit:
119 if (NamespaceData != NULL) {
120 FreePool (NamespaceData);
121 }
122
123 return Status;
124 }
125
126 /**
127 Discover all Nvm Express device active namespaces.
128
129 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
130
131 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.
132 @return EFI_NOT_FOUND No active namespaces can be found.
133
134 **/
135 EFI_STATUS
136 NvmeDiscoverNamespaces (
137 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
138 )
139 {
140 UINT32 NamespaceId;
141
142 Private->ActiveNamespaceNum = 0;
143 Private->NamespaceInfo = AllocateZeroPool (Private->ControllerData->Nn * sizeof (PEI_NVME_NAMESPACE_INFO));
144
145 //
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.
150 //
151 for (NamespaceId = 1; NamespaceId <= Private->ControllerData->Nn; NamespaceId++) {
152 //
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.
155 //
156 EnumerateNvmeDevNamespace (Private, NamespaceId);
157 }
158 if (Private->ActiveNamespaceNum == 0) {
159 return EFI_NOT_FOUND;
160 }
161
162 return EFI_SUCCESS;
163 }
164
165 /**
166 One notified function to cleanup the allocated resources at the end of PEI.
167
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.
172
173 @retval EFI_SUCCESS The function completes successfully
174
175 **/
176 EFI_STATUS
177 EFIAPI
178 NvmePeimEndOfPei (
179 IN EFI_PEI_SERVICES **PeiServices,
180 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
181 IN VOID *Ppi
182 )
183 {
184 PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
185
186 Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
187 NvmeFreeDmaResource (Private);
188
189 return EFI_SUCCESS;
190 }
191
192 /**
193 Entry point of the PEIM.
194
195 @param[in] FileHandle Handle of the file being invoked.
196 @param[in] PeiServices Describes the list of possible PEI Services.
197
198 @retval EFI_SUCCESS PPI successfully installed.
199
200 **/
201 EFI_STATUS
202 EFIAPI
203 NvmExpressPeimEntry (
204 IN EFI_PEI_FILE_HANDLE FileHandle,
205 IN CONST EFI_PEI_SERVICES **PeiServices
206 )
207 {
208 EFI_STATUS Status;
209 EFI_BOOT_MODE BootMode;
210 EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *NvmeHcPpi;
211 UINT8 Controller;
212 UINTN MmioBase;
213 UINTN DevicePathLength;
214 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
215 PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
216 EFI_PHYSICAL_ADDRESS DeviceAddress;
217
218 DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));
219
220 //
221 // Get the current boot mode.
222 //
223 Status = PeiServicesGetBootMode (&BootMode);
224 if (EFI_ERROR (Status)) {
225 DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __FUNCTION__));
226 return Status;
227 }
228
229 //
230 // Locate the NVME host controller PPI
231 //
232 Status = PeiServicesLocatePpi (
233 &gEdkiiPeiNvmExpressHostControllerPpiGuid,
234 0,
235 NULL,
236 (VOID **) &NvmeHcPpi
237 );
238 if (EFI_ERROR (Status)) {
239 DEBUG ((DEBUG_ERROR, "%a: Fail to locate NvmeHostControllerPpi.\n", __FUNCTION__));
240 return EFI_UNSUPPORTED;
241 }
242
243 Controller = 0;
244 MmioBase = 0;
245 while (TRUE) {
246 Status = NvmeHcPpi->GetNvmeHcMmioBar (
247 NvmeHcPpi,
248 Controller,
249 &MmioBase
250 );
251 //
252 // When status is error, meant no controller is found
253 //
254 if (EFI_ERROR (Status)) {
255 break;
256 }
257
258 Status = NvmeHcPpi->GetNvmeHcDevicePath (
259 NvmeHcPpi,
260 Controller,
261 &DevicePathLength,
262 &DevicePath
263 );
264 if (EFI_ERROR (Status)) {
265 DEBUG ((
266 DEBUG_ERROR, "%a: Fail to allocate get the device path for Controller %d.\n",
267 __FUNCTION__, Controller
268 ));
269 return Status;
270 }
271
272 //
273 // Check validity of the device path of the NVM Express controller.
274 //
275 Status = NvmeIsHcDevicePathValid (DevicePath, DevicePathLength);
276 if (EFI_ERROR (Status)) {
277 DEBUG ((
278 DEBUG_ERROR, "%a: The device path is invalid for Controller %d.\n",
279 __FUNCTION__, Controller
280 ));
281 Controller++;
282 continue;
283 }
284
285 //
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
289 // during S3 resume.
290 //
291 if ((BootMode == BOOT_ON_S3_RESUME) &&
292 (NvmeS3SkipThisController (DevicePath, DevicePathLength))) {
293 DEBUG ((
294 DEBUG_ERROR, "%a: Controller %d is skipped during S3.\n",
295 __FUNCTION__, Controller
296 ));
297 Controller++;
298 continue;
299 }
300
301 //
302 // Memory allocation for controller private data
303 //
304 Private = AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA));
305 if (Private == NULL) {
306 DEBUG ((
307 DEBUG_ERROR, "%a: Fail to allocate private data for Controller %d.\n",
308 __FUNCTION__, Controller
309 ));
310 return EFI_OUT_OF_RESOURCES;
311 }
312
313 //
314 // Memory allocation for transfer-related data
315 //
316 Status = IoMmuAllocateBuffer (
317 NVME_MEM_MAX_PAGES,
318 &Private->Buffer,
319 &DeviceAddress,
320 &Private->BufferMapping
321 );
322 if (EFI_ERROR (Status)) {
323 DEBUG ((
324 DEBUG_ERROR, "%a: Fail to allocate DMA buffers for Controller %d.\n",
325 __FUNCTION__, Controller
326 ));
327 return Status;
328 }
329 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Private->Buffer));
330 DEBUG ((DEBUG_INFO, "%a: DMA buffer base at 0x%x\n", __FUNCTION__, Private->Buffer));
331
332 //
333 // Initialize controller private data
334 //
335 Private->Signature = NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE;
336 Private->MmioBase = MmioBase;
337 Private->DevicePathLength = DevicePathLength;
338 Private->DevicePath = DevicePath;
339
340 //
341 // Initialize the NVME controller
342 //
343 Status = NvmeControllerInit (Private);
344 if (EFI_ERROR (Status)) {
345 DEBUG ((
346 DEBUG_ERROR,
347 "%a: Controller initialization fail for Controller %d with Status - %r.\n",
348 __FUNCTION__, Controller, Status
349 ));
350 NvmeFreeDmaResource (Private);
351 Controller++;
352 continue;
353 }
354
355 //
356 // Enumerate the NVME namespaces on the controller
357 //
358 Status = NvmeDiscoverNamespaces (Private);
359 if (EFI_ERROR (Status)) {
360 //
361 // No active namespace was found on the controller
362 //
363 DEBUG ((
364 DEBUG_ERROR,
365 "%a: Namespaces discovery fail for Controller %d with Status - %r.\n",
366 __FUNCTION__, Controller, Status
367 ));
368 NvmeFreeDmaResource (Private);
369 Controller++;
370 continue;
371 }
372
373 Private->BlkIoPpi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo;
374 Private->BlkIoPpi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo;
375 Private->BlkIoPpi.ReadBlocks = NvmeBlockIoPeimReadBlocks;
376 CopyMem (
377 &Private->BlkIoPpiList,
378 &mNvmeBlkIoPpiListTemplate,
379 sizeof (EFI_PEI_PPI_DESCRIPTOR)
380 );
381 Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi;
382
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;
387 CopyMem (
388 &Private->BlkIo2PpiList,
389 &mNvmeBlkIo2PpiListTemplate,
390 sizeof (EFI_PEI_PPI_DESCRIPTOR)
391 );
392 Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;
393 PeiServicesInstallPpi (&Private->BlkIoPpiList);
394
395 //
396 // Check if the NVME controller supports the Security Receive/Send commands
397 //
398 if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) {
399 DEBUG ((
400 DEBUG_INFO,
401 "%a: Security Security Command PPI will be produced for Controller %d.\n",
402 __FUNCTION__, Controller
403 ));
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;
409 CopyMem (
410 &Private->StorageSecurityPpiList,
411 &mNvmeStorageSecurityPpiListTemplate,
412 sizeof (EFI_PEI_PPI_DESCRIPTOR)
413 );
414 Private->StorageSecurityPpiList.Ppi = &Private->StorageSecurityPpi;
415 PeiServicesInstallPpi (&Private->StorageSecurityPpiList);
416 }
417
418 CopyMem (
419 &Private->EndOfPeiNotifyList,
420 &mNvmeEndOfPeiNotifyListTemplate,
421 sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)
422 );
423 PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
424
425 DEBUG ((
426 DEBUG_INFO, "%a: Controller %d has been successfully initialized.\n",
427 __FUNCTION__, Controller
428 ));
429 Controller++;
430 }
431
432 return EFI_SUCCESS;
433 }