summaryrefslogtreecommitdiffstats
path: root/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiS3.c
blob: 42e4203a22984c627b01085dd22e26c7eae6eedc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/** @file
  The AhciPei driver is used to manage ATA hard disk device working under AHCI
  mode at PEI phase.

  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "AhciPei.h"

#include <Guid/S3StorageDeviceInitList.h>

#include <Library/LockBoxLib.h>

/**
  Collect the ports that need to be enumerated on a controller for S3 phase.

  @param[in]  HcDevicePath          Device path of the controller.
  @param[in]  HcDevicePathLength    Length of the device path specified by
                                    HcDevicePath.
  @param[out] PortBitMap            Bitmap that indicates the ports that need
                                    to be enumerated on the controller.

  @retval    The number of ports that need to be enumerated.

**/
UINT8
AhciS3GetEumeratePorts (
  IN  EFI_DEVICE_PATH_PROTOCOL  *HcDevicePath,
  IN  UINTN                     HcDevicePathLength,
  OUT UINT32                    *PortBitMap
  )
{
  EFI_STATUS                Status;
  UINT8                     DummyData;
  UINTN                     S3InitDevicesLength;
  EFI_DEVICE_PATH_PROTOCOL  *S3InitDevices;
  EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;
  UINTN                     DevicePathInstLength;
  BOOLEAN                   EntireEnd;
  SATA_DEVICE_PATH          *SataDeviceNode;

  *PortBitMap = 0;

  //
  // From the LockBox, get the list of device paths for devices need to be
  // initialized in S3.
  //
  S3InitDevices       = NULL;
  S3InitDevicesLength = sizeof (DummyData);
  EntireEnd           = FALSE;
  Status              = RestoreLockBox (&gS3StorageDeviceInitListGuid, &DummyData, &S3InitDevicesLength);
  if (Status != EFI_BUFFER_TOO_SMALL) {
    return 0;
  } else {
    S3InitDevices = AllocatePool (S3InitDevicesLength);
    if (S3InitDevices == NULL) {
      return 0;
    }

    Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, S3InitDevices, &S3InitDevicesLength);
    if (EFI_ERROR (Status)) {
      return 0;
    }
  }

  if (S3InitDevices == NULL) {
    return 0;
  }

  //
  // Only enumerate the ports 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)
    {
      //
      // Get the port number.
      //
      while (DevicePathInst->Type != END_DEVICE_PATH_TYPE) {
        if ((DevicePathInst->Type == MESSAGING_DEVICE_PATH) &&
            (DevicePathInst->SubType == MSG_SATA_DP))
        {
          SataDeviceNode = (SATA_DEVICE_PATH *)DevicePathInst;
          //
          // For now, the driver only support upto AHCI_MAX_PORTS ports and
          // devices directly connected to a HBA.
          //
          if ((SataDeviceNode->HBAPortNumber >= AHCI_MAX_PORTS) ||
              (SataDeviceNode->PortMultiplierPortNumber != 0xFFFF))
          {
            break;
          }

          *PortBitMap |= (UINT32)BIT0 << SataDeviceNode->HBAPortNumber;
          break;
        }

        DevicePathInst = NextDevicePathNode (DevicePathInst);
      }
    }
  } while (!EntireEnd);

  //
  // Return the number of ports need to be enumerated on this controller.
  //
  return AhciGetNumberOfPortsFromMap (*PortBitMap);
}