aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c')
-rw-r--r--roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c717
1 files changed, 717 insertions, 0 deletions
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c
new file mode 100644
index 000000000..1d7e3d26e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiHci.c
@@ -0,0 +1,717 @@
+/** @file
+ The NvmExpressPei driver is used to manage non-volatile memory subsystem
+ which follows NVM Express specification at PEI phase.
+
+ Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "NvmExpressPei.h"
+
+/**
+ Transfer MMIO Data to memory.
+
+ @param[in,out] MemBuffer Destination: Memory address.
+ @param[in] MmioAddr Source: MMIO address.
+ @param[in] Size Size for read.
+
+ @retval EFI_SUCCESS MMIO read sucessfully.
+
+**/
+EFI_STATUS
+NvmeMmioRead (
+ IN OUT VOID *MemBuffer,
+ IN UINTN MmioAddr,
+ IN UINTN Size
+ )
+{
+ UINTN Offset;
+ UINT8 Data;
+ UINT8 *Ptr;
+
+ // priority has adjusted
+ switch (Size) {
+ case 4:
+ *((UINT32 *)MemBuffer) = MmioRead32 (MmioAddr);
+ break;
+
+ case 8:
+ *((UINT64 *)MemBuffer) = MmioRead64 (MmioAddr);
+ break;
+
+ case 2:
+ *((UINT16 *)MemBuffer) = MmioRead16 (MmioAddr);
+ break;
+
+ case 1:
+ *((UINT8 *)MemBuffer) = MmioRead8 (MmioAddr);
+ break;
+
+ default:
+ Ptr = (UINT8 *)MemBuffer;
+ for (Offset = 0; Offset < Size; Offset += 1) {
+ Data = MmioRead8 (MmioAddr + Offset);
+ Ptr[Offset] = Data;
+ }
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Transfer memory data to MMIO.
+
+ @param[in,out] MmioAddr Destination: MMIO address.
+ @param[in] MemBuffer Source: Memory address.
+ @param[in] Size Size for write.
+
+ @retval EFI_SUCCESS MMIO write sucessfully.
+
+**/
+EFI_STATUS
+NvmeMmioWrite (
+ IN OUT UINTN MmioAddr,
+ IN VOID *MemBuffer,
+ IN UINTN Size
+ )
+{
+ UINTN Offset;
+ UINT8 Data;
+ UINT8 *Ptr;
+
+ // priority has adjusted
+ switch (Size) {
+ case 4:
+ MmioWrite32 (MmioAddr, *((UINT32 *)MemBuffer));
+ break;
+
+ case 8:
+ MmioWrite64 (MmioAddr, *((UINT64 *)MemBuffer));
+ break;
+
+ case 2:
+ MmioWrite16 (MmioAddr, *((UINT16 *)MemBuffer));
+ break;
+
+ case 1:
+ MmioWrite8 (MmioAddr, *((UINT8 *)MemBuffer));
+ break;
+
+ default:
+ Ptr = (UINT8 *)MemBuffer;
+ for (Offset = 0; Offset < Size; Offset += 1) {
+ Data = Ptr[Offset];
+ MmioWrite8 (MmioAddr + Offset, Data);
+ }
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the page offset for specific NVME based memory.
+
+ @param[in] BaseMemIndex The Index of BaseMem (0-based).
+
+ @retval - The page count for specific BaseMem Index
+
+**/
+UINT32
+NvmeBaseMemPageOffset (
+ IN UINTN BaseMemIndex
+ )
+{
+ UINT32 Pages;
+ UINTN Index;
+ UINT32 PageSizeList[5];
+
+ PageSizeList[0] = 1; /* ASQ */
+ PageSizeList[1] = 1; /* ACQ */
+ PageSizeList[2] = 1; /* SQs */
+ PageSizeList[3] = 1; /* CQs */
+ PageSizeList[4] = NVME_PRP_SIZE; /* PRPs */
+
+ if (BaseMemIndex > MAX_BASEMEM_COUNT) {
+ DEBUG ((DEBUG_ERROR, "%a: The input BaseMem index is invalid.\n", __FUNCTION__));
+ ASSERT (FALSE);
+ return 0;
+ }
+
+ Pages = 0;
+ for (Index = 0; Index < BaseMemIndex; Index++) {
+ Pages += PageSizeList[Index];
+ }
+
+ return Pages;
+}
+
+/**
+ Wait for NVME controller status to be ready or not.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param[in] WaitReady Flag for waitting status ready or not.
+
+ @return EFI_SUCCESS Successfully to wait specific status.
+ @return others Fail to wait for specific controller status.
+
+**/
+EFI_STATUS
+NvmeWaitController (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN BOOLEAN WaitReady
+ )
+{
+ NVME_CSTS Csts;
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT8 Timeout;
+
+ //
+ // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set after
+ // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.
+ //
+ if (Private->Cap.To == 0) {
+ Timeout = 1;
+ } else {
+ Timeout = Private->Cap.To;
+ }
+
+ Status = EFI_SUCCESS;
+ for(Index = (Timeout * 500); Index != 0; --Index) {
+ MicroSecondDelay (1000);
+
+ //
+ // Check if the controller is initialized
+ //
+ Status = NVME_GET_CSTS (Private, &Csts);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NVME_GET_CSTS fail, Status - %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+
+ if ((BOOLEAN) Csts.Rdy == WaitReady) {
+ break;
+ }
+ }
+
+ if (Index == 0) {
+ Status = EFI_TIMEOUT;
+ }
+
+ return Status;
+}
+
+/**
+ Disable the Nvm Express controller.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @return EFI_SUCCESS Successfully disable the controller.
+ @return others Fail to disable the controller.
+
+**/
+EFI_STATUS
+NvmeDisableController (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ NVME_CC Cc;
+ NVME_CSTS Csts;
+ EFI_STATUS Status;
+
+ Status = NVME_GET_CSTS (Private, &Csts);
+
+ //
+ // Read Controller Configuration Register.
+ //
+ Status = NVME_GET_CC (Private, &Cc);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NVME_GET_CC fail, Status - %r\n", __FUNCTION__, Status));
+ goto ErrorExit;
+ }
+
+ if (Cc.En == 1) {
+ Cc.En = 0;
+ //
+ // Disable the controller.
+ //
+ Status = NVME_SET_CC (Private, &Cc);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NVME_SET_CC fail, Status - %r\n", __FUNCTION__, Status));
+ goto ErrorExit;
+ }
+ }
+
+ Status = NvmeWaitController (Private, FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NvmeWaitController fail, Status - %r\n", __FUNCTION__, Status));
+ goto ErrorExit;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ DEBUG ((DEBUG_ERROR, "%a fail, Status - %r\n", __FUNCTION__, Status));
+ return Status;
+}
+
+/**
+ Enable the Nvm Express controller.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @return EFI_SUCCESS Successfully enable the controller.
+ @return EFI_DEVICE_ERROR Fail to enable the controller.
+ @return EFI_TIMEOUT Fail to enable the controller in given time slot.
+
+**/
+EFI_STATUS
+NvmeEnableController (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ NVME_CC Cc;
+ EFI_STATUS Status;
+
+ //
+ // Enable the controller
+ // CC.AMS, CC.MPS and CC.CSS are all set to 0
+ //
+ ZeroMem (&Cc, sizeof (NVME_CC));
+ Cc.En = 1;
+ Cc.Iosqes = 6;
+ Cc.Iocqes = 4;
+ Status = NVME_SET_CC (Private, &Cc);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NVME_SET_CC fail, Status - %r\n", __FUNCTION__, Status));
+ goto ErrorExit;
+ }
+
+ Status = NvmeWaitController (Private, TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NvmeWaitController fail, Status - %r\n", __FUNCTION__, Status));
+ goto ErrorExit;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ DEBUG ((DEBUG_ERROR, "%a fail, Status: %r\n", __FUNCTION__, Status));
+ return Status;
+}
+
+/**
+ Get the Identify Controller data.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param[in] Buffer The Buffer used to store the Identify Controller data.
+
+ @return EFI_SUCCESS Successfully get the Identify Controller data.
+ @return others Fail to get the Identify Controller data.
+
+**/
+EFI_STATUS
+NvmeIdentifyController (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN VOID *Buffer
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
+ //
+ // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
+ // For the Identify command, the Namespace Identifier is only used for the Namespace Data structure.
+ //
+ Command.Nsid = 0;
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+ CommandPacket.TransferBuffer = Buffer;
+ CommandPacket.TransferLength = sizeof (NVME_ADMIN_CONTROLLER_DATA);
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+ //
+ // Set bit 0 (Cns bit) to 1 to identify the controller
+ //
+ CommandPacket.NvmeCmd->Cdw10 = 1;
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID;
+
+ Status = NvmePassThruExecute (
+ Private,
+ NVME_CONTROLLER_NSID,
+ &CommandPacket
+ );
+ return Status;
+}
+
+/**
+ Get specified identify namespace data.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+ @param[in] NamespaceId The specified namespace identifier.
+ @param[in] Buffer The buffer used to store the identify namespace data.
+
+ @return EFI_SUCCESS Successfully get the identify namespace data.
+ @return EFI_DEVICE_ERROR Fail to get the identify namespace data.
+
+**/
+EFI_STATUS
+NvmeIdentifyNamespace (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINT32 NamespaceId,
+ IN VOID *Buffer
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
+ Command.Nsid = NamespaceId;
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+ CommandPacket.TransferBuffer = Buffer;
+ CommandPacket.TransferLength = sizeof (NVME_ADMIN_NAMESPACE_DATA);
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+ //
+ // Set bit 0 (Cns bit) to 1 to identify a namespace
+ //
+ CommandPacket.NvmeCmd->Cdw10 = 0;
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID;
+
+ Status = NvmePassThruExecute (
+ Private,
+ NamespaceId,
+ &CommandPacket
+ );
+ return Status;
+}
+
+/**
+ Dump the Identify Controller data.
+
+ @param[in] ControllerData The pointer to the NVME_ADMIN_CONTROLLER_DATA data structure.
+
+**/
+VOID
+NvmeDumpControllerData (
+ IN NVME_ADMIN_CONTROLLER_DATA *ControllerData
+ )
+{
+ UINT8 Sn[21];
+ UINT8 Mn[41];
+
+ CopyMem (Sn, ControllerData->Sn, sizeof (ControllerData->Sn));
+ Sn[20] = 0;
+ CopyMem (Mn, ControllerData->Mn, sizeof (ControllerData->Mn));
+ Mn[40] = 0;
+
+ DEBUG ((DEBUG_INFO, " == NVME IDENTIFY CONTROLLER DATA ==\n"));
+ DEBUG ((DEBUG_INFO, " PCI VID : 0x%x\n", ControllerData->Vid));
+ DEBUG ((DEBUG_INFO, " PCI SSVID : 0x%x\n", ControllerData->Ssvid));
+ DEBUG ((DEBUG_INFO, " SN : %a\n", Sn));
+ DEBUG ((DEBUG_INFO, " MN : %a\n", Mn));
+ DEBUG ((DEBUG_INFO, " FR : 0x%lx\n", *((UINT64*)ControllerData->Fr)));
+ DEBUG ((DEBUG_INFO, " RAB : 0x%x\n", ControllerData->Rab));
+ DEBUG ((DEBUG_INFO, " IEEE : 0x%x\n", *(UINT32*)ControllerData->Ieee_oui));
+ DEBUG ((DEBUG_INFO, " AERL : 0x%x\n", ControllerData->Aerl));
+ DEBUG ((DEBUG_INFO, " SQES : 0x%x\n", ControllerData->Sqes));
+ DEBUG ((DEBUG_INFO, " CQES : 0x%x\n", ControllerData->Cqes));
+ DEBUG ((DEBUG_INFO, " NN : 0x%x\n", ControllerData->Nn));
+ return;
+}
+
+/**
+ Create IO completion queue.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @return EFI_SUCCESS Successfully create io completion queue.
+ @return others Fail to create io completion queue.
+
+**/
+EFI_STATUS
+NvmeCreateIoCompletionQueue (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+ NVME_ADMIN_CRIOCQ CrIoCq;
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+ ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+
+ Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_CMD;
+ CommandPacket.TransferBuffer = Private->CqBuffer[NVME_IO_QUEUE];
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+
+ CrIoCq.Qid = NVME_IO_QUEUE;
+ CrIoCq.Qsize = NVME_CCQ_SIZE;
+ CrIoCq.Pc = 1;
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof (NVME_ADMIN_CRIOCQ));
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
+
+ Status = NvmePassThruExecute (
+ Private,
+ NVME_CONTROLLER_NSID,
+ &CommandPacket
+ );
+ return Status;
+}
+
+/**
+ Create IO submission queue.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @return EFI_SUCCESS Successfully create io submission queue.
+ @return others Fail to create io submission queue.
+
+**/
+EFI_STATUS
+NvmeCreateIoSubmissionQueue (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ EFI_NVM_EXPRESS_COMMAND Command;
+ EFI_NVM_EXPRESS_COMPLETION Completion;
+ EFI_STATUS Status;
+ NVME_ADMIN_CRIOSQ CrIoSq;
+
+ ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
+ ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
+ ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeCompletion = &Completion;
+
+ Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_CMD;
+ CommandPacket.TransferBuffer = Private->SqBuffer[NVME_IO_QUEUE];
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueType = NVME_ADMIN_QUEUE;
+
+ CrIoSq.Qid = NVME_IO_QUEUE;
+ CrIoSq.Qsize = NVME_CSQ_SIZE;
+ CrIoSq.Pc = 1;
+ CrIoSq.Cqid = NVME_IO_QUEUE;
+ CrIoSq.Qprio = 0;
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof (NVME_ADMIN_CRIOSQ));
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
+
+ Status = NvmePassThruExecute (
+ Private,
+ NVME_CONTROLLER_NSID,
+ &CommandPacket
+ );
+ return Status;
+}
+
+/**
+ Initialize the Nvm Express controller.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+ @retval EFI_SUCCESS The NVM Express Controller is initialized successfully.
+ @retval Others A device error occurred while initializing the controller.
+
+**/
+EFI_STATUS
+NvmeControllerInit (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ NVME_AQA Aqa;
+ NVME_ASQ Asq;
+ NVME_ACQ Acq;
+ NVME_VER Ver;
+
+ //
+ // Dump the NVME controller implementation version
+ //
+ NVME_GET_VER (Private, &Ver);
+ DEBUG ((DEBUG_INFO, "NVME controller implementation version: %d.%d\n", Ver.Mjr, Ver.Mnr));
+
+ //
+ // Read the controller Capabilities register and verify that the NVM command set is supported
+ //
+ NVME_GET_CAP (Private, &Private->Cap);
+ if (Private->Cap.Css != 0x01) {
+ DEBUG ((DEBUG_ERROR, "%a: The NVME controller doesn't support NVMe command set.\n", __FUNCTION__));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Currently, the driver only supports 4k page size
+ //
+ if ((Private->Cap.Mpsmin + 12) > EFI_PAGE_SHIFT) {
+ DEBUG ((DEBUG_ERROR, "%a: The driver doesn't support page size other than 4K.\n", __FUNCTION__));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ for (Index = 0; Index < NVME_MAX_QUEUES; Index++) {
+ Private->Pt[Index] = 0;
+ Private->Cid[Index] = 0;
+ ZeroMem ((VOID *)(UINTN)(&Private->SqTdbl[Index]), sizeof (NVME_SQTDBL));
+ ZeroMem ((VOID *)(UINTN)(&Private->CqHdbl[Index]), sizeof (NVME_CQHDBL));
+ }
+ ZeroMem (Private->Buffer, EFI_PAGE_SIZE * NVME_MEM_MAX_PAGES);
+
+ //
+ // Disable the NVME controller first
+ //
+ Status = NvmeDisableController (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NvmeDisableController fail, Status - %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+
+ //
+ // Set the number of entries in admin submission & completion queues
+ //
+ Aqa.Asqs = NVME_ASQ_SIZE;
+ Aqa.Rsvd1 = 0;
+ Aqa.Acqs = NVME_ACQ_SIZE;
+ Aqa.Rsvd2 = 0;
+
+ //
+ // Address of admin submission & completion queues
+ //
+ Asq = (UINT64)(UINTN)(NVME_ASQ_BASE (Private) & ~0xFFF);
+ Acq = (UINT64)(UINTN)(NVME_ACQ_BASE (Private) & ~0xFFF);
+
+ //
+ // Address of I/O submission & completion queues
+ //
+ Private->SqBuffer[0] = (NVME_SQ *)(UINTN)NVME_ASQ_BASE (Private); // NVME_ADMIN_QUEUE
+ Private->CqBuffer[0] = (NVME_CQ *)(UINTN)NVME_ACQ_BASE (Private); // NVME_ADMIN_QUEUE
+ Private->SqBuffer[1] = (NVME_SQ *)(UINTN)NVME_SQ_BASE (Private, 0); // NVME_IO_QUEUE
+ Private->CqBuffer[1] = (NVME_CQ *)(UINTN)NVME_CQ_BASE (Private, 0); // NVME_IO_QUEUE
+ DEBUG ((DEBUG_INFO, "Admin Submission Queue Size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));
+ DEBUG ((DEBUG_INFO, "Admin Completion Queue Size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));
+ DEBUG ((DEBUG_INFO, "Admin Submission Queue (SqBuffer[0]) = [%08X]\n", Private->SqBuffer[0]));
+ DEBUG ((DEBUG_INFO, "Admin Completion Queue (CqBuffer[0]) = [%08X]\n", Private->CqBuffer[0]));
+ DEBUG ((DEBUG_INFO, "I/O Submission Queue (SqBuffer[1]) = [%08X]\n", Private->SqBuffer[1]));
+ DEBUG ((DEBUG_INFO, "I/O Completion Queue (CqBuffer[1]) = [%08X]\n", Private->CqBuffer[1]));
+
+ //
+ // Program admin queue attributes
+ //
+ NVME_SET_AQA (Private, &Aqa);
+
+ //
+ // Program admin submission & completion queues address
+ //
+ NVME_SET_ASQ (Private, &Asq);
+ NVME_SET_ACQ (Private, &Acq);
+
+ //
+ // Enable the NVME controller
+ //
+ Status = NvmeEnableController (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NvmeEnableController fail, Status - %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+
+ //
+ // Get the Identify Controller data
+ //
+ if (Private->ControllerData == NULL) {
+ Private->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_CONTROLLER_DATA));
+ if (Private->ControllerData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ Status = NvmeIdentifyController (Private, Private->ControllerData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: NvmeIdentifyController fail, Status - %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+ NvmeDumpControllerData (Private->ControllerData);
+
+ //
+ // Check the namespace number for storing the namespaces information
+ //
+ if (Private->ControllerData->Nn > MAX_UINT32 / sizeof (PEI_NVME_NAMESPACE_INFO)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Number of Namespaces field in Identify Controller data not supported by the driver.\n",
+ __FUNCTION__
+ ));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Create one I/O completion queue and one I/O submission queue
+ //
+ Status = NvmeCreateIoCompletionQueue (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Create IO completion queue fail, Status - %r\n", __FUNCTION__, Status));
+ return Status;
+ }
+ Status = NvmeCreateIoSubmissionQueue (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Create IO submission queue fail, Status - %r\n", __FUNCTION__, Status));
+ }
+
+ return Status;
+}
+
+/**
+ Free the DMA resources allocated by an NVME controller.
+
+ @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
+
+**/
+VOID
+NvmeFreeDmaResource (
+ IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private
+ )
+{
+ ASSERT (Private != NULL);
+
+ if (Private->BufferMapping != NULL) {
+ IoMmuFreeBuffer (
+ NVME_MEM_MAX_PAGES,
+ Private->Buffer,
+ Private->BufferMapping
+ );
+ }
+
+ return;
+}