AcpiDsdt.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  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 <Guid/RootComplexInfoHob.h>
  6. #include <Protocol/PciRootBridgeIo.h>
  7. #include <Library/NVParamLib.h>
  8. #include <NVParamDef.h>
  9. #include "AcpiNfit.h"
  10. #include "AcpiPlatform.h"
  11. #define PCIE_DEVICE_CONTROL_OFFSET 0x078
  12. #define PCIE_DEVICE_CONTROL_UNSUPPORT_REQ_REP_EN 0x08
  13. #define PCIE_DEVICE_CONTROL_FATAL_ERR_REPORT_EN 0x04
  14. #define PCIE_DEVICE_CONTROL_NON_FATAL_ERR_REPORT_EN 0x02
  15. #define PCIE_DEVICE_CONTROL_CORR_ERR_REPORT_EN 0x01
  16. #define PCIE_ROOT_ERR_CMD_OFFSET 0x12C
  17. #define PCIE_ROOT_ERR_CMD_FATAL_ERR_REPORTING_EN 0x4
  18. #define PCIE_ROOT_ERR_CMD_NON_FATAL_ERR_REPORTING_EN 0x2
  19. #define PCIE_ROOT_ERR_CMD_CORR_ERR_REPORTING_EN 0x1
  20. #define PCIE_MAX_DEVICE_PER_ROOT_PORT 8
  21. #pragma pack(1)
  22. typedef struct {
  23. UINT8 DWordPrefix;
  24. UINT32 DWordData;
  25. } OP_REGION_DWORD_DATA;
  26. typedef struct {
  27. UINT8 ExtOpPrefix;
  28. UINT8 ExtOpCode;
  29. UINT8 NameString[4];
  30. UINT8 RegionSpace;
  31. OP_REGION_DWORD_DATA RegionBase;
  32. OP_REGION_DWORD_DATA RegionLen;
  33. } AML_OP_REGION;
  34. typedef struct {
  35. UINT64 AddressGranularity;
  36. UINT64 AddressMin;
  37. UINT64 AddressMax;
  38. UINT64 AddressTranslation;
  39. UINT64 RangeLength;
  40. } QWORD_MEMORY;
  41. STATIC QWORD_MEMORY mQMemList[] = {
  42. { AC01_PCIE_RCA2_QMEM_LIST },
  43. { AC01_PCIE_RCA3_QMEM_LIST },
  44. { AC01_PCIE_RCB0_QMEM_LIST },
  45. { AC01_PCIE_RCB1_QMEM_LIST },
  46. { AC01_PCIE_RCB2_QMEM_LIST },
  47. { AC01_PCIE_RCB3_QMEM_LIST }
  48. };
  49. #pragma pack()
  50. EFI_STATUS
  51. UpdateStatusMethodObject (
  52. EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
  53. EFI_ACPI_HANDLE TableHandle,
  54. CHAR8 *AsciiObjectPath,
  55. CHAR8 ReturnValue
  56. )
  57. {
  58. EFI_STATUS Status;
  59. EFI_ACPI_HANDLE ObjectHandle;
  60. EFI_ACPI_DATA_TYPE DataType;
  61. CHAR8 *Buffer;
  62. UINTN DataSize;
  63. Status = AcpiSdtProtocol->FindPath (TableHandle, AsciiObjectPath, &ObjectHandle);
  64. if (EFI_ERROR (Status) || ObjectHandle == NULL) {
  65. return EFI_SUCCESS;
  66. }
  67. ASSERT (ObjectHandle != NULL);
  68. Status = AcpiSdtProtocol->GetOption (ObjectHandle, 2, &DataType, (VOID *)&Buffer, &DataSize);
  69. if (!EFI_ERROR (Status) && Buffer[2] == AML_BYTE_PREFIX) {
  70. //
  71. // Only patch when the initial value is byte object.
  72. //
  73. Buffer[3] = ReturnValue;
  74. }
  75. AcpiSdtProtocol->Close (ObjectHandle);
  76. return Status;
  77. }
  78. EFI_STATUS
  79. GetOpRegionBase (
  80. EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
  81. EFI_ACPI_HANDLE TableHandle,
  82. CHAR8 *AsciiObjectPath,
  83. UINT32 *Value
  84. )
  85. {
  86. EFI_STATUS Status;
  87. EFI_ACPI_HANDLE ObjectHandle;
  88. EFI_ACPI_DATA_TYPE DataType;
  89. CHAR8 *Buffer;
  90. UINTN DataSize;
  91. AML_OP_REGION *OpRegion;
  92. Status = AcpiSdtProtocol->FindPath (TableHandle, AsciiObjectPath, &ObjectHandle);
  93. if (EFI_ERROR (Status)) {
  94. Status = EFI_NOT_FOUND;
  95. goto Exit;
  96. }
  97. Status = AcpiSdtProtocol->GetOption (ObjectHandle, 0, &DataType, (VOID *)&Buffer, &DataSize);
  98. if (!EFI_ERROR (Status) && Buffer != NULL) {
  99. OpRegion = (AML_OP_REGION *)Buffer;
  100. if (OpRegion->ExtOpCode != AML_EXT_REGION_OP
  101. || OpRegion->RegionBase.DWordPrefix != AML_DWORD_PREFIX)
  102. {
  103. AcpiSdtProtocol->Close (TableHandle);
  104. Status = EFI_NOT_FOUND;
  105. goto Exit;
  106. }
  107. *Value = OpRegion->RegionBase.DWordData;
  108. }
  109. Exit:
  110. AcpiSdtProtocol->Close (ObjectHandle);
  111. return Status;
  112. }
  113. EFI_STATUS
  114. SetOpRegionBase (
  115. EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
  116. EFI_ACPI_HANDLE TableHandle,
  117. CHAR8 *AsciiObjectPath,
  118. UINT32 Value
  119. )
  120. {
  121. EFI_STATUS Status;
  122. EFI_ACPI_HANDLE ObjectHandle;
  123. EFI_ACPI_DATA_TYPE DataType;
  124. CHAR8 *Buffer;
  125. UINTN DataSize;
  126. AML_OP_REGION *OpRegion;
  127. Status = AcpiSdtProtocol->FindPath (TableHandle, AsciiObjectPath, &ObjectHandle);
  128. if (EFI_ERROR (Status)) {
  129. Status = EFI_NOT_FOUND;
  130. goto Exit;
  131. }
  132. Status = AcpiSdtProtocol->GetOption (ObjectHandle, 0, &DataType, (VOID *)&Buffer, &DataSize);
  133. if (!EFI_ERROR (Status) && Buffer != NULL) {
  134. OpRegion = (AML_OP_REGION *)Buffer;
  135. if (OpRegion->ExtOpCode != AML_EXT_REGION_OP
  136. || OpRegion->RegionBase.DWordPrefix != AML_DWORD_PREFIX)
  137. {
  138. AcpiSdtProtocol->Close (TableHandle);
  139. Status = EFI_NOT_FOUND;
  140. goto Exit;
  141. }
  142. OpRegion->RegionBase.DWordData = Value;
  143. }
  144. Exit:
  145. AcpiSdtProtocol->Close (ObjectHandle);
  146. return Status;
  147. }
  148. STATIC VOID
  149. AcpiPatchCmn600 (
  150. EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
  151. EFI_ACPI_HANDLE TableHandle
  152. )
  153. {
  154. CHAR8 NodePath[256];
  155. UINTN Index;
  156. for (Index = 0; Index < GetNumberOfSupportedSockets (); Index++) {
  157. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.CMN%1X._STA", Index);
  158. if (GetNumberOfActiveCPMsPerSocket (Index) > 0) {
  159. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0xF);
  160. } else {
  161. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  162. }
  163. }
  164. }
  165. STATIC VOID
  166. AcpiPatchDmc620 (
  167. EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
  168. EFI_ACPI_HANDLE TableHandle
  169. )
  170. {
  171. CHAR8 NodePath[256];
  172. UINTN Index, Index1;
  173. PLATFORM_INFO_HOB *PlatformHob;
  174. UINT32 McuMask;
  175. VOID *Hob;
  176. Hob = GetFirstGuidHob (&gPlatformInfoHobGuid);
  177. if (Hob == NULL) {
  178. return;
  179. }
  180. PlatformHob = (PLATFORM_INFO_HOB *)GET_GUID_HOB_DATA (Hob);
  181. for (Index = 0; Index < GetNumberOfSupportedSockets (); Index++) {
  182. McuMask = PlatformHob->DramInfo.McuMask[Index];
  183. for (Index1 = 0; Index1 < sizeof (McuMask) * 8; Index1++) {
  184. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.MC%1X%1X._STA", Index, Index1);
  185. if (McuMask & (0x1 << Index1)) {
  186. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0xF);
  187. } else {
  188. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  189. }
  190. }
  191. }
  192. }
  193. STATIC VOID
  194. AcpiPatchNvdimm (
  195. EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
  196. EFI_ACPI_HANDLE TableHandle
  197. )
  198. {
  199. CHAR8 NodePath[256];
  200. UINTN NvdRegionNumSK0, NvdRegionNumSK1, NvdRegionNum, Count;
  201. PLATFORM_INFO_HOB *PlatformHob;
  202. VOID *Hob;
  203. UINT32 OpRegionBase;;
  204. EFI_STATUS Status;
  205. Hob = GetFirstGuidHob (&gPlatformInfoHobGuid);
  206. if (Hob == NULL) {
  207. return;
  208. }
  209. PlatformHob = (PLATFORM_INFO_HOB *)GET_GUID_HOB_DATA (Hob);
  210. NvdRegionNumSK0 = 0;
  211. NvdRegionNumSK1 = 0;
  212. for (Count = 0; Count < PlatformHob->DramInfo.NumRegion; Count++) {
  213. if (PlatformHob->DramInfo.NvdRegion[Count] > 0) {
  214. if (PlatformHob->DramInfo.Socket[Count] == 0) {
  215. NvdRegionNumSK0++;
  216. } else {
  217. NvdRegionNumSK1++;
  218. }
  219. }
  220. }
  221. NvdRegionNum = NvdRegionNumSK0 + NvdRegionNumSK1;
  222. /* Disable NVDIMM Root Device */
  223. if (NvdRegionNum == 0) {
  224. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.NVDR._STA");
  225. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  226. }
  227. /* Update NVDIMM Device _STA for SK0 */
  228. if (NvdRegionNumSK0 == 0) {
  229. /* Disable NVD1/2 */
  230. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.NVDR.NVD1._STA");
  231. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  232. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.NVDR.NVD2._STA");
  233. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  234. } else if (NvdRegionNumSK0 == 1) {
  235. if (PlatformHob->DramInfo.NvdimmMode[NVDIMM_SK0] == NvdimmNonHashed) {
  236. for (Count = 0; Count < PlatformHob->DramInfo.NumRegion; Count++) {
  237. if (PlatformHob->DramInfo.NvdRegion[Count] > 0 &&
  238. PlatformHob->DramInfo.Socket[Count] == 0)
  239. {
  240. if (PlatformHob->DramInfo.Base[Count] ==
  241. AC01_NVDIMM_SK0_NHASHED_REGION0_BASE)
  242. {
  243. /* Disable NVD2 */
  244. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.NVDR.NVD2._STA");
  245. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  246. } else if (PlatformHob->DramInfo.Base[Count] ==
  247. AC01_NVDIMM_SK0_NHASHED_REGION1_BASE)
  248. {
  249. /* Disable NVD1 */
  250. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.NVDR.NVD1._STA");
  251. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  252. }
  253. }
  254. }
  255. }
  256. }
  257. /* Update NVDIMM Device _STA and OpRegions for SK1 */
  258. if (NvdRegionNumSK1 == 0) {
  259. /* Use NVD1 OpRegion base for NVD3 */
  260. OpRegionBase = 0;
  261. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.NVDR.NVD1.BUF1");
  262. Status = GetOpRegionBase (AcpiSdtProtocol, TableHandle, NodePath, &OpRegionBase);
  263. ASSERT ((!EFI_ERROR (Status)) && (OpRegionBase != 0));
  264. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.NVDR.NVD3.BUF1");
  265. Status = SetOpRegionBase (AcpiSdtProtocol, TableHandle, NodePath, OpRegionBase);
  266. /* Use NVD2 OpRegion base for NVD4 */
  267. OpRegionBase = 0;
  268. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.NVDR.NVD2.BUF1");
  269. Status = GetOpRegionBase (AcpiSdtProtocol, TableHandle, NodePath, &OpRegionBase);
  270. ASSERT ((!EFI_ERROR (Status)) && (OpRegionBase != 0));
  271. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.NVDR.NVD4.BUF1");
  272. Status = SetOpRegionBase (AcpiSdtProtocol, TableHandle, NodePath, OpRegionBase);
  273. /* Disable NVD3/4 */
  274. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.NVDR.NVD3._STA");
  275. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  276. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.NVDR.NVD4._STA");
  277. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  278. } else if (NvdRegionNumSK1 == 1) {
  279. if (PlatformHob->DramInfo.NvdimmMode[NVDIMM_SK1] == NvdimmNonHashed) {
  280. for (Count = 0; Count < PlatformHob->DramInfo.NumRegion; Count++) {
  281. if (PlatformHob->DramInfo.NvdRegion[Count] > 0 &&
  282. PlatformHob->DramInfo.Socket[Count] == 1)
  283. {
  284. if (PlatformHob->DramInfo.Base[Count] ==
  285. AC01_NVDIMM_SK1_NHASHED_REGION0_BASE)
  286. {
  287. /* Disable NVD4 */
  288. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.NVDR.NVD4._STA");
  289. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  290. } else if (PlatformHob->DramInfo.Base[Count] ==
  291. AC01_NVDIMM_SK1_NHASHED_REGION1_BASE)
  292. {
  293. /* Disable NVD3 */
  294. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.NVDR.NVD3._STA");
  295. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  296. }
  297. }
  298. }
  299. }
  300. }
  301. }
  302. STATIC VOID
  303. AcpiPatchHwmon (
  304. EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
  305. EFI_ACPI_HANDLE TableHandle
  306. )
  307. {
  308. CHAR8 NodePath[256];
  309. UINT8 Index;
  310. // PCC Hardware Monitor Devices
  311. for (Index = 0; Index < GetNumberOfSupportedSockets (); Index++) {
  312. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.HM0%1X._STA", Index);
  313. if (GetNumberOfActiveCPMsPerSocket (Index) > 0) {
  314. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0xF);
  315. } else {
  316. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  317. }
  318. }
  319. // Ampere Altra SoC Hardware Monitor Devices
  320. for (Index = 0; Index < GetNumberOfSupportedSockets (); Index++) {
  321. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.HM0%1X._STA", Index + 2);
  322. if (GetNumberOfActiveCPMsPerSocket (Index) > 0) {
  323. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0xF);
  324. } else {
  325. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  326. }
  327. }
  328. }
  329. STATIC VOID
  330. AcpiPatchDsu (
  331. EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
  332. EFI_ACPI_HANDLE TableHandle
  333. )
  334. {
  335. CHAR8 NodePath[256];
  336. UINTN Index;
  337. for (Index = 0; Index < PLATFORM_CPU_MAX_NUM_CORES; Index += PLATFORM_CPU_NUM_CORES_PER_CPM) {
  338. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.DU%2X._STA", Index / PLATFORM_CPU_NUM_CORES_PER_CPM);
  339. if (IsCpuEnabled (Index)) {
  340. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0xF);
  341. } else {
  342. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  343. }
  344. }
  345. }
  346. VOID
  347. AcpiPatchPcieNuma (
  348. EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
  349. EFI_ACPI_HANDLE TableHandle
  350. )
  351. {
  352. CHAR8 NodePath[256];
  353. UINTN Index;
  354. UINTN NumaIdx;
  355. UINTN NumPciePort;
  356. UINTN NumaAssignment[3][16] = {
  357. { 0, 0, 0, 0, 0, 0, 0, 0, // Monolithic Node 0 (S0)
  358. 1, 1, 1, 1, 1, 1, 1, 1 }, // Monolithic Node 1 (S1)
  359. { 0, 1, 0, 1, 0, 0, 1, 1, // Hemisphere Node 0, 1 (S0)
  360. 2, 3, 2, 3, 2, 2, 3, 3 }, // Hemisphere Node 2, 3 (S1)
  361. { 0, 2, 1, 3, 1, 1, 3, 3, // Quadrant Node 0, 1, 2, 3 (S0)
  362. 4, 6, 5, 7, 5, 5, 7, 7 }, // Quadrant Node 4, 5, 6, 7 (S1)
  363. };
  364. switch (CpuGetSubNumaMode ()) {
  365. case SUBNUMA_MODE_MONOLITHIC:
  366. NumaIdx = 0;
  367. break;
  368. case SUBNUMA_MODE_HEMISPHERE:
  369. NumaIdx = 1;
  370. break;
  371. case SUBNUMA_MODE_QUADRANT:
  372. NumaIdx = 2;
  373. break;
  374. default:
  375. NumaIdx = 0;
  376. break;
  377. }
  378. if (IsSlaveSocketActive ()) {
  379. NumPciePort = 16; // 16 ports total (8 per socket)
  380. } else {
  381. NumPciePort = 8; // 8 ports total
  382. }
  383. for (Index = 0; Index < NumPciePort; Index++) {
  384. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.PCI%X._PXM", Index);
  385. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, NumaAssignment[NumaIdx][Index]);
  386. }
  387. }
  388. EFI_STATUS
  389. AcpiPatchPcieAerFwFirst (
  390. EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
  391. EFI_ACPI_HANDLE TableHandle
  392. )
  393. {
  394. EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS Address;
  395. EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
  396. EFI_HANDLE *HandleBuffer;
  397. UINTN HandleCount;
  398. CHAR8 ObjectPath[8];
  399. EFI_STATUS Status;
  400. UINT32 AerFwFirstConfigValue;
  401. UINT32 RegData;
  402. UINT16 Device;
  403. UINT32 Index;
  404. //
  405. // Check if PCIe AER Firmware First should be enabled
  406. //
  407. Status = NVParamGet (
  408. NV_SI_RAS_PCIE_AER_FW_FIRST,
  409. NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
  410. &AerFwFirstConfigValue
  411. );
  412. if (EFI_ERROR (Status)) {
  413. Status = NVParamGet (
  414. NV_SI_RO_BOARD_PCIE_AER_FW_FIRST,
  415. NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
  416. &AerFwFirstConfigValue
  417. );
  418. if (EFI_ERROR (Status)) {
  419. AerFwFirstConfigValue = 0;
  420. }
  421. }
  422. if (AerFwFirstConfigValue == 0) {
  423. //
  424. // By default, the PCIe AER FW-First (ACPI Object "AERF") is set to 0
  425. // in the DSDT table.
  426. //
  427. return EFI_SUCCESS;
  428. }
  429. //
  430. // Update Name Object "AERF" (PCIe AER Firmware-First) to enable PCIe AER Firmware-First
  431. //
  432. AsciiSPrint (ObjectPath, sizeof (ObjectPath), "\\AERF");
  433. Status = AcpiAmlObjectUpdateInteger (AcpiSdtProtocol, TableHandle, ObjectPath, 1);
  434. //
  435. // For PCIe AER Firmware First, PCIe capability registers need
  436. // to be updated to allow Firmware to detect AER errors.
  437. //
  438. HandleCount = 0;
  439. HandleBuffer = NULL;
  440. PciRootBridgeIo = NULL;
  441. Status = gBS->LocateHandleBuffer (
  442. ByProtocol,
  443. &gEfiPciRootBridgeIoProtocolGuid,
  444. NULL,
  445. &HandleCount,
  446. &HandleBuffer
  447. );
  448. if (EFI_ERROR (Status)) {
  449. return Status;
  450. }
  451. //
  452. // Loop through each root complex
  453. //
  454. for (Index = 0; Index < HandleCount; Index++) {
  455. Status = gBS->HandleProtocol (
  456. HandleBuffer[Index],
  457. &gEfiPciRootBridgeIoProtocolGuid,
  458. (VOID **)&PciRootBridgeIo
  459. );
  460. if (EFI_ERROR (Status)) {
  461. return Status;
  462. }
  463. //
  464. // Loop through each root port
  465. //
  466. for (Device = 1; Device <= PCIE_MAX_DEVICE_PER_ROOT_PORT; Device++) {
  467. Address.Bus = 0;
  468. Address.Device = Device;
  469. Address.Function = 0;
  470. Address.Register = 0;
  471. Address.ExtendedRegister = PCIE_DEVICE_CONTROL_OFFSET;
  472. PciRootBridgeIo->Pci.Read (PciRootBridgeIo, EfiPciWidthUint32, *((UINT64 *)&Address), 1, &RegData);
  473. if (RegData == 0xFFFFFFFF) {
  474. continue;
  475. }
  476. RegData |= PCIE_DEVICE_CONTROL_UNSUPPORT_REQ_REP_EN
  477. | PCIE_DEVICE_CONTROL_FATAL_ERR_REPORT_EN
  478. | PCIE_DEVICE_CONTROL_NON_FATAL_ERR_REPORT_EN
  479. | PCIE_DEVICE_CONTROL_CORR_ERR_REPORT_EN;
  480. PciRootBridgeIo->Pci.Write (PciRootBridgeIo, EfiPciWidthUint32, *((UINT64 *)&Address), 1, &RegData);
  481. RegData = 0;
  482. Address.ExtendedRegister = PCIE_ROOT_ERR_CMD_OFFSET;
  483. PciRootBridgeIo->Pci.Read (PciRootBridgeIo, EfiPciWidthUint32, *((UINT64 *)&Address), 1, &RegData);
  484. RegData |= PCIE_ROOT_ERR_CMD_FATAL_ERR_REPORTING_EN
  485. | PCIE_ROOT_ERR_CMD_NON_FATAL_ERR_REPORTING_EN
  486. | PCIE_ROOT_ERR_CMD_CORR_ERR_REPORTING_EN;
  487. PciRootBridgeIo->Pci.Write (PciRootBridgeIo, EfiPciWidthUint32, *((UINT64 *)&Address), 1, &RegData);
  488. }
  489. }
  490. return Status;
  491. }
  492. VOID
  493. AcpiPatchPcieMmio32 (
  494. EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
  495. EFI_ACPI_HANDLE TableHandle
  496. )
  497. {
  498. AC01_ROOT_COMPLEX *RootComplexList;
  499. CHAR8 *NextDescriptor, *Buffer;
  500. CHAR8 NodePath[256];
  501. EFI_ACPI_DATA_TYPE DataType;
  502. EFI_ACPI_HANDLE ObjectHandle;
  503. EFI_STATUS Status;
  504. EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
  505. UINTN DataSize;
  506. UINTN Idx;
  507. VOID *Hob;
  508. Hob = GetFirstGuidHob (&gRootComplexInfoHobGuid);
  509. if (Hob == NULL) {
  510. return;
  511. }
  512. RootComplexList = (AC01_ROOT_COMPLEX *)GET_GUID_HOB_DATA (Hob);
  513. for (Idx = 0; Idx < AC01_PCIE_MAX_ROOT_COMPLEX; Idx++) {
  514. if (!RootComplexList[Idx].Active) {
  515. //
  516. // Patch for disabled Root Complex
  517. //
  518. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.PCI%X._STA", Idx);
  519. UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
  520. continue;
  521. }
  522. if (!IsSlaveSocketActive () && Idx <= SOCKET0_LAST_RC) {
  523. //
  524. // Patch MMIO32 resource in 1P system
  525. //
  526. AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.PCI%X.RBUF", Idx);
  527. Status = AcpiSdtProtocol->FindPath (TableHandle, NodePath, &ObjectHandle);
  528. if (EFI_ERROR (Status)) {
  529. continue;
  530. }
  531. Status = AcpiSdtProtocol->GetOption (ObjectHandle, 2, &DataType, (VOID *)&Buffer, &DataSize);
  532. if (EFI_ERROR (Status)) {
  533. continue;
  534. }
  535. if (DataType != EFI_ACPI_DATA_TYPE_CHILD) {
  536. AcpiSdtProtocol->Close (ObjectHandle);
  537. continue;
  538. }
  539. NextDescriptor = Buffer + 5; // Point to first address space descriptor
  540. while ((NextDescriptor - Buffer) < DataSize) {
  541. Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)NextDescriptor;
  542. if (Descriptor->Desc == ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR
  543. && Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
  544. CopyMem (&Descriptor->AddrSpaceGranularity, &mQMemList[Idx - 2], sizeof (QWORD_MEMORY));
  545. break;
  546. }
  547. NextDescriptor += (Descriptor->Len + sizeof (ACPI_LARGE_RESOURCE_HEADER));
  548. }
  549. AcpiSdtProtocol->Close (ObjectHandle);
  550. }
  551. }
  552. }
  553. EFI_STATUS
  554. AcpiPatchDsdtTable (
  555. VOID
  556. )
  557. {
  558. EFI_STATUS Status;
  559. EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol;
  560. EFI_ACPI_DESCRIPTION_HEADER *Table;
  561. UINTN TableKey;
  562. UINTN TableIndex;
  563. EFI_ACPI_HANDLE TableHandle;
  564. Status = gBS->LocateProtocol (
  565. &gEfiAcpiSdtProtocolGuid,
  566. NULL,
  567. (VOID **)&AcpiSdtProtocol
  568. );
  569. if (EFI_ERROR (Status)) {
  570. DEBUG ((DEBUG_ERROR, "Unable to locate ACPI table protocol\n"));
  571. return Status;
  572. }
  573. TableIndex = 0;
  574. Status = AcpiLocateTableBySignature (
  575. AcpiSdtProtocol,
  576. EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
  577. &TableIndex,
  578. &Table,
  579. &TableKey
  580. );
  581. if (EFI_ERROR (Status)) {
  582. DEBUG ((DEBUG_ERROR, "ACPI DSDT table not found!\n"));
  583. ASSERT_EFI_ERROR (Status);
  584. return Status;
  585. }
  586. Status = AcpiSdtProtocol->OpenSdt (TableKey, &TableHandle);
  587. if (EFI_ERROR (Status)) {
  588. ASSERT_EFI_ERROR (Status);
  589. AcpiSdtProtocol->Close (TableHandle);
  590. return Status;
  591. }
  592. AcpiPatchCmn600 (AcpiSdtProtocol, TableHandle);
  593. AcpiPatchDmc620 (AcpiSdtProtocol, TableHandle);
  594. AcpiPatchDsu (AcpiSdtProtocol, TableHandle);
  595. AcpiPatchHwmon (AcpiSdtProtocol, TableHandle);
  596. AcpiPatchNvdimm (AcpiSdtProtocol, TableHandle);
  597. AcpiPatchPcieNuma (AcpiSdtProtocol, TableHandle);
  598. AcpiPatchPcieAerFwFirst (AcpiSdtProtocol, TableHandle);
  599. AcpiPatchPcieMmio32 (AcpiSdtProtocol, TableHandle);
  600. AcpiSdtProtocol->Close (TableHandle);
  601. AcpiUpdateChecksum ((UINT8 *)Table, Table->Length);
  602. return EFI_SUCCESS;
  603. }