AcpiPlatformLibSlit.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146
  1. /** @file
  2. ACPI Platform Driver Hooks
  3. @copyright
  4. Copyright 1996 - 2020 Intel Corporation. <BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. //
  8. // Statements that include other files
  9. //
  10. #include "AcpiPlatformLibLocal.h"
  11. extern SYSTEM_MEMORY_MAP_HOB *mSystemMemoryMap;
  12. extern EFI_IIO_UDS_PROTOCOL *mIioUds;
  13. extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTable;
  14. extern CPU_CSR_ACCESS_VAR *mCpuCsrAccessVarPtr;
  15. EFI_ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE_PMEM_INFO mSlitPmemInfo[EFI_ACPI_SLIT_PMEM_INFO_CNT];
  16. /**
  17. Displays System Locality Distance Information Table (SLIT)
  18. @param None
  19. @retval None
  20. **/
  21. VOID
  22. DisplayEntries (
  23. IN ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitPtr
  24. )
  25. {
  26. UINT16 EntryIdx = 0;
  27. UINT16 MaxTableEntries;
  28. UINT8 NodeCount;
  29. if (SlitPtr == NULL) {
  30. ASSERT (SlitPtr != NULL);
  31. return;
  32. }
  33. NodeCount = (UINT8)SlitPtr->Header.NumberOfSystemLocalities;
  34. MaxTableEntries = NodeCount * NodeCount;
  35. DEBUG ((DEBUG_INFO, "SLIT: Dump table (size %d):\n", NodeCount));
  36. while (EntryIdx < MaxTableEntries) {
  37. DEBUG ((DEBUG_INFO, "%02X ", SlitPtr->NumSlit[EntryIdx].Entry));
  38. if ((EntryIdx % NodeCount) == (NodeCount - 1)) {
  39. DEBUG ((DEBUG_INFO, "\n"));
  40. }
  41. EntryIdx++;
  42. }
  43. }
  44. /**
  45. Stores correlation between AEP PMEM NUMA node and socket
  46. @param[in] Pmem AEP PMEM NUMA node number
  47. @param[in] Socket Socket number
  48. @retval None
  49. **/
  50. VOID
  51. SavePmemInfo (
  52. IN UINT8 Pmem,
  53. IN UINT8 Socket,
  54. MEM_TYPE Type
  55. )
  56. {
  57. if (Pmem < EFI_ACPI_SLIT_PMEM_INFO_CNT) {
  58. DEBUG ((DEBUG_INFO, "SLIT: Found PMem %d at socket %d (mem type 0x%X)\n", Pmem, Socket, Type));
  59. mSlitPmemInfo[Pmem].Pmem = Pmem;
  60. mSlitPmemInfo[Pmem].Socket = Socket;
  61. mSlitPmemInfo[Pmem].Valid = TRUE;
  62. return;
  63. }
  64. DEBUG ((DEBUG_ERROR, "SLIT: Error - Number of PMem nodes (%d) exceed PMem info data table size (%d)\n",
  65. Pmem, EFI_ACPI_SLIT_PMEM_INFO_CNT));
  66. ASSERT (FALSE);
  67. }
  68. /**
  69. Retrieves socket correlated with given AEP PMEM NUMA node
  70. @param[in] Pmem AEP PMEM Numa node
  71. @retval Socket correlated with given AEP PMEM NUMA node
  72. **/
  73. UINT8
  74. GetSocketForPmem (
  75. IN UINT8 Pmem
  76. )
  77. {
  78. UINT8 PmemInfoEntry;
  79. for (PmemInfoEntry = 0; PmemInfoEntry < EFI_ACPI_SLIT_PMEM_INFO_CNT; PmemInfoEntry++) {
  80. if (mSlitPmemInfo[PmemInfoEntry].Valid && mSlitPmemInfo[PmemInfoEntry].Pmem == Pmem) {
  81. return mSlitPmemInfo[PmemInfoEntry].Socket;
  82. }
  83. }
  84. DEBUG ((DEBUG_ERROR, "SLIT: Error - PMem node (%d) is not associated with any socket\n", Pmem));
  85. ASSERT (FALSE);
  86. return PMEM_INVALID_SOCKET;
  87. }
  88. /**
  89. This function gets the physical node index for given FPGA NUMA node.
  90. If the given FPGA NUMA node doesn't exist, an invalid physical node
  91. index 0xff will be returned.
  92. @param[in] FpgaNumaNodeId FPGA NUMA node index (0 based).
  93. @retval Physical node index of given FPGA NUMA node (0 based).
  94. **/
  95. UINT8
  96. GetPhyNodeIdForFpga (
  97. IN UINT8 FpgaNumaNodeId
  98. )
  99. {
  100. UINT32 FpgaPresentBitMap;
  101. UINT8 PhyNodeId;
  102. PhyNodeId = 0;
  103. FpgaPresentBitMap = mCpuCsrAccessVarPtr->FpgaPresentBitMap;
  104. while ((FpgaNumaNodeId != (UINT8) -1) && (FpgaPresentBitMap != 0)) {
  105. if ((FpgaPresentBitMap & BIT0) != 0) {
  106. FpgaNumaNodeId--;
  107. }
  108. FpgaPresentBitMap >>= 1;
  109. PhyNodeId++;
  110. }
  111. if ((FpgaPresentBitMap == 0) && (FpgaNumaNodeId != (UINT8) -1)) {
  112. return (UINT8) -1;
  113. }
  114. return PhyNodeId - 1;
  115. }
  116. /**
  117. Retrieves number of FPGA Presents
  118. @retval Number of FPGA Presents in the system
  119. **/
  120. UINT8
  121. GetFpgaCount (
  122. VOID)
  123. {
  124. UINT8 FpgaCount = 0;
  125. UINT32 FpgaPresentBitMap = mCpuCsrAccessVarPtr->FpgaPresentBitMap;
  126. while (FpgaPresentBitMap) {
  127. if (FpgaPresentBitMap & BIT0) {
  128. FpgaCount++;
  129. }
  130. FpgaPresentBitMap >>= 1;
  131. }
  132. return FpgaCount;
  133. }
  134. /**
  135. Retrieves number of AEP PMEM NUMA nodes
  136. @retval Number of AEP PMEM NUMA nodes
  137. **/
  138. UINT8
  139. GetPmemNodeCount (
  140. VOID
  141. )
  142. {
  143. UINT8 Socket;
  144. UINT8 SadRule;
  145. UINT8 PmemNodeCount = 0;
  146. EFI_STATUS Status = EFI_SUCCESS;
  147. DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL;
  148. Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, (VOID **) &DynamicSiLibraryProtocol2);
  149. if (EFI_ERROR (Status)) {
  150. ASSERT_EFI_ERROR (Status);
  151. return 0;
  152. }
  153. for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
  154. if ((mCpuCsrAccessVarPtr->socketPresentBitMap & (BIT0 << Socket)) == 0) {
  155. continue;
  156. }
  157. for (SadRule = 0; SadRule < MAX_SAD_RULES; SadRule++) {
  158. //
  159. // Only local SADs of PMEM type should be taken into consideration.
  160. // Skip any memory region marked reserved.
  161. //
  162. if (mSystemMemoryMap->Socket[Socket].SAD[SadRule].local &&
  163. DynamicSiLibraryProtocol2->IsMemTypeAppDirect (mSystemMemoryMap->Socket[Socket].SAD[SadRule].type) &&
  164. !DynamicSiLibraryProtocol2->IsMemTypeReserved (mSystemMemoryMap->Socket[Socket].SAD[SadRule].type)) {
  165. SavePmemInfo (PmemNodeCount++, Socket, mSystemMemoryMap->Socket[Socket].SAD[SadRule].type);
  166. }
  167. }
  168. }
  169. return PmemNodeCount;
  170. }
  171. /**
  172. Retrieves number of clusters in the system if system is in SNC mode. If system is not
  173. in SNC mode, the return 1.
  174. @return Number of clusters in the system in SNC mode or 1 if system is not in SNC mode.
  175. **/
  176. UINT8
  177. GetNumClusters (
  178. VOID
  179. )
  180. {
  181. UINT8 NumClusters;
  182. NumClusters = mIioUds->IioUdsPtr->SystemStatus.OutNumOfCluster;
  183. if ((NumClusters == 0) || (mIioUds->IioUdsPtr->SystemStatus.OutSncEn == 0)) {
  184. NumClusters = 1; // For non-SNC mode, we should also return 1.
  185. }
  186. if (mSystemMemoryMap->VirtualNumaEnable) {
  187. NumClusters = NumClusters * mSystemMemoryMap->VirtualNumOfCluster;
  188. }
  189. return NumClusters;
  190. }
  191. /**
  192. Retrieves number of enabled CPUs in the system
  193. @param None
  194. @retval Number of enabled CPUs in the system
  195. **/
  196. UINT8
  197. GetNumCpus (
  198. VOID
  199. )
  200. {
  201. return mIioUds->IioUdsPtr->SystemStatus.numCpus;
  202. }
  203. /**
  204. Calculates total number of nodes
  205. @param[in] NumCpus Number of CPUs
  206. @param[in] NumClusters Number of clusters
  207. @param[in] PmemNodeCount Number of AEP PMEM NUMA nodes
  208. @retval Total number of nodes
  209. **/
  210. UINT8
  211. GetNodeCount (
  212. IN UINT8 NumCpus,
  213. IN UINT8 NumClusters,
  214. IN UINT8 PmemNodeCount,
  215. IN UINT8 FpgaCount
  216. )
  217. {
  218. UINT8 NodeCount;
  219. if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_MIX_1LM2LM) {
  220. NodeCount = ((NumCpus * NumClusters * EFI_ACPI_SLIT_DOMAINS_NODES_MAX_CNT) + PmemNodeCount + FpgaCount);
  221. } else {
  222. NodeCount = ((NumCpus * NumClusters) + PmemNodeCount + FpgaCount);
  223. }
  224. if ((NodeCount * NodeCount) < EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT) {
  225. return NodeCount;
  226. }
  227. DEBUG ((DEBUG_ERROR, "SLIT: Error - Nodes distances info data size (%d) exceed SLIT distances info table size (%d)\n",
  228. (NodeCount * NodeCount), EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT));
  229. ASSERT (FALSE);
  230. return 0;
  231. }
  232. /**
  233. Verifies whether sockets are linked
  234. @param[in] SourceSocket Source Socket ID
  235. @param[in] TargetSocket Targer Socket ID
  236. @retval TRUE link between source socket and target socket was found
  237. FALSE otherwise
  238. **/
  239. BOOLEAN
  240. SocketsLinked (
  241. IN UINT32 SourceSocket,
  242. IN UINT32 TargetSocket
  243. )
  244. {
  245. UINT8 PeerSocket;
  246. UINT8 LinkValid;
  247. UINT8 PeerSocId;
  248. EFI_STATUS Status = EFI_SUCCESS;
  249. DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL;
  250. Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, (VOID **) &DynamicSiLibraryProtocol2);
  251. if (EFI_ERROR (Status)) {
  252. ASSERT_EFI_ERROR (Status);
  253. return FALSE;
  254. }
  255. //
  256. // Validate sockets ids
  257. //
  258. if ((SourceSocket < MAX_SOCKET) && (TargetSocket < MAX_SOCKET)) {
  259. //
  260. // Do not process when source socket is the same as target socket
  261. //
  262. if (SourceSocket != TargetSocket) {
  263. for (PeerSocket = 0; PeerSocket < (DynamicSiLibraryProtocol2->GetKtiPortCnt()); PeerSocket++) {
  264. LinkValid = mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[SourceSocket].PeerInfo[PeerSocket].Valid;
  265. PeerSocId = mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[SourceSocket].PeerInfo[PeerSocket].PeerSocId;
  266. if (LinkValid && (PeerSocId == TargetSocket)) {
  267. //
  268. // Link found
  269. //
  270. return TRUE;
  271. }
  272. }
  273. }
  274. //
  275. // Link not found
  276. //
  277. return FALSE;
  278. }
  279. DEBUG ((DEBUG_ERROR, "SLIT: Error when checking if sockets are linked (source socket id %d, target socket id %d)\n", SourceSocket, TargetSocket));
  280. return FALSE;
  281. }
  282. /**
  283. Initializes SLIT Table entries
  284. @param[in,out] Table Pointer to SLIT ACPI tables
  285. @retval EFI_SUCCESS operation completed successfully
  286. **/
  287. EFI_STATUS
  288. InitEntries (
  289. IN OUT ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitPtr
  290. )
  291. {
  292. if (SlitPtr == NULL) {
  293. ASSERT (SlitPtr != NULL);
  294. return EFI_INVALID_PARAMETER;
  295. }
  296. SetMem (&SlitPtr->NumSlit[0].Entry, EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT, 0xFF);
  297. return EFI_SUCCESS;
  298. }
  299. /**
  300. Processes socket nodes
  301. @param[in,out] Table Pointer to SLIT ACPI tables
  302. @param[in] NumCpus Number of CPUs
  303. @param[in] NumClusters Number of clusters
  304. @param[in] PmemNodeCount Number of AEP PMEM NUMA nodes
  305. @param[in] FpgaCount Number of FPGA NUMA nodes
  306. @param[in] NodeCount Number of all nodes
  307. @retval EFI_SUCCESS operation completed successfully
  308. **/
  309. EFI_STATUS
  310. ProcessSockets (
  311. IN OUT EFI_ACPI_COMMON_HEADER *Table,
  312. IN UINT8 NumCpus,
  313. IN UINT8 NumClusters,
  314. IN UINT8 PmemNodeCount,
  315. IN UINT8 FpgaCount,
  316. IN UINT8 NodeCount
  317. )
  318. {
  319. ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable;
  320. UINT16 EntryIdx;
  321. UINT8 SourceNode;
  322. UINT8 SourceSocket;
  323. UINT8 SourceCluster;
  324. UINT8 TargetSocket;
  325. UINT8 TargetCluster;
  326. UINT8 VirtualNumaFactor;
  327. if (NULL == Table) {
  328. DEBUG ((DEBUG_ERROR, "SLIT: Error in SLIT update with data about nodes on same socket\n"));
  329. return EFI_INVALID_PARAMETER;
  330. }
  331. VirtualNumaFactor = 1;
  332. if (mSystemMemoryMap->VirtualNumaEnable) {
  333. VirtualNumaFactor = mSystemMemoryMap->VirtualNumOfCluster;
  334. }
  335. DEBUG ((DEBUG_INFO, "SLIT: Update with data about nodes on same socket\n"));
  336. SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
  337. for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount) ; SourceNode++) {
  338. SourceSocket = SourceNode / NumClusters;
  339. SourceCluster = SourceNode % NumClusters;
  340. for (TargetSocket = 0; TargetSocket < NumCpus; TargetSocket++) {
  341. for (TargetCluster = 0; TargetCluster < NumClusters; TargetCluster++) {
  342. if (SourceSocket == TargetSocket) {
  343. EntryIdx = (SourceNode * (NodeCount)) + (TargetSocket * NumClusters) + TargetCluster;
  344. //
  345. // Source and target are nodes on same socket
  346. //
  347. if ((SourceCluster / VirtualNumaFactor) == (TargetCluster / VirtualNumaFactor)) {
  348. //
  349. // a) Same socket same physical cluster
  350. //
  351. SlitAcpiTable->NumSlit[EntryIdx].Entry = ZERO_HOP;
  352. } else {
  353. //
  354. // b) Same socket different cluster
  355. //
  356. SlitAcpiTable->NumSlit[EntryIdx].Entry = ZERO_ONE;
  357. }
  358. }
  359. }
  360. }
  361. }
  362. return EFI_SUCCESS;
  363. }
  364. /**
  365. Processes socket nodes
  366. @param[in,out] Table Pointer to SLIT ACPI tables
  367. @param[in] NumCpus Number of CPUs
  368. @param[in] NumClusters Number of clusters
  369. @param[in] PmemNodeCount Number of AEP PMEM NUMA nodes
  370. @param[in] FpgaCount Number of FPGA NUMA nodes
  371. @param[in] NodeCount Number of all nodes
  372. @retval EFI_SUCCESS operation completed successfully
  373. **/
  374. EFI_STATUS
  375. ProcessMixedModeSockets (
  376. IN OUT EFI_ACPI_COMMON_HEADER *Table,
  377. IN UINT8 NumCpus,
  378. IN UINT8 NumClusters,
  379. IN UINT8 PmemNodeCount,
  380. IN UINT8 FpgaCount,
  381. IN UINT8 NodeCount
  382. )
  383. {
  384. ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable;
  385. UINT16 EntryIdx1LM;
  386. UINT16 EntryIdx2LM;
  387. UINT8 SourceNode;
  388. UINT8 SourceSocket;
  389. UINT8 SourceCluster;
  390. UINT8 TargetSocket;
  391. UINT8 TargetCluster;
  392. BOOLEAN Is2LM;
  393. if (NULL == Table) {
  394. DEBUG ((DEBUG_ERROR, "SLIT: Error in SLIT update with data about nodes on same socket for Mixed Mode\n"));
  395. return EFI_INVALID_PARAMETER;
  396. }
  397. DEBUG ((DEBUG_INFO, "SLIT: Update with data about nodes on same socket for Mixed Mode\n"));
  398. SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
  399. for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount) ; SourceNode++) {
  400. Is2LM = (SourceNode >= NumCpus * NumClusters) ? TRUE : FALSE;
  401. SourceSocket = (SourceNode - NumCpus * NumClusters * (Is2LM ? 1 : 0)) / NumClusters;
  402. SourceCluster = (SourceNode - NumCpus * NumClusters * (Is2LM ? 1 : 0)) % NumClusters;
  403. TargetSocket = SourceSocket;
  404. for (TargetCluster = 0; TargetCluster < NumClusters; TargetCluster++) {
  405. EntryIdx1LM = (UINT16)((SourceNode * NodeCount) + (TargetSocket * NumClusters) + TargetCluster);
  406. EntryIdx2LM = EntryIdx1LM + NumCpus * NumClusters;
  407. if ((SourceCluster == TargetCluster) && (Is2LM == FALSE)) {
  408. //
  409. // CPU -> 1LM at the same socket, the same cluster
  410. //
  411. SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ZERO_HOP;
  412. //
  413. // CPU -> 2LM at the same socket, the same cluster
  414. //
  415. SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ZERO_ONE;
  416. } else if ((SourceCluster == TargetCluster) && (Is2LM == TRUE)) {
  417. //
  418. // CPU -> 2LM at the same socket, the same cluster
  419. //
  420. SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ZERO_ONE;
  421. //
  422. // not effective
  423. //
  424. SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ZERO_HOP;
  425. } else if ((SourceCluster != TargetCluster) && (Is2LM == FALSE)) {
  426. //
  427. // CPU -> 1LM at the same socket, different cluster
  428. //
  429. SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ZERO_ONE;
  430. //
  431. // CPU -> 2LM at the same socket, different cluster
  432. //
  433. SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ZERO_TWO;
  434. } else {
  435. //
  436. // branch condition: ((SourceCluster != TargetCluster) && (Is2LM == TRUE))
  437. // CPU -> 2LM at the same socket, different cluster
  438. //
  439. SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ZERO_TWO;
  440. //
  441. // not effective
  442. //
  443. SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ZERO_TWO;
  444. }
  445. }
  446. }
  447. return EFI_SUCCESS;
  448. }
  449. /**
  450. Processes connections between sockets to retrieve valid distances
  451. @param[in,out] Table Pointer to SLIT ACPI tables
  452. @param[in] NumCpus Number of CPUs
  453. @param[in] NumClusters Number of clusters
  454. @param[in] PmemNodeCount Number of AEP PMEM NUMA nodes
  455. @param[in] FpgaCount Number of FPGA NUMA nodes
  456. @param[in] NodeCount Number of all nodes
  457. @retval EFI_SUCCESS operation completed successfully
  458. **/
  459. EFI_STATUS
  460. ProcessSocketsLinks (
  461. IN OUT EFI_ACPI_COMMON_HEADER *Table,
  462. IN UINT8 NumCpus,
  463. IN UINT8 NumClusters,
  464. IN UINT8 PmemNodeCount,
  465. IN UINT8 FpgaCount,
  466. IN UINT8 NodeCount
  467. )
  468. {
  469. ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable;
  470. UINT8 SourceNode;
  471. UINT8 SourceSocket;
  472. UINT8 TargetSocket;
  473. if (NULL == Table) {
  474. DEBUG ((DEBUG_ERROR, "SLIT: Error in processing links between sockets\n"));
  475. return EFI_INVALID_PARAMETER;
  476. }
  477. DEBUG ((DEBUG_INFO, "SLIT: Update table with links between sockets\n"));
  478. SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
  479. for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount); SourceNode++) {
  480. SourceSocket = SourceNode / NumClusters;
  481. for (TargetSocket = 0; TargetSocket < NumCpus; TargetSocket++) {
  482. if (SocketsLinked (GetSocketPhysicalId (SourceSocket), GetSocketPhysicalId (TargetSocket))) {
  483. SetMem (&SlitAcpiTable->NumSlit[(SourceNode * NodeCount) + (TargetSocket * NumClusters)].Entry,
  484. NumClusters, ONE_HOP);
  485. }
  486. }
  487. }
  488. return EFI_SUCCESS;
  489. }
  490. /**
  491. Processes connections between sockets to retrieve valid distances
  492. @param[in,out] Table Pointer to SLIT ACPI tables
  493. @param[in] NumCpus Number of CPUs
  494. @param[in] NumClusters Number of clusters
  495. @param[in] PmemNodeCount Number of AEP PMEM NUMA nodes
  496. @param[in] FpgaCount Number of FPGA NUMA nodes
  497. @param[in] NodeCount Number of all nodes
  498. @retval EFI_SUCCESS operation completed successfully
  499. **/
  500. EFI_STATUS
  501. ProcessMixedModeSocketsLinks (
  502. IN OUT EFI_ACPI_COMMON_HEADER *Table,
  503. IN UINT8 NumCpus,
  504. IN UINT8 NumClusters,
  505. IN UINT8 PmemNodeCount,
  506. IN UINT8 FpgaCount,
  507. IN UINT8 NodeCount
  508. )
  509. {
  510. ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable;
  511. UINT16 EntryIdx1LM;
  512. UINT16 EntryIdx2LM;
  513. UINT8 SourceNode;
  514. UINT8 SourceSocket;
  515. UINT8 TargetSocket;
  516. UINT8 TargetCluster;
  517. BOOLEAN Is2LM;
  518. if (NULL == Table) {
  519. DEBUG ((DEBUG_ERROR, "SLIT: Error in processing links between sockets in Mixed Mode\n"));
  520. return EFI_INVALID_PARAMETER;
  521. }
  522. DEBUG ((DEBUG_INFO, "SLIT: Update table with links between sockets in Mixed Mode\n"));
  523. SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
  524. for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount); SourceNode++) {
  525. Is2LM = (SourceNode >= NumCpus * NumClusters) ? TRUE : FALSE;
  526. SourceSocket = (SourceNode - NumCpus * NumClusters * (Is2LM ? 1 : 0)) / NumClusters;
  527. for (TargetSocket = 0; TargetSocket < NumCpus; TargetSocket++) {
  528. if (SocketsLinked (GetSocketPhysicalId (SourceSocket), GetSocketPhysicalId (TargetSocket))) {
  529. //
  530. // If both sockets are linked by KTI and not the same socket.
  531. //
  532. for (TargetCluster = 0; TargetCluster < NumClusters; TargetCluster++) {
  533. EntryIdx1LM = (UINT16)((SourceNode * NodeCount) + (TargetSocket * NumClusters) + TargetCluster);
  534. EntryIdx2LM = EntryIdx1LM + NumCpus * NumClusters;
  535. if (Is2LM == FALSE) {
  536. //
  537. // CPU -> 1LM at different socket
  538. //
  539. SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ONE_HOP;
  540. //
  541. // CPU -> 2LM at different socket
  542. //
  543. SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ONE_ONE;
  544. } else {
  545. //
  546. // branch condition: (Is2LM == TRUE)
  547. // CPU -> 2LM at different socket
  548. //
  549. SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ONE_ONE;
  550. //
  551. // not effective
  552. //
  553. SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ONE_TWO;
  554. }
  555. }
  556. }
  557. }
  558. }
  559. return EFI_SUCCESS;
  560. }
  561. /**
  562. Processes all AEP PMEM NUMA nodes
  563. @param[in,out] Table Pointer to SLIT ACPI tables
  564. @param[in] NumCpus Number of CPUs
  565. @param[in] NumClusters Number of clusters
  566. @param[in] PmemNodeCount Number of AEP PMEM NUMA nodes
  567. @param[in] FpgaCount Number of FPGA NUMA nodes
  568. @param[in] NodeCount Number of all nodes
  569. @retval EFI_SUCCESS operation completed successfully
  570. **/
  571. EFI_STATUS
  572. ProcessPmems (
  573. IN OUT EFI_ACPI_COMMON_HEADER *Table,
  574. IN UINT8 NumCpus,
  575. IN UINT8 NumClusters,
  576. IN UINT8 PmemNodeCount,
  577. IN UINT8 FpgaCount,
  578. IN UINT8 NodeCount
  579. )
  580. {
  581. ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable;
  582. UINT16 EntryIdx;
  583. UINT8 SourceNode;
  584. UINT8 TargetNode;
  585. UINT8 SourceSocket;
  586. UINT8 TargetCluster;
  587. UINT8 TargetSocket;
  588. UINT8 SourcePmem;
  589. UINT8 TargetPmem;
  590. UINT8 SourcePmemSocket;
  591. UINT8 TargetPmemSocket;
  592. UINT8 TotalVolMemNodes;
  593. if (NULL == Table) {
  594. DEBUG ((DEBUG_ERROR, "SLIT: Error in processing PMems\n"));
  595. return EFI_INVALID_PARAMETER;
  596. }
  597. if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_MIX_1LM2LM) {
  598. TotalVolMemNodes = NumCpus * NumClusters * EFI_ACPI_SLIT_DOMAINS_NODES_MAX_CNT;
  599. } else {
  600. TotalVolMemNodes = NumCpus * NumClusters;
  601. }
  602. DEBUG ((DEBUG_INFO, "SLIT: Include PMem NUMA nodes\n"));
  603. if (PmemNodeCount > 0) {
  604. SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
  605. //
  606. // 1) AEP PMEM nodes to AEP PMEM nodes distances
  607. //
  608. for (SourceNode = (NodeCount - PmemNodeCount - FpgaCount); SourceNode < (NodeCount - FpgaCount); SourceNode++) {
  609. SourcePmem = SourceNode - TotalVolMemNodes;
  610. for (TargetPmem = 0; TargetPmem < PmemNodeCount; TargetPmem++) {
  611. TargetNode = TargetPmem + TotalVolMemNodes;
  612. EntryIdx = (SourceNode * NodeCount) + TargetNode;
  613. if (SourcePmem == TargetPmem) {
  614. SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ZERO_HOP;
  615. } else {
  616. //
  617. // Retrieve sockets associated with PMEMs
  618. //
  619. SourcePmemSocket = GetSocketForPmem (SourcePmem);
  620. TargetPmemSocket = GetSocketForPmem (TargetPmem);
  621. if (SourcePmemSocket == TargetPmemSocket) {
  622. //
  623. // PMEMs are on the same socket
  624. //
  625. SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_ONE;
  626. } else {
  627. //
  628. // Assign 2 hop and process with PeerInfo checking
  629. //
  630. SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_TWO_HOP;
  631. //
  632. // Examine PeerInfo to look for link between AEP PMEM source socket and AEP PMEM target socket
  633. //
  634. if (SocketsLinked (SourcePmemSocket, TargetPmemSocket)) {
  635. //
  636. // Link found assign 1 hop
  637. //
  638. SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_HOP;
  639. }
  640. }
  641. }
  642. }
  643. }
  644. //
  645. // 2) Sockets to AEP PMEM nodes distances
  646. //
  647. for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount); SourceNode++) {
  648. SourceSocket = GetSocketPhysicalId (SourceNode / NumClusters);
  649. for (TargetPmem = 0; TargetPmem < PmemNodeCount; TargetPmem++) {
  650. TargetPmemSocket = GetSocketForPmem (TargetPmem);
  651. TargetNode = TargetPmem + TotalVolMemNodes;
  652. EntryIdx = (SourceNode * NodeCount) + TargetNode;
  653. if (SourceSocket == TargetPmemSocket) {
  654. SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_ONE;
  655. } else {
  656. //
  657. // Assign 2 hop and process with PeerInfo checking
  658. //
  659. SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_TWO_HOP;
  660. //
  661. // Examine PeerInfo to look for link between source socket and AEP PMEM socket
  662. //
  663. if (SocketsLinked (SourceSocket, TargetPmemSocket)) {
  664. //
  665. // Link found assign 1 hop
  666. //
  667. SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_HOP;
  668. }
  669. }
  670. }
  671. }
  672. //
  673. // 3) AEP PMEM nodes to sockets distances
  674. //
  675. for (SourceNode = (NodeCount - PmemNodeCount - FpgaCount); SourceNode < (NodeCount - FpgaCount); SourceNode++) {
  676. SourcePmem = SourceNode - TotalVolMemNodes;
  677. SourcePmemSocket = GetSocketForPmem (SourcePmem);
  678. for (TargetSocket = 0; TargetSocket < NumCpus; TargetSocket++) {
  679. for (TargetCluster = 0; TargetCluster < NumClusters; TargetCluster++) {
  680. EntryIdx = (SourceNode * NodeCount) + (TargetSocket * NumClusters) + TargetCluster;
  681. if(SourcePmemSocket == GetSocketPhysicalId (TargetSocket)) {
  682. SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_ONE;
  683. } else {
  684. //
  685. // Assign 2 hop and process with PeerInfo checking
  686. //
  687. SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_TWO_HOP;
  688. //
  689. // Examine PeerInfo to look for link between source socket and AEP PMEM socket
  690. //
  691. if (SocketsLinked (SourcePmemSocket, GetSocketPhysicalId (TargetSocket))) {
  692. //
  693. // Link found assign 1 hop
  694. //
  695. SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_HOP;
  696. }
  697. }
  698. }
  699. }
  700. }
  701. } else {
  702. DEBUG ((DEBUG_INFO, "SLIT: PMem NUMA nodes not present\n"));
  703. }
  704. return EFI_SUCCESS;
  705. }
  706. /**
  707. This function processes all FPGA NUMA nodes.
  708. @param[in,out] Table Pointer to SLIT ACPI tables.
  709. @param[in] NumClusters Number of clusters.
  710. @param[in] PmemNodeCount Number of AEP PMEM NUMA nodes.
  711. @param[in] FpgaCount Number of FPGA NUMA nodes.
  712. @param[in] NodeCount Number of all nodes.
  713. @retval EFI_SUCCESS This function is executed successfully.
  714. @retval EFI_INVALID_PARAMETER Some of input parameters are invalid.
  715. **/
  716. EFI_STATUS
  717. ProcessFpgaNodes (
  718. IN OUT EFI_ACPI_COMMON_HEADER *Table,
  719. IN UINT8 NumClusters,
  720. IN UINT8 PmemNodeCount,
  721. IN UINT8 FpgaCount,
  722. IN UINT8 NodeCount
  723. )
  724. {
  725. ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable;
  726. UINT8 SourceNode;
  727. UINT8 TargetNode;
  728. UINT8 SourceSocket;
  729. UINT8 TargetSocket;
  730. if (Table == NULL) {
  731. DEBUG ((DEBUG_ERROR, "SLIT: Error in processing FPGA nodes\n"));
  732. return EFI_INVALID_PARAMETER;
  733. }
  734. if (FpgaCount == 0) {
  735. return EFI_SUCCESS;
  736. }
  737. SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
  738. for (SourceNode = (NodeCount - FpgaCount); SourceNode < NodeCount; SourceNode++) {
  739. SourceSocket = GetPhyNodeIdForFpga (SourceNode - (NodeCount - FpgaCount));
  740. for (TargetNode = 0; TargetNode < NodeCount; TargetNode++) {
  741. if (TargetNode < (NodeCount- PmemNodeCount - FpgaCount)) {
  742. TargetSocket = GetSocketPhysicalId (TargetNode / NumClusters); // Normal nodes
  743. } else if (TargetNode < (NodeCount - FpgaCount)) {
  744. TargetSocket = GetSocketForPmem (TargetNode - (NodeCount - PmemNodeCount - FpgaCount)); // PMEM nodes
  745. } else {
  746. TargetSocket = GetPhyNodeIdForFpga (TargetNode - (NodeCount - FpgaCount)); // FPGA nodes
  747. }
  748. if (SourceSocket == TargetSocket) {
  749. SlitAcpiTable->NumSlit[SourceNode * NodeCount + TargetNode].Entry = ZERO_HOP;
  750. } else if (SocketsLinked (SourceSocket, TargetSocket)) {
  751. SlitAcpiTable->NumSlit[SourceNode * NodeCount + TargetNode].Entry = ONE_HOP;
  752. SlitAcpiTable->NumSlit[TargetNode * NodeCount + SourceNode].Entry = ONE_HOP;
  753. } else {
  754. SlitAcpiTable->NumSlit[SourceNode * NodeCount + TargetNode].Entry = TWO_HOP;
  755. SlitAcpiTable->NumSlit[TargetNode * NodeCount + SourceNode].Entry = TWO_HOP;
  756. }
  757. }
  758. }
  759. return EFI_SUCCESS;
  760. }
  761. /**
  762. Processes all remaining valid SLIT nodes
  763. @param[in,out] Table pointer to SLIT ACPI tables
  764. @retval EFI_SUCCESS operation completed successfully
  765. **/
  766. EFI_STATUS
  767. ProcessRemainingNodes (
  768. IN OUT EFI_ACPI_COMMON_HEADER *Table
  769. )
  770. {
  771. ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable;
  772. UINT16 EntryIdx = 0;
  773. UINT16 MaxTableEntries;
  774. UINT8 NodeCount;
  775. if (NULL == Table) {
  776. DEBUG ((DEBUG_ERROR, "SLIT: Error while processing remaining valid nodes\n"));
  777. return EFI_INVALID_PARAMETER;
  778. }
  779. DEBUG ((DEBUG_INFO, "SLIT: Fill in the rest of the SLIT table\n"));
  780. SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
  781. NodeCount = (UINT8)SlitAcpiTable->Header.NumberOfSystemLocalities;
  782. MaxTableEntries = NodeCount * NodeCount;
  783. while (EntryIdx < MaxTableEntries) {
  784. if (SlitAcpiTable->NumSlit[EntryIdx].Entry == 0xFF) {
  785. //
  786. // This entry has not been filled yet, assign 2 hop to this table entry
  787. //
  788. SlitAcpiTable->NumSlit[EntryIdx].Entry = TWO_HOP;
  789. }
  790. if ((EntryIdx % NodeCount) == 0) {
  791. DEBUG ((DEBUG_INFO, "[%2d - %2d] ", EntryIdx/NodeCount, EntryIdx%NodeCount));
  792. }
  793. EntryIdx++;
  794. }
  795. return EFI_SUCCESS;
  796. }
  797. /**
  798. Processes unused SLIT nodes
  799. @param[in,out] Table pointer to SLIT ACPI tables
  800. @retval EFI_SUCCESS operation completed successfully
  801. **/
  802. EFI_STATUS
  803. ProcessUnusedNodes (
  804. IN OUT EFI_ACPI_COMMON_HEADER *Table
  805. )
  806. {
  807. ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable;
  808. UINT16 MaxTableEntries;
  809. UINT8 NodeCount;
  810. if (NULL == Table) {
  811. DEBUG ((DEBUG_ERROR, "SLIT: Error while processing unused nodes\n"));
  812. return EFI_INVALID_PARAMETER;
  813. }
  814. DEBUG ((DEBUG_INFO, "SLIT: Zero out the unused nodes\n"));
  815. SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
  816. NodeCount = (UINT8)SlitAcpiTable->Header.NumberOfSystemLocalities;
  817. MaxTableEntries = NodeCount * NodeCount;
  818. SetMem (&SlitAcpiTable->NumSlit[MaxTableEntries],
  819. (UINTN)&SlitAcpiTable->NumSlit[EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT] - (UINTN)&SlitAcpiTable->NumSlit[MaxTableEntries], 0);
  820. return EFI_SUCCESS;
  821. }
  822. /**
  823. Updates System Locality Distance Information Table (SLIT)
  824. @param[in,out] Table pointer to SLIT ACPI tables
  825. @retval EFI_SUCCESS operation completed successfully
  826. @retval EFI_ABORTED operation not completed due to processing error
  827. **/
  828. EFI_STATUS
  829. PatchSLitTable (
  830. IN OUT EFI_ACPI_COMMON_HEADER *Table
  831. )
  832. {
  833. ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable;
  834. EFI_STATUS Status;
  835. UINT8 NodeCount;
  836. UINT8 NumCpus;
  837. UINT8 NumClusters;
  838. UINT8 PmemNodeCount;
  839. UINT8 FpgaCount;
  840. NumCpus = GetNumCpus ();
  841. NumClusters = GetNumClusters ();
  842. PmemNodeCount = GetPmemNodeCount ();
  843. FpgaCount = GetFpgaCount();
  844. NodeCount = GetNodeCount (NumCpus, NumClusters, PmemNodeCount, FpgaCount);
  845. DEBUG ((DEBUG_INFO, "SLIT: NumCpus %d, NumClusters %d, PmemNodeCount %d -> NodeCount %d FpgaCount %d\n",
  846. NumCpus, NumClusters, PmemNodeCount, NodeCount,FpgaCount));
  847. SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table;
  848. SlitAcpiTable->Header.NumberOfSystemLocalities = NodeCount;
  849. //
  850. // 1) Initialize all entries to 0xFF
  851. //
  852. Status = InitEntries (SlitAcpiTable);
  853. //
  854. // 2) Update SLIT table with data about nodes on same socket
  855. //
  856. if (!EFI_ERROR(Status)) {
  857. if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_MIX_1LM2LM) {
  858. Status = ProcessMixedModeSockets (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount);
  859. } else {
  860. Status = ProcessSockets (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount);
  861. }
  862. }
  863. //
  864. // 3) Update table with links between sockets by examining PeerInfo structure
  865. //
  866. if (!EFI_ERROR (Status)) {
  867. if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_MIX_1LM2LM) {
  868. Status = ProcessMixedModeSocketsLinks (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount);
  869. } else {
  870. Status = ProcessSocketsLinks (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount);
  871. }
  872. }
  873. //
  874. // 4) Update table with PMEMs
  875. //
  876. if (!EFI_ERROR (Status)) {
  877. Status = ProcessPmems (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount);
  878. }
  879. //
  880. // 5 Update table with FPGA
  881. //
  882. if (!EFI_ERROR (Status)) {
  883. Status = ProcessFpgaNodes (Table, NumClusters, PmemNodeCount, FpgaCount, NodeCount);
  884. }
  885. //
  886. // 6) Fill in the rest of the Slit table, 2 hops between any remaining valid nodes
  887. //
  888. if (!EFI_ERROR (Status)) {
  889. Status = ProcessRemainingNodes (Table);
  890. }
  891. //
  892. // 7) Zero out the unused nodes
  893. //
  894. if (!EFI_ERROR (Status)) {
  895. Status = ProcessUnusedNodes (Table);
  896. }
  897. //
  898. // 8) Print the entire SLIT table
  899. //
  900. if (!EFI_ERROR (Status)) {
  901. DisplayEntries (SlitAcpiTable);
  902. }
  903. ASSERT_EFI_ERROR (Status);
  904. return Status;
  905. }
  906. /**
  907. Allocate memory and fill SLIT information to this buffer, then
  908. install this table to ACPI table.
  909. @retval EFI_SUCCESS Install table success.
  910. @retval EFI_OUT_OF_RESOURCES Out of memory.
  911. **/
  912. EFI_STATUS
  913. InstallSlitTable (
  914. VOID
  915. )
  916. {
  917. ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *Table;
  918. UINTN TableSize;
  919. UINTN TableHandle = 0;
  920. EFI_STATUS Status;
  921. TableSize = sizeof (EFI_ACPI_6_2_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER) +
  922. sizeof (ACPI_SYSTEM_LOCALITIES_STRUCTURE) * EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT;
  923. Table = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *) AllocateZeroPool (TableSize);
  924. if (Table == NULL) {
  925. return EFI_OUT_OF_RESOURCES;
  926. }
  927. Table->Header.Header.Signature = EFI_ACPI_6_2_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE;
  928. Table->Header.Header.Length = (UINT32) TableSize;
  929. Table->Header.Header.Revision = EFI_ACPI_6_2_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_REVISION;
  930. Table->Header.Header.OemRevision = EFI_ACPI_OEM_SLIT_REVISION;
  931. CopyMem (Table->Header.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->Header.Header.OemId));
  932. Table->Header.Header.OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
  933. Table->Header.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
  934. Table->Header.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
  935. //
  936. // All node init with 0 before pass to patcher
  937. //
  938. PatchSLitTable ((EFI_ACPI_COMMON_HEADER *)&Table->Header.Header);
  939. //
  940. // Publish SLIT Structure to ACPI
  941. //
  942. Status = mAcpiTable->InstallAcpiTable (
  943. mAcpiTable,
  944. Table,
  945. Table->Header.Header.Length,
  946. &TableHandle
  947. );
  948. //
  949. // Free memory
  950. //
  951. if (Table != NULL) {
  952. FreePool (Table);
  953. }
  954. return Status;
  955. }