Skip to content

Commit b273e57

Browse files
committed
MdeModulePkg: NvmExpressDxe: Request queues from
the controller. Instead of assuming we always want to create two sets of data queues, we request two and the controller will determine how many are allocated. Signed-off-by: Vivian Nowka-Keane <vnowkakeane@linux.microsoft.com>
1 parent 7a58252 commit b273e57

File tree

4 files changed

+199
-31
lines changed

4 files changed

+199
-31
lines changed

MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c

Lines changed: 83 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,13 @@ EnumerateNvmeDevNamespace (
7474
UINT32 LbaFmtIdx;
7575
UINT8 Sn[21];
7676
UINT8 Mn[41];
77+
BOOLEAN MultipleDataQueues;
7778
VOID *DummyInterface;
7879

79-
NewDevicePathNode = NULL;
80-
DevicePath = NULL;
81-
Device = NULL;
80+
NewDevicePathNode = NULL;
81+
DevicePath = NULL;
82+
Device = NULL;
83+
MultipleDataQueues = FALSE;
8284

8385
//
8486
// Allocate a buffer for Identify Namespace data
@@ -107,6 +109,20 @@ EnumerateNvmeDevNamespace (
107109
if (NamespaceData->Ncap == 0) {
108110
Status = EFI_DEVICE_ERROR;
109111
} else {
112+
//
113+
// Send Set Features Command to request the maximum number of data queues
114+
//
115+
Status = NvmeSetFeaturesNumberOfQueues (Private, NVME_MAX_QUEUES - 1, NVME_MAX_QUEUES - 1);
116+
117+
if (EFI_ERROR (Status)) {
118+
goto Exit;
119+
}
120+
121+
if (Private->NSQA > 1) {
122+
// There are multiple data queue pairs (non-admin queues) available
123+
MultipleDataQueues = TRUE;
124+
}
125+
110126
//
111127
// allocate device private data for each discovered namespace
112128
//
@@ -172,15 +188,17 @@ EnumerateNvmeDevNamespace (
172188
Device->BlockIo.WriteBlocks = NvmeBlockIoWriteBlocks;
173189
Device->BlockIo.FlushBlocks = NvmeBlockIoFlushBlocks;
174190

175-
//
176-
// Create BlockIo2 Protocol instance
177-
//
178-
Device->BlockIo2.Media = &Device->Media;
179-
Device->BlockIo2.Reset = NvmeBlockIoResetEx;
180-
Device->BlockIo2.ReadBlocksEx = NvmeBlockIoReadBlocksEx;
181-
Device->BlockIo2.WriteBlocksEx = NvmeBlockIoWriteBlocksEx;
182-
Device->BlockIo2.FlushBlocksEx = NvmeBlockIoFlushBlocksEx;
183-
InitializeListHead (&Device->AsyncQueue);
191+
if (MultipleDataQueues) {
192+
//
193+
// Create BlockIo2 Protocol instance
194+
//
195+
Device->BlockIo2.Media = &Device->Media;
196+
Device->BlockIo2.Reset = NvmeBlockIoResetEx;
197+
Device->BlockIo2.ReadBlocksEx = NvmeBlockIoReadBlocksEx;
198+
Device->BlockIo2.WriteBlocksEx = NvmeBlockIoWriteBlocksEx;
199+
Device->BlockIo2.FlushBlocksEx = NvmeBlockIoFlushBlocksEx;
200+
InitializeListHead (&Device->AsyncQueue);
201+
}
184202

185203
// MU_CHANGE Start - Add Media Sanitize
186204
//
@@ -260,8 +278,6 @@ EnumerateNvmeDevNamespace (
260278
Device->DevicePath,
261279
&gEfiBlockIoProtocolGuid,
262280
&Device->BlockIo,
263-
&gEfiBlockIo2ProtocolGuid,
264-
&Device->BlockIo2,
265281
&gEfiDiskInfoProtocolGuid,
266282
&Device->DiskInfo,
267283
NULL
@@ -271,6 +287,18 @@ EnumerateNvmeDevNamespace (
271287
goto Exit;
272288
}
273289

290+
if (MultipleDataQueues) {
291+
Status = gBS->InstallProtocolInterface (
292+
&Device->DeviceHandle,
293+
&gEfiBlockIo2ProtocolGuid,
294+
EFI_NATIVE_INTERFACE, // this is the only option in the enum..?
295+
&Device->BlockIo2
296+
);
297+
if (EFI_ERROR (Status)) {
298+
goto Exit;
299+
}
300+
}
301+
274302
//
275303
// Check if the NVMe controller supports the Security Send and Security Receive commands
276304
//
@@ -288,12 +316,19 @@ EnumerateNvmeDevNamespace (
288316
Device->DevicePath,
289317
&gEfiBlockIoProtocolGuid,
290318
&Device->BlockIo,
291-
&gEfiBlockIo2ProtocolGuid,
292-
&Device->BlockIo2,
293319
&gEfiDiskInfoProtocolGuid,
294320
&Device->DiskInfo,
295321
NULL
296322
);
323+
324+
if (MultipleDataQueues) {
325+
gBS->UninstallProtocolInterface (
326+
Device->DeviceHandle,
327+
&gEfiBlockIo2ProtocolGuid,
328+
&Device->BlockIo2
329+
);
330+
}
331+
297332
goto Exit;
298333
}
299334
}
@@ -430,6 +465,7 @@ UnregisterNvmeNamespace (
430465
{
431466
EFI_STATUS Status;
432467
EFI_BLOCK_IO_PROTOCOL *BlockIo;
468+
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
433469
NVME_DEVICE_PRIVATE_DATA *Device;
434470
EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;
435471
BOOLEAN IsEmpty;
@@ -487,8 +523,6 @@ UnregisterNvmeNamespace (
487523
Device->DevicePath,
488524
&gEfiBlockIoProtocolGuid,
489525
&Device->BlockIo,
490-
&gEfiBlockIo2ProtocolGuid,
491-
&Device->BlockIo2,
492526
&gEfiDiskInfoProtocolGuid,
493527
&Device->DiskInfo,
494528
NULL
@@ -506,6 +540,37 @@ UnregisterNvmeNamespace (
506540
return Status;
507541
}
508542

543+
//
544+
// If BlockIo2 is installed, uninstall it.
545+
//
546+
Status = gBS->OpenProtocol (
547+
Handle,
548+
&gEfiBlockIo2ProtocolGuid,
549+
(VOID **)&BlockIo2,
550+
This->DriverBindingHandle,
551+
Controller,
552+
EFI_OPEN_PROTOCOL_GET_PROTOCOL
553+
);
554+
555+
if (!EFI_ERROR (Status)) {
556+
Status = gBS->UninstallProtocolInterface (
557+
Handle,
558+
&gEfiBlockIo2ProtocolGuid,
559+
&Device->BlockIo2
560+
);
561+
if (EFI_ERROR (Status)) {
562+
gBS->OpenProtocol (
563+
Controller,
564+
&gEfiNvmExpressPassThruProtocolGuid,
565+
(VOID **)&DummyInterface,
566+
This->DriverBindingHandle,
567+
Handle,
568+
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
569+
);
570+
return Status;
571+
}
572+
}
573+
509574
//
510575
// If Storage Security Command Protocol is installed, then uninstall this protocol.
511576
//

MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ extern EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gNvmExpressDriverSupportedEfiV
7878
//
7979
#define NVME_ASYNC_CCQ_SIZE 255
8080

81-
#define NVME_MAX_QUEUES 3 // Number of queues supported by the driver
81+
// Maximum number of queue pairs supported by the driver, including the admin queues.
82+
#define NVME_MAX_QUEUES 3
8283

8384
// MU_CHANGE Start - Add Media Sanitize
8485
//
@@ -161,6 +162,12 @@ struct _NVME_CONTROLLER_PRIVATE_DATA {
161162
//
162163
NVME_ADMIN_CONTROLLER_DATA *ControllerData;
163164

165+
//
166+
// Number of Queues Allocated by the controller (0-based where 0 is 1 queue)
167+
//
168+
UINT32 NSQA; // Number of Submission Queues Allocated
169+
UINT32 NCQA; // Number of Completion Queues Allocated
170+
164171
//
165172
// 6 x 4kB aligned buffers will be carved out of this buffer.
166173
// 1st 4kB boundary is the start of the admin submission queue.

MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,19 @@ NvmeIdentifyNamespace (
6666
IN VOID *Buffer
6767
);
6868

69+
/**
70+
* Request queues from Nvm Express controller .
71+
*
72+
* @param Private
73+
* @param NCQR
74+
* @param NSQR
75+
* @return EFI_STATUS
76+
*/
77+
EFI_STATUS
78+
NvmeSetFeaturesNumberOfQueues (
79+
IN NVME_CONTROLLER_PRIVATE_DATA *Private,
80+
IN UINT16 NSQR,
81+
IN UINT16 NCQR
82+
);
83+
6984
#endif

0 commit comments

Comments
 (0)