]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
MdeModulePkg/NvmExpressPei: Use PCI_DEVICE_PPI to manage Nvme device
[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
9ca7ece8
CX
43EFI_PEI_NOTIFY_DESCRIPTOR mNvmeHostControllerNotify = {\r
44 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
45 &gEdkiiPeiNvmExpressHostControllerPpiGuid,\r
46 NvmeHostControllerPpiInstallationCallback\r
47};\r
48\r
49EFI_PEI_NOTIFY_DESCRIPTOR mPciDevicePpiNotify = {\r
50 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
51 &gEdkiiPeiPciDevicePpiGuid,\r
52 NvmePciDevicePpiInstallationCallback\r
53};\r
54\r
b8b69433
HW
55/**\r
56 Check if the specified Nvm Express device namespace is active, and then get the Identify\r
57 Namespace data.\r
58\r
59 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
60 @param[in] NamespaceId The specified namespace identifier.\r
61\r
62 @retval EFI_SUCCESS The specified namespace in the device is successfully enumerated.\r
63 @return Others Error occurs when enumerating the namespace.\r
64\r
65**/\r
66EFI_STATUS\r
67EnumerateNvmeDevNamespace (\r
1436aea4
MK
68 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,\r
69 IN UINT32 NamespaceId\r
b8b69433
HW
70 )\r
71{\r
1436aea4
MK
72 EFI_STATUS Status;\r
73 NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
74 PEI_NVME_NAMESPACE_INFO *NamespaceInfo;\r
75 UINT32 DeviceIndex;\r
76 UINT32 Lbads;\r
77 UINT32 Flbas;\r
78 UINT32 LbaFmtIdx;\r
79\r
80 NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
b8b69433
HW
81 if (NamespaceData == NULL) {\r
82 return EFI_OUT_OF_RESOURCES;\r
83 }\r
84\r
85 //\r
86 // Identify Namespace\r
87 //\r
88 Status = NvmeIdentifyNamespace (\r
89 Private,\r
90 NamespaceId,\r
91 NamespaceData\r
92 );\r
93 if (EFI_ERROR (Status)) {\r
94 DEBUG ((DEBUG_ERROR, "%a: NvmeIdentifyNamespace fail, Status - %r\n", __FUNCTION__, Status));\r
95 goto Exit;\r
96 }\r
97\r
98 //\r
99 // Validate Namespace\r
100 //\r
101 if (NamespaceData->Ncap == 0) {\r
102 DEBUG ((DEBUG_INFO, "%a: Namespace ID %d is an inactive one.\n", __FUNCTION__, NamespaceId));\r
103 Status = EFI_DEVICE_ERROR;\r
104 goto Exit;\r
105 }\r
106\r
1436aea4
MK
107 DeviceIndex = Private->ActiveNamespaceNum;\r
108 NamespaceInfo = &Private->NamespaceInfo[DeviceIndex];\r
b8b69433
HW
109 NamespaceInfo->NamespaceId = NamespaceId;\r
110 NamespaceInfo->NamespaceUuid = NamespaceData->Eui64;\r
111 NamespaceInfo->Controller = Private;\r
112 Private->ActiveNamespaceNum++;\r
113\r
114 //\r
115 // Build BlockIo media structure\r
116 //\r
117 Flbas = NamespaceData->Flbas;\r
118 LbaFmtIdx = Flbas & 0xF;\r
79f2734e
MH
119\r
120 //\r
121 // Currently this NVME driver only suport Metadata Size == 0\r
122 //\r
123 if (NamespaceData->LbaFormat[LbaFmtIdx].Ms != 0) {\r
124 DEBUG ((\r
125 DEBUG_ERROR,\r
126 "NVME IDENTIFY NAMESPACE [%d] Ms(%d) is not supported.\n",\r
127 NamespaceId,\r
128 NamespaceData->LbaFormat[LbaFmtIdx].Ms\r
129 ));\r
130 Status = EFI_UNSUPPORTED;\r
131 goto Exit;\r
132 }\r
133\r
134 Lbads = NamespaceData->LbaFormat[LbaFmtIdx].Lbads;\r
b8b69433
HW
135\r
136 NamespaceInfo->Media.InterfaceType = MSG_NVME_NAMESPACE_DP;\r
137 NamespaceInfo->Media.RemovableMedia = FALSE;\r
138 NamespaceInfo->Media.MediaPresent = TRUE;\r
139 NamespaceInfo->Media.ReadOnly = FALSE;\r
1436aea4
MK
140 NamespaceInfo->Media.BlockSize = (UINT32)1 << Lbads;\r
141 NamespaceInfo->Media.LastBlock = (EFI_PEI_LBA)NamespaceData->Nsze - 1;\r
b8b69433
HW
142 DEBUG ((\r
143 DEBUG_INFO,\r
144 "%a: Namespace ID %d - BlockSize = 0x%x, LastBlock = 0x%lx\n",\r
145 __FUNCTION__,\r
146 NamespaceId,\r
147 NamespaceInfo->Media.BlockSize,\r
148 NamespaceInfo->Media.LastBlock\r
149 ));\r
150\r
151Exit:\r
152 if (NamespaceData != NULL) {\r
153 FreePool (NamespaceData);\r
154 }\r
155\r
156 return Status;\r
157}\r
158\r
159/**\r
160 Discover all Nvm Express device active namespaces.\r
161\r
162 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
163\r
164 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.\r
165 @return EFI_NOT_FOUND No active namespaces can be found.\r
166\r
167**/\r
168EFI_STATUS\r
169NvmeDiscoverNamespaces (\r
1436aea4 170 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA *Private\r
b8b69433
HW
171 )\r
172{\r
1436aea4 173 UINT32 NamespaceId;\r
b8b69433
HW
174\r
175 Private->ActiveNamespaceNum = 0;\r
176 Private->NamespaceInfo = AllocateZeroPool (Private->ControllerData->Nn * sizeof (PEI_NVME_NAMESPACE_INFO));\r
177\r
178 //\r
179 // According to Nvm Express 1.1 spec Figure 82, the field 'Nn' of the identify\r
180 // controller data defines the number of valid namespaces present for the\r
181 // controller. Namespaces shall be allocated in order (starting with 1) and\r
182 // packed sequentially.\r
183 //\r
184 for (NamespaceId = 1; NamespaceId <= Private->ControllerData->Nn; NamespaceId++) {\r
185 //\r
186 // For now, we do not care the return status. Since if a valid namespace is inactive,\r
187 // error status will be returned. But we continue to enumerate other valid namespaces.\r
188 //\r
189 EnumerateNvmeDevNamespace (Private, NamespaceId);\r
190 }\r
1436aea4 191\r
b8b69433
HW
192 if (Private->ActiveNamespaceNum == 0) {\r
193 return EFI_NOT_FOUND;\r
194 }\r
195\r
196 return EFI_SUCCESS;\r
197}\r
198\r
199/**\r
200 One notified function to cleanup the allocated resources at the end of PEI.\r
201\r
202 @param[in] PeiServices Pointer to PEI Services Table.\r
203 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification\r
204 event that caused this function to execute.\r
205 @param[in] Ppi Pointer to the PPI data associated with this function.\r
206\r
207 @retval EFI_SUCCESS The function completes successfully\r
208\r
209**/\r
210EFI_STATUS\r
211EFIAPI\r
212NvmePeimEndOfPei (\r
213 IN EFI_PEI_SERVICES **PeiServices,\r
214 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
215 IN VOID *Ppi\r
216 )\r
217{\r
1436aea4 218 PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;\r
b8b69433
HW
219\r
220 Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);\r
2e15b750 221 NvmeFreeDmaResource (Private);\r
b8b69433
HW
222\r
223 return EFI_SUCCESS;\r
224}\r
225\r
226/**\r
9ca7ece8 227 Initialize and install PrivateData PPIs.\r
b8b69433 228\r
9ca7ece8
CX
229 @param[in] MmioBase MMIO base address of specific Nvme controller\r
230 @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL\r
231 structure.\r
232 @param[in] DevicePathLength Length of the device path.\r
b8b69433 233\r
9ca7ece8
CX
234 @retval EFI_SUCCESS Nvme controller initialized and PPIs installed\r
235 @retval others Failed to initialize Nvme controller\r
b8b69433
HW
236**/\r
237EFI_STATUS\r
9ca7ece8
CX
238NvmeInitPrivateData (\r
239 IN UINTN MmioBase,\r
240 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
241 IN UINTN DevicePathLength\r
b8b69433
HW
242 )\r
243{\r
9ca7ece8
CX
244 EFI_STATUS Status;\r
245 EFI_BOOT_MODE BootMode;\r
246 PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;\r
247 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
b8b69433 248\r
2e15b750
HW
249 DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));\r
250\r
05fd2a92
HW
251 //\r
252 // Get the current boot mode.\r
253 //\r
254 Status = PeiServicesGetBootMode (&BootMode);\r
255 if (EFI_ERROR (Status)) {\r
256 DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __FUNCTION__));\r
257 return Status;\r
258 }\r
259\r
b8b69433 260 //\r
9ca7ece8 261 // Check validity of the device path of the NVM Express controller.\r
b8b69433 262 //\r
9ca7ece8
CX
263 Status = NvmeIsHcDevicePathValid (DevicePath, DevicePathLength);\r
264 if (EFI_ERROR (Status)) {\r
265 DEBUG ((\r
266 DEBUG_ERROR,\r
267 "%a: The device path is invalid for Controller %d.\n",\r
268 __FUNCTION__\r
269 ));\r
270 return Status;\r
271 }\r
272\r
273 //\r
274 // For S3 resume performance consideration, not all NVM Express controllers\r
275 // will be initialized. The driver consumes the content within\r
276 // S3StorageDeviceInitList LockBox to see if a controller will be skipped\r
277 // during S3 resume.\r
278 //\r
279 if ((BootMode == BOOT_ON_S3_RESUME) &&\r
280 (NvmeS3SkipThisController (DevicePath, DevicePathLength)))\r
281 {\r
282 DEBUG ((\r
283 DEBUG_ERROR,\r
284 "%a: skipped during S3.\n",\r
285 __FUNCTION__\r
286 ));\r
287 return EFI_SUCCESS;\r
288 }\r
289\r
290 //\r
291 // Memory allocation for controller private data\r
292 //\r
293 Private = AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA));\r
294 if (Private == NULL) {\r
295 DEBUG ((\r
296 DEBUG_ERROR,\r
297 "%a: Fail to allocate private data.\n",\r
298 __FUNCTION__\r
299 ));\r
300 return EFI_OUT_OF_RESOURCES;\r
301 }\r
302\r
303 //\r
304 // Memory allocation for transfer-related data\r
305 //\r
306 Status = IoMmuAllocateBuffer (\r
307 NVME_MEM_MAX_PAGES,\r
308 &Private->Buffer,\r
309 &DeviceAddress,\r
310 &Private->BufferMapping\r
b8b69433
HW
311 );\r
312 if (EFI_ERROR (Status)) {\r
9ca7ece8
CX
313 DEBUG ((\r
314 DEBUG_ERROR,\r
315 "%a: Fail to allocate DMA buffers.\n",\r
316 __FUNCTION__\r
317 ));\r
318 return Status;\r
319 }\r
320\r
321 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS)(UINTN)Private->Buffer));\r
322 DEBUG ((DEBUG_INFO, "%a: DMA buffer base at 0x%x\n", __FUNCTION__, Private->Buffer));\r
323\r
324 //\r
325 // Initialize controller private data\r
326 //\r
327 Private->Signature = NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE;\r
328 Private->MmioBase = MmioBase;\r
329 Private->DevicePathLength = DevicePathLength;\r
330 Private->DevicePath = DevicePath;\r
331\r
332 //\r
333 // Initialize the NVME controller\r
334 //\r
335 Status = NvmeControllerInit (Private);\r
336 if (EFI_ERROR (Status)) {\r
337 DEBUG ((\r
338 DEBUG_ERROR,\r
339 "%a: Controller initialization fail with Status - %r.\n",\r
340 __FUNCTION__,\r
341 Status\r
342 ));\r
343 NvmeFreeDmaResource (Private);\r
344 return Status;\r
345 }\r
346\r
347 //\r
348 // Enumerate the NVME namespaces on the controller\r
349 //\r
350 Status = NvmeDiscoverNamespaces (Private);\r
351 if (EFI_ERROR (Status)) {\r
352 //\r
353 // No active namespace was found on the controller\r
354 //\r
355 DEBUG ((\r
356 DEBUG_ERROR,\r
357 "%a: Namespaces discovery fail with Status - %r.\n",\r
358 __FUNCTION__,\r
359 Status\r
360 ));\r
361 NvmeFreeDmaResource (Private);\r
362 return Status;\r
363 }\r
364\r
365 //\r
366 // Nvm Express Pass Thru PPI\r
367 //\r
368 Private->PassThruMode.Attributes = EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL |\r
369 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL |\r
370 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVM;\r
371 Private->PassThruMode.IoAlign = sizeof (UINTN);\r
372 Private->PassThruMode.NvmeVersion = EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI_REVISION;\r
373 Private->NvmePassThruPpi.Mode = &Private->PassThruMode;\r
374 Private->NvmePassThruPpi.GetDevicePath = NvmePassThruGetDevicePath;\r
375 Private->NvmePassThruPpi.GetNextNameSpace = NvmePassThruGetNextNameSpace;\r
376 Private->NvmePassThruPpi.PassThru = NvmePassThru;\r
377 CopyMem (\r
378 &Private->NvmePassThruPpiList,\r
379 &mNvmePassThruPpiListTemplate,\r
380 sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
381 );\r
382 Private->NvmePassThruPpiList.Ppi = &Private->NvmePassThruPpi;\r
383 PeiServicesInstallPpi (&Private->NvmePassThruPpiList);\r
384\r
385 //\r
386 // Block Io PPI\r
387 //\r
388 Private->BlkIoPpi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo;\r
389 Private->BlkIoPpi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo;\r
390 Private->BlkIoPpi.ReadBlocks = NvmeBlockIoPeimReadBlocks;\r
391 CopyMem (\r
392 &Private->BlkIoPpiList,\r
393 &mNvmeBlkIoPpiListTemplate,\r
394 sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
395 );\r
396 Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi;\r
397\r
398 Private->BlkIo2Ppi.Revision = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;\r
399 Private->BlkIo2Ppi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo2;\r
400 Private->BlkIo2Ppi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo2;\r
401 Private->BlkIo2Ppi.ReadBlocks = NvmeBlockIoPeimReadBlocks2;\r
402 CopyMem (\r
403 &Private->BlkIo2PpiList,\r
404 &mNvmeBlkIo2PpiListTemplate,\r
405 sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
406 );\r
407 Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;\r
408 PeiServicesInstallPpi (&Private->BlkIoPpiList);\r
409\r
410 //\r
411 // Check if the NVME controller supports the Security Receive/Send commands\r
412 //\r
413 if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) {\r
414 DEBUG ((\r
415 DEBUG_INFO,\r
416 "%a: Security Security Command PPI will be produced.\n",\r
417 __FUNCTION__\r
418 ));\r
419 Private->StorageSecurityPpi.Revision = EDKII_STORAGE_SECURITY_PPI_REVISION;\r
420 Private->StorageSecurityPpi.GetNumberofDevices = NvmeStorageSecurityGetDeviceNo;\r
421 Private->StorageSecurityPpi.GetDevicePath = NvmeStorageSecurityGetDevicePath;\r
422 Private->StorageSecurityPpi.ReceiveData = NvmeStorageSecurityReceiveData;\r
423 Private->StorageSecurityPpi.SendData = NvmeStorageSecuritySendData;\r
424 CopyMem (\r
425 &Private->StorageSecurityPpiList,\r
426 &mNvmeStorageSecurityPpiListTemplate,\r
427 sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
428 );\r
429 Private->StorageSecurityPpiList.Ppi = &Private->StorageSecurityPpi;\r
430 PeiServicesInstallPpi (&Private->StorageSecurityPpiList);\r
431 }\r
432\r
433 CopyMem (\r
434 &Private->EndOfPeiNotifyList,\r
435 &mNvmeEndOfPeiNotifyListTemplate,\r
436 sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)\r
437 );\r
438 PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);\r
439\r
440 return EFI_SUCCESS;\r
441}\r
442\r
443/**\r
444 Initialize Nvme controller from fiven PCI_DEVICE_PPI.\r
445\r
446 @param[in] PciDevice Pointer to the PCI Device PPI instance.\r
447\r
448 @retval EFI_SUCCESS The function completes successfully\r
449 @retval Others Cannot initialize Nvme controller for given device\r
450**/\r
451EFI_STATUS\r
452NvmeInitControllerDataFromPciDevice (\r
453 EDKII_PCI_DEVICE_PPI *PciDevice\r
454 )\r
455{\r
456 EFI_STATUS Status;\r
457 PCI_TYPE00 PciData;\r
458 UINTN MmioBase;\r
459 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
460 UINTN DevicePathLength;\r
461 UINT64 EnabledPciAttributes;\r
462 UINT32 MmioBaseH;\r
463\r
464 //\r
465 // Now further check the PCI header: Base Class (offset 0x0B), Sub Class (offset 0x0A) and\r
466 // Programming Interface (offset 0x09). This controller should be an Nvme controller\r
467 //\r
468 Status = PciDevice->PciIo.Pci.Read (\r
469 &PciDevice->PciIo,\r
470 EfiPciIoWidthUint8,\r
471 PCI_CLASSCODE_OFFSET,\r
472 sizeof (PciData.Hdr.ClassCode),\r
473 PciData.Hdr.ClassCode\r
474 );\r
475 if (EFI_ERROR (Status)) {\r
476 return EFI_UNSUPPORTED;\r
477 }\r
478\r
479 if (!IS_PCI_NVMHCI (&PciData)) {\r
480 return EFI_UNSUPPORTED;\r
481 }\r
482\r
483 Status = PciDevice->PciIo.Attributes (\r
484 &PciDevice->PciIo,\r
485 EfiPciIoAttributeOperationSupported,\r
486 0,\r
487 &EnabledPciAttributes\r
488 );\r
489 if (EFI_ERROR (Status)) {\r
b8b69433 490 return EFI_UNSUPPORTED;\r
9ca7ece8
CX
491 } else {\r
492 EnabledPciAttributes &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
493 Status = PciDevice->PciIo.Attributes (\r
494 &PciDevice->PciIo,\r
495 EfiPciIoAttributeOperationEnable,\r
496 EnabledPciAttributes,\r
497 NULL\r
498 );\r
499 if (EFI_ERROR (Status)) {\r
500 return EFI_UNSUPPORTED;\r
501 }\r
502 }\r
503\r
504 Status = PciDevice->PciIo.Pci.Read (\r
505 &PciDevice->PciIo,\r
506 EfiPciIoWidthUint32,\r
507 PCI_BASE_ADDRESSREG_OFFSET,\r
508 1,\r
509 &MmioBase\r
510 );\r
511 if (EFI_ERROR (Status)) {\r
512 return EFI_UNSUPPORTED;\r
513 }\r
514\r
515 switch (MmioBase & 0x07) {\r
516 case 0x0:\r
517 //\r
518 // Memory space for 32 bit bar address\r
519 //\r
520 MmioBase = MmioBase & 0xFFFFFFF0;\r
521 break;\r
522 case 0x4:\r
523 //\r
524 // For 64 bit bar address, read the high 32bits of this 64 bit bar\r
525 //\r
526 Status = PciDevice->PciIo.Pci.Read (\r
527 &PciDevice->PciIo,\r
528 EfiPciIoWidthUint32,\r
529 PCI_BASE_ADDRESSREG_OFFSET + 4,\r
530 1,\r
531 &MmioBaseH\r
532 );\r
533 //\r
534 // For 32 bit environment, high 32bits of the bar should be zero.\r
535 //\r
536 if ( EFI_ERROR (Status)\r
537 || ((MmioBaseH != 0) && (sizeof (UINTN) == sizeof (UINT32))))\r
538 {\r
539 return EFI_UNSUPPORTED;\r
540 }\r
541\r
542 MmioBase = MmioBase & 0xFFFFFFF0;\r
543 MmioBase |= LShiftU64 ((UINT64)MmioBaseH, 32);\r
544 break;\r
545 default:\r
546 //\r
547 // Unknown bar type\r
548 //\r
549 return EFI_UNSUPPORTED;\r
550 }\r
551\r
552 DevicePathLength = GetDevicePathSize (PciDevice->DevicePath);\r
553 DevicePath = PciDevice->DevicePath;\r
554\r
555 Status = NvmeInitPrivateData (MmioBase, DevicePath, DevicePathLength);\r
556 if (EFI_ERROR (Status)) {\r
557 DEBUG ((\r
558 DEBUG_INFO,\r
559 "%a: Failed to init controller, with Status - %r\n",\r
560 __FUNCTION__,\r
561 Status\r
562 ));\r
b8b69433
HW
563 }\r
564\r
9ca7ece8
CX
565 return EFI_SUCCESS;\r
566}\r
567\r
568/**\r
569 Callback for EDKII_PCI_DEVICE_PPI installation.\r
570\r
571 @param[in] PeiServices Pointer to PEI Services Table.\r
572 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification\r
573 event that caused this function to execute.\r
574 @param[in] Ppi Pointer to the PPI data associated with this function.\r
575\r
576 @retval EFI_SUCCESS The function completes successfully\r
577 @retval Others Cannot initialize Nvme controller from given PCI_DEVICE_PPI\r
578\r
579**/\r
580EFI_STATUS\r
581EFIAPI\r
582NvmePciDevicePpiInstallationCallback (\r
583 IN EFI_PEI_SERVICES **PeiServices,\r
584 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
585 IN VOID *Ppi\r
586 )\r
587{\r
588 EDKII_PCI_DEVICE_PPI *PciDevice;\r
589\r
590 PciDevice = (EDKII_PCI_DEVICE_PPI *)Ppi;\r
591\r
592 return NvmeInitControllerDataFromPciDevice (PciDevice);\r
593}\r
594\r
595/**\r
596 Initialize Nvme controller from EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI instance.\r
597\r
598 @param[in] NvmeHcPpi Pointer to the Nvme Host Controller PPI instance.\r
599\r
600 @retval EFI_SUCCESS PPI successfully installed.\r
601**/\r
602EFI_STATUS\r
603NvmeInitControllerFromHostControllerPpi (\r
604 IN EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *NvmeHcPpi\r
605 )\r
606{\r
607 UINT8 Controller;\r
608 UINTN MmioBase;\r
609 UINTN DevicePathLength;\r
610 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
611 EFI_STATUS Status;\r
612\r
b8b69433
HW
613 Controller = 0;\r
614 MmioBase = 0;\r
615 while (TRUE) {\r
616 Status = NvmeHcPpi->GetNvmeHcMmioBar (\r
617 NvmeHcPpi,\r
618 Controller,\r
619 &MmioBase\r
620 );\r
621 //\r
622 // When status is error, meant no controller is found\r
623 //\r
624 if (EFI_ERROR (Status)) {\r
625 break;\r
626 }\r
627\r
2e15b750
HW
628 Status = NvmeHcPpi->GetNvmeHcDevicePath (\r
629 NvmeHcPpi,\r
630 Controller,\r
631 &DevicePathLength,\r
632 &DevicePath\r
633 );\r
634 if (EFI_ERROR (Status)) {\r
635 DEBUG ((\r
1436aea4
MK
636 DEBUG_ERROR,\r
637 "%a: Fail to allocate get the device path for Controller %d.\n",\r
638 __FUNCTION__,\r
639 Controller\r
2e15b750
HW
640 ));\r
641 return Status;\r
642 }\r
643\r
9ca7ece8 644 Status = NvmeInitPrivateData (MmioBase, DevicePath, DevicePathLength);\r
2e15b750
HW
645 if (EFI_ERROR (Status)) {\r
646 DEBUG ((\r
1436aea4 647 DEBUG_ERROR,\r
9ca7ece8 648 "%a: Controller initialization fail for Controller %d with Status - %r.\n",\r
1436aea4 649 __FUNCTION__,\r
9ca7ece8
CX
650 Controller,\r
651 Status\r
2e15b750 652 ));\r
9ca7ece8 653 } else {\r
05fd2a92 654 DEBUG ((\r
9ca7ece8
CX
655 DEBUG_INFO,\r
656 "%a: Controller %d has been successfully initialized.\n",\r
1436aea4
MK
657 __FUNCTION__,\r
658 Controller\r
05fd2a92 659 ));\r
05fd2a92
HW
660 }\r
661\r
9ca7ece8
CX
662 Controller++;\r
663 }\r
b8b69433 664\r
9ca7ece8
CX
665 return EFI_SUCCESS;\r
666}\r
1436aea4 667\r
9ca7ece8
CX
668/**\r
669 Callback for EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI installation.\r
b8b69433 670\r
9ca7ece8
CX
671 @param[in] PeiServices Pointer to PEI Services Table.\r
672 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification\r
673 event that caused this function to execute.\r
674 @param[in] Ppi Pointer to the PPI data associated with this function.\r
b8b69433 675\r
9ca7ece8
CX
676 @retval EFI_SUCCESS The function completes successfully\r
677 @retval Others Cannot initialize Nvme controller from given EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI\r
b8b69433 678\r
9ca7ece8
CX
679**/\r
680EFI_STATUS\r
681EFIAPI\r
682NvmeHostControllerPpiInstallationCallback (\r
683 IN EFI_PEI_SERVICES **PeiServices,\r
684 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
685 IN VOID *Ppi\r
686 )\r
687{\r
688 EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *NvmeHcPpi;\r
b8b69433 689\r
9ca7ece8
CX
690 if (Ppi == NULL) {\r
691 return EFI_INVALID_PARAMETER;\r
692 }\r
dc254af6 693\r
9ca7ece8 694 NvmeHcPpi = (EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *)Ppi;\r
2e15b750 695\r
9ca7ece8
CX
696 return NvmeInitControllerFromHostControllerPpi (NvmeHcPpi);\r
697}\r
2e15b750 698\r
9ca7ece8
CX
699/**\r
700 Entry point of the PEIM.\r
2e15b750 701\r
9ca7ece8
CX
702 @param[in] FileHandle Handle of the file being invoked.\r
703 @param[in] PeiServices Describes the list of possible PEI Services.\r
2e15b750 704\r
9ca7ece8
CX
705 @retval EFI_SUCCESS PPI successfully installed.\r
706\r
707**/\r
708EFI_STATUS\r
709EFIAPI\r
710NvmExpressPeimEntry (\r
711 IN EFI_PEI_FILE_HANDLE FileHandle,\r
712 IN CONST EFI_PEI_SERVICES **PeiServices\r
713 )\r
714{\r
715 DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));\r
716\r
717 PeiServicesNotifyPpi (&mNvmeHostControllerNotify);\r
718\r
719 PeiServicesNotifyPpi (&mPciDevicePpiNotify);\r
b8b69433
HW
720\r
721 return EFI_SUCCESS;\r
722}\r