]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
f73053fc3feb53f760da2bacb7b786842658684a
[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_PPI_DESCRIPTOR mNvmePassThruPpiListTemplate = {
32 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
33 &gEdkiiPeiNvmExpressPassThruPpiGuid,
34 NULL
35 };
36
37 EFI_PEI_NOTIFY_DESCRIPTOR mNvmeEndOfPeiNotifyListTemplate = {
38 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
39 &gEfiEndOfPeiSignalPpiGuid,
40 NvmePeimEndOfPei
41 };
42
43 /**
44 Check if the specified Nvm Express device namespace is active, and then get the Identify
45 Namespace data.
46
47 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
48 @param[in] NamespaceId The specified namespace identifier.
49
50 @retval EFI_SUCCESS The specified namespace in the device is successfully enumerated.
51 @return Others Error occurs when enumerating the namespace.
52
53 **/
54 EFI_STATUS
55 EnumerateNvmeDevNamespace (
56 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
57 IN UINT32 NamespaceId
58 )
59 {
60 EFI_STATUS Status;
61 NVME_ADMIN_NAMESPACE_DATA *NamespaceData;
62 PEI_NVME_NAMESPACE_INFO *NamespaceInfo;
63 UINT32 DeviceIndex;
64 UINT32 Lbads;
65 UINT32 Flbas;
66 UINT32 LbaFmtIdx;
67
68 NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));
69 if (NamespaceData == NULL) {
70 return EFI_OUT_OF_RESOURCES;
71 }
72
73 //
74 // Identify Namespace
75 //
76 Status = NvmeIdentifyNamespace (
77 Private,
78 NamespaceId,
79 NamespaceData
80 );
81 if (EFI_ERROR (Status)) {
82 DEBUG ((DEBUG_ERROR, "%a: NvmeIdentifyNamespace fail, Status - %r\n", __FUNCTION__, Status));
83 goto Exit;
84 }
85
86 //
87 // Validate Namespace
88 //
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;
92 goto Exit;
93 }
94
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++;
101
102 //
103 // Build BlockIo media structure
104 //
105 Flbas = NamespaceData->Flbas;
106 LbaFmtIdx = Flbas & 0xF;
107 Lbads = NamespaceData->LbaFormat[LbaFmtIdx].Lbads;
108
109 NamespaceInfo->Media.InterfaceType = MSG_NVME_NAMESPACE_DP;
110 NamespaceInfo->Media.RemovableMedia = FALSE;
111 NamespaceInfo->Media.MediaPresent = TRUE;
112 NamespaceInfo->Media.ReadOnly = FALSE;
113 NamespaceInfo->Media.BlockSize = (UINT32)1 << Lbads;
114 NamespaceInfo->Media.LastBlock = (EFI_PEI_LBA)NamespaceData->Nsze - 1;
115 DEBUG ((
116 DEBUG_INFO,
117 "%a: Namespace ID %d - BlockSize = 0x%x, LastBlock = 0x%lx\n",
118 __FUNCTION__,
119 NamespaceId,
120 NamespaceInfo->Media.BlockSize,
121 NamespaceInfo->Media.LastBlock
122 ));
123
124 Exit:
125 if (NamespaceData != NULL) {
126 FreePool (NamespaceData);
127 }
128
129 return Status;
130 }
131
132 /**
133 Discover all Nvm Express device active namespaces.
134
135 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
136
137 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.
138 @return EFI_NOT_FOUND No active namespaces can be found.
139
140 **/
141 EFI_STATUS
142 NvmeDiscoverNamespaces (
143 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
144 )
145 {
146 UINT32 NamespaceId;
147
148 Private->ActiveNamespaceNum = 0;
149 Private->NamespaceInfo = AllocateZeroPool (Private->ControllerData->Nn * sizeof (PEI_NVME_NAMESPACE_INFO));
150
151 //
152 // According to Nvm Express 1.1 spec Figure 82, the field 'Nn' of the identify
153 // controller data defines the number of valid namespaces present for the
154 // controller. Namespaces shall be allocated in order (starting with 1) and
155 // packed sequentially.
156 //
157 for (NamespaceId = 1; NamespaceId <= Private->ControllerData->Nn; NamespaceId++) {
158 //
159 // For now, we do not care the return status. Since if a valid namespace is inactive,
160 // error status will be returned. But we continue to enumerate other valid namespaces.
161 //
162 EnumerateNvmeDevNamespace (Private, NamespaceId);
163 }
164
165 if (Private->ActiveNamespaceNum == 0) {
166 return EFI_NOT_FOUND;
167 }
168
169 return EFI_SUCCESS;
170 }
171
172 /**
173 One notified function to cleanup the allocated resources at the end of PEI.
174
175 @param[in] PeiServices Pointer to PEI Services Table.
176 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
177 event that caused this function to execute.
178 @param[in] Ppi Pointer to the PPI data associated with this function.
179
180 @retval EFI_SUCCESS The function completes successfully
181
182 **/
183 EFI_STATUS
184 EFIAPI
185 NvmePeimEndOfPei (
186 IN EFI_PEI_SERVICES **PeiServices,
187 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
188 IN VOID *Ppi
189 )
190 {
191 PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
192
193 Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
194 NvmeFreeDmaResource (Private);
195
196 return EFI_SUCCESS;
197 }
198
199 /**
200 Entry point of the PEIM.
201
202 @param[in] FileHandle Handle of the file being invoked.
203 @param[in] PeiServices Describes the list of possible PEI Services.
204
205 @retval EFI_SUCCESS PPI successfully installed.
206
207 **/
208 EFI_STATUS
209 EFIAPI
210 NvmExpressPeimEntry (
211 IN EFI_PEI_FILE_HANDLE FileHandle,
212 IN CONST EFI_PEI_SERVICES **PeiServices
213 )
214 {
215 EFI_STATUS Status;
216 EFI_BOOT_MODE BootMode;
217 EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *NvmeHcPpi;
218 UINT8 Controller;
219 UINTN MmioBase;
220 UINTN DevicePathLength;
221 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
222 PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;
223 EFI_PHYSICAL_ADDRESS DeviceAddress;
224
225 DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));
226
227 //
228 // Get the current boot mode.
229 //
230 Status = PeiServicesGetBootMode (&BootMode);
231 if (EFI_ERROR (Status)) {
232 DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __FUNCTION__));
233 return Status;
234 }
235
236 //
237 // Locate the NVME host controller PPI
238 //
239 Status = PeiServicesLocatePpi (
240 &gEdkiiPeiNvmExpressHostControllerPpiGuid,
241 0,
242 NULL,
243 (VOID **)&NvmeHcPpi
244 );
245 if (EFI_ERROR (Status)) {
246 DEBUG ((DEBUG_ERROR, "%a: Fail to locate NvmeHostControllerPpi.\n", __FUNCTION__));
247 return EFI_UNSUPPORTED;
248 }
249
250 Controller = 0;
251 MmioBase = 0;
252 while (TRUE) {
253 Status = NvmeHcPpi->GetNvmeHcMmioBar (
254 NvmeHcPpi,
255 Controller,
256 &MmioBase
257 );
258 //
259 // When status is error, meant no controller is found
260 //
261 if (EFI_ERROR (Status)) {
262 break;
263 }
264
265 Status = NvmeHcPpi->GetNvmeHcDevicePath (
266 NvmeHcPpi,
267 Controller,
268 &DevicePathLength,
269 &DevicePath
270 );
271 if (EFI_ERROR (Status)) {
272 DEBUG ((
273 DEBUG_ERROR,
274 "%a: Fail to allocate get the device path for Controller %d.\n",
275 __FUNCTION__,
276 Controller
277 ));
278 return Status;
279 }
280
281 //
282 // Check validity of the device path of the NVM Express controller.
283 //
284 Status = NvmeIsHcDevicePathValid (DevicePath, DevicePathLength);
285 if (EFI_ERROR (Status)) {
286 DEBUG ((
287 DEBUG_ERROR,
288 "%a: The device path is invalid for Controller %d.\n",
289 __FUNCTION__,
290 Controller
291 ));
292 Controller++;
293 continue;
294 }
295
296 //
297 // For S3 resume performance consideration, not all NVM Express controllers
298 // will be initialized. The driver consumes the content within
299 // S3StorageDeviceInitList LockBox to see if a controller will be skipped
300 // during S3 resume.
301 //
302 if ((BootMode == BOOT_ON_S3_RESUME) &&
303 (NvmeS3SkipThisController (DevicePath, DevicePathLength)))
304 {
305 DEBUG ((
306 DEBUG_ERROR,
307 "%a: Controller %d is skipped during S3.\n",
308 __FUNCTION__,
309 Controller
310 ));
311 Controller++;
312 continue;
313 }
314
315 //
316 // Memory allocation for controller private data
317 //
318 Private = AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA));
319 if (Private == NULL) {
320 DEBUG ((
321 DEBUG_ERROR,
322 "%a: Fail to allocate private data for Controller %d.\n",
323 __FUNCTION__,
324 Controller
325 ));
326 return EFI_OUT_OF_RESOURCES;
327 }
328
329 //
330 // Memory allocation for transfer-related data
331 //
332 Status = IoMmuAllocateBuffer (
333 NVME_MEM_MAX_PAGES,
334 &Private->Buffer,
335 &DeviceAddress,
336 &Private->BufferMapping
337 );
338 if (EFI_ERROR (Status)) {
339 DEBUG ((
340 DEBUG_ERROR,
341 "%a: Fail to allocate DMA buffers for Controller %d.\n",
342 __FUNCTION__,
343 Controller
344 ));
345 return Status;
346 }
347
348 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS)(UINTN)Private->Buffer));
349 DEBUG ((DEBUG_INFO, "%a: DMA buffer base at 0x%x\n", __FUNCTION__, Private->Buffer));
350
351 //
352 // Initialize controller private data
353 //
354 Private->Signature = NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE;
355 Private->MmioBase = MmioBase;
356 Private->DevicePathLength = DevicePathLength;
357 Private->DevicePath = DevicePath;
358
359 //
360 // Initialize the NVME controller
361 //
362 Status = NvmeControllerInit (Private);
363 if (EFI_ERROR (Status)) {
364 DEBUG ((
365 DEBUG_ERROR,
366 "%a: Controller initialization fail for Controller %d with Status - %r.\n",
367 __FUNCTION__,
368 Controller,
369 Status
370 ));
371 NvmeFreeDmaResource (Private);
372 Controller++;
373 continue;
374 }
375
376 //
377 // Enumerate the NVME namespaces on the controller
378 //
379 Status = NvmeDiscoverNamespaces (Private);
380 if (EFI_ERROR (Status)) {
381 //
382 // No active namespace was found on the controller
383 //
384 DEBUG ((
385 DEBUG_ERROR,
386 "%a: Namespaces discovery fail for Controller %d with Status - %r.\n",
387 __FUNCTION__,
388 Controller,
389 Status
390 ));
391 NvmeFreeDmaResource (Private);
392 Controller++;
393 continue;
394 }
395
396 //
397 // Nvm Express Pass Thru PPI
398 //
399 Private->PassThruMode.Attributes = EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL |
400 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL |
401 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVM;
402 Private->PassThruMode.IoAlign = sizeof (UINTN);
403 Private->PassThruMode.NvmeVersion = EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI_REVISION;
404 Private->NvmePassThruPpi.Mode = &Private->PassThruMode;
405 Private->NvmePassThruPpi.GetDevicePath = NvmePassThruGetDevicePath;
406 Private->NvmePassThruPpi.GetNextNameSpace = NvmePassThruGetNextNameSpace;
407 Private->NvmePassThruPpi.PassThru = NvmePassThru;
408 CopyMem (
409 &Private->NvmePassThruPpiList,
410 &mNvmePassThruPpiListTemplate,
411 sizeof (EFI_PEI_PPI_DESCRIPTOR)
412 );
413 Private->NvmePassThruPpiList.Ppi = &Private->NvmePassThruPpi;
414 PeiServicesInstallPpi (&Private->NvmePassThruPpiList);
415
416 //
417 // Block Io PPI
418 //
419 Private->BlkIoPpi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo;
420 Private->BlkIoPpi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo;
421 Private->BlkIoPpi.ReadBlocks = NvmeBlockIoPeimReadBlocks;
422 CopyMem (
423 &Private->BlkIoPpiList,
424 &mNvmeBlkIoPpiListTemplate,
425 sizeof (EFI_PEI_PPI_DESCRIPTOR)
426 );
427 Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi;
428
429 Private->BlkIo2Ppi.Revision = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;
430 Private->BlkIo2Ppi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo2;
431 Private->BlkIo2Ppi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo2;
432 Private->BlkIo2Ppi.ReadBlocks = NvmeBlockIoPeimReadBlocks2;
433 CopyMem (
434 &Private->BlkIo2PpiList,
435 &mNvmeBlkIo2PpiListTemplate,
436 sizeof (EFI_PEI_PPI_DESCRIPTOR)
437 );
438 Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;
439 PeiServicesInstallPpi (&Private->BlkIoPpiList);
440
441 //
442 // Check if the NVME controller supports the Security Receive/Send commands
443 //
444 if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) {
445 DEBUG ((
446 DEBUG_INFO,
447 "%a: Security Security Command PPI will be produced for Controller %d.\n",
448 __FUNCTION__,
449 Controller
450 ));
451 Private->StorageSecurityPpi.Revision = EDKII_STORAGE_SECURITY_PPI_REVISION;
452 Private->StorageSecurityPpi.GetNumberofDevices = NvmeStorageSecurityGetDeviceNo;
453 Private->StorageSecurityPpi.GetDevicePath = NvmeStorageSecurityGetDevicePath;
454 Private->StorageSecurityPpi.ReceiveData = NvmeStorageSecurityReceiveData;
455 Private->StorageSecurityPpi.SendData = NvmeStorageSecuritySendData;
456 CopyMem (
457 &Private->StorageSecurityPpiList,
458 &mNvmeStorageSecurityPpiListTemplate,
459 sizeof (EFI_PEI_PPI_DESCRIPTOR)
460 );
461 Private->StorageSecurityPpiList.Ppi = &Private->StorageSecurityPpi;
462 PeiServicesInstallPpi (&Private->StorageSecurityPpiList);
463 }
464
465 CopyMem (
466 &Private->EndOfPeiNotifyList,
467 &mNvmeEndOfPeiNotifyListTemplate,
468 sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)
469 );
470 PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
471
472 DEBUG ((
473 DEBUG_INFO,
474 "%a: Controller %d has been successfully initialized.\n",
475 __FUNCTION__,
476 Controller
477 ));
478 Controller++;
479 }
480
481 return EFI_SUCCESS;
482 }