/** @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;
|
|
/**
|
Return TRUE if the specified socket/stack combination exists,
|
otherwise return FALSE
|
|
@param Socket - the socket to be checked
|
@param Stack - the stack of the socket to be checked
|
|
@retval TRUE - the socket/stack combination exists
|
@retval FALSE - the socket/stack combination does not exist
|
*/
|
STATIC BOOLEAN
|
IsStackPresent (
|
UINT8 Socket,
|
UINT8 Stack
|
)
|
{
|
BOOLEAN Result;
|
UINT64 Mask;
|
|
ASSERT (Socket < ARRAY_SIZE (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo)); // simple overrun check
|
if (Socket >= ARRAY_SIZE (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo)) {
|
Result = FALSE;
|
goto err_exit;
|
}
|
|
//
|
// if the StackPresentBitmap is a single byte, then we can track 8 stacks,
|
// the sizeof will tell us how many bytes we have, we scale by 8 to
|
// determine the maximum number of stacks we can track. Stacks larger
|
// than this are not present essentially by definition, but could also
|
// be a sign that we need a wider type to store the information; hence we
|
// assert
|
//
|
ASSERT (Stack < 8 * sizeof(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[0].stackPresentBitmap));
|
if (Stack >= 8 * sizeof(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[0].stackPresentBitmap)) {
|
Result = FALSE;
|
goto err_exit;
|
}
|
|
Mask = 1;
|
Mask <<= Stack;
|
Result = (Mask & mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap) != 0;
|
|
err_exit:
|
return Result;
|
}
|
|
|
/**
|
Adjust resource assignment among sockets to fit the IO
|
resources from the PCI() devices in the system
|
|
@param SocketResources - CPU_RESOURCE structure pointer that stores all resources need per socket
|
@param ResourceType - type of resource that requires alignment
|
@param ValidSockets - Number of Valid Sockets, need it
|
to calculate how resources need to
|
be split
|
|
@retval EFI_SUCCESS - Succeed.
|
@retval EFI_OUT_OF_RESOURCES - Not enough resources to be adjusted within the socket.
|
**/
|
EFI_STATUS
|
AdjustSocketIo (
|
CPU_RESOURCE *SocketResources,
|
UINT8 ResourceType,
|
UINT8 ValidSockets
|
)
|
{
|
UINT64 Base; ///< Next base I/O port number to use
|
UINT64 Limit; ///< Most recent limit for I/O port numbers
|
CONST UINT64 MaxLimit = ((UINT64)1 << 16) - 1; ///< Maximum value for limit; used to ensure we don't overflow
|
CPU_RESOURCE *CurSocketResources; ///< Pointer to the CPU_RESOURE structure for the CPU we
|
///< are examining
|
STACK_RESOURCE *CurStackResources; ///< Pointer to the STACK_RESOURCE structure for the CPU/Stack
|
///< we are examining
|
UINT16 NumFreePorts; ///< Number of i/o ports allocated to sockets that are not used
|
UINT8 LastStack; ///< Last enabled stack of the last enabled socket
|
CONST UINT8 LastSocketIndex = ValidSockets - 1; ///< Index of the last socket
|
UINT64 TotalResourceSize;
|
UINT64 ResourceSize;
|
UINT8 Socket; ///< Loop variable used to iterate over the sockets
|
UINT8 Stack; ///< Loop variable used to iterate over the stacks of a given socket
|
|
NumFreePorts = 0;
|
for (Socket = 0; Socket < ValidSockets; Socket++) {
|
CurSocketResources = &SocketResources[Socket];
|
if (CurSocketResources->IoResourceNeeds == 0 && CurSocketResources->IoResourcesLeft != 0) {
|
ASSERT (NumFreePorts < NumFreePorts + CurSocketResources->IoResourcesLeft + 1); // check for overflow
|
NumFreePorts += CurSocketResources->IoResourcesLeft + 1;
|
CurSocketResources->IoResourcesLeft = 0;
|
}
|
}
|
|
for (Socket = 0; Socket < ValidSockets; Socket++) {
|
CurSocketResources = &SocketResources[Socket];
|
if (CurSocketResources->IoResourceNeeds != 0 && NumFreePorts >= CurSocketResources->IoResourceNeeds) {
|
ASSERT (NumFreePorts > NumFreePorts - CurSocketResources->IoResourceNeeds); // check for underflow
|
NumFreePorts -= CurSocketResources->IoResourceNeeds;
|
CurSocketResources->IoResourceNeeds = 0;
|
}
|
}
|
|
LastStack = LastStackOfSocket (LastSocketIndex);
|
|
if (NumFreePorts > 0) {
|
CurStackResources = &SocketResources[LastSocketIndex].StackRes[LastStack];
|
if (CurStackResources->NumIoPortsDesired != 0) {
|
CurStackResources->NumIoPortsDesired += NumFreePorts;
|
} else {
|
CurStackResources->NumIoPortsDesired += NumFreePorts - 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, "Total Request IO Range = %xh\n", TotalResourceSize));
|
DEBUG ((DEBUG_INFO, "Total System IO Range = %xh\n", MaxLimit));
|
if (TotalResourceSize > MaxLimit) {
|
//
|
// 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].NeedIoUpdate = 0;
|
}
|
}
|
DEBUG ((DEBUG_ERROR, "ERROR: Out of adjustable IO resources. Can't adjust across sockets\n"));
|
return EFI_OUT_OF_RESOURCES;
|
}
|
|
DEBUG((DEBUG_ERROR, "Assigning new socket i/o range...\n"));
|
|
Base = mIioUds->IioUdsPtr->PlatformData.IIO_resource[0].PciResourceIoBase;
|
Limit = Base; // assume no resources are allocated
|
for (Socket = 0, CurSocketResources = SocketResources; Socket < ValidSockets; Socket++, CurSocketResources++) {
|
DEBUG ((DEBUG_INFO, "socket = %d, Base = %x, Limit =%x, MaxLimit = %x\n", Socket, Base, Limit, MaxLimit));
|
ASSERT (Base < MaxLimit);
|
CurSocketResources->IoBase = (UINT16)Base;
|
DEBUG ((DEBUG_INFO, "set socket io base to %x\n", Base));
|
|
for (Stack = 0, CurStackResources = CurSocketResources->StackRes;
|
Stack < MAX_IIO_STACK;
|
Stack++, CurStackResources++) {
|
if (!IsStackPresent (Socket, Stack)) {
|
DEBUG ((DEBUG_INFO, " Stack %d not present, setting base/limit to 0xffff/0\n", Stack));
|
CurStackResources->IoBase = 0xffff;
|
CurStackResources->IoLimit = 0;
|
continue;
|
}
|
|
if (CurStackResources->NumIoPortsDesired == 0) {
|
DEBUG ((DEBUG_INFO, " Stack %d doesn't need i/o resources, setting base/limit to 0xffff/0\n", Stack));
|
CurStackResources->IoBase = 0xffff;
|
CurStackResources->IoLimit = 0;
|
CurStackResources->NeedIoUpdate = TRUE;
|
continue;
|
}
|
|
DEBUG((DEBUG_INFO, " Stack %d setting i/o base to %x, ports desired was %x\n",
|
Stack, Base, CurStackResources->NumIoPortsDesired));
|
ASSERT (Base < MaxLimit);
|
CurStackResources->IoBase = (UINT16)Base;
|
Limit = Base + CurStackResources->NumIoPortsDesired;
|
DEBUG ((DEBUG_INFO, " limit set to %x (var and stack)\n", Limit));
|
ASSERT (Base <= Limit);
|
ASSERT (Limit <= MaxLimit);
|
CurStackResources->IoLimit = (UINT16)Limit;
|
CurStackResources->NeedIoUpdate = TRUE;
|
Base = Limit + 1;
|
DEBUG ((DEBUG_INFO, " Base variable updated to %x\n", Base));
|
}
|
ASSERT (Limit <= MaxLimit);
|
DEBUG ((DEBUG_INFO, " Socket %d limit set to %x\n", Socket, Limit));
|
CurSocketResources->IoLimit = (UINT16)Limit;
|
}
|
|
DEBUG ((DEBUG_INFO, "Dumping new I/O requests\n"));
|
for (Socket = 0, CurSocketResources = SocketResources; Socket < ValidSockets; Socket++, CurSocketResources++) {
|
DEBUG((DEBUG_INFO, "socket %d %x/%x\n", Socket, CurSocketResources->IoBase, CurSocketResources->IoLimit));
|
for (Stack = 0, CurStackResources = CurSocketResources->StackRes;
|
Stack < MAX_IIO_STACK;
|
Stack++, CurStackResources++) {
|
DEBUG ((DEBUG_INFO, "%d/%d: %x/%x\n", Socket, Stack, CurStackResources->IoBase, CurStackResources->IoLimit));
|
}
|
}
|
|
return EFI_SUCCESS;
|
}
|
|