mirror of https://github.com/acidanthera/audk.git
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>
This commit is contained in:
parent
2e15b750c4
commit
05fd2a9268
|
@ -88,6 +88,59 @@ NextDevicePathNode (
|
|||
return (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)(Node) + DevicePathNodeLength(Node));
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
|
||||
|
|
|
@ -213,6 +213,7 @@ NvmExpressPeimEntry (
|
|||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_BOOT_MODE BootMode;
|
||||
EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *NvmeHcPpi;
|
||||
UINT8 Controller;
|
||||
UINTN MmioBase;
|
||||
|
@ -223,6 +224,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
|
||||
//
|
||||
|
@ -279,6 +289,22 @@ NvmExpressPeimEntry (
|
|||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// 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
|
||||
//
|
||||
|
|
|
@ -266,6 +266,26 @@ NvmePeimEndOfPei (
|
|||
IN VOID *Ppi
|
||||
);
|
||||
|
||||
/**
|
||||
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.
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue