AcpiSlit.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /** @file
  2. Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. **/
  5. #include "AcpiPlatform.h"
  6. #define MAX_NODES_PER_SOCKET 4
  7. #define SELF_DISTANCE 10
  8. #define REMOTE_DISTANCE 20
  9. EFI_ACPI_6_3_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER SLITTableHeaderTemplate = {
  10. __ACPI_HEADER (
  11. EFI_ACPI_6_3_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE,
  12. 0, /* need fill in */
  13. EFI_ACPI_6_3_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_REVISION
  14. ),
  15. 0,
  16. };
  17. VOID
  18. ComputeCoordinatesForNode (
  19. UINTN Node,
  20. UINTN *X,
  21. UINTN *Y
  22. )
  23. {
  24. switch (Node) {
  25. case 0:
  26. *X = 0;
  27. *Y = 0;
  28. break;
  29. case 1:
  30. *X = 1;
  31. *Y = 0;
  32. break;
  33. case 2:
  34. *X = 0;
  35. *Y = 1;
  36. break;
  37. case 3:
  38. *X = 1;
  39. *Y = 1;
  40. break;
  41. default:
  42. *X = 0;
  43. *Y = 0;
  44. break;
  45. }
  46. }
  47. /**
  48. Compute the distance between between two nodes on socket.
  49. **/
  50. UINT8
  51. ComputeSlitDistanceOnSocket (
  52. UINTN Node1,
  53. UINTN Node2
  54. )
  55. {
  56. UINTN X1, Y1, X2, Y2;
  57. UINTN XDistance, YDistance;
  58. ComputeCoordinatesForNode (Node1, &X1, &Y1);
  59. ComputeCoordinatesForNode (Node2, &X2, &Y2);
  60. XDistance = ABS ((INTN)(X1 - X2));
  61. YDistance = ABS ((INTN)(Y1 - Y2));
  62. return (UINT8)(XDistance + YDistance + SELF_DISTANCE);
  63. }
  64. /**
  65. Compute the distance between between two nodes on
  66. different sockets.
  67. Node1 - local socket node number
  68. Node2 - remote socket node number
  69. **/
  70. UINT8
  71. ComputeSlitDistanceOnRemoteSocket (
  72. UINTN LocalNode,
  73. UINTN RemoteNode
  74. )
  75. {
  76. UINTN LocalDistance, RemoteDistance;
  77. //
  78. // Mesh forwards traffic between sockets over both CCIX links when going from
  79. // one quadrant to another. For example, memory access from Node 0 to Node 4
  80. // results in traffic being split between RCA0 and 1. Hence distance is
  81. // different only between upper half and lower half of sockets and not
  82. // between quadrants. Hemisphere configuration is not impacted as there
  83. // is no upper-half.
  84. //
  85. LocalDistance = 0;
  86. RemoteDistance = 0;
  87. if (LocalNode >= (MAX_NODES_PER_SOCKET / 2)) {
  88. LocalDistance = 1;
  89. }
  90. if (RemoteNode >= (MAX_NODES_PER_SOCKET / 2)) {
  91. RemoteDistance = 1;
  92. }
  93. return (UINT8)(LocalDistance + RemoteDistance + REMOTE_DISTANCE);
  94. }
  95. UINT8
  96. ComputeSlitDistance (
  97. UINTN Node1,
  98. UINTN Node2,
  99. UINTN DomainsPerSocket
  100. )
  101. {
  102. UINT8 Distance;
  103. Distance = 0;
  104. if ((Node1 / DomainsPerSocket) == (Node2 / DomainsPerSocket)) {
  105. Distance = ComputeSlitDistanceOnSocket (
  106. Node1 % DomainsPerSocket,
  107. Node2 % DomainsPerSocket
  108. );
  109. } else {
  110. Distance = ComputeSlitDistanceOnRemoteSocket (
  111. Node1 % DomainsPerSocket,
  112. Node2 % DomainsPerSocket
  113. );
  114. }
  115. return Distance;
  116. }
  117. EFI_STATUS
  118. AcpiInstallSlitTable (
  119. VOID
  120. )
  121. {
  122. EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
  123. EFI_STATUS Status;
  124. UINTN NumDomain, Count, Count1;
  125. EFI_ACPI_6_3_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER *SlitTablePointer;
  126. UINT8 *TmpPtr;
  127. UINTN SlitTableKey;
  128. UINTN NumDomainPerSocket;
  129. Status = gBS->LocateProtocol (
  130. &gEfiAcpiTableProtocolGuid,
  131. NULL,
  132. (VOID **)&AcpiTableProtocol
  133. );
  134. if (EFI_ERROR (Status)) {
  135. return Status;
  136. }
  137. NumDomainPerSocket = CpuGetNumberOfSubNumaRegion ();
  138. NumDomain = NumDomainPerSocket * GetNumberOfActiveSockets ();
  139. SlitTablePointer = (EFI_ACPI_6_3_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER *)
  140. AllocateZeroPool (sizeof (SLITTableHeaderTemplate) + NumDomain * NumDomain);
  141. if (SlitTablePointer == NULL) {
  142. return EFI_OUT_OF_RESOURCES;
  143. }
  144. CopyMem ((VOID *)SlitTablePointer, (VOID *)&SLITTableHeaderTemplate, sizeof (SLITTableHeaderTemplate));
  145. SlitTablePointer->NumberOfSystemLocalities = NumDomain;
  146. TmpPtr = (UINT8 *)SlitTablePointer + sizeof (SLITTableHeaderTemplate);
  147. for (Count = 0; Count < NumDomain; Count++) {
  148. for (Count1 = 0; Count1 < NumDomain; Count1++, TmpPtr++) {
  149. *TmpPtr = ComputeSlitDistance (Count, Count1, NumDomainPerSocket);
  150. }
  151. }
  152. SlitTablePointer->Header.Length = sizeof (SLITTableHeaderTemplate) + NumDomain * NumDomain;
  153. AcpiUpdateChecksum ((UINT8 *)SlitTablePointer, SlitTablePointer->Header.Length);
  154. Status = AcpiTableProtocol->InstallAcpiTable (
  155. AcpiTableProtocol,
  156. (VOID *)SlitTablePointer,
  157. SlitTablePointer->Header.Length,
  158. &SlitTableKey
  159. );
  160. FreePool ((VOID *)SlitTablePointer);
  161. return Status;
  162. }