REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1409
For the NvmExpressPei driver, this commit will update the driver to consume the S3StorageDeviceInitList LockBox in S3 phase. The purpose is to perform an on-demand (partial) NVM Express device enumeration/initialization to benefit the S3 resume performance. Cc: Jian J Wang <jian.j.w...@intel.com> Cc: Ray Ni <ray...@intel.com> Cc: Eric Dong <eric.d...@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Hao Wu <hao.a...@intel.com> --- MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf | 8 +- MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h | 16 +++ MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c | 20 ++++ MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c | 106 ++++++++++++++++++++ 4 files changed, 149 insertions(+), 1 deletion(-) diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf index 0666e5892b..22b703e971 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf +++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf @@ -40,6 +40,7 @@ NvmExpressPeiHci.h NvmExpressPeiPassThru.c NvmExpressPeiPassThru.h + NvmExpressPeiS3.c NvmExpressPeiStorageSecurity.c NvmExpressPeiStorageSecurity.h @@ -54,6 +55,7 @@ BaseMemoryLib IoLib TimerLib + LockBoxLib PeimEntryPoint [Ppis] @@ -64,9 +66,13 @@ gEfiPeiVirtualBlockIo2PpiGuid ## SOMETIMES_PRODUCES gEdkiiPeiStorageSecurityCommandPpiGuid ## SOMETIMES_PRODUCES +[Guids] + gS3StorageDeviceInitListGuid ## SOMETIMES_CONSUMES ## UNDEFINED + [Depex] gEfiPeiMemoryDiscoveredPpiGuid AND - gEdkiiPeiNvmExpressHostControllerPpiGuid + gEdkiiPeiNvmExpressHostControllerPpiGuid AND + gEfiPeiMasterBootModePpiGuid [UserExtensions.TianoCore."ExtraFiles"] NvmExpressPeiExtra.uni diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h index 7047c4f3ff..6f01413e6d 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h +++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h @@ -332,4 +332,20 @@ NvmeBuildDevicePath ( OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath ); +/** + Determine if a specific NVM Express controller can be skipped for S3 phase. + + @param[in] HcDevicePath Device path of the controller. + @param[in] HcDevicePathLength Length of the device path specified by + HcDevicePath. + + @retval The number of ports that need to be enumerated. + +**/ +BOOLEAN +NvmeS3SkipThisController ( + IN EFI_DEVICE_PATH_PROTOCOL *HcDevicePath, + IN UINTN HcDevicePathLength + ); + #endif diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c index 96622e6fd5..43b2dfc3e7 100644 --- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c +++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c @@ -213,6 +213,7 @@ NvmExpressPeimEntry ( ) { EFI_STATUS Status; + EFI_BOOT_MODE BootMode; EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *NvmeHcPpi; UINT8 Controller; UINTN MmioBase; @@ -224,6 +225,15 @@ NvmExpressPeimEntry ( DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__)); // + // Get the current boot mode. + // + Status = PeiServicesGetBootMode (&BootMode); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __FUNCTION__)); + return Status; + } + + // // Locate the NVME host controller PPI // Status = PeiServicesLocatePpi ( @@ -279,6 +289,16 @@ NvmExpressPeimEntry ( continue; } + if ((BootMode == BOOT_ON_S3_RESUME) && + (NvmeS3SkipThisController (DevicePath, DevicePathLength))) { + DEBUG (( + DEBUG_ERROR, "%a: Controller %d is skipped during S3.\n", + __FUNCTION__, Controller + )); + Controller++; + continue; + } + // // Memory allocation for controller private data // diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c new file mode 100644 index 0000000000..afcf5f6c0a --- /dev/null +++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c @@ -0,0 +1,106 @@ +/** @file + The NvmExpressPei driver is used to manage non-volatile memory subsystem + which follows NVM Express specification at PEI phase. + + Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions + of the BSD License which accompanies this distribution. The + full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "NvmExpressPei.h" + +#include <Guid/S3StorageDeviceInitList.h> + +#include <Library/LockBoxLib.h> + +/** + Determine if a specific NVM Express controller can be skipped for S3 phase. + + @param[in] HcDevicePath Device path of the controller. + @param[in] HcDevicePathLength Length of the device path specified by + HcDevicePath. + + @retval The number of ports that need to be enumerated. + +**/ +BOOLEAN +NvmeS3SkipThisController ( + IN EFI_DEVICE_PATH_PROTOCOL *HcDevicePath, + IN UINTN HcDevicePathLength + ) +{ + EFI_STATUS Status; + UINT8 DummyData; + UINTN S3InitDevicesLength; + EFI_DEVICE_PATH_PROTOCOL *S3InitDevices; + EFI_DEVICE_PATH_PROTOCOL *DevicePathInst; + UINTN DevicePathInstLength; + BOOLEAN Skip; + + // + // From the LockBox, get the list of device paths for devices need to be + // initialized in S3. + // + S3InitDevices = NULL; + S3InitDevicesLength = sizeof (DummyData); + Skip = TRUE; + Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, &DummyData, &S3InitDevicesLength); + if (Status != EFI_BUFFER_TOO_SMALL) { + return Skip; + } else { + S3InitDevices = AllocatePool (S3InitDevicesLength); + if (S3InitDevices == NULL) { + return Skip; + } + + Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, S3InitDevices, &S3InitDevicesLength); + if (EFI_ERROR (Status)) { + return Skip; + } + } + + if (S3InitDevices == NULL) { + return Skip; + } + + // + // Only need to initialize the controllers that exist in the device list. + // + do { + // + // Fetch the next device path instance. + // + DevicePathInst = GetNextDevicePathInstance (&S3InitDevices, &DevicePathInstLength); + if (DevicePathInst == NULL) { + break; + } + + if ((HcDevicePathLength >= DevicePathInstLength) || + (HcDevicePathLength <= sizeof (EFI_DEVICE_PATH_PROTOCOL))) { + continue; + } + + // + // Compare the device paths to determine if the device is managed by this + // controller. + // + if (CompareMem ( + DevicePathInst, + HcDevicePath, + HcDevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL) + ) == 0) { + Skip = FALSE; + break; + } + } while (S3InitDevices != NULL); + + return Skip; +} -- 2.12.0.windows.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel