SsdtPcieSupportLib.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /** @file
  2. SSDT PCIe Support Library.
  3. Copyright (c) 2021 - 2022, Arm Limited. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. @par Reference(s):
  6. - PCI Firmware Specification - Revision 3.0
  7. - ACPI 6.4 specification:
  8. - s6.2.13 "_PRT (PCI Routing Table)"
  9. - s6.1.1 "_ADR (Address)"
  10. - linux kernel code
  11. - Arm Base Boot Requirements v1.0
  12. - Arm Base System Architecture v1.0
  13. **/
  14. #include <Library/AcpiLib.h>
  15. #include <Library/BaseLib.h>
  16. #include <Library/BaseMemoryLib.h>
  17. #include <Library/DebugLib.h>
  18. #include <Library/MemoryAllocationLib.h>
  19. #include <Protocol/AcpiTable.h>
  20. // Module specific include files.
  21. #include <AcpiTableGenerator.h>
  22. #include <ConfigurationManagerObject.h>
  23. #include <ConfigurationManagerHelper.h>
  24. #include <Library/AcpiHelperLib.h>
  25. #include <Library/TableHelperLib.h>
  26. #include <Library/AmlLib/AmlLib.h>
  27. #include <Library/SsdtPcieSupportLib.h>
  28. #include <Protocol/ConfigurationManagerProtocol.h>
  29. #include "SsdtPcieSupportLibPrivate.h"
  30. /** Generate Pci slots devices.
  31. PCI Firmware Specification - Revision 3.3,
  32. s4.8 "Generic ACPI PCI Slot Description" requests to describe the PCI slot
  33. used. It should be possible to enumerate them, but this is additional
  34. information.
  35. @param [in] PciInfo Pci device information.
  36. @param [in] MappingTable The mapping table structure.
  37. @param [in, out] PciNode Pci node to amend.
  38. @retval EFI_SUCCESS Success.
  39. @retval EFI_INVALID_PARAMETER Invalid parameter.
  40. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
  41. **/
  42. EFI_STATUS
  43. EFIAPI
  44. GeneratePciSlots (
  45. IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
  46. IN CONST MAPPING_TABLE *MappingTable,
  47. IN OUT AML_OBJECT_NODE_HANDLE PciNode
  48. )
  49. {
  50. EFI_STATUS Status;
  51. UINT32 Index;
  52. UINT32 LastIndex;
  53. UINT32 DeviceId;
  54. CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
  55. AML_OBJECT_NODE_HANDLE DeviceNode;
  56. ASSERT (MappingTable != NULL);
  57. ASSERT (PciNode != NULL);
  58. // Generic device name is "Dxx".
  59. CopyMem (AslName, "Dxx_", AML_NAME_SEG_SIZE + 1);
  60. LastIndex = MappingTable->LastIndex;
  61. // There are at most 32 devices on a Pci bus.
  62. if (LastIndex >= 32) {
  63. ASSERT (0);
  64. return EFI_INVALID_PARAMETER;
  65. }
  66. for (Index = 0; Index < LastIndex; Index++) {
  67. DeviceId = MappingTable->Table[Index];
  68. AslName[AML_NAME_SEG_SIZE - 3] = AsciiFromHex (DeviceId & 0xF);
  69. AslName[AML_NAME_SEG_SIZE - 2] = AsciiFromHex ((DeviceId >> 4) & 0xF);
  70. // ASL:
  71. // Device (Dxx) {
  72. // Name (_ADR, <address value>)
  73. // }
  74. Status = AmlCodeGenDevice (AslName, PciNode, &DeviceNode);
  75. if (EFI_ERROR (Status)) {
  76. ASSERT (0);
  77. return Status;
  78. }
  79. /* ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
  80. High word-Device #, Low word-Function #. (for example, device 3,
  81. function 2 is 0x00030002). To refer to all the functions on a device #,
  82. use a function number of FFFF).
  83. */
  84. Status = AmlCodeGenNameInteger (
  85. "_ADR",
  86. (DeviceId << 16) | 0xFFFF,
  87. DeviceNode,
  88. NULL
  89. );
  90. if (EFI_ERROR (Status)) {
  91. ASSERT (0);
  92. return Status;
  93. }
  94. // _SUN object is not generated as we don't know which slot will be used.
  95. }
  96. return Status;
  97. }
  98. /** Add an _OSC template method to the PciNode.
  99. The _OSC method is provided as an AML blob. The blob is
  100. parsed and attached at the end of the PciNode list of variable elements.
  101. @param [in] PciInfo Pci device information.
  102. @param [in, out] PciNode Pci node to amend.
  103. @retval EFI_SUCCESS The function completed successfully.
  104. @retval EFI_INVALID_PARAMETER Invalid parameter.
  105. @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
  106. **/
  107. EFI_STATUS
  108. EFIAPI
  109. AddOscMethod (
  110. IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
  111. IN OUT AML_OBJECT_NODE_HANDLE PciNode
  112. )
  113. {
  114. EFI_STATUS Status;
  115. EFI_STATUS Status1;
  116. EFI_ACPI_DESCRIPTION_HEADER *SsdtPcieOscTemplate;
  117. AML_ROOT_NODE_HANDLE OscTemplateRoot;
  118. AML_OBJECT_NODE_HANDLE OscNode;
  119. ASSERT (PciNode != NULL);
  120. // Parse the Ssdt Pci Osc Template.
  121. SsdtPcieOscTemplate = (EFI_ACPI_DESCRIPTION_HEADER *)
  122. ssdtpcieosctemplate_aml_code;
  123. OscNode = NULL;
  124. OscTemplateRoot = NULL;
  125. Status = AmlParseDefinitionBlock (
  126. SsdtPcieOscTemplate,
  127. &OscTemplateRoot
  128. );
  129. if (EFI_ERROR (Status)) {
  130. DEBUG ((
  131. DEBUG_ERROR,
  132. "ERROR: SSDT-PCI-OSC: Failed to parse SSDT PCI OSC Template."
  133. " Status = %r\n",
  134. Status
  135. ));
  136. return Status;
  137. }
  138. Status = AmlFindNode (OscTemplateRoot, "\\_OSC", &OscNode);
  139. if (EFI_ERROR (Status)) {
  140. goto error_handler;
  141. }
  142. Status = AmlDetachNode (OscNode);
  143. if (EFI_ERROR (Status)) {
  144. goto error_handler;
  145. }
  146. Status = AmlAttachNode (PciNode, OscNode);
  147. if (EFI_ERROR (Status)) {
  148. // Free the detached node.
  149. AmlDeleteTree (OscNode);
  150. goto error_handler;
  151. }
  152. error_handler:
  153. // Cleanup
  154. Status1 = AmlDeleteTree (OscTemplateRoot);
  155. if (EFI_ERROR (Status1)) {
  156. DEBUG ((
  157. DEBUG_ERROR,
  158. "ERROR: SSDT-PCI-OSC: Failed to cleanup AML tree."
  159. " Status = %r\n",
  160. Status1
  161. ));
  162. // If Status was success but we failed to delete the AML Tree
  163. // return Status1 else return the original error code, i.e. Status.
  164. if (!EFI_ERROR (Status)) {
  165. return Status1;
  166. }
  167. }
  168. return Status;
  169. }