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