]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg/NvmExpressPei: Consume S3StorageDeviceInitList LockBox
authorHao Wu <hao.a.wu@intel.com>
Mon, 21 Jan 2019 06:14:19 +0000 (14:14 +0800)
committerHao Wu <hao.a.wu@intel.com>
Fri, 22 Feb 2019 00:20:07 +0000 (08:20 +0800)
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>
MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.h
MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.inf
MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c [new file with mode: 0644]

index fd30ad519faa6df7edf0aa5b6ff76912a45bdc89..ff95f20329e74aa8c0e7aee3345be793cd7b2567 100644 (file)
@@ -88,6 +88,59 @@ NextDevicePathNode (
   return (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)(Node) + DevicePathNodeLength(Node));\r
 }\r
 \r
+/**\r
+  Get the size of the current device path instance.\r
+\r
+  @param[in]  DevicePath             A pointer to the EFI_DEVICE_PATH_PROTOCOL\r
+                                     structure.\r
+  @param[out] InstanceSize           The size of the current device path instance.\r
+  @param[out] EntireDevicePathEnd    Indicate whether the instance is the last\r
+                                     one in the device path strucure.\r
+\r
+  @retval EFI_SUCCESS    The size of the current device path instance is fetched.\r
+  @retval Others         Fails to get the size of the current device path instance.\r
+\r
+**/\r
+EFI_STATUS\r
+GetDevicePathInstanceSize (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath,\r
+  OUT UINTN                       *InstanceSize,\r
+  OUT BOOLEAN                     *EntireDevicePathEnd\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL    *Walker;\r
+\r
+  if (DevicePath == NULL || InstanceSize == NULL || EntireDevicePathEnd == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Find the end of the device path instance\r
+  //\r
+  Walker = DevicePath;\r
+  while (Walker->Type != END_DEVICE_PATH_TYPE) {\r
+    Walker = NextDevicePathNode (Walker);\r
+  }\r
+\r
+  //\r
+  // Check if 'Walker' points to the end of an entire device path\r
+  //\r
+  if (Walker->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE) {\r
+    *EntireDevicePathEnd = TRUE;\r
+  } else if (Walker->SubType == END_INSTANCE_DEVICE_PATH_SUBTYPE) {\r
+    *EntireDevicePathEnd = FALSE;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Compute the size of the device path instance\r
+  //\r
+  *InstanceSize = ((UINTN) Walker - (UINTN) (DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Check the validity of the device path of a NVM Express host controller.\r
 \r
index bf33b4b9a03b9ff0b35b39c815513102761d3714..2dbf54fd3f0eaca88a0e43369339db7d6596bc43 100644 (file)
@@ -213,6 +213,7 @@ NvmExpressPeimEntry (
   )\r
 {\r
   EFI_STATUS                               Status;\r
+  EFI_BOOT_MODE                            BootMode;\r
   EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI    *NvmeHcPpi;\r
   UINT8                                    Controller;\r
   UINTN                                    MmioBase;\r
@@ -223,6 +224,15 @@ NvmExpressPeimEntry (
 \r
   DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));\r
 \r
+  //\r
+  // Get the current boot mode.\r
+  //\r
+  Status = PeiServicesGetBootMode (&BootMode);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __FUNCTION__));\r
+    return Status;\r
+  }\r
+\r
   //\r
   // Locate the NVME host controller PPI\r
   //\r
@@ -279,6 +289,22 @@ NvmExpressPeimEntry (
       continue;\r
     }\r
 \r
+    //\r
+    // For S3 resume performance consideration, not all NVM Express controllers\r
+    // will be initialized. The driver consumes the content within\r
+    // S3StorageDeviceInitList LockBox to see if a controller will be skipped\r
+    // during S3 resume.\r
+    //\r
+    if ((BootMode == BOOT_ON_S3_RESUME) &&\r
+        (NvmeS3SkipThisController (DevicePath, DevicePathLength))) {\r
+      DEBUG ((\r
+        DEBUG_ERROR, "%a: Controller %d is skipped during S3.\n",\r
+        __FUNCTION__, Controller\r
+        ));\r
+      Controller++;\r
+      continue;\r
+    }\r
+\r
     //\r
     // Memory allocation for controller private data\r
     //\r
index 89666160a19652c582c5f51da6ba880d77109d05..74e2daf511090a196dea359fca5c7c81251cffa8 100644 (file)
@@ -266,6 +266,26 @@ NvmePeimEndOfPei (
   IN VOID                       *Ppi\r
   );\r
 \r
+/**\r
+  Get the size of the current device path instance.\r
+\r
+  @param[in]  DevicePath             A pointer to the EFI_DEVICE_PATH_PROTOCOL\r
+                                     structure.\r
+  @param[out] InstanceSize           The size of the current device path instance.\r
+  @param[out] EntireDevicePathEnd    Indicate whether the instance is the last\r
+                                     one in the device path strucure.\r
+\r
+  @retval EFI_SUCCESS    The size of the current device path instance is fetched.\r
+  @retval Others         Fails to get the size of the current device path instance.\r
+\r
+**/\r
+EFI_STATUS\r
+GetDevicePathInstanceSize (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath,\r
+  OUT UINTN                       *InstanceSize,\r
+  OUT BOOLEAN                     *EntireDevicePathEnd\r
+  );\r
+\r
 /**\r
   Check the validity of the device path of a NVM Express host controller.\r
 \r
@@ -309,4 +329,20 @@ NvmeBuildDevicePath (
   OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath\r
   );\r
 \r
+/**\r
+  Determine if a specific NVM Express controller can be skipped for S3 phase.\r
+\r
+  @param[in]  HcDevicePath          Device path of the controller.\r
+  @param[in]  HcDevicePathLength    Length of the device path specified by\r
+                                    HcDevicePath.\r
+\r
+  @retval    The number of ports that need to be enumerated.\r
+\r
+**/\r
+BOOLEAN\r
+NvmeS3SkipThisController (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL    *HcDevicePath,\r
+  IN  UINTN                       HcDevicePathLength\r
+  );\r
+\r
 #endif\r
index 0666e5892bb8d8b115b0b2c98f8d6cbbb50c78ac..22b703e9714120295338fe2dc79563165aecefee 100644 (file)
@@ -40,6 +40,7 @@
   NvmExpressPeiHci.h\r
   NvmExpressPeiPassThru.c\r
   NvmExpressPeiPassThru.h\r
+  NvmExpressPeiS3.c\r
   NvmExpressPeiStorageSecurity.c\r
   NvmExpressPeiStorageSecurity.h\r
 \r
@@ -54,6 +55,7 @@
   BaseMemoryLib\r
   IoLib\r
   TimerLib\r
+  LockBoxLib\r
   PeimEntryPoint\r
 \r
 [Ppis]\r
   gEfiPeiVirtualBlockIo2PpiGuid                  ## SOMETIMES_PRODUCES\r
   gEdkiiPeiStorageSecurityCommandPpiGuid         ## SOMETIMES_PRODUCES\r
 \r
+[Guids]\r
+  gS3StorageDeviceInitListGuid                   ## SOMETIMES_CONSUMES ## UNDEFINED\r
+\r
 [Depex]\r
   gEfiPeiMemoryDiscoveredPpiGuid AND\r
-  gEdkiiPeiNvmExpressHostControllerPpiGuid\r
+  gEdkiiPeiNvmExpressHostControllerPpiGuid AND\r
+  gEfiPeiMasterBootModePpiGuid\r
 \r
 [UserExtensions.TianoCore."ExtraFiles"]\r
   NvmExpressPeiExtra.uni\r
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPeiS3.c
new file mode 100644 (file)
index 0000000..eb3af75
--- /dev/null
@@ -0,0 +1,114 @@
+/** @file\r
+  The NvmExpressPei driver is used to manage non-volatile memory subsystem\r
+  which follows NVM Express specification at PEI phase.\r
+\r
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions\r
+  of the BSD License which accompanies this distribution.  The\r
+  full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "NvmExpressPei.h"\r
+\r
+#include <Guid/S3StorageDeviceInitList.h>\r
+\r
+#include <Library/LockBoxLib.h>\r
+\r
+/**\r
+  Determine if a specific NVM Express controller can be skipped for S3 phase.\r
+\r
+  @param[in]  HcDevicePath          Device path of the controller.\r
+  @param[in]  HcDevicePathLength    Length of the device path specified by\r
+                                    HcDevicePath.\r
+\r
+  @retval    The number of ports that need to be enumerated.\r
+\r
+**/\r
+BOOLEAN\r
+NvmeS3SkipThisController (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL    *HcDevicePath,\r
+  IN  UINTN                       HcDevicePathLength\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  UINT8                       DummyData;\r
+  UINTN                       S3InitDevicesLength;\r
+  EFI_DEVICE_PATH_PROTOCOL    *S3InitDevices;\r
+  EFI_DEVICE_PATH_PROTOCOL    *DevicePathInst;\r
+  UINTN                       DevicePathInstLength;\r
+  BOOLEAN                     EntireEnd;\r
+  BOOLEAN                     Skip;\r
+\r
+  //\r
+  // From the LockBox, get the list of device paths for devices need to be\r
+  // initialized in S3.\r
+  //\r
+  S3InitDevices       = NULL;\r
+  S3InitDevicesLength = sizeof (DummyData);\r
+  EntireEnd           = FALSE;\r
+  Skip                = TRUE;\r
+  Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, &DummyData, &S3InitDevicesLength);\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    return Skip;\r
+  } else {\r
+    S3InitDevices = AllocatePool (S3InitDevicesLength);\r
+    if (S3InitDevices == NULL) {\r
+      return Skip;\r
+    }\r
+\r
+    Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, S3InitDevices, &S3InitDevicesLength);\r
+    if (EFI_ERROR (Status)) {\r
+      return Skip;\r
+    }\r
+  }\r
+\r
+  if (S3InitDevices == NULL) {\r
+    return Skip;\r
+  }\r
+\r
+  //\r
+  // Only need to initialize the controllers that exist in the device list.\r
+  //\r
+  do {\r
+    //\r
+    // Fetch the size of current device path instance.\r
+    //\r
+    Status = GetDevicePathInstanceSize (\r
+               S3InitDevices,\r
+               &DevicePathInstLength,\r
+               &EntireEnd\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    DevicePathInst = S3InitDevices;\r
+    S3InitDevices  = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN) S3InitDevices + DevicePathInstLength);\r
+\r
+    if (HcDevicePathLength >= DevicePathInstLength) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Compare the device paths to determine if the device is managed by this\r
+    // controller.\r
+    //\r
+    if (CompareMem (\r
+          DevicePathInst,\r
+          HcDevicePath,\r
+          HcDevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)\r
+          ) == 0) {\r
+      Skip = FALSE;\r
+      break;\r
+    }\r
+  } while (!EntireEnd);\r
+\r
+  return Skip;\r
+}\r