summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus
diff options
context:
space:
mode:
authorHao Wu <hao.a.wu@intel.com>2019-01-21 14:14:19 +0800
committerHao Wu <hao.a.wu@intel.com>2019-02-22 08:20:07 +0800
commit05fd2a9268332d770dd082be4af076ba0217cf54 (patch)
treeb3415a2de48fca27b6b14045a2658d07eb4348d7 /MdeModulePkg/Bus
parent2e15b750c4b09896aca11188c8727eaf4888a1c0 (diff)
downloadedk2-05fd2a9268332d770dd082be4af076ba0217cf54.zip
edk2-05fd2a9268332d770dd082be4af076ba0217cf54.tar.gz
edk2-05fd2a9268332d770dd082be4af076ba0217cf54.tar.bz2
MdeModulePkg/NvmExpressPei: Consume S3StorageDeviceInitList LockBox
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.wang@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Eric Dong <eric.dong@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com>
Diffstat (limited to 'MdeModulePkg/Bus')
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c53
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c26
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h36
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf8
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c114
5 files changed, 236 insertions, 1 deletions
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
index fd30ad5..ff95f20 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
@@ -89,6 +89,59 @@ NextDevicePathNode (
}
/**
+ Get the size of the current device path instance.
+
+ @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
+ structure.
+ @param[out] InstanceSize The size of the current device path instance.
+ @param[out] EntireDevicePathEnd Indicate whether the instance is the last
+ one in the device path strucure.
+
+ @retval EFI_SUCCESS The size of the current device path instance is fetched.
+ @retval Others Fails to get the size of the current device path instance.
+
+**/
+EFI_STATUS
+GetDevicePathInstanceSize (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINTN *InstanceSize,
+ OUT BOOLEAN *EntireDevicePathEnd
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Walker;
+
+ if (DevicePath == NULL || InstanceSize == NULL || EntireDevicePathEnd == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the end of the device path instance
+ //
+ Walker = DevicePath;
+ while (Walker->Type != END_DEVICE_PATH_TYPE) {
+ Walker = NextDevicePathNode (Walker);
+ }
+
+ //
+ // Check if 'Walker' points to the end of an entire device path
+ //
+ if (Walker->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
+ *EntireDevicePathEnd = TRUE;
+ } else if (Walker->SubType == END_INSTANCE_DEVICE_PATH_SUBTYPE) {
+ *EntireDevicePathEnd = FALSE;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Compute the size of the device path instance
+ //
+ *InstanceSize = ((UINTN) Walker - (UINTN) (DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
+
+ return EFI_SUCCESS;
+}
+
+/**
Check the validity of the device path of a NVM Express host controller.
@param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
index bf33b4b..2dbf54f 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 (
@@ -280,6 +290,22 @@ NvmExpressPeimEntry (
}
//
+ // For S3 resume performance consideration, not all NVM Express controllers
+ // will be initialized. The driver consumes the content within
+ // S3StorageDeviceInitList LockBox to see if a controller will be skipped
+ // during S3 resume.
+ //
+ 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
//
Private = AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA));
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
index 8966616..74e2daf 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
@@ -267,6 +267,26 @@ NvmePeimEndOfPei (
);
/**
+ Get the size of the current device path instance.
+
+ @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
+ structure.
+ @param[out] InstanceSize The size of the current device path instance.
+ @param[out] EntireDevicePathEnd Indicate whether the instance is the last
+ one in the device path strucure.
+
+ @retval EFI_SUCCESS The size of the current device path instance is fetched.
+ @retval Others Fails to get the size of the current device path instance.
+
+**/
+EFI_STATUS
+GetDevicePathInstanceSize (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINTN *InstanceSize,
+ OUT BOOLEAN *EntireDevicePathEnd
+ );
+
+/**
Check the validity of the device path of a NVM Express host controller.
@param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
@@ -309,4 +329,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.inf b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf
index 0666e58..22b703e 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/NvmExpressPeiS3.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c
new file mode 100644
index 0000000..eb3af75
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c
@@ -0,0 +1,114 @@
+/** @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 EntireEnd;
+ BOOLEAN Skip;
+
+ //
+ // From the LockBox, get the list of device paths for devices need to be
+ // initialized in S3.
+ //
+ S3InitDevices = NULL;
+ S3InitDevicesLength = sizeof (DummyData);
+ EntireEnd = FALSE;
+ 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 size of current device path instance.
+ //
+ Status = GetDevicePathInstanceSize (
+ S3InitDevices,
+ &DevicePathInstLength,
+ &EntireEnd
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ DevicePathInst = S3InitDevices;
+ S3InitDevices = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN) S3InitDevices + DevicePathInstLength);
+
+ if (HcDevicePathLength >= DevicePathInstLength) {
+ 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 (!EntireEnd);
+
+ return Skip;
+}