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