@@ -567,7 +567,88 @@ NvmeIdentifyNamespace (
567567}
568568
569569/**
570- Create io completion queue.
570+ Send the Set Features Command to the controller for the number of queues requested.
571+ Note that the number of queues allocated may be less than the number of queues requested.
572+
573+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
574+ @param NCQR The number of completion queues requested
575+ @param NSQR The number of submission queues requested
576+
577+ @return EFI_SUCCESS Successfully set the number of queues.
578+ @return EFI_DEVICE_ERROR Fail to set the number of queues.
579+
580+ **/
581+ EFI_STATUS
582+ NvmeSetFeaturesNumberOfQueues (
583+ IN NVME_CONTROLLER_PRIVATE_DATA * Private ,
584+ IN UINT16 NSQR ,
585+ IN UINT16 NCQR
586+ )
587+ {
588+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket ;
589+ EFI_NVM_EXPRESS_COMMAND Command ;
590+ EFI_NVM_EXPRESS_COMPLETION Completion ;
591+ EFI_STATUS Status ;
592+ NVME_ADMIN_SET_FEATURES_CDW10 SetFeatures ;
593+ NVME_ADMIN_SET_FEATURES_NUM_QUEUES NumberOfQueuesRequested ;
594+ NVME_ADMIN_SET_FEATURES_NUM_QUEUES NumberOfQueuesAllocated ;
595+
596+ Status = EFI_SUCCESS ;
597+
598+ ZeroMem (& CommandPacket , sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET ));
599+ ZeroMem (& Command , sizeof (EFI_NVM_EXPRESS_COMMAND ));
600+ ZeroMem (& Completion , sizeof (EFI_NVM_EXPRESS_COMPLETION ));
601+ ZeroMem (& SetFeatures , sizeof (NVME_ADMIN_SET_FEATURES ));
602+ ZeroMem (& NumberOfQueuesRequested , sizeof (NVME_ADMIN_SET_FEATURES_NUM_QUEUES ));
603+ ZeroMem (& NumberOfQueuesAllocated , sizeof (NVME_ADMIN_SET_FEATURES_NUM_QUEUES ));
604+
605+ CommandPacket .NvmeCmd = & Command ;
606+ CommandPacket .NvmeCompletion = & Completion ;
607+ CommandPacket .CommandTimeout = NVME_GENERIC_TIMEOUT ;
608+ CommandPacket .QueueType = NVME_ADMIN_QUEUE ;
609+ Command .Nsid = 0 ; // NSID must be set to 0h or FFFFFFFFh for an admin command
610+ Command .Cdw0 .Opcode = NVME_ADMIN_SET_FEATURES_CMD ;
611+
612+ // Populate the Set Features Cdw10 and Cdw11 according to Nvm Express 1.3d Spec
613+ SetFeatures .Bits .Fid = NVME_FEATURE_NUMBER_OF_QUEUES ;
614+ NumberOfQueuesRequested .Bits .NCQ = NCQR ;
615+ NumberOfQueuesRequested .Bits .NSQ = NSQR ;
616+ CommandPacket .NvmeCmd -> Cdw10 = SetFeatures .Uint32 ;
617+ CommandPacket .NvmeCmd -> Cdw11 = NumberOfQueuesRequested .Uint32 ;
618+
619+ CommandPacket .NvmeCmd -> Flags = CDW10_VALID | CDW11_VALID ;
620+
621+ DEBUG ((DEBUG_INFO , "Vnk: Number of Queues Requested: NSQR=%d, NCQR=%d\n" , NSQR , NCQR ));
622+
623+ // Send the Set Features Command for Number of Queues
624+ Status = Private -> Passthru .PassThru (
625+ & Private -> Passthru ,
626+ 0 ,
627+ & CommandPacket ,
628+ NULL
629+ );
630+
631+ if (EFI_ERROR (Status )) {
632+ DEBUG ((DEBUG_ERROR , "Set Features Command for Number of Queues failed with Status %r\n" , Status ));
633+ return Status ;
634+ }
635+
636+ //
637+ // Save the number of queues allocated, adding 1 to account for it being a 0-based value.
638+ // E.g. if 1 pair of data queues is allocated NSQ=0, NCQ=0, then NSQA=1, NCQA=1
639+ // These numbers do not include the admin queues.
640+ //
641+ NumberOfQueuesAllocated .Uint32 = CommandPacket .NvmeCompletion -> DW0 ;
642+ Private -> NSQA = NumberOfQueuesAllocated .Bits .NSQ + 1 ;
643+ Private -> NCQA = NumberOfQueuesAllocated .Bits .NCQ + 1 ;
644+
645+ DEBUG ((DEBUG_INFO , "Vnk: Number of Queues Allocated: NSQA=%d, NCQA=%d\n" , Private -> NSQA , Private -> NCQA ));
646+
647+ return Status ;
648+ }
649+
650+ /**
651+ Create io completion queue(s).
571652
572653 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
573654
@@ -591,7 +672,8 @@ NvmeCreateIoCompletionQueue (
591672 Status = EFI_SUCCESS ;
592673 Private -> CreateIoQueue = TRUE;
593674
594- for (Index = 1 ; Index < NVME_MAX_QUEUES ; Index ++ ) {
675+ // Start from Index 1 because Index 0 is reserved for admin queue
676+ for (Index = 1 ; Index <= Private -> NCQA ; Index ++ ) {
595677 ZeroMem (& CommandPacket , sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET ));
596678 ZeroMem (& Command , sizeof (EFI_NVM_EXPRESS_COMMAND ));
597679 ZeroMem (& Completion , sizeof (EFI_NVM_EXPRESS_COMPLETION ));
@@ -610,11 +692,9 @@ NvmeCreateIoCompletionQueue (
610692 if (PcdGetBool (PcdSupportAlternativeQueueSize )) {
611693 QueueSize = MIN (NVME_ALTERNATIVE_MAX_QUEUE_SIZE , Private -> Cap .Mqes );
612694 } else if (Index == 1 ) {
613- QueueSize = NVME_CCQ_SIZE ;
614- } else if (Private -> Cap .Mqes > NVME_ASYNC_CCQ_SIZE ) {
615- QueueSize = NVME_ASYNC_CCQ_SIZE ;
695+ QueueSize = MIN (NVME_CCQ_SIZE , Private -> Cap .Mqes );
616696 } else {
617- QueueSize = Private -> Cap .Mqes ;
697+ QueueSize = MIN ( NVME_ASYNC_CCQ_SIZE , Private -> Cap .Mqes ) ;
618698 }
619699
620700 // MU_CHANGE [END]
@@ -632,6 +712,7 @@ NvmeCreateIoCompletionQueue (
632712 NULL
633713 );
634714 if (EFI_ERROR (Status )) {
715+ DEBUG ((DEBUG_ERROR , "Create Completion Queue Command %d failed with Status %r\n" , Index , Status ));
635716 break ;
636717 }
637718 }
@@ -642,7 +723,7 @@ NvmeCreateIoCompletionQueue (
642723}
643724
644725/**
645- Create io submission queue.
726+ Create io submission queue(s) .
646727
647728 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
648729
@@ -666,7 +747,8 @@ NvmeCreateIoSubmissionQueue (
666747 Status = EFI_SUCCESS ;
667748 Private -> CreateIoQueue = TRUE;
668749
669- for (Index = 1 ; Index < NVME_MAX_QUEUES ; Index ++ ) {
750+ // Start from Index 1 because Index 0 is reserved for admin queue
751+ for (Index = 1 ; Index <= Private -> NSQA ; Index ++ ) {
670752 ZeroMem (& CommandPacket , sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET ));
671753 ZeroMem (& Command , sizeof (EFI_NVM_EXPRESS_COMMAND ));
672754 ZeroMem (& Completion , sizeof (EFI_NVM_EXPRESS_COMPLETION ));
@@ -685,11 +767,9 @@ NvmeCreateIoSubmissionQueue (
685767 if (PcdGetBool (PcdSupportAlternativeQueueSize )) {
686768 QueueSize = MIN (NVME_ALTERNATIVE_MAX_QUEUE_SIZE , Private -> Cap .Mqes );
687769 } else if (Index == 1 ) {
688- QueueSize = NVME_CCQ_SIZE ;
689- } else if (Private -> Cap .Mqes > NVME_ASYNC_CCQ_SIZE ) {
690- QueueSize = NVME_ASYNC_CCQ_SIZE ;
770+ QueueSize = MIN (NVME_CCQ_SIZE , Private -> Cap .Mqes );
691771 } else {
692- QueueSize = Private -> Cap .Mqes ;
772+ QueueSize = MIN ( NVME_ASYNC_CCQ_SIZE , Private -> Cap .Mqes ) ;
693773 }
694774
695775 // MU_CHANGE [END]
@@ -709,6 +789,7 @@ NvmeCreateIoSubmissionQueue (
709789 NULL
710790 );
711791 if (EFI_ERROR (Status )) {
792+ DEBUG ((DEBUG_ERROR , "Create Submission Queue Command %d failed with Status %r\n" , Index , Status ));
712793 break ;
713794 }
714795 }
0 commit comments