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