Skip to content

Commit c076875

Browse files
chris-ooapop5
authored andcommitted
MdeModulePkg: Add alternative queue sizes in nvme driver to support specific devices
Add a new PCD that toggles between the old driver behavior and new behavior that uses a different hardcoded queue size to support specific devices. Default behavior should not change. MdeModulePkg/NvmExpressDxe: Improve NVMe controller init robustness It has been observed that some faulty NVMe devices may return invalid values. The code in NvmExpressDxe recognizes the controller is not responding correctly and issues an ASSERT() often in DEBUG builds or a reset in RELEASE builds. The following changes are made to NvmeControllerInit() to prevent a faulty NVMe device from halting the overall boot: 1. Check the Vendor ID and Device ID to verify they are read properly and if not, return EFI_DEVICE_ERROR 2. Replace the ASSERT() when Memory Page Size Minimum (Cap.Mpsmin) with an error message and return EFI_DEVICE_ERROR Signed-off-by: Michael Kubacki <[email protected]> MdeModulePkg/NvmExpressDxe: Correct function parameter modifer Updates the `Cap` parameter for `ReadNvmeControllerCapabilities()` to be `OUT` since the buffer pointed to is written within the function. Signed-off-by: Michael Kubacki <[email protected]>
1 parent 1aa501c commit c076875

File tree

6 files changed

+120
-18
lines changed

6 files changed

+120
-18
lines changed

MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,9 @@ ProcessAsyncTaskList (
655655
EFI_BLOCK_IO2_TOKEN *Token;
656656
BOOLEAN HasNewItem;
657657
EFI_STATUS Status;
658+
// MU_CHANGE - Support alternative hardware queue sizes in NVME driver
659+
UINT16 QueueSize = PcdGetBool (PcdSupportAlternativeQueueSize) ?
660+
NVME_ALTERNATIVE_MAX_QUEUE_SIZE : NVME_ASYNC_CCQ_SIZE;
658661

659662
Private = (NVME_CONTROLLER_PRIVATE_DATA *)Context;
660663
QueueId = 2;
@@ -797,7 +800,8 @@ ProcessAsyncTaskList (
797800
}
798801

799802
Private->CqHdbl[QueueId].Cqh++;
800-
if (Private->CqHdbl[QueueId].Cqh > MIN (NVME_ASYNC_CCQ_SIZE, Private->Cap.Mqes)) {
803+
// MU_CHANGE - Support alternative hardware queue sizes in NVME driver
804+
if (Private->CqHdbl[QueueId].Cqh > MIN (QueueSize, Private->Cap.Mqes)) {
801805
Private->CqHdbl[QueueId].Cqh = 0;
802806
Private->Pt[QueueId] ^= 1;
803807
}

MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,20 @@ extern EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gNvmExpressDriverSupportedEfiV
136136

137137
#define NVME_ALL_NAMESPACES 0xFFFFFFFF
138138

139+
// MU_CHANGE [BEGIN] - Support alternative hardware queue sizes in NVME driver
140+
141+
//
142+
// NVMe DXE to accommodate hardware which requires queue size 255.
143+
// Driver supports queue size up to 255 (4 page SQ buffer).
144+
// DXE driver creates queue size MIN(Cap.Mqes, NVME_MAX_QUEUE_SIZE) for all queues.
145+
// Driver allocates queue buffer to support 255 max queue size.
146+
// Each submission queue buffer is allocated as 64B * 256 = 4 * 4kB = 4 pages.
147+
// Each completion queue buffer is allocated as 16B * 256 = 4kB = 1 page.
148+
//
149+
#define NVME_ALTERNATIVE_MAX_QUEUE_SIZE 255
150+
151+
// MU_CHANGE [END] - Support alternative hardware queue sizes in NVME driver
152+
139153
#define NVME_CONTROLLER_ID 0
140154

141155
//

MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@
7777
gMediaSanitizeProtocolGuid ## PRODUCES
7878
gEfiResetNotificationProtocolGuid ## CONSUMES
7979

80+
[Pcd]
81+
## MU_CHANGE [BEGIN] - Support alternative hardware queue sizes in NVME driver
82+
gEfiMdeModulePkgTokenSpaceGuid.PcdSupportAlternativeQueueSize ## CONSUMES
83+
## MU_CHANGE [END] - Support alternative hardware queue sizes in NVME driver
84+
8085
# [Event]
8186
# EVENT_TYPE_RELATIVE_TIMER ## SOMETIMES_CONSUMES
8287
#

MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,11 @@ NvmeCreateIoCompletionQueue (
769769
CommandPacket.QueueType = NVME_ADMIN_QUEUE;
770770

771771
// MU_CHANGE [BEGIN] - Use the Mqes value from the Cap register
772-
if (Index == 1) {
772+
// MU_CHANGE [BEGIN] - Support alternative hardware queue sizes in NVME driver
773+
if (PcdGetBool (PcdSupportAlternativeQueueSize)) {
774+
QueueSize = MIN (NVME_ALTERNATIVE_MAX_QUEUE_SIZE, Private->Cap.Mqes);
775+
} else if (Index == 1) {
776+
// MU_CHANGE [END] - Support alternative hardware queue sizes in NVME driver
773777
QueueSize = MIN (NVME_CCQ_SIZE, Private->Cap.Mqes);
774778
} else {
775779
QueueSize = MIN (NVME_ASYNC_CCQ_SIZE, Private->Cap.Mqes);
@@ -846,7 +850,11 @@ NvmeCreateIoSubmissionQueue (
846850
CommandPacket.QueueType = NVME_ADMIN_QUEUE;
847851

848852
// MU_CHANGE [BEGIN] - Use the Mqes value from the Cap register
849-
if (Index == 1) {
853+
// MU_CHANGE [BEGIN] - Support alternative hardware queue sizes in NVME driver
854+
if (PcdGetBool (PcdSupportAlternativeQueueSize)) {
855+
QueueSize = MIN (NVME_ALTERNATIVE_MAX_QUEUE_SIZE, Private->Cap.Mqes);
856+
} else if (Index == 1) {
857+
// MU_CHANGE [END] - Support alternative hardware queue sizes in NVME driver
850858
QueueSize = MIN (NVME_CSQ_SIZE, Private->Cap.Mqes);
851859
} else {
852860
QueueSize = MIN (NVME_ASYNC_CSQ_SIZE, Private->Cap.Mqes);
@@ -1036,7 +1044,7 @@ NvmeControllerInit (
10361044
EFI_STATUS Status;
10371045
EFI_PCI_IO_PROTOCOL *PciIo;
10381046
UINT64 Supports;
1039-
// NVME_AQA Aqa;
1047+
UINT16 VidDid[2]; // MU_CHANGE - Improve NVMe controller init robustness
10401048
// NVME_ASQ Asq;
10411049
// NVME_ACQ Acq;
10421050
UINT8 Sn[21];
@@ -1050,10 +1058,33 @@ NvmeControllerInit (
10501058

10511059
// MU_CHANGE [END] - Allocate IO Queue Buffer
10521060

1061+
// MU_CHANGE [BEGIN] - Improve NVMe controller init robustness
1062+
PciIo = Private->PciIo;
1063+
1064+
//
1065+
// Verify the controller is still accessible
1066+
//
1067+
Status = PciIo->Pci.Read (
1068+
PciIo,
1069+
EfiPciIoWidthUint16,
1070+
PCI_VENDOR_ID_OFFSET,
1071+
ARRAY_SIZE (VidDid),
1072+
VidDid
1073+
);
1074+
if (EFI_ERROR (Status)) {
1075+
ASSERT_EFI_ERROR (Status);
1076+
return EFI_DEVICE_ERROR;
1077+
}
1078+
1079+
if ((VidDid[0] == NVME_INVALID_VID_DID) || (VidDid[1] == NVME_INVALID_VID_DID)) {
1080+
return EFI_DEVICE_ERROR;
1081+
}
1082+
1083+
// MU_CHANGE [END] - Improve NVMe controller init robustness
1084+
10531085
//
10541086
// Enable this controller.
10551087
//
1056-
PciIo = Private->PciIo;
10571088
Status = PciIo->Attributes (
10581089
PciIo,
10591090
EfiPciIoAttributeOperationSupported,
@@ -1092,7 +1123,16 @@ NvmeControllerInit (
10921123
//
10931124
// Currently the driver only supports 4k page size.
10941125
//
1095-
ASSERT ((Private->Cap.Mpsmin + 12) <= EFI_PAGE_SHIFT);
1126+
// MU_CHANGE [BEGIN] - Improve NVMe controller init robustness
1127+
1128+
// Currently, this means Cap.Mpsmin must be zero for an EFI_PAGE_SHIFT size of 12.
1129+
// ASSERT ((Private->Cap.Mpsmin + 12) <= EFI_PAGE_SHIFT);
1130+
if ((Private->Cap.Mpsmin + 12) > EFI_PAGE_SHIFT) {
1131+
DEBUG ((DEBUG_ERROR, "NvmeControllerInit: Mpsmin is larger than expected (0x%02x).\n", Private->Cap.Mpsmin));
1132+
return EFI_DEVICE_ERROR;
1133+
}
1134+
1135+
// MU_CHANGE [END] - Improve NVMe controller init robustness
10961136

10971137
// MU_CHANGE [BEGIN] - Allocate IO Queue Buffer
10981138

@@ -1122,10 +1162,12 @@ NvmeControllerInit (
11221162
//
11231163
// set number of entries admin submission & completion queues.
11241164
//
1125-
Aqa.Asqs = MIN (NVME_ASQ_SIZE, Private->Cap.Mqes);
1165+
// MU_CHANGE [BEGIN] - Support alternative hardware queue sizes in NVME driver
1166+
Aqa.Asqs = PcdGetBool (PcdSupportAlternativeQueueSize) ? MIN (NVME_ALTERNATIVE_MAX_QUEUE_SIZE, Private->Cap.Mqes) : MIN (NVME_ASQ_SIZE, Private->Cap.Mqes);
11261167
Aqa.Rsvd1 = 0;
1127-
Aqa.Acqs = MIN (NVME_ACQ_SIZE, Private->Cap.Mqes);
1168+
Aqa.Acqs = PcdGetBool (PcdSupportAlternativeQueueSize) ? MIN (NVME_ALTERNATIVE_MAX_QUEUE_SIZE, Private->Cap.Mqes) : MIN (NVME_ACQ_SIZE, Private->Cap.Mqes);
11281169
Aqa.Rsvd2 = 0;
1170+
// MU_CHANGE [END] - Support alternative hardware queue sizes in NVME driver
11291171

11301172
//
11311173
// Set admin queue entry size to default

MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,15 @@ NvmExpressPassThru (
553553
Prp = NULL;
554554
TimerEvent = NULL;
555555
Status = EFI_SUCCESS;
556-
QueueSize = MIN (NVME_ASYNC_CSQ_SIZE, Private->Cap.Mqes) + 1;
556+
557+
// MU_CHANGE [BEGIN] - Support alternative hardware queue sizes in NVME driver
558+
if (PcdGetBool (PcdSupportAlternativeQueueSize)) {
559+
QueueSize = MIN (NVME_ALTERNATIVE_MAX_QUEUE_SIZE, Private->Cap.Mqes) + 1;
560+
} else {
561+
QueueSize = MIN (NVME_ASYNC_CSQ_SIZE, Private->Cap.Mqes) + 1;
562+
}
563+
564+
// MU_CHANGE [END] - Support alternative hardware queue sizes in NVME driver
557565

558566
if (Packet->QueueType == NVME_ADMIN_QUEUE) {
559567
QueueId = 0;
@@ -581,6 +589,14 @@ NvmExpressPassThru (
581589
return EFI_INVALID_PARAMETER;
582590
}
583591

592+
// MU_CHANGE - Support alternative hardware queue sizes in NVME driver
593+
//
594+
// Nvme DXE driver polls phase bit for CQe completion.
595+
// Explicitly assign phase bit with the bit before completion.
596+
// A flipped phase bit will be assigned by device upon CQe completes.
597+
//
598+
Cq->Pt = Private->Pt[QueueId];
599+
584600
ZeroMem (Sq, sizeof (NVME_SQ));
585601
Sq->Opc = (UINT8)Packet->NvmeCmd->Cdw0.Opcode;
586602
Sq->Fuse = (UINT8)Packet->NvmeCmd->Cdw0.FusedOperation;
@@ -723,16 +739,23 @@ NvmExpressPassThru (
723739
Sq->Payload.Raw.Cdw15 = Packet->NvmeCmd->Cdw15;
724740
}
725741

726-
//
727-
// Ring the submission queue doorbell.
728-
//
729-
if ((Event != NULL) && (QueueId != 0)) {
730-
Private->SqTdbl[QueueId].Sqt =
731-
(Private->SqTdbl[QueueId].Sqt + 1) % QueueSize;
742+
// MU_CHANGE [BEGIN] - Support alternative hardware queue sizes in NVME driver
743+
if (PcdGetBool (PcdSupportAlternativeQueueSize)) {
744+
Private->SqTdbl[QueueId].Sqt = (Private->SqTdbl[QueueId].Sqt + 1) % QueueSize;
732745
} else {
733-
Private->SqTdbl[QueueId].Sqt ^= 1;
746+
//
747+
// Ring the submission queue doorbell.
748+
//
749+
if ((Event != NULL) && (QueueId != 0)) {
750+
Private->SqTdbl[QueueId].Sqt =
751+
(Private->SqTdbl[QueueId].Sqt + 1) % QueueSize;
752+
} else {
753+
Private->SqTdbl[QueueId].Sqt ^= 1;
754+
}
734755
}
735756

757+
// MU_CHANGE [END] - Support alternative hardware queue sizes in NVME driver
758+
736759
Data = ReadUnaligned32 ((UINT32 *)&Private->SqTdbl[QueueId]);
737760
Status = PciIo->Mem.Write (
738761
PciIo,
@@ -865,10 +888,20 @@ NvmExpressPassThru (
865888
goto EXIT;
866889
}
867890

868-
if ((Private->CqHdbl[QueueId].Cqh ^= 1) == 0) {
869-
Private->Pt[QueueId] ^= 1;
891+
// MU_CHANGE [BEGIN] - Support alternative hardware queue sizes in NVME driver
892+
if (PcdGetBool (PcdSupportAlternativeQueueSize)) {
893+
Private->CqHdbl[QueueId].Cqh = (Private->CqHdbl[QueueId].Cqh + 1) % QueueSize;
894+
if (Private->CqHdbl[QueueId].Cqh == 0) {
895+
Private->Pt[QueueId] ^= 1;
896+
}
897+
} else {
898+
if ((Private->CqHdbl[QueueId].Cqh ^= 1) == 0) {
899+
Private->Pt[QueueId] ^= 1;
900+
}
870901
}
871902

903+
// MU_CHANGE [END] - Support alternative hardware queue sizes in NVME driver
904+
872905
Data = ReadUnaligned32 ((UINT32 *)&Private->CqHdbl[QueueId]);
873906
PreviousStatus = Status;
874907
Status = PciIo->Mem.Write (

MdeModulePkg/MdeModulePkg.dec

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,10 @@
13851385
# Default is 2000, it represent delay is 2 ms.
13861386
# @Prompt Delay access XHCI register after it issues HCRST (us)
13871387
gEfiMdeModulePkgTokenSpaceGuid.PcdDelayXhciHCReset|2000|UINT16|0x30001060
1388+
1389+
# MU_CHANGE [BEGIN] - Support alternative hardware queue sizes in NVME driver
1390+
gEfiMdeModulePkgTokenSpaceGuid.PcdSupportAlternativeQueueSize|FALSE|BOOLEAN|0x40000151
1391+
# MU_CHANGE [END]
13881392

13891393
## Specifies the page count allocated for the MM communication buffer.
13901394
# @Prompt Defines the page allocation for the MM communication buffer; default is 128 pages (512KB).

0 commit comments

Comments
 (0)