| /** @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] Uid Unique Id of the Pci device. | |
| @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_ARCH_COMMON_PCI_CONFIG_SPACE_INFO *PciInfo, | |
| IN CONST MAPPING_TABLE *MappingTable, | |
| IN UINT32 Uid, | |
| 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_ARCH_COMMON_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; | |
| } |