|
@@ -0,0 +1,200 @@
|
|
|
+/** @file
|
|
|
+ SSDT PCIe Support Library.
|
|
|
+
|
|
|
+ Copyright (c) 2021 - 2022, Arm Limited. All rights reserved.<BR>
|
|
|
+
|
|
|
+ SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
+
|
|
|
+ @par Reference(s):
|
|
|
+ - PCI Firmware Specification - Revision 3.0
|
|
|
+ - ACPI 6.4 specification:
|
|
|
+ - s6.2.13 "_PRT (PCI Routing Table)"
|
|
|
+ - s6.1.1 "_ADR (Address)"
|
|
|
+ - linux kernel code
|
|
|
+ - Arm Base Boot Requirements v1.0
|
|
|
+ - Arm Base System Architecture v1.0
|
|
|
+**/
|
|
|
+
|
|
|
+#include <Library/AcpiLib.h>
|
|
|
+#include <Library/BaseLib.h>
|
|
|
+#include <Library/BaseMemoryLib.h>
|
|
|
+#include <Library/DebugLib.h>
|
|
|
+#include <Library/MemoryAllocationLib.h>
|
|
|
+#include <Protocol/AcpiTable.h>
|
|
|
+
|
|
|
+// Module specific include files.
|
|
|
+#include <AcpiTableGenerator.h>
|
|
|
+#include <ConfigurationManagerObject.h>
|
|
|
+#include <ConfigurationManagerHelper.h>
|
|
|
+#include <Library/AcpiHelperLib.h>
|
|
|
+#include <Library/TableHelperLib.h>
|
|
|
+#include <Library/AmlLib/AmlLib.h>
|
|
|
+#include <Library/SsdtPcieSupportLib.h>
|
|
|
+#include <Protocol/ConfigurationManagerProtocol.h>
|
|
|
+
|
|
|
+#include "SsdtPcieSupportLibPrivate.h"
|
|
|
+
|
|
|
+/** Generate Pci slots devices.
|
|
|
+
|
|
|
+ PCI Firmware Specification - Revision 3.3,
|
|
|
+ s4.8 "Generic ACPI PCI Slot Description" requests to describe the PCI slot
|
|
|
+ used. It should be possible to enumerate them, but this is additional
|
|
|
+ information.
|
|
|
+
|
|
|
+ @param [in] PciInfo Pci device information.
|
|
|
+ @param [in] MappingTable The mapping table structure.
|
|
|
+ @param [in, out] PciNode Pci node to amend.
|
|
|
+
|
|
|
+ @retval EFI_SUCCESS Success.
|
|
|
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
|
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+GeneratePciSlots (
|
|
|
+ IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
|
|
|
+ IN CONST MAPPING_TABLE *MappingTable,
|
|
|
+ IN OUT AML_OBJECT_NODE_HANDLE PciNode
|
|
|
+ )
|
|
|
+{
|
|
|
+ EFI_STATUS Status;
|
|
|
+ UINT32 Index;
|
|
|
+ UINT32 LastIndex;
|
|
|
+ UINT32 DeviceId;
|
|
|
+ CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
|
|
|
+ AML_OBJECT_NODE_HANDLE DeviceNode;
|
|
|
+
|
|
|
+ ASSERT (MappingTable != NULL);
|
|
|
+ ASSERT (PciNode != NULL);
|
|
|
+
|
|
|
+ // Generic device name is "Dxx".
|
|
|
+ CopyMem (AslName, "Dxx_", AML_NAME_SEG_SIZE + 1);
|
|
|
+
|
|
|
+ LastIndex = MappingTable->LastIndex;
|
|
|
+
|
|
|
+ // There are at most 32 devices on a Pci bus.
|
|
|
+ if (LastIndex >= 32) {
|
|
|
+ ASSERT (0);
|
|
|
+ return EFI_INVALID_PARAMETER;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (Index = 0; Index < LastIndex; Index++) {
|
|
|
+ DeviceId = MappingTable->Table[Index];
|
|
|
+ AslName[AML_NAME_SEG_SIZE - 3] = AsciiFromHex (DeviceId & 0xF);
|
|
|
+ AslName[AML_NAME_SEG_SIZE - 2] = AsciiFromHex ((DeviceId >> 4) & 0xF);
|
|
|
+
|
|
|
+ // ASL:
|
|
|
+ // Device (Dxx) {
|
|
|
+ // Name (_ADR, <address value>)
|
|
|
+ // }
|
|
|
+ Status = AmlCodeGenDevice (AslName, PciNode, &DeviceNode);
|
|
|
+ if (EFI_ERROR (Status)) {
|
|
|
+ ASSERT (0);
|
|
|
+ return Status;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
|
|
|
+ High word-Device #, Low word-Function #. (for example, device 3,
|
|
|
+ function 2 is 0x00030002). To refer to all the functions on a device #,
|
|
|
+ use a function number of FFFF).
|
|
|
+ */
|
|
|
+ Status = AmlCodeGenNameInteger (
|
|
|
+ "_ADR",
|
|
|
+ (DeviceId << 16) | 0xFFFF,
|
|
|
+ DeviceNode,
|
|
|
+ NULL
|
|
|
+ );
|
|
|
+ if (EFI_ERROR (Status)) {
|
|
|
+ ASSERT (0);
|
|
|
+ return Status;
|
|
|
+ }
|
|
|
+
|
|
|
+ // _SUN object is not generated as we don't know which slot will be used.
|
|
|
+ }
|
|
|
+
|
|
|
+ return Status;
|
|
|
+}
|
|
|
+
|
|
|
+/** Add an _OSC template method to the PciNode.
|
|
|
+
|
|
|
+ The _OSC method is provided as an AML blob. The blob is
|
|
|
+ parsed and attached at the end of the PciNode list of variable elements.
|
|
|
+
|
|
|
+ @param [in] PciInfo Pci device information.
|
|
|
+ @param [in, out] PciNode Pci node to amend.
|
|
|
+
|
|
|
+ @retval EFI_SUCCESS The function completed successfully.
|
|
|
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
|
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
|
|
+**/
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+AddOscMethod (
|
|
|
+ IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *PciInfo,
|
|
|
+ IN OUT AML_OBJECT_NODE_HANDLE PciNode
|
|
|
+ )
|
|
|
+{
|
|
|
+ EFI_STATUS Status;
|
|
|
+ EFI_STATUS Status1;
|
|
|
+ EFI_ACPI_DESCRIPTION_HEADER *SsdtPcieOscTemplate;
|
|
|
+ AML_ROOT_NODE_HANDLE OscTemplateRoot;
|
|
|
+ AML_OBJECT_NODE_HANDLE OscNode;
|
|
|
+
|
|
|
+ ASSERT (PciNode != NULL);
|
|
|
+
|
|
|
+ // Parse the Ssdt Pci Osc Template.
|
|
|
+ SsdtPcieOscTemplate = (EFI_ACPI_DESCRIPTION_HEADER *)
|
|
|
+ ssdtpcieosctemplate_aml_code;
|
|
|
+
|
|
|
+ OscNode = NULL;
|
|
|
+ OscTemplateRoot = NULL;
|
|
|
+ Status = AmlParseDefinitionBlock (
|
|
|
+ SsdtPcieOscTemplate,
|
|
|
+ &OscTemplateRoot
|
|
|
+ );
|
|
|
+ if (EFI_ERROR (Status)) {
|
|
|
+ DEBUG ((
|
|
|
+ DEBUG_ERROR,
|
|
|
+ "ERROR: SSDT-PCI-OSC: Failed to parse SSDT PCI OSC Template."
|
|
|
+ " Status = %r\n",
|
|
|
+ Status
|
|
|
+ ));
|
|
|
+ return Status;
|
|
|
+ }
|
|
|
+
|
|
|
+ Status = AmlFindNode (OscTemplateRoot, "\\_OSC", &OscNode);
|
|
|
+ if (EFI_ERROR (Status)) {
|
|
|
+ goto error_handler;
|
|
|
+ }
|
|
|
+
|
|
|
+ Status = AmlDetachNode (OscNode);
|
|
|
+ if (EFI_ERROR (Status)) {
|
|
|
+ goto error_handler;
|
|
|
+ }
|
|
|
+
|
|
|
+ Status = AmlAttachNode (PciNode, OscNode);
|
|
|
+ if (EFI_ERROR (Status)) {
|
|
|
+ // Free the detached node.
|
|
|
+ AmlDeleteTree (OscNode);
|
|
|
+ goto error_handler;
|
|
|
+ }
|
|
|
+
|
|
|
+error_handler:
|
|
|
+ // Cleanup
|
|
|
+ Status1 = AmlDeleteTree (OscTemplateRoot);
|
|
|
+ if (EFI_ERROR (Status1)) {
|
|
|
+ DEBUG ((
|
|
|
+ DEBUG_ERROR,
|
|
|
+ "ERROR: SSDT-PCI-OSC: Failed to cleanup AML tree."
|
|
|
+ " Status = %r\n",
|
|
|
+ Status1
|
|
|
+ ));
|
|
|
+ // If Status was success but we failed to delete the AML Tree
|
|
|
+ // return Status1 else return the original error code, i.e. Status.
|
|
|
+ if (!EFI_ERROR (Status)) {
|
|
|
+ return Status1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return Status;
|
|
|
+}
|