]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c
MdeModulePkg/NvmExpressPei: Add logic to produce SSC PPI
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NvmExpressPei / NvmExpressPeiHci.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
2e15b750 5 Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>\r
b8b69433
HW
6\r
7 This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions\r
9 of the BSD License which accompanies this distribution. The\r
10 full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12\r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15\r
16**/\r
17\r
18#include "NvmExpressPei.h"\r
19\r
20/**\r
21 Transfer MMIO Data to memory.\r
22\r
23 @param[in,out] MemBuffer Destination: Memory address.\r
24 @param[in] MmioAddr Source: MMIO address.\r
25 @param[in] Size Size for read.\r
26\r
27 @retval EFI_SUCCESS MMIO read sucessfully.\r
28\r
29**/\r
30EFI_STATUS\r
31NvmeMmioRead (\r
32 IN OUT VOID *MemBuffer,\r
33 IN UINTN MmioAddr,\r
34 IN UINTN Size\r
35 )\r
36{\r
37 UINTN Offset;\r
38 UINT8 Data;\r
39 UINT8 *Ptr;\r
40\r
41 // priority has adjusted\r
42 switch (Size) {\r
43 case 4:\r
44 *((UINT32 *)MemBuffer) = MmioRead32 (MmioAddr);\r
45 break;\r
46\r
47 case 8:\r
48 *((UINT64 *)MemBuffer) = MmioRead64 (MmioAddr);\r
49 break;\r
50\r
51 case 2:\r
52 *((UINT16 *)MemBuffer) = MmioRead16 (MmioAddr);\r
53 break;\r
54\r
55 case 1:\r
56 *((UINT8 *)MemBuffer) = MmioRead8 (MmioAddr);\r
57 break;\r
58\r
59 default:\r
60 Ptr = (UINT8 *)MemBuffer;\r
61 for (Offset = 0; Offset < Size; Offset += 1) {\r
62 Data = MmioRead8 (MmioAddr + Offset);\r
63 Ptr[Offset] = Data;\r
64 }\r
65 break;\r
66 }\r
67\r
68 return EFI_SUCCESS;\r
69}\r
70\r
71/**\r
72 Transfer memory data to MMIO.\r
73\r
74 @param[in,out] MmioAddr Destination: MMIO address.\r
75 @param[in] MemBuffer Source: Memory address.\r
76 @param[in] Size Size for write.\r
77\r
78 @retval EFI_SUCCESS MMIO write sucessfully.\r
79\r
80**/\r
81EFI_STATUS\r
82NvmeMmioWrite (\r
83 IN OUT UINTN MmioAddr,\r
84 IN VOID *MemBuffer,\r
85 IN UINTN Size\r
86 )\r
87{\r
88 UINTN Offset;\r
89 UINT8 Data;\r
90 UINT8 *Ptr;\r
91\r
92 // priority has adjusted\r
93 switch (Size) {\r
94 case 4:\r
95 MmioWrite32 (MmioAddr, *((UINT32 *)MemBuffer));\r
96 break;\r
97\r
98 case 8:\r
99 MmioWrite64 (MmioAddr, *((UINT64 *)MemBuffer));\r
100 break;\r
101\r
102 case 2:\r
103 MmioWrite16 (MmioAddr, *((UINT16 *)MemBuffer));\r
104 break;\r
105\r
106 case 1:\r
107 MmioWrite8 (MmioAddr, *((UINT8 *)MemBuffer));\r
108 break;\r
109\r
110 default:\r
111 Ptr = (UINT8 *)MemBuffer;\r
112 for (Offset = 0; Offset < Size; Offset += 1) {\r
113 Data = Ptr[Offset];\r
114 MmioWrite8 (MmioAddr + Offset, Data);\r
115 }\r
116 break;\r
117 }\r
118\r
119 return EFI_SUCCESS;\r
120}\r
121\r
122/**\r
123 Get the page offset for specific NVME based memory.\r
124\r
125 @param[in] BaseMemIndex The Index of BaseMem (0-based).\r
126\r
127 @retval - The page count for specific BaseMem Index\r
128\r
129**/\r
130UINT32\r
131NvmeBaseMemPageOffset (\r
132 IN UINTN BaseMemIndex\r
133 )\r
134{\r
135 UINT32 Pages;\r
136 UINTN Index;\r
137 UINT32 PageSizeList[5];\r
138\r
139 PageSizeList[0] = 1; /* ASQ */\r
140 PageSizeList[1] = 1; /* ACQ */\r
141 PageSizeList[2] = 1; /* SQs */\r
142 PageSizeList[3] = 1; /* CQs */\r
143 PageSizeList[4] = NVME_PRP_SIZE; /* PRPs */\r
144\r
145 if (BaseMemIndex > MAX_BASEMEM_COUNT) {\r
146 DEBUG ((DEBUG_ERROR, "%a: The input BaseMem index is invalid.\n", __FUNCTION__));\r
147 ASSERT (FALSE);\r
148 return 0;\r
149 }\r
150\r
151 Pages = 0;\r
152 for (Index = 0; Index < BaseMemIndex; Index++) {\r
153 Pages += PageSizeList[Index];\r
154 }\r
155\r
156 return Pages;\r
157}\r
158\r
159/**\r
160 Wait for NVME controller status to be ready or not.\r
161\r
162 @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
163 @param[in] WaitReady Flag for waitting status ready or not.\r
164\r
165 @return EFI_SUCCESS Successfully to wait specific status.\r
166 @return others Fail to wait for specific controller status.\r
167\r
168**/\r
169EFI_STATUS\r
170NvmeWaitController (\r
171 IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,\r
172 IN BOOLEAN WaitReady\r
173 )\r
174{\r
175 NVME_CSTS Csts;\r
176 EFI_STATUS Status;\r
177 UINT32 Index;\r
178 UINT8 Timeout;\r
179\r
180 //\r
181 // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set after\r
182 // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.\r
183 //\r
184 if (Private->Cap.To == 0) {\r
185 Timeout = 1;\r
186 } else {\r
187 Timeout = Private->Cap.To;\r
188 }\r
189\r
190 Status = EFI_SUCCESS;\r
191 for(Index = (Timeout * 500); Index != 0; --Index) {\r
192 MicroSecondDelay (1000);\r
193\r
194 //\r
195 // Check if the controller is initialized\r
196 //\r
197 Status = NVME_GET_CSTS (Private, &Csts);\r
198 if (EFI_ERROR(Status)) {\r
199 DEBUG ((DEBUG_ERROR, "%a: NVME_GET_CSTS fail, Status - %r\n", __FUNCTION__, Status));\r
200 return Status;\r
201 }\r
202\r
203 if ((BOOLEAN) Csts.Rdy == WaitReady) {\r
204 break;\r
205 }\r
206 }\r
207\r
208 if (Index == 0) {\r
209 Status = EFI_TIMEOUT;\r
210 }\r
211\r
212 return Status;\r
213}\r
214\r
215/**\r
216 Disable the Nvm Express controller.\r
217\r
218 @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
219\r
220 @return EFI_SUCCESS Successfully disable the controller.\r
221 @return others Fail to disable the controller.\r
222\r
223**/\r
224EFI_STATUS\r
225NvmeDisableController (\r
226 IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private\r
227 )\r
228{\r
229 NVME_CC Cc;\r
230 NVME_CSTS Csts;\r
231 EFI_STATUS Status;\r
232\r
233 Status = NVME_GET_CSTS (Private, &Csts);\r
234\r
235 //\r
236 // Read Controller Configuration Register.\r
237 //\r
238 Status = NVME_GET_CC (Private, &Cc);\r
239 if (EFI_ERROR (Status)) {\r
240 DEBUG ((DEBUG_ERROR, "%a: NVME_GET_CC fail, Status - %r\n", __FUNCTION__, Status));\r
241 goto ErrorExit;\r
242 }\r
243\r
244 if (Cc.En == 1) {\r
245 Cc.En = 0;\r
246 //\r
247 // Disable the controller.\r
248 //\r
249 Status = NVME_SET_CC (Private, &Cc);\r
250 if (EFI_ERROR (Status)) {\r
251 DEBUG ((DEBUG_ERROR, "%a: NVME_SET_CC fail, Status - %r\n", __FUNCTION__, Status));\r
252 goto ErrorExit;\r
253 }\r
254 }\r
255\r
256 Status = NvmeWaitController (Private, FALSE);\r
257 if (EFI_ERROR (Status)) {\r
258 DEBUG ((DEBUG_ERROR, "%a: NvmeWaitController fail, Status - %r\n", __FUNCTION__, Status));\r
259 goto ErrorExit;\r
260 }\r
261\r
262 return EFI_SUCCESS;\r
263\r
264ErrorExit:\r
265 DEBUG ((DEBUG_ERROR, "%a fail, Status - %r\n", __FUNCTION__, Status));\r
266 return Status;\r
267}\r
268\r
269/**\r
270 Enable the Nvm Express controller.\r
271\r
272 @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
273\r
274 @return EFI_SUCCESS Successfully enable the controller.\r
275 @return EFI_DEVICE_ERROR Fail to enable the controller.\r
276 @return EFI_TIMEOUT Fail to enable the controller in given time slot.\r
277\r
278**/\r
279EFI_STATUS\r
280NvmeEnableController (\r
281 IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private\r
282 )\r
283{\r
284 NVME_CC Cc;\r
285 EFI_STATUS Status;\r
286\r
287 //\r
288 // Enable the controller\r
289 // CC.AMS, CC.MPS and CC.CSS are all set to 0\r
290 //\r
291 ZeroMem (&Cc, sizeof (NVME_CC));\r
292 Cc.En = 1;\r
293 Cc.Iosqes = 6;\r
294 Cc.Iocqes = 4;\r
295 Status = NVME_SET_CC (Private, &Cc);\r
296 if (EFI_ERROR (Status)) {\r
297 DEBUG ((DEBUG_ERROR, "%a: NVME_SET_CC fail, Status - %r\n", __FUNCTION__, Status));\r
298 goto ErrorExit;\r
299 }\r
300\r
301 Status = NvmeWaitController (Private, TRUE);\r
302 if (EFI_ERROR (Status)) {\r
303 DEBUG ((DEBUG_ERROR, "%a: NvmeWaitController fail, Status - %r\n", __FUNCTION__, Status));\r
304 goto ErrorExit;\r
305 }\r
306\r
307 return EFI_SUCCESS;\r
308\r
309ErrorExit:\r
310 DEBUG ((DEBUG_ERROR, "%a fail, Status: %r\n", __FUNCTION__, Status));\r
311 return Status;\r
312}\r
313\r
314/**\r
315 Get the Identify Controller data.\r
316\r
317 @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
318 @param[in] Buffer The Buffer used to store the Identify Controller data.\r
319\r
320 @return EFI_SUCCESS Successfully get the Identify Controller data.\r
321 @return others Fail to get the Identify Controller data.\r
322\r
323**/\r
324EFI_STATUS\r
325NvmeIdentifyController (\r
326 IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,\r
327 IN VOID *Buffer\r
328 )\r
329{\r
330 EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
331 EDKII_PEI_NVM_EXPRESS_COMMAND Command;\r
332 EDKII_PEI_NVM_EXPRESS_COMPLETION Completion;\r
333 EFI_STATUS Status;\r
334\r
335 ZeroMem (&CommandPacket, sizeof(EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
336 ZeroMem (&Command, sizeof(EDKII_PEI_NVM_EXPRESS_COMMAND));\r
337 ZeroMem (&Completion, sizeof(EDKII_PEI_NVM_EXPRESS_COMPLETION));\r
338\r
339 Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;\r
340 //\r
341 // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.\r
342 // For the Identify command, the Namespace Identifier is only used for the Namespace Data structure.\r
343 //\r
344 Command.Nsid = 0;\r
345\r
346 CommandPacket.NvmeCmd = &Command;\r
347 CommandPacket.NvmeCompletion = &Completion;\r
348 CommandPacket.TransferBuffer = Buffer;\r
349 CommandPacket.TransferLength = sizeof (NVME_ADMIN_CONTROLLER_DATA);\r
350 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
351 CommandPacket.QueueType = NVME_ADMIN_QUEUE;\r
352 //\r
353 // Set bit 0 (Cns bit) to 1 to identify the controller\r
354 //\r
355 CommandPacket.NvmeCmd->Cdw10 = 1;\r
356 CommandPacket.NvmeCmd->Flags = CDW10_VALID;\r
357\r
358 Status = NvmePassThru (\r
359 Private,\r
360 NVME_CONTROLLER_NSID,\r
361 &CommandPacket\r
362 );\r
363 return Status;\r
364}\r
365\r
366/**\r
367 Get specified identify namespace data.\r
368\r
369 @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
370 @param[in] NamespaceId The specified namespace identifier.\r
371 @param[in] Buffer The buffer used to store the identify namespace data.\r
372\r
373 @return EFI_SUCCESS Successfully get the identify namespace data.\r
374 @return EFI_DEVICE_ERROR Fail to get the identify namespace data.\r
375\r
376**/\r
377EFI_STATUS\r
378NvmeIdentifyNamespace (\r
379 IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,\r
380 IN UINT32 NamespaceId,\r
381 IN VOID *Buffer\r
382 )\r
383{\r
384 EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
385 EDKII_PEI_NVM_EXPRESS_COMMAND Command;\r
386 EDKII_PEI_NVM_EXPRESS_COMPLETION Completion;\r
387 EFI_STATUS Status;\r
388\r
389 ZeroMem (&CommandPacket, sizeof(EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
390 ZeroMem (&Command, sizeof(EDKII_PEI_NVM_EXPRESS_COMMAND));\r
391 ZeroMem (&Completion, sizeof(EDKII_PEI_NVM_EXPRESS_COMPLETION));\r
392\r
393 Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;\r
394 Command.Nsid = NamespaceId;\r
395\r
396 CommandPacket.NvmeCmd = &Command;\r
397 CommandPacket.NvmeCompletion = &Completion;\r
398 CommandPacket.TransferBuffer = Buffer;\r
399 CommandPacket.TransferLength = sizeof (NVME_ADMIN_NAMESPACE_DATA);\r
400 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
401 CommandPacket.QueueType = NVME_ADMIN_QUEUE;\r
402 //\r
403 // Set bit 0 (Cns bit) to 1 to identify a namespace\r
404 //\r
405 CommandPacket.NvmeCmd->Cdw10 = 0;\r
406 CommandPacket.NvmeCmd->Flags = CDW10_VALID;\r
407\r
408 Status = NvmePassThru (\r
409 Private,\r
410 NamespaceId,\r
411 &CommandPacket\r
412 );\r
413 return Status;\r
414}\r
415\r
416/**\r
417 Dump the Identify Controller data.\r
418\r
419 @param[in] ControllerData The pointer to the NVME_ADMIN_CONTROLLER_DATA data structure.\r
420\r
421**/\r
422VOID\r
423NvmeDumpControllerData (\r
424 IN NVME_ADMIN_CONTROLLER_DATA *ControllerData\r
425 )\r
426{\r
427 UINT8 Sn[21];\r
428 UINT8 Mn[41];\r
429\r
430 CopyMem (Sn, ControllerData->Sn, sizeof (ControllerData->Sn));\r
431 Sn[20] = 0;\r
432 CopyMem (Mn, ControllerData->Mn, sizeof (ControllerData->Mn));\r
433 Mn[40] = 0;\r
434\r
435 DEBUG ((DEBUG_INFO, " == NVME IDENTIFY CONTROLLER DATA ==\n"));\r
436 DEBUG ((DEBUG_INFO, " PCI VID : 0x%x\n", ControllerData->Vid));\r
437 DEBUG ((DEBUG_INFO, " PCI SSVID : 0x%x\n", ControllerData->Ssvid));\r
438 DEBUG ((DEBUG_INFO, " SN : %a\n", Sn));\r
439 DEBUG ((DEBUG_INFO, " MN : %a\n", Mn));\r
440 DEBUG ((DEBUG_INFO, " FR : 0x%lx\n", *((UINT64*)ControllerData->Fr)));\r
441 DEBUG ((DEBUG_INFO, " RAB : 0x%x\n", ControllerData->Rab));\r
442 DEBUG ((DEBUG_INFO, " IEEE : 0x%x\n", *(UINT32*)ControllerData->Ieee_oui));\r
443 DEBUG ((DEBUG_INFO, " AERL : 0x%x\n", ControllerData->Aerl));\r
444 DEBUG ((DEBUG_INFO, " SQES : 0x%x\n", ControllerData->Sqes));\r
445 DEBUG ((DEBUG_INFO, " CQES : 0x%x\n", ControllerData->Cqes));\r
446 DEBUG ((DEBUG_INFO, " NN : 0x%x\n", ControllerData->Nn));\r
447 return;\r
448}\r
449\r
450/**\r
451 Create IO completion queue.\r
452\r
453 @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
454\r
455 @return EFI_SUCCESS Successfully create io completion queue.\r
456 @return others Fail to create io completion queue.\r
457\r
458**/\r
459EFI_STATUS\r
460NvmeCreateIoCompletionQueue (\r
461 IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private\r
462 )\r
463{\r
464 EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
465 EDKII_PEI_NVM_EXPRESS_COMMAND Command;\r
466 EDKII_PEI_NVM_EXPRESS_COMPLETION Completion;\r
467 EFI_STATUS Status;\r
468 NVME_ADMIN_CRIOCQ CrIoCq;\r
469\r
470 ZeroMem (&CommandPacket, sizeof(EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
471 ZeroMem (&Command, sizeof(EDKII_PEI_NVM_EXPRESS_COMMAND));\r
472 ZeroMem (&Completion, sizeof(EDKII_PEI_NVM_EXPRESS_COMPLETION));\r
473 ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ));\r
474\r
475 CommandPacket.NvmeCmd = &Command;\r
476 CommandPacket.NvmeCompletion = &Completion;\r
477\r
478 Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_CMD;\r
479 Command.Cdw0.Cid = Private->Cid[NVME_ADMIN_QUEUE]++;\r
480 CommandPacket.TransferBuffer = Private->CqBuffer[NVME_IO_QUEUE];\r
481 CommandPacket.TransferLength = EFI_PAGE_SIZE;\r
482 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
483 CommandPacket.QueueType = NVME_ADMIN_QUEUE;\r
484\r
485 CrIoCq.Qid = NVME_IO_QUEUE;\r
486 CrIoCq.Qsize = NVME_CCQ_SIZE;\r
487 CrIoCq.Pc = 1;\r
488 CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof (NVME_ADMIN_CRIOCQ));\r
489 CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
490\r
491 Status = NvmePassThru (\r
492 Private,\r
493 NVME_CONTROLLER_NSID,\r
494 &CommandPacket\r
495 );\r
496 return Status;\r
497}\r
498\r
499/**\r
500 Create IO submission queue.\r
501\r
502 @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
503\r
504 @return EFI_SUCCESS Successfully create io submission queue.\r
505 @return others Fail to create io submission queue.\r
506\r
507**/\r
508EFI_STATUS\r
509NvmeCreateIoSubmissionQueue (\r
510 IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private\r
511 )\r
512{\r
513 EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
514 EDKII_PEI_NVM_EXPRESS_COMMAND Command;\r
515 EDKII_PEI_NVM_EXPRESS_COMPLETION Completion;\r
516 EFI_STATUS Status;\r
517 NVME_ADMIN_CRIOSQ CrIoSq;\r
518\r
519 ZeroMem (&CommandPacket, sizeof(EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
520 ZeroMem (&Command, sizeof(EDKII_PEI_NVM_EXPRESS_COMMAND));\r
521 ZeroMem (&Completion, sizeof(EDKII_PEI_NVM_EXPRESS_COMPLETION));\r
522 ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ));\r
523\r
524 CommandPacket.NvmeCmd = &Command;\r
525 CommandPacket.NvmeCompletion = &Completion;\r
526\r
527 Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_CMD;\r
528 Command.Cdw0.Cid = Private->Cid[NVME_ADMIN_QUEUE]++;\r
529 CommandPacket.TransferBuffer = Private->SqBuffer[NVME_IO_QUEUE];\r
530 CommandPacket.TransferLength = EFI_PAGE_SIZE;\r
531 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
532 CommandPacket.QueueType = NVME_ADMIN_QUEUE;\r
533\r
534 CrIoSq.Qid = NVME_IO_QUEUE;\r
535 CrIoSq.Qsize = NVME_CSQ_SIZE;\r
536 CrIoSq.Pc = 1;\r
537 CrIoSq.Cqid = NVME_IO_QUEUE;\r
538 CrIoSq.Qprio = 0;\r
539 CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof (NVME_ADMIN_CRIOSQ));\r
540 CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
541\r
542 Status = NvmePassThru (\r
543 Private,\r
544 NVME_CONTROLLER_NSID,\r
545 &CommandPacket\r
546 );\r
547 return Status;\r
548}\r
549\r
550/**\r
551 Initialize the Nvm Express controller.\r
552\r
553 @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
554\r
555 @retval EFI_SUCCESS The NVM Express Controller is initialized successfully.\r
556 @retval Others A device error occurred while initializing the controller.\r
557\r
558**/\r
559EFI_STATUS\r
560NvmeControllerInit (\r
561 IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private\r
562 )\r
563{\r
564 EFI_STATUS Status;\r
565 UINTN Index;\r
566 NVME_AQA Aqa;\r
567 NVME_ASQ Asq;\r
568 NVME_ACQ Acq;\r
569 NVME_VER Ver;\r
570\r
571 //\r
572 // Dump the NVME controller implementation version\r
573 //\r
574 NVME_GET_VER (Private, &Ver);\r
575 DEBUG ((DEBUG_INFO, "NVME controller implementation version: %d.%d\n", Ver.Mjr, Ver.Mnr));\r
576\r
577 //\r
578 // Read the controller Capabilities register and verify that the NVM command set is supported\r
579 //\r
580 NVME_GET_CAP (Private, &Private->Cap);\r
581 if (Private->Cap.Css != 0x01) {\r
582 DEBUG ((DEBUG_ERROR, "%a: The NVME controller doesn't support NVMe command set.\n", __FUNCTION__));\r
583 return EFI_UNSUPPORTED;\r
584 }\r
585\r
586 //\r
587 // Currently, the driver only supports 4k page size\r
588 //\r
589 if ((Private->Cap.Mpsmin + 12) > EFI_PAGE_SHIFT) {\r
590 DEBUG ((DEBUG_ERROR, "%a: The driver doesn't support page size other than 4K.\n", __FUNCTION__));\r
591 ASSERT (FALSE);\r
592 return EFI_UNSUPPORTED;\r
593 }\r
594\r
595 for (Index = 0; Index < NVME_MAX_QUEUES; Index++) {\r
596 Private->Pt[Index] = 0;\r
597 Private->Cid[Index] = 0;\r
598 ZeroMem ((VOID *)(UINTN)(&Private->SqTdbl[Index]), sizeof (NVME_SQTDBL));\r
599 ZeroMem ((VOID *)(UINTN)(&Private->CqHdbl[Index]), sizeof (NVME_CQHDBL));\r
600 }\r
601 ZeroMem (Private->Buffer, EFI_PAGE_SIZE * NVME_MEM_MAX_PAGES);\r
602\r
603 //\r
604 // Disable the NVME controller first\r
605 //\r
606 Status = NvmeDisableController (Private);\r
607 if (EFI_ERROR (Status)) {\r
608 DEBUG ((DEBUG_ERROR, "%a: NvmeDisableController fail, Status - %r\n", __FUNCTION__, Status));\r
609 return Status;\r
610 }\r
611\r
612 //\r
613 // Set the number of entries in admin submission & completion queues\r
614 //\r
615 Aqa.Asqs = NVME_ASQ_SIZE;\r
616 Aqa.Rsvd1 = 0;\r
617 Aqa.Acqs = NVME_ACQ_SIZE;\r
618 Aqa.Rsvd2 = 0;\r
619\r
620 //\r
621 // Address of admin submission & completion queues\r
622 //\r
623 Asq = (UINT64)(UINTN)(NVME_ASQ_BASE (Private) & ~0xFFF);\r
624 Acq = (UINT64)(UINTN)(NVME_ACQ_BASE (Private) & ~0xFFF);\r
625\r
626 //\r
627 // Address of I/O submission & completion queues\r
628 //\r
629 Private->SqBuffer[0] = (NVME_SQ *)(UINTN)NVME_ASQ_BASE (Private); // NVME_ADMIN_QUEUE\r
630 Private->CqBuffer[0] = (NVME_CQ *)(UINTN)NVME_ACQ_BASE (Private); // NVME_ADMIN_QUEUE\r
631 Private->SqBuffer[1] = (NVME_SQ *)(UINTN)NVME_SQ_BASE (Private, 0); // NVME_IO_QUEUE\r
632 Private->CqBuffer[1] = (NVME_CQ *)(UINTN)NVME_CQ_BASE (Private, 0); // NVME_IO_QUEUE\r
633 DEBUG ((DEBUG_INFO, "Admin Submission Queue Size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));\r
634 DEBUG ((DEBUG_INFO, "Admin Completion Queue Size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));\r
635 DEBUG ((DEBUG_INFO, "Admin Submission Queue (SqBuffer[0]) = [%08X]\n", Private->SqBuffer[0]));\r
636 DEBUG ((DEBUG_INFO, "Admin Completion Queue (CqBuffer[0]) = [%08X]\n", Private->CqBuffer[0]));\r
637 DEBUG ((DEBUG_INFO, "I/O Submission Queue (SqBuffer[1]) = [%08X]\n", Private->SqBuffer[1]));\r
638 DEBUG ((DEBUG_INFO, "I/O Completion Queue (CqBuffer[1]) = [%08X]\n", Private->CqBuffer[1]));\r
639\r
640 //\r
641 // Program admin queue attributes\r
642 //\r
643 NVME_SET_AQA (Private, &Aqa);\r
644\r
645 //\r
646 // Program admin submission & completion queues address\r
647 //\r
648 NVME_SET_ASQ (Private, &Asq);\r
649 NVME_SET_ACQ (Private, &Acq);\r
650\r
651 //\r
652 // Enable the NVME controller\r
653 //\r
654 Status = NvmeEnableController (Private);\r
655 if (EFI_ERROR (Status)) {\r
656 DEBUG ((DEBUG_ERROR, "%a: NvmeEnableController fail, Status - %r\n", __FUNCTION__, Status));\r
657 return Status;\r
658 }\r
659\r
660 //\r
661 // Get the Identify Controller data\r
662 //\r
663 if (Private->ControllerData == NULL) {\r
664 Private->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_CONTROLLER_DATA));\r
665 if (Private->ControllerData == NULL) {\r
666 return EFI_OUT_OF_RESOURCES;\r
667 }\r
668 }\r
669 Status = NvmeIdentifyController (Private, Private->ControllerData);\r
670 if (EFI_ERROR (Status)) {\r
671 DEBUG ((DEBUG_ERROR, "%a: NvmeIdentifyController fail, Status - %r\n", __FUNCTION__, Status));\r
672 return Status;\r
673 }\r
674 NvmeDumpControllerData (Private->ControllerData);\r
675\r
676 //\r
677 // Check the namespace number for storing the namespaces information\r
678 //\r
679 if (Private->ControllerData->Nn > MAX_UINT32 / sizeof (PEI_NVME_NAMESPACE_INFO)) {\r
680 DEBUG ((\r
681 DEBUG_ERROR,\r
682 "%a: Number of Namespaces field in Identify Controller data not supported by the driver.\n",\r
683 __FUNCTION__\r
684 ));\r
685 return EFI_UNSUPPORTED;\r
686 }\r
687\r
688 //\r
689 // Create one I/O completion queue and one I/O submission queue\r
690 //\r
691 Status = NvmeCreateIoCompletionQueue (Private);\r
692 if (EFI_ERROR (Status)) {\r
693 DEBUG ((DEBUG_ERROR, "%a: Create IO completion queue fail, Status - %r\n", __FUNCTION__, Status));\r
694 return Status;\r
695 }\r
696 Status = NvmeCreateIoSubmissionQueue (Private);\r
697 if (EFI_ERROR (Status)) {\r
698 DEBUG ((DEBUG_ERROR, "%a: Create IO submission queue fail, Status - %r\n", __FUNCTION__, Status));\r
699 }\r
700\r
701 return Status;\r
702}\r
703\r
704/**\r
2e15b750 705 Free the DMA resources allocated by an NVME controller.\r
b8b69433
HW
706\r
707 @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
708\r
709**/\r
710VOID\r
2e15b750 711NvmeFreeDmaResource (\r
b8b69433
HW
712 IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private\r
713 )\r
714{\r
2e15b750 715 ASSERT (Private != NULL);\r
b8b69433 716\r
2e15b750 717 if (Private->BufferMapping != NULL) {\r
b8b69433
HW
718 IoMmuFreeBuffer (\r
719 NVME_MEM_MAX_PAGES,\r
720 Private->Buffer,\r
721 Private->BufferMapping\r
722 );\r
b8b69433
HW
723 }\r
724\r
b8b69433
HW
725 return;\r
726}\r