hc
2024-03-22 a0752693d998599af469473b8dc239ef973a012f
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/** @file
 
  @copyright
  Copyright 1999 - 2021 Intel Corporation. <BR>
 
  SPDX-License-Identifier: BSD-2-Clause-Patent
**/
 
#include <Guid/SocketPciResourceData.h>
#include <Guid/SocketIioVariable.h>
#include <Protocol/IioUds.h>
 
#include "PciHostBridge.h"
#include "PciRootBridge.h"
#include "PciRebalance.h"
 
 
extern EFI_IIO_UDS_PROTOCOL *mIioUds;
 
 
/**
  Adjust resource assignments among sockets to fit the high
  MMIO resources (64-bit addresses, typically above 4GB) from
  the PCI(e) devices in the system
 
  @param[in,out] SocketResources - CPU_RESOURCE structure pointer that stores all resources need per socket
  @param[in]     ResourceType    - Type of resource that requires alignment
  @param[in]     ValidSockets    - Number of Valid Sockets, need it to calculate how resources need to be splitted
 
  @retval EFI_SUCCESS            -  Succeed.
  @retval EFI_OUT_OF_RESOURCES   -  Not enough resources to be adjusted within the socket.
 */
EFI_STATUS
AdjustSocketMmioH (
  IN OUT CPU_RESOURCE *SocketResources,
  IN     UINT8         ResourceType,
  IN     UINT8         ValidSockets
  )
{
  CONST UINT8 LastSocket = ValidSockets - 1;
  UINT8       Socket;
  UINT8       Stack;
  UINT8       LastStack;
  UINT64      Take;
  UINT32      UboxMmioSize;
  UINT64      UnAllocatedMmioh;
  UINT64      MaxMmioh;
  UINT64      ResourceSize;
  UINT64      TotalResourceSize;
  UINT64      TempMmioBase;
  UINT64      TempMmioLimit;
 
  Take = 0;
  UboxMmioSize = mIioUds->IioUdsPtr->PlatformData.UboxMmioSize;
  UnAllocatedMmioh = 0;
  //
  // Get first and last IO base address
  //
  TempMmioBase  = mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio64Base;
  TempMmioLimit = mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio64Limit;
 
  // Find all the extra space left
  for (Socket = 0; Socket < ValidSockets; Socket ++) {
    if ((SocketResources[Socket].MmiohResourceNeeds == 0) && (SocketResources[Socket].MmiohResourcesLeft != 0)) {
 
      Take += SocketResources[Socket].MmiohResourcesLeft + 1;
      SocketResources[Socket].MmiohResourcesLeft = 0;
    }
  }
 
  MaxMmioh = (UINT64) mIioUds->IioUdsPtr->PlatformData.MmiohGranularity.lo;
  MaxMmioh |= ((UINT64) mIioUds->IioUdsPtr->PlatformData.MmiohGranularity.hi) << 32;
  //
  // Maximum chunk accessible in the system based on the given granularity
  //
  if (UboxMmioSize == 0) {
    MaxMmioh = MaxMmioh * 32; //for 14nm
  } else {
    MaxMmioh = ((UINT64) 1 << mIioUds->IioUdsPtr->PlatformData.MaxAddressBits);
  }
 
  //
  // Find out how much MMIOH has not been allocated
  //
  if (MaxMmioh > (TempMmioLimit - TempMmioBase)) {
    UnAllocatedMmioh = MaxMmioh - (TempMmioLimit - TempMmioBase) - 1;
  } else {
    //
    // Extra MMIOH is not enough to close the gap for a successful adjustment.
    // Use all extra MMIOH in case if only a small amount is needed for adjustment or
    // the granularity was reduced due to MMIOH base.
    // (14nm only) or remove if map is rejected for this case to start over with correct values.
    // (10nm only) does not have this problem and doesn't need the code below because the limit is removed and we can use max address lines.
    //
    Take += MaxMmioh;
  }
 
  // Give space to sockets that needs more space favoring first come first served
  for (Socket = 0; Socket < ValidSockets; Socket ++) {
    if ((SocketResources[Socket].MmiohResourceNeeds != 0) && (Take >= SocketResources[Socket].MmiohResourceNeeds)) {
      //
      // The socket requesting additional resources can be granted by using the already
      // allocated range given to the whole system originally.
      //
      Take -= SocketResources[Socket].MmiohResourceNeeds;
      DEBUG ((DEBUG_ERROR, "SocketResources[%x].MmiohResourceNeeds = %llX\n",Socket, SocketResources[Socket].MmiohResourceNeeds));
      SocketResources[Socket].MmiohResourceNeeds = 0;
    } else if ((SocketResources[Socket].MmiohResourceNeeds != 0) &&
               (Take < SocketResources[Socket].MmiohResourceNeeds) &&
               ((UnAllocatedMmioh + Take) >= SocketResources[Socket].MmiohResourceNeeds)) {
      //
      // Apply unallocated Mmioh to the socket that requires more to satisfy its request
      // that's outside the allocated range given to the whole system originally.
      //
      SocketResources[Socket].MmiohResourceNeeds -= Take;
      UnAllocatedMmioh -= SocketResources[Socket].MmiohResourceNeeds;
      DEBUG ((DEBUG_INFO, "SocketResources[%x].MmiohResourceNeeds = %llX\n", Socket, SocketResources[Socket].MmiohResourceNeeds));
      DEBUG ((DEBUG_INFO, "Unallocated MMIOH left = %llX\n", UnAllocatedMmioh));
      SocketResources[Socket].MmiohResourceNeeds = 0;
    }
  }
  //
  // Give away leftover resources
  //
  LastStack = LastStackOfSocket (LastSocket);
  if (Take != 0) {
    if (SocketResources[LastSocket].StackRes[LastStack].MmiohLength != 0) {
      SocketResources[LastSocket].StackRes[LastStack].MmiohLength += Take;
    } else{
      SocketResources[LastSocket].StackRes[LastStack].MmiohLength += (Take - 1);
    }
  }
  //
  // Verify all resource requested can fit into the systems address range.
  //
  TotalResourceSize = 0;
  for (Socket = 0; Socket < ValidSockets; Socket++) {
    LastStackWithResources (&SocketResources[Socket], Socket, ResourceType, &LastStack, &ResourceSize);
    TotalResourceSize += ResourceSize;
  }
  DEBUG ((DEBUG_INFO, "MaxMmioh                 = %016llXh\n", MaxMmioh));
  DEBUG ((DEBUG_INFO, "Total Request MMIOH Range= %016llXh\n", TotalResourceSize));
  DEBUG ((DEBUG_INFO, "Total System MMIOH Range = %016llXh\n", (MaxMmioh - TempMmioBase)));
  if (TotalResourceSize > MaxMmioh) {
    //
    // Not enough system resources to support the request.
    // Remove all request to update NVRAM variable for this resource type.
    //
    for (Socket = 0; Socket < ValidSockets; Socket ++) {
      for (Stack = 0; Stack < MAX_IIO_STACK; Stack ++) {
        if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
          continue;
        }
        SocketResources[Socket].StackRes[Stack].MmiohUpdate = 0;
      }
    }
    DEBUG ((DEBUG_ERROR, "[PCI] ERROR: Out of adjustable MMIOH resources. Can't adjust across sockets\n"));
    return EFI_OUT_OF_RESOURCES;
  }
 
  DEBUG ((DEBUG_ERROR, "Assigning new socket MMIOH range...\n"));
  for (Socket = 0, TempMmioLimit = TempMmioBase - 1; Socket < ValidSockets; Socket++) {
 
    SocketResources[Socket].MmiohBase = TempMmioLimit + 1;
    //
    // Update the stacks base and limit values.
    //
    for (Stack = 0; Stack < MAX_IIO_STACK; Stack++) {
 
      if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
 
       SocketResources[Socket].StackRes[Stack].MmiohBase = 0;
       SocketResources[Socket].StackRes[Stack].MmiohLimit = 0;
 
      } else {
 
        SocketResources[Socket].StackRes[Stack].MmiohBase = TempMmioLimit + 1;
        if (SocketResources[Socket].StackRes[Stack].MmiohLength != 0) {
          //
          // MmiohLength is actually length-1, so we should move TempMmioLimit by MmiohLength+1,
          // but only when it is >0, i.e. only for stack that has resources.
          //
          TempMmioLimit += SocketResources[Socket].StackRes[Stack].MmiohLength + 1;
          SocketResources[Socket].StackRes[Stack].MmiohLimit = TempMmioLimit;
 
        } else {
 
          SocketResources[Socket].StackRes[Stack].MmiohLimit = SocketResources[Socket].StackRes[Stack].MmiohBase;
        }
        SocketResources[Socket].StackRes[Stack].MmiohUpdate = 1;
      }
      DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiohBase  = %llX   newLength = %llX\n", Socket, Stack,
              SocketResources[Socket].StackRes[Stack].MmiohBase, SocketResources[Socket].StackRes[Stack].MmiohLength));
      DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiohLimit = %llX\n", Socket, Stack,
              SocketResources[Socket].StackRes[Stack].MmiohLimit));
      DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiohUpdate= %d\n", Socket, Stack,
              SocketResources[Socket].StackRes[Stack].MmiohUpdate));
    } // for (Stack...)
 
    SocketResources[Socket].MmiohLimit = TempMmioLimit;
  } // for (Socket...)
  return EFI_SUCCESS;
}