/** @file @copyright Copyright 1999 - 2021 Intel Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #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; }