AcpiIort.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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 <AcpiHeader.h>
  6. #include <Guid/RootComplexConfigHii.h>
  7. #include <Guid/RootComplexInfoHob.h>
  8. #include <IndustryStandard/Acpi30.h>
  9. #include <IndustryStandard/IoRemappingTable.h>
  10. #include <Library/AcpiLib.h>
  11. #include <Library/AmpereCpuLib.h>
  12. #include <Library/BaseMemoryLib.h>
  13. #include <Library/DebugLib.h>
  14. #include <Library/HobLib.h>
  15. #include <Library/MemoryAllocationLib.h>
  16. #include <Library/UefiBootServicesTableLib.h>
  17. #include <Library/UefiRuntimeServicesTableLib.h>
  18. #include <Platform/Ac01.h>
  19. #include <Protocol/AcpiTable.h>
  20. #define __AC01_ID_MAPPING(In, Num, Out, Ref, Flags) \
  21. { \
  22. In, \
  23. Num, \
  24. Out, \
  25. OFFSET_OF (AC01_IO_REMAPPING_STRUCTURE, Ref), \
  26. Flags \
  27. }
  28. #define TCU_TO_SMMU_OFFSET 0x2000
  29. #define PAGE1_TO_PMCG_OFFSET 0x10000
  30. STATIC AC01_ROOT_COMPLEX *mRootComplexList;
  31. STATIC UINT32 mTbuPmuIrqArray[] = { AC01_SMMU_TBU_PMU_IRQS_LIST };
  32. STATIC UINT32 mTcuPmuIrqArray[] = { AC01_SMMU_TCU_PMU_IRQS_LIST };
  33. STATIC UINT64 mRcaTbuPmuOffset[] = { AC01_RCA_TBU_PMU_OFFSET_LIST };
  34. STATIC UINT64 mRcbTbuPmuOffset[] = { AC01_RCB_TBU_PMU_OFFSET_LIST };
  35. #pragma pack(1)
  36. typedef struct {
  37. EFI_ACPI_6_0_IO_REMAPPING_NODE Node;
  38. UINT64 Base;
  39. UINT32 Flags;
  40. UINT32 Reserved;
  41. UINT64 VatosAddress;
  42. UINT32 Model;
  43. UINT32 Event;
  44. UINT32 Pri;
  45. UINT32 Gerr;
  46. UINT32 Sync;
  47. UINT32 ProximityDomain;
  48. UINT32 DeviceIdMapping;
  49. } EFI_ACPI_6_2_IO_REMAPPING_SMMU3_NODE;
  50. typedef struct {
  51. EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE Node;
  52. UINT32 ItsIdentifier;
  53. } AC01_ITS_NODE;
  54. typedef struct {
  55. EFI_ACPI_6_0_IO_REMAPPING_RC_NODE Node;
  56. EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE RcIdMapping;
  57. } AC01_RC_NODE;
  58. typedef struct {
  59. EFI_ACPI_6_2_IO_REMAPPING_SMMU3_NODE Node;
  60. EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE InterruptMsiMapping;
  61. EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE InterruptMsiMappingSingle;
  62. } AC01_SMMU_NODE;
  63. typedef struct {
  64. EFI_ACPI_6_0_IO_REMAPPING_TABLE Iort;
  65. AC01_ITS_NODE ItsNode[2];
  66. AC01_RC_NODE RcNode[2];
  67. AC01_SMMU_NODE SmmuNode[2];
  68. } AC01_IO_REMAPPING_STRUCTURE;
  69. #pragma pack()
  70. EFI_ACPI_6_0_IO_REMAPPING_TABLE mIortHeader = {
  71. .Header = __ACPI_HEADER (
  72. EFI_ACPI_6_0_IO_REMAPPING_TABLE_SIGNATURE,
  73. AC01_IO_REMAPPING_STRUCTURE,
  74. EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00
  75. ),
  76. .NumNodes = 0, // To be filled
  77. .NodeOffset = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE),
  78. 0
  79. };
  80. AC01_ITS_NODE mItsNodeTemplate = {
  81. .Node = {
  82. {
  83. EFI_ACPI_IORT_TYPE_ITS_GROUP,
  84. sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE) + 4,
  85. 0x0,
  86. 0x0,
  87. 0x0,
  88. 0x0,
  89. },
  90. .NumItsIdentifiers = 1,
  91. },
  92. .ItsIdentifier = 1,
  93. };
  94. AC01_RC_NODE mRcNodeTemplate = {
  95. {
  96. {
  97. EFI_ACPI_IORT_TYPE_ROOT_COMPLEX,
  98. sizeof (AC01_RC_NODE),
  99. 0x1,
  100. 0x0,
  101. 0x1,
  102. OFFSET_OF (AC01_RC_NODE, RcIdMapping),
  103. },
  104. EFI_ACPI_IORT_MEM_ACCESS_PROP_CCA,
  105. 0x0,
  106. 0x0,
  107. EFI_ACPI_IORT_MEM_ACCESS_FLAGS_CPM |
  108. EFI_ACPI_IORT_MEM_ACCESS_FLAGS_DACS,
  109. EFI_ACPI_IORT_ROOT_COMPLEX_ATS_UNSUPPORTED,
  110. .PciSegmentNumber = 0,
  111. .MemoryAddressSize = 64,
  112. },
  113. __AC01_ID_MAPPING (0x0, 0xffff, 0x0, SmmuNode, 0),
  114. };
  115. AC01_SMMU_NODE mSmmuNodeTemplate = {
  116. {
  117. {
  118. EFI_ACPI_IORT_TYPE_SMMUv3,
  119. sizeof (AC01_SMMU_NODE),
  120. 0x2, // Revision
  121. 0x0,
  122. 0x2, // Mapping Count
  123. OFFSET_OF (AC01_SMMU_NODE, InterruptMsiMapping),
  124. },
  125. .Base = 0,
  126. EFI_ACPI_IORT_SMMUv3_FLAG_COHAC_OVERRIDE | EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN,
  127. 0,
  128. 0,
  129. 0,
  130. 0,
  131. 0,
  132. 0x0,
  133. 0x0,
  134. 0, // Proximity domain - need fill in
  135. .DeviceIdMapping = 1,
  136. },
  137. __AC01_ID_MAPPING (0x0, 0xffff, 0, SmmuNode, 0),
  138. __AC01_ID_MAPPING (0x0, 0x1, 0, SmmuNode, 1),
  139. };
  140. EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE mPmcgNodeTemplate = {
  141. {
  142. EFI_ACPI_IORT_TYPE_PMCG,
  143. sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE),
  144. 0x1,
  145. 0x0,
  146. 0x0,
  147. 0x0,
  148. },
  149. 0, // Page 0 Base. Need to be filled
  150. 0, // GSIV. Need to be filled
  151. 0, // Node reference. Need to be filled
  152. 0, // Page 1 Base. Need to be filled
  153. };
  154. STATIC
  155. VOID
  156. ConstructIort (
  157. VOID *IortBuffer,
  158. UINT32 RcCount,
  159. UINT32 SmmuPmuAgentCount,
  160. UINT32 HeaderCount,
  161. INT32 *EnabledRCs
  162. )
  163. {
  164. AC01_ROOT_COMPLEX *RootComplex;
  165. UINT32 Idx, Idx1;
  166. UINT32 ItsOffset[AC01_PCIE_MAX_ROOT_COMPLEX];
  167. UINT32 SmmuNodeOffset[AC01_PCIE_MAX_ROOT_COMPLEX];
  168. UINT64 *TbuPmuOffset;
  169. UINTN MaxTbuPmu;
  170. VOID *IortIter, *SmmuIter, *PmcgIter;
  171. IortIter = IortBuffer;
  172. mIortHeader.Header.Length = HeaderCount;
  173. mIortHeader.NumNodes = (3 * RcCount) + SmmuPmuAgentCount,
  174. CopyMem (IortIter, &mIortHeader, sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE));
  175. IortIter += sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);
  176. for (Idx = 0; Idx < RcCount; Idx++) {
  177. ItsOffset[Idx] = IortIter - IortBuffer;
  178. mItsNodeTemplate.ItsIdentifier = EnabledRCs[Idx];
  179. CopyMem (IortIter, &mItsNodeTemplate, sizeof (AC01_ITS_NODE));
  180. IortIter += sizeof (AC01_ITS_NODE);
  181. }
  182. SmmuIter = IortIter + RcCount * sizeof (AC01_RC_NODE);
  183. PmcgIter = SmmuIter + RcCount * sizeof (AC01_SMMU_NODE);
  184. for (Idx = 0; Idx < RcCount; Idx++) {
  185. SmmuNodeOffset[Idx] = SmmuIter - IortBuffer;
  186. RootComplex = &mRootComplexList[EnabledRCs[Idx]];
  187. mSmmuNodeTemplate.Node.Base = RootComplex->TcuBase;
  188. mSmmuNodeTemplate.InterruptMsiMapping.OutputBase = EnabledRCs[Idx] << 16;
  189. mSmmuNodeTemplate.InterruptMsiMapping.OutputReference = ItsOffset[Idx];
  190. mSmmuNodeTemplate.InterruptMsiMappingSingle.OutputBase = EnabledRCs[Idx] << 16;
  191. mSmmuNodeTemplate.InterruptMsiMappingSingle.OutputReference = ItsOffset[Idx];
  192. /* All RCs on master be assigned to node 0, while remote RCs will be assigned to first remote node */
  193. mSmmuNodeTemplate.Node.ProximityDomain = 0;
  194. if ((RootComplex->TcuBase & SLAVE_SOCKET_BASE_ADDRESS_OFFSET) != 0) {
  195. // RootComplex on remote socket
  196. switch (CpuGetSubNumaMode ()) {
  197. case SUBNUMA_MODE_MONOLITHIC:
  198. mSmmuNodeTemplate.Node.ProximityDomain += MONOLITIC_NUM_OF_REGION;
  199. break;
  200. case SUBNUMA_MODE_HEMISPHERE:
  201. mSmmuNodeTemplate.Node.ProximityDomain += HEMISPHERE_NUM_OF_REGION;
  202. break;
  203. case SUBNUMA_MODE_QUADRANT:
  204. mSmmuNodeTemplate.Node.ProximityDomain += QUADRANT_NUM_OF_REGION;
  205. break;
  206. }
  207. }
  208. CopyMem (SmmuIter, &mSmmuNodeTemplate, sizeof (AC01_SMMU_NODE));
  209. SmmuIter += sizeof (AC01_SMMU_NODE);
  210. if (SmmuPmuAgentCount == 0) {
  211. continue;
  212. }
  213. //
  214. // Add TBU PMCG nodes
  215. //
  216. if (RootComplex->Type == RootComplexTypeA) {
  217. MaxTbuPmu = AC01_RCA_MAX_TBU_PMU;
  218. TbuPmuOffset = mRcaTbuPmuOffset;
  219. } else {
  220. MaxTbuPmu = AC01_RCB_MAX_TBU_PMU;
  221. TbuPmuOffset = mRcbTbuPmuOffset;
  222. }
  223. for (Idx1 = 0; Idx1 < MaxTbuPmu; Idx1++) {
  224. mPmcgNodeTemplate.Base = RootComplex->TcuBase + TCU_TO_SMMU_OFFSET + TbuPmuOffset[Idx1];
  225. mPmcgNodeTemplate.Page1Base = mPmcgNodeTemplate.Base + PAGE1_TO_PMCG_OFFSET;
  226. mPmcgNodeTemplate.NodeReference = SmmuNodeOffset[Idx];
  227. mPmcgNodeTemplate.OverflowInterruptGsiv = mTbuPmuIrqArray[EnabledRCs[Idx]] + Idx1;
  228. CopyMem (PmcgIter, &mPmcgNodeTemplate, sizeof (mPmcgNodeTemplate));
  229. PmcgIter += sizeof (mPmcgNodeTemplate);
  230. }
  231. //
  232. // Add TCU PMCG node
  233. //
  234. mPmcgNodeTemplate.Base = RootComplex->TcuBase + TCU_TO_SMMU_OFFSET;
  235. mPmcgNodeTemplate.Page1Base = mPmcgNodeTemplate.Base + PAGE1_TO_PMCG_OFFSET;
  236. mPmcgNodeTemplate.NodeReference = SmmuNodeOffset[Idx];
  237. mPmcgNodeTemplate.OverflowInterruptGsiv = mTcuPmuIrqArray[EnabledRCs[Idx]];
  238. CopyMem (PmcgIter, &mPmcgNodeTemplate, sizeof (mPmcgNodeTemplate));
  239. PmcgIter += sizeof (mPmcgNodeTemplate);
  240. }
  241. for (Idx = 0; Idx < RcCount; Idx++) {
  242. mRcNodeTemplate.Node.PciSegmentNumber = mRootComplexList[EnabledRCs[Idx]].Logical;
  243. mRcNodeTemplate.RcIdMapping.OutputReference = SmmuNodeOffset[Idx];
  244. CopyMem (IortIter, &mRcNodeTemplate, sizeof (AC01_RC_NODE));
  245. IortIter += sizeof (AC01_RC_NODE);
  246. }
  247. }
  248. EFI_STATUS
  249. EFIAPI
  250. AcpiInstallIort (
  251. VOID
  252. )
  253. {
  254. EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
  255. EFI_STATUS Status;
  256. INT32 EnabledRCs[AC01_PCIE_MAX_ROOT_COMPLEX];
  257. ROOT_COMPLEX_CONFIG_VARSTORE_DATA VarStoreConfig;
  258. UINT32 RcCount, SmmuPmuAgentCount, TotalCount;
  259. UINT8 Idx;
  260. UINTN BufferSize;
  261. UINTN TableKey;
  262. VOID *Hob;
  263. VOID *IortBuffer;
  264. Hob = GetFirstGuidHob (&gRootComplexInfoHobGuid);
  265. if (Hob == NULL) {
  266. return EFI_NOT_FOUND;
  267. }
  268. mRootComplexList = (AC01_ROOT_COMPLEX *)GET_GUID_HOB_DATA (Hob);
  269. for (Idx = 0, RcCount = 0; Idx < AC01_PCIE_MAX_ROOT_COMPLEX; Idx++) {
  270. if (mRootComplexList[Idx].Active) {
  271. EnabledRCs[RcCount++] = Idx;
  272. }
  273. }
  274. EnabledRCs[RcCount] = -1;
  275. Status = gBS->LocateProtocol (
  276. &gEfiAcpiTableProtocolGuid,
  277. NULL,
  278. (VOID **)&AcpiTableProtocol
  279. );
  280. if (EFI_ERROR (Status)) {
  281. DEBUG ((DEBUG_ERROR, "IORT: Unable to locate ACPI table entry\n"));
  282. return Status;
  283. }
  284. SmmuPmuAgentCount = 0;
  285. //
  286. // Check SMMU setting
  287. //
  288. BufferSize = sizeof (VarStoreConfig);
  289. Status = gRT->GetVariable (
  290. ROOT_COMPLEX_CONFIG_VARSTORE_NAME,
  291. &gRootComplexConfigFormSetGuid,
  292. NULL,
  293. &BufferSize,
  294. &VarStoreConfig
  295. );
  296. if (!EFI_ERROR (Status) && VarStoreConfig.SmmuPmu) {
  297. for (Idx = 0; Idx < RcCount; Idx++) {
  298. if (mRootComplexList[EnabledRCs[Idx]].Type == RootComplexTypeA) {
  299. SmmuPmuAgentCount += AC01_RCA_MAX_TBU_PMU;
  300. } else {
  301. SmmuPmuAgentCount += AC01_RCB_MAX_TBU_PMU;
  302. }
  303. // Plus 1 TCU
  304. SmmuPmuAgentCount += 1;
  305. }
  306. }
  307. TotalCount = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE) +
  308. RcCount * (sizeof (AC01_ITS_NODE) + sizeof (AC01_RC_NODE) + sizeof (AC01_SMMU_NODE)) +
  309. SmmuPmuAgentCount * sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE);
  310. IortBuffer = AllocateZeroPool (TotalCount);
  311. if (IortBuffer == NULL) {
  312. return EFI_OUT_OF_RESOURCES;
  313. }
  314. ConstructIort (IortBuffer, RcCount, SmmuPmuAgentCount, TotalCount, EnabledRCs);
  315. Status = AcpiTableProtocol->InstallAcpiTable (
  316. AcpiTableProtocol,
  317. IortBuffer,
  318. TotalCount,
  319. &TableKey
  320. );
  321. if (EFI_ERROR (Status)) {
  322. DEBUG ((DEBUG_ERROR, "IORT: Unable to install IORT table entry\n"));
  323. }
  324. FreePool (IortBuffer);
  325. return Status;
  326. }