]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AhciPei/AhciPeiS3.c
MdeModulePkg/AhciPei: Add AHCI mode ATA device support in PEI
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AhciPei / AhciPeiS3.c
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiS3.c b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiS3.c
new file mode 100644 (file)
index 0000000..3f77b97
--- /dev/null
@@ -0,0 +1,139 @@
+/** @file\r
+  The AhciPei driver is used to manage ATA hard disk device working under AHCI\r
+  mode 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 "AhciPei.h"\r
+\r
+#include <Guid/S3StorageDeviceInitList.h>\r
+\r
+#include <Library/LockBoxLib.h>\r
+\r
+/**\r
+  Collect the ports that need to be enumerated on a controller 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
+  @param[out] PortBitMap            Bitmap that indicates the ports that need\r
+                                    to be enumerated on the controller.\r
+\r
+  @retval    The number of ports that need to be enumerated.\r
+\r
+**/\r
+UINT8\r
+AhciS3GetEumeratePorts (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL    *HcDevicePath,\r
+  IN  UINTN                       HcDevicePathLength,\r
+  OUT UINT32                      *PortBitMap\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
+  SATA_DEVICE_PATH            *SataDeviceNode;\r
+\r
+  *PortBitMap = 0;\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
+  Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, &DummyData, &S3InitDevicesLength);\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    return 0;\r
+  } else {\r
+    S3InitDevices = AllocatePool (S3InitDevicesLength);\r
+    if (S3InitDevices == NULL) {\r
+      return 0;\r
+    }\r
+\r
+    Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, S3InitDevices, &S3InitDevicesLength);\r
+    if (EFI_ERROR (Status)) {\r
+      return 0;\r
+    }\r
+  }\r
+\r
+  if (S3InitDevices == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Only enumerate the ports 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
+      //\r
+      // Get the port number.\r
+      //\r
+      while (DevicePathInst->Type != END_DEVICE_PATH_TYPE) {\r
+        if ((DevicePathInst->Type == MESSAGING_DEVICE_PATH) &&\r
+            (DevicePathInst->SubType == MSG_SATA_DP)) {\r
+          SataDeviceNode = (SATA_DEVICE_PATH *) DevicePathInst;\r
+          //\r
+          // For now, the driver only support upto AHCI_MAX_PORTS ports and\r
+          // devices directly connected to a HBA.\r
+          //\r
+          if ((SataDeviceNode->HBAPortNumber >= AHCI_MAX_PORTS) ||\r
+              (SataDeviceNode->PortMultiplierPortNumber != 0xFFFF)) {\r
+            break;\r
+          }\r
+          *PortBitMap |= (UINT32)BIT0 << SataDeviceNode->HBAPortNumber;\r
+          break;\r
+        }\r
+        DevicePathInst = NextDevicePathNode (DevicePathInst);\r
+      }\r
+    }\r
+  } while (!EntireEnd);\r
+\r
+  //\r
+  // Return the number of ports need to be enumerated on this controller.\r
+  //\r
+  return AhciGetNumberOfPortsFromMap (*PortBitMap);\r
+}\r