PciRebalanceIo.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /** @file
  2. @copyright
  3. Copyright 1999 - 2021 Intel Corporation. <BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Guid/SocketPciResourceData.h>
  7. #include <Guid/SocketIioVariable.h>
  8. #include <Protocol/IioUds.h>
  9. #include "PciHostBridge.h"
  10. #include "PciRootBridge.h"
  11. #include "PciRebalance.h"
  12. extern EFI_IIO_UDS_PROTOCOL *mIioUds;
  13. /**
  14. Return TRUE if the specified socket/stack combination exists,
  15. otherwise return FALSE
  16. @param Socket - the socket to be checked
  17. @param Stack - the stack of the socket to be checked
  18. @retval TRUE - the socket/stack combination exists
  19. @retval FALSE - the socket/stack combination does not exist
  20. */
  21. STATIC BOOLEAN
  22. IsStackPresent (
  23. UINT8 Socket,
  24. UINT8 Stack
  25. )
  26. {
  27. BOOLEAN Result;
  28. UINT64 Mask;
  29. ASSERT (Socket < ARRAY_SIZE (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo)); // simple overrun check
  30. if (Socket >= ARRAY_SIZE (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo)) {
  31. Result = FALSE;
  32. goto err_exit;
  33. }
  34. //
  35. // if the StackPresentBitmap is a single byte, then we can track 8 stacks,
  36. // the sizeof will tell us how many bytes we have, we scale by 8 to
  37. // determine the maximum number of stacks we can track. Stacks larger
  38. // than this are not present essentially by definition, but could also
  39. // be a sign that we need a wider type to store the information; hence we
  40. // assert
  41. //
  42. ASSERT (Stack < 8 * sizeof(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[0].stackPresentBitmap));
  43. if (Stack >= 8 * sizeof(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[0].stackPresentBitmap)) {
  44. Result = FALSE;
  45. goto err_exit;
  46. }
  47. Mask = 1;
  48. Mask <<= Stack;
  49. Result = (Mask & mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap) != 0;
  50. err_exit:
  51. return Result;
  52. }
  53. /**
  54. Adjust resource assignment among sockets to fit the IO
  55. resources from the PCI() devices in the system
  56. @param SocketResources - CPU_RESOURCE structure pointer that stores all resources need per socket
  57. @param ResourceType - type of resource that requires alignment
  58. @param ValidSockets - Number of Valid Sockets, need it
  59. to calculate how resources need to
  60. be split
  61. @retval EFI_SUCCESS - Succeed.
  62. @retval EFI_OUT_OF_RESOURCES - Not enough resources to be adjusted within the socket.
  63. **/
  64. EFI_STATUS
  65. AdjustSocketIo (
  66. CPU_RESOURCE *SocketResources,
  67. UINT8 ResourceType,
  68. UINT8 ValidSockets
  69. )
  70. {
  71. UINT64 Base; ///< Next base I/O port number to use
  72. UINT64 Limit; ///< Most recent limit for I/O port numbers
  73. CONST UINT64 MaxLimit = ((UINT64)1 << 16) - 1; ///< Maximum value for limit; used to ensure we don't overflow
  74. CPU_RESOURCE *CurSocketResources; ///< Pointer to the CPU_RESOURE structure for the CPU we
  75. ///< are examining
  76. STACK_RESOURCE *CurStackResources; ///< Pointer to the STACK_RESOURCE structure for the CPU/Stack
  77. ///< we are examining
  78. UINT16 NumFreePorts; ///< Number of i/o ports allocated to sockets that are not used
  79. UINT8 LastStack; ///< Last enabled stack of the last enabled socket
  80. CONST UINT8 LastSocketIndex = ValidSockets - 1; ///< Index of the last socket
  81. UINT64 TotalResourceSize;
  82. UINT64 ResourceSize;
  83. UINT8 Socket; ///< Loop variable used to iterate over the sockets
  84. UINT8 Stack; ///< Loop variable used to iterate over the stacks of a given socket
  85. NumFreePorts = 0;
  86. for (Socket = 0; Socket < ValidSockets; Socket++) {
  87. CurSocketResources = &SocketResources[Socket];
  88. if (CurSocketResources->IoResourceNeeds == 0 && CurSocketResources->IoResourcesLeft != 0) {
  89. ASSERT (NumFreePorts < NumFreePorts + CurSocketResources->IoResourcesLeft + 1); // check for overflow
  90. NumFreePorts += CurSocketResources->IoResourcesLeft + 1;
  91. CurSocketResources->IoResourcesLeft = 0;
  92. }
  93. }
  94. for (Socket = 0; Socket < ValidSockets; Socket++) {
  95. CurSocketResources = &SocketResources[Socket];
  96. if (CurSocketResources->IoResourceNeeds != 0 && NumFreePorts >= CurSocketResources->IoResourceNeeds) {
  97. ASSERT (NumFreePorts > NumFreePorts - CurSocketResources->IoResourceNeeds); // check for underflow
  98. NumFreePorts -= CurSocketResources->IoResourceNeeds;
  99. CurSocketResources->IoResourceNeeds = 0;
  100. }
  101. }
  102. LastStack = LastStackOfSocket (LastSocketIndex);
  103. if (NumFreePorts > 0) {
  104. CurStackResources = &SocketResources[LastSocketIndex].StackRes[LastStack];
  105. if (CurStackResources->NumIoPortsDesired != 0) {
  106. CurStackResources->NumIoPortsDesired += NumFreePorts;
  107. } else {
  108. CurStackResources->NumIoPortsDesired += NumFreePorts - 1;
  109. }
  110. }
  111. //
  112. // Verify all resource requested can fit into the systems address range.
  113. //
  114. TotalResourceSize = 0;
  115. for (Socket = 0; Socket < ValidSockets; Socket ++) {
  116. LastStackWithResources (&SocketResources[Socket], Socket, ResourceType, &LastStack, &ResourceSize);
  117. TotalResourceSize += ResourceSize;
  118. }
  119. DEBUG ((DEBUG_INFO, "Total Request IO Range = %xh\n", TotalResourceSize));
  120. DEBUG ((DEBUG_INFO, "Total System IO Range = %xh\n", MaxLimit));
  121. if (TotalResourceSize > MaxLimit) {
  122. //
  123. // Not enough system resources to support the request.
  124. // Remove all request to update NVRAM variable for this resource type.
  125. //
  126. for (Socket = 0; Socket < ValidSockets; Socket ++) {
  127. for (Stack = 0; Stack < MAX_IIO_STACK; Stack ++) {
  128. if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
  129. continue;
  130. }
  131. SocketResources[Socket].StackRes[Stack].NeedIoUpdate = 0;
  132. }
  133. }
  134. DEBUG ((DEBUG_ERROR, "ERROR: Out of adjustable IO resources. Can't adjust across sockets\n"));
  135. return EFI_OUT_OF_RESOURCES;
  136. }
  137. DEBUG((DEBUG_ERROR, "Assigning new socket i/o range...\n"));
  138. Base = mIioUds->IioUdsPtr->PlatformData.IIO_resource[0].PciResourceIoBase;
  139. Limit = Base; // assume no resources are allocated
  140. for (Socket = 0, CurSocketResources = SocketResources; Socket < ValidSockets; Socket++, CurSocketResources++) {
  141. DEBUG ((DEBUG_INFO, "socket = %d, Base = %x, Limit =%x, MaxLimit = %x\n", Socket, Base, Limit, MaxLimit));
  142. ASSERT (Base < MaxLimit);
  143. CurSocketResources->IoBase = (UINT16)Base;
  144. DEBUG ((DEBUG_INFO, "set socket io base to %x\n", Base));
  145. for (Stack = 0, CurStackResources = CurSocketResources->StackRes;
  146. Stack < MAX_IIO_STACK;
  147. Stack++, CurStackResources++) {
  148. if (!IsStackPresent (Socket, Stack)) {
  149. DEBUG ((DEBUG_INFO, " Stack %d not present, setting base/limit to 0xffff/0\n", Stack));
  150. CurStackResources->IoBase = 0xffff;
  151. CurStackResources->IoLimit = 0;
  152. continue;
  153. }
  154. if (CurStackResources->NumIoPortsDesired == 0) {
  155. DEBUG ((DEBUG_INFO, " Stack %d doesn't need i/o resources, setting base/limit to 0xffff/0\n", Stack));
  156. CurStackResources->IoBase = 0xffff;
  157. CurStackResources->IoLimit = 0;
  158. CurStackResources->NeedIoUpdate = TRUE;
  159. continue;
  160. }
  161. DEBUG((DEBUG_INFO, " Stack %d setting i/o base to %x, ports desired was %x\n",
  162. Stack, Base, CurStackResources->NumIoPortsDesired));
  163. ASSERT (Base < MaxLimit);
  164. CurStackResources->IoBase = (UINT16)Base;
  165. Limit = Base + CurStackResources->NumIoPortsDesired;
  166. DEBUG ((DEBUG_INFO, " limit set to %x (var and stack)\n", Limit));
  167. ASSERT (Base <= Limit);
  168. ASSERT (Limit <= MaxLimit);
  169. CurStackResources->IoLimit = (UINT16)Limit;
  170. CurStackResources->NeedIoUpdate = TRUE;
  171. Base = Limit + 1;
  172. DEBUG ((DEBUG_INFO, " Base variable updated to %x\n", Base));
  173. }
  174. ASSERT (Limit <= MaxLimit);
  175. DEBUG ((DEBUG_INFO, " Socket %d limit set to %x\n", Socket, Limit));
  176. CurSocketResources->IoLimit = (UINT16)Limit;
  177. }
  178. DEBUG ((DEBUG_INFO, "Dumping new I/O requests\n"));
  179. for (Socket = 0, CurSocketResources = SocketResources; Socket < ValidSockets; Socket++, CurSocketResources++) {
  180. DEBUG((DEBUG_INFO, "socket %d %x/%x\n", Socket, CurSocketResources->IoBase, CurSocketResources->IoLimit));
  181. for (Stack = 0, CurStackResources = CurSocketResources->StackRes;
  182. Stack < MAX_IIO_STACK;
  183. Stack++, CurStackResources++) {
  184. DEBUG ((DEBUG_INFO, "%d/%d: %x/%x\n", Socket, Stack, CurStackResources->IoBase, CurStackResources->IoLimit));
  185. }
  186. }
  187. return EFI_SUCCESS;
  188. }