From: "Sami Mujawar" <sami.mujawar@arm.com>
To: Pierre.Gondois@arm.com, devel@edk2.groups.io,
Alexei Fedorov <Alexei.Fedorov@arm.com>
Cc: Akanksha Jain <akanksha.jain2@arm.com>,
Alexandru Elisei <alexandru.elisei@arm.com>, nd <nd@arm.com>
Subject: Re: [PATCH v1 07/14] DynamicTablesPkg: FdtHwInfoParser: Add GICC parser
Date: Fri, 5 Nov 2021 14:28:04 +0000 [thread overview]
Message-ID: <bd9bcc7a-a0c9-c513-1d3c-42404a5bd1d3@arm.com> (raw)
In-Reply-To: <20210623123828.23693-8-Pierre.Gondois@arm.com>
Hi Pierre,
Please find my feedback inline marked [SAMI].
Regards,
Sami Mujawar
On 23/06/2021 01:38 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> The GIC CPU Interface (GICC) structure is part of the Multiple
> APIC Description Table (MADT) that describes the interrupt model
> for the platform. The MADT table is a mandatory table required
> for booting a standards-based operating system.
>
> Arm requires the GIC interrupt model, in which the logical
> processors are required to have a Processor Device object in
> the DSDT, and must convey each processors GIC information to
> the OS using the GICC structure.
>
> The CPU and GIC information is described in the platform Device
> Tree, the bindings for which can be found at:
> - linux/Documentation/devicetree/bindings/arm/cpus.yaml
> - linux/Documentation/devicetree/bindings/interrupt-controller/
> arm,gic.yaml
> - linux/Documentation/devicetree/bindings/interrupt-controller/
> arm,gic-v3.yaml
>
> The FdtHwInfoParser implements a GIC CPU Interface Parser that
> parses the platform Device Tree to create CM_ARM_GICC_INFO
> objects which are encapsulated in a Configuration Manager
> descriptor object and added to the platform information
> repository.
>
> The platform Configuration Manager can then utilise this
> information when generating the MADT and the SSDT CPU
> information tables.
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> ---
> .../FdtHwInfoParserLib/Gic/ArmGicCParser.c | 762 ++++++++++++++++++
> .../FdtHwInfoParserLib/Gic/ArmGicCParser.h | 67 ++
> 2 files changed, 829 insertions(+)
> create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.c
> create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.h
>
> diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.c
> new file mode 100644
> index 000000000000..2163888c870e
> --- /dev/null
> +++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.c
> @@ -0,0 +1,762 @@
> +/** @file
> + Arm Gic cpu parser.
> +
> + Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + @par Reference(s):
> + - linux/Documentation/devicetree/bindings/arm/cpus.yaml
> + - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic.yaml
> + - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
> +**/
> +
> +#include "FdtHwInfoParser.h"
> +#include "CmObjectDescUtility.h"
> +#include "Gic/ArmGicCParser.h"
> +#include "Gic/ArmGicDispatcher.h"
> +
> +/** List of "compatible" property values for CPU nodes.
> +
> + Any other "compatible" value is not supported by this module.
> +*/
> +STATIC CONST COMPATIBILITY_STR CpuCompatibleStr[] = {
> + {"arm,arm-v7"},
> + {"arm,arm-v8"},
> + {"arm,cortex-a15"},
> + {"arm,cortex-a7"},
> + {"arm,cortex-a57"}
> +};
> +
> +/** COMPATIBILITY_INFO structure for CPU nodes.
> +*/
> +STATIC CONST COMPATIBILITY_INFO CpuCompatibleInfo = {
> + ARRAY_SIZE (CpuCompatibleStr),
> + CpuCompatibleStr
> +};
> +
> +/** Parse a "cpu" node.
> +
> + @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
> + @param [in] CpuNode Offset of a cpu node.
> + @param [in] GicVersion Version of the GIC.
> + @param [in] AddressCells Number of address cells used for the reg
> + property.
> + @param [out] GicCInfo CM_ARM_GICC_INFO structure to populate.
> +
> + @retval EFI_SUCCESS The function completed successfully.
> + @retval EFI_ABORTED An error occurred.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_UNSUPPORTED Unsupported.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +CpuNodeParser (
> + IN CONST VOID * Fdt,
> + IN INT32 CpuNode,
> + IN UINT32 GicVersion,
> + IN UINT32 AddressCells,
> + OUT CM_ARM_GICC_INFO * GicCInfo
> +)
> +{
> + UINT32 CpuRegProp;
> + CONST VOID * Data;
> + INT32 DataSize;
> + UINT64 MpIdr;
> +
> + if (GicCInfo == NULL) {
> + ASSERT (0);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Data = fdt_getprop (Fdt, CpuNode, "reg", &DataSize);
> + if ((Data == NULL) ||
> + ((DataSize != sizeof (UINT32)) &&
> + (DataSize != sizeof (UINT64)))) {
> + ASSERT (0);
> + return EFI_ABORTED;
> + }
> +
> + if (AddressCells == 1) {
> + MpIdr = fdt32_to_cpu (*((UINT32*)Data));
> + } else if (AddressCells == 2) {
> + MpIdr = fdt64_to_cpu (*((UINT64*)Data));
> + } else {
> + ASSERT (0);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + // Currently we only support 3 affinity levels.
> + if ((MpIdr & ~(ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2)) != 0) {
> + ASSERT (0);
> + return EFI_UNSUPPORTED;
> + }
[SAMI] Is there a reason we are not supporting AFF3?
> +
> + CpuRegProp = (MpIdr & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2));
> +
> + /* ACPI 6.3, s5.2.12.14 GIC CPU Interface (GICC) Structure:
> + GIC 's CPU Interface Number. In GICv1/v2 implementations,
> + this value matches the bit index of the associated processor
> + in the GIC distributor's GICD_ITARGETSR register. For
> + GICv3/4 implementations this field must be provided by the
> + platform, if compatibility mode is supported. If it is not supported
> + by the implementation, then this field must be zero.
> +
> + Note: We do not support compatibility mode for GicV3
> + */
> + if (GicVersion == 2) {
> + GicCInfo->CPUInterfaceNumber = CpuRegProp;
> + } else {
> + GicCInfo->CPUInterfaceNumber = 0;
> + }
> +
> + GicCInfo->AcpiProcessorUid = CpuRegProp;
> + GicCInfo->Flags = EFI_ACPI_6_3_GIC_ENABLED;
> + GicCInfo->MPIDR= MpIdr;
> +
> + return EFI_SUCCESS;
> +}
> +
> +/** Parse a "cpus" node and its children "cpu" nodes.
> +
> + Create as many CM_ARM_GICC_INFO structures as "cpu" nodes.
> +
> + @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
> + @param [in] CpusNode Offset of a cpus node.
> + @param [in] GicVersion Version of the GIC.
> + @param [out] NewGicCmObjDesc If success, CM_OBJ_DESCRIPTOR containing
> + all the created CM_ARM_GICC_INFO.
> +
> + @retval EFI_SUCCESS The function completed successfully.
> + @retval EFI_ABORTED An error occurred.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_UNSUPPORTED Unsupported.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +CpusNodeParser (
> + IN CONST VOID * Fdt,
> + IN INT32 CpusNode,
> + IN UINT32 GicVersion,
> + OUT CM_OBJ_DESCRIPTOR ** NewGicCmObjDesc
> + )
> +{
> + EFI_STATUS Status;
> + INT32 CpuNode;
> + UINT32 CpuNodeCount;
> + INT32 AddressCells;
> +
> + UINT32 Index;
> + CM_ARM_GICC_INFO * GicCInfoBuffer;
> + UINT32 GicCInfoBufferSize;
> +
> + if (NewGicCmObjDesc == NULL) {
> + ASSERT (0);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + AddressCells = fdt_address_cells (Fdt, CpusNode);
> + if (AddressCells < 0) {
> + ASSERT (0);
> + return EFI_ABORTED;
> + }
> +
> + // Count the number of "cpu" nodes under the "cpus" node.
> + Status = FdtCountNamedNodeInBranch (Fdt, CpusNode, "cpu", &CpuNodeCount);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + if (CpuNodeCount == 0) {
> + ASSERT (0);
> + return EFI_NOT_FOUND;
> + }
> +
> + // Allocate memory for CpuNodeCount CM_ARM_GICC_INFO structures.
> + GicCInfoBufferSize = CpuNodeCount * sizeof (CM_ARM_GICC_INFO);
> + GicCInfoBuffer = AllocateZeroPool (GicCInfoBufferSize);
> + if (GicCInfoBuffer == NULL) {
> + ASSERT (0);
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + CpuNode = CpusNode;
> + for (Index = 0; Index < CpuNodeCount; Index++) {
> + Status = FdtGetNextNamedNodeInBranch (Fdt, CpusNode, "cpu", &CpuNode);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + if (Status == EFI_NOT_FOUND) {
> + // Should have found the node.
> + Status = EFI_ABORTED;
> + }
> + goto exit_handler;
> + }
> +
> + // Parse the "cpu" node.
> + if (!FdtNodeIsCompatible (Fdt, CpuNode, &CpuCompatibleInfo)) {
> + ASSERT (0);
> + Status = EFI_UNSUPPORTED;
> + goto exit_handler;
> + }
> +
> + Status = CpuNodeParser (
> + Fdt,
> + CpuNode,
> + GicVersion,
> + AddressCells,
> + &GicCInfoBuffer[Index]
> + );
[SAMI] Please adjust code alignment.
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + goto exit_handler;
> + }
> + } // for
> +
> + Status = CreateCmObjDesc (
> + CREATE_CM_ARM_OBJECT_ID (EArmObjGicCInfo),
> + CpuNodeCount,
> + GicCInfoBuffer,
> + GicCInfoBufferSize,
> + NewGicCmObjDesc
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + }
> +
> +exit_handler:
> + FreePool (GicCInfoBuffer);
> + return Status;
> +}
> +
> +/** Parse a Gic compatible interrupt-controller node,
> + extracting GicC information generic to Gic v2 and v3.
> +
> + This function modifies a CM_OBJ_DESCRIPTOR object.
> + The following CM_ARM_GICC_INFO fields are patched:
> + - VGICMaintenanceInterrupt;
> + - Flags;
> +
> + @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
> + @param [in] GicIntcNode Offset of a Gic compatible
> + interrupt-controller node.
> + @param [in, out] GicCCmObjDesc The CM_ARM_GICC_INFO to patch.
> +
> + @retval EFI_SUCCESS The function completed successfully.
> + @retval EFI_ABORTED An error occurred.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +GicCIntcNodeParser (
> + IN CONST VOID * Fdt,
> + IN INT32 GicIntcNode,
> + IN OUT CM_OBJ_DESCRIPTOR * GicCCmObjDesc
> + )
> +{
> + EFI_STATUS Status;
> + INT32 IntCells;
> + CM_ARM_GICC_INFO * GicCInfo;
> +
> + CONST UINT8 * Data;
> + INT32 DataSize;
> +
> + if (GicCCmObjDesc == NULL) {
> + ASSERT (0);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + // Get the number of cells used to encode an interrupt.
> + Status = FdtGetInterruptCellsInfo (Fdt, GicIntcNode, &IntCells);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // Get the GSIV maintenance interrupt.
> + // According to the DT bindings, this could be the:
> + // "Interrupt source of the parent interrupt controller on secondary GICs"
> + // but it is assumed that only one Gic is available.
> + Data = fdt_getprop (Fdt, GicIntcNode, "interrupts", &DataSize);
> + if ((Data != NULL) && (DataSize == (IntCells * sizeof (UINT32)))) {
> + GicCInfo = (CM_ARM_GICC_INFO*)GicCCmObjDesc->Data;
> + GicCInfo->VGICMaintenanceInterrupt =
> + FdtGetInterruptId ((CONST UINT32*)Data);
> + GicCInfo->Flags = DT_IRQ_IS_EDGE_TRIGGERED (
> + fdt32_to_cpu (((UINT32*)Data)[IRQ_FLAGS_OFFSET])
> + ) ?
> + EFI_ACPI_6_3_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS :
> + 0;
> + return Status;
> + } else if (DataSize < 0) {
> + // This property is optional and was not found. Just return.
> + return Status;
> + }
> + // The property exists and its size doesn't match for one interrupt.
> + ASSERT (0);
> + return EFI_ABORTED;
> +}
> +
> +/** Parse a Gic compatible interrupt-controller node,
> + extracting GicCv2 information.
> +
> + This function modifies a CM_OBJ_DESCRIPTOR object.
> + The following CM_ARM_GICC_INFO fields are patched:
> + - PhysicalAddress;
> + - GICH;
> + - GICV;
> +
> + @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
> + @param [in] Gicv2IntcNode Offset of a Gicv2 compatible
> + interrupt-controller node.
> + @param [in, out] GicCCmObjDesc The CM_ARM_GICC_INFO to patch.
> +
> + @retval EFI_SUCCESS The function completed successfully.
> + @retval EFI_ABORTED An error occurred.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +GicCv2IntcNodeParser (
> + IN CONST VOID * Fdt,
> + IN INT32 Gicv2IntcNode,
> + IN OUT CM_OBJ_DESCRIPTOR * GicCCmObjDesc
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 Index;
> + CM_ARM_GICC_INFO * GicCInfo;
> + INT32 AddressCells;
> + INT32 SizeCells;
> +
> + CONST UINT8 * GicCValue;
> + CONST UINT8 * GicVValue;
> + CONST UINT8 * GicHValue;
> +
> + CONST UINT8 * Data;
> + INT32 DataSize;
> + UINT32 RegSize;
> + UINT32 RegCount;
> +
> + if (GicCCmObjDesc == NULL) {
> + ASSERT (0);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + GicCInfo = (CM_ARM_GICC_INFO*)GicCCmObjDesc->Data;
> + GicVValue = NULL;
> + GicHValue = NULL;
> +
> + // Get the #address-cells and #size-cells property values.
> + Status = FdtGetParentAddressInfo (
> + Fdt,
> + Gicv2IntcNode,
> + &AddressCells,
> + &SizeCells
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // Don't support more than 64 bits and less than 32 bits addresses.
> + if ((AddressCells < 1) ||
> + (AddressCells > 2) ||
> + (SizeCells < 1) ||
> + (SizeCells > 2)) {
> + ASSERT (0);
> + return EFI_ABORTED;
> + }
> +
> + RegSize = (AddressCells + SizeCells) * sizeof (UINT32);
> +
> + Data = fdt_getprop (Fdt, Gicv2IntcNode, "reg", &DataSize);
> + if ((Data == NULL) ||
> + (DataSize < 0) ||
> + ((DataSize % RegSize) != 0)) {
> + // If error or wrong size.
> + ASSERT (0);
> + return EFI_ABORTED;
> + }
> +
> + RegCount = DataSize/RegSize;
> +
> + switch (RegCount) {
> + case 4:
> + {
> + // GicV is at index 3 in the reg property. GicV is optional.
> + GicVValue = Data + (sizeof (UINT32) *
> + GET_DT_REG_ADDRESS_OFFSET (3, AddressCells, SizeCells));
> + // fall-through.
> + }
> + case 3:
> + {
> + // GicH is at index 2 in the reg property. GicH is optional.
> + GicHValue = Data + (sizeof (UINT32) *
> + GET_DT_REG_ADDRESS_OFFSET (2, AddressCells, SizeCells));
> + // fall-through.
> + }
> + case 2:
> + {
> + // GicC is at index 1 in the reg property. GicC is mandatory.
> + GicCValue = Data + (sizeof (UINT32) *
> + GET_DT_REG_ADDRESS_OFFSET (1, AddressCells, SizeCells));
> + break;
> + }
> + default:
> + {
> + // Not enough or too much information.
> + ASSERT (0);
> + return EFI_ABORTED;
> + }
> + }
> +
> + // Patch the relevant fields of the CM_ARM_GICC_INFO objects.
> + for (Index = 0; Index < GicCCmObjDesc->Count; Index++) {
> + if (AddressCells == 2) {
> + GicCInfo[Index].PhysicalBaseAddress = fdt64_to_cpu (*(UINT64*)GicCValue);
> + GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
> + fdt64_to_cpu (*(UINT64*)GicHValue);
> + GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
> + fdt64_to_cpu (*(UINT64*)GicVValue);
> + } else {
> + GicCInfo[Index].PhysicalBaseAddress = fdt32_to_cpu (*(UINT32*)GicCValue);
> + GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
> + fdt32_to_cpu (*(UINT32*)GicHValue);
> + GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
> + fdt32_to_cpu (*(UINT32*)GicVValue);
> + }
> + } // for
> +
> + return EFI_SUCCESS;
> +}
> +
> +/** Parse a Gic compatible interrupt-controller node,
> + extracting GicCv3 information.
> +
> + This function modifies a CM_OBJ_DESCRIPTOR object.
> + The following CM_ARM_GICC_INFO fields are patched:
> + - PhysicalAddress;
> + - GICH;
> + - GICV;
> +
> + @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
> + @param [in] Gicv3IntcNode Offset of a Gicv3 compatible
> + interrupt-controller node.
> + @param [in, out] GicCCmObjDesc The CM_ARM_GICC_INFO to patch.
> +
> + @retval EFI_SUCCESS The function completed successfully.
> + @retval EFI_ABORTED An error occurred.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +GicCv3IntcNodeParser (
> + IN CONST VOID * Fdt,
> + IN INT32 Gicv3IntcNode,
> + IN OUT CM_OBJ_DESCRIPTOR * GicCCmObjDesc
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 Index;
> + CM_ARM_GICC_INFO * GicCInfo;
> + INT32 AddressCells;
> + INT32 SizeCells;
> + UINT32 AdditionalRedistReg;
> +
> + CONST UINT8 * GicCValue;
> + CONST UINT8 * GicVValue;
> + CONST UINT8 * GicHValue;
> +
> + CONST UINT8 * Data;
> + INT32 DataSize;
> + UINT32 RegSize;
> + UINT32 RegCount;
> +
> + if (GicCCmObjDesc == NULL) {
> + ASSERT (0);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + GicCInfo = (CM_ARM_GICC_INFO*)GicCCmObjDesc->Data;
> + GicCValue = NULL;
> + GicVValue = NULL;
> + GicHValue = NULL;
> +
> + // Get the #address-cells and #size-cells property values.
> + Status = FdtGetParentAddressInfo (
> + Fdt,
> + Gicv3IntcNode,
> + &AddressCells,
> + &SizeCells
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // Don't support more than 64 bits and less than 32 bits addresses.
> + if ((AddressCells < 1) ||
> + (AddressCells > 2) ||
> + (SizeCells < 1) ||
> + (SizeCells > 2)) {
> + ASSERT (0);
> + return EFI_ABORTED;
> + }
> +
> + // The "#redistributor-regions" property is optional.
> + Data = fdt_getprop (Fdt, Gicv3IntcNode, "#redistributor-regions", &DataSize);
> + if ((Data != NULL) && (DataSize == sizeof (UINT32))) {
> + ASSERT (fdt32_to_cpu (*(UINT32*)Data) > 1);
> + AdditionalRedistReg = fdt32_to_cpu (*(UINT32*)Data) - 1;
> + } else {
> + AdditionalRedistReg = 0;
> + }
> +
> + RegSize = (AddressCells + SizeCells) * sizeof (UINT32);
> +
> + /*
> + Ref: linux/blob/master/Documentation/devicetree/bindings/
> + interrupt-controller/arm%2Cgic-v3.yaml
> +
> + reg:
> + description: |
> + Specifies base physical address(s) and size of the GIC
> + registers, in the following order:
> + - GIC Distributor interface (GICD)
> + - GIC Redistributors (GICR), one range per redistributor region
> + - GIC CPU interface (GICC)
> + - GIC Hypervisor interface (GICH)
> + - GIC Virtual CPU interface (GICV)
> + GICC, GICH and GICV are optional.
> + minItems: 2
> + maxItems: 4096
> + */
> + Data = fdt_getprop (Fdt, Gicv3IntcNode, "reg", &DataSize);
> + if ((Data == NULL) ||
> + (DataSize < 0) ||
> + ((DataSize % RegSize) != 0)) {
> + // If error or wrong size.
> + ASSERT (0);
> + return EFI_ABORTED;
> + }
> +
> + RegCount = (DataSize / RegSize) - AdditionalRedistReg;
> +
> + // The GicD and GicR info is mandatory.
> + switch (RegCount) {
> + case 5:
> + {
> + // GicV is at index 4 in the reg property. GicV is optional.
> + GicVValue = Data + (sizeof (UINT32) *
> + GET_DT_REG_ADDRESS_OFFSET (
> + 4 + AdditionalRedistReg,
> + AddressCells,
> + SizeCells
> + ));
> + // fall-through.
> + }
> + case 4:
> + {
> + // GicH is at index 3 in the reg property. GicH is optional.
> + GicHValue = Data + (sizeof (UINT32) *
> + GET_DT_REG_ADDRESS_OFFSET (
> + 3 + AdditionalRedistReg,
> + AddressCells,
> + SizeCells
> + ));
> + // fall-through.
> + }
> + case 3:
> + {
> + // GicC is at index 2 in the reg property. GicC is optional.
> + // Even though GicC is optional, it is made mandatory in this parser.
> + GicCValue = Data + (sizeof (UINT32) *
> + GET_DT_REG_ADDRESS_OFFSET (
> + 2 + AdditionalRedistReg,
> + AddressCells,
> + SizeCells
> + ));
> + // fall-through
> + }
> + case 2:
> + {
> + // GicR is discribed by the CM_ARM_GIC_REDIST_INFO object.
> + // GicD is described by the CM_ARM_GICD_INFO object.
> + break;
> + }
> + default:
> + {
> + // Not enough or too much information.
> + ASSERT (0);
> + return EFI_ABORTED;
> + }
> + }
> +
> + // Patch the relevant fields of the CM_ARM_GICC_INFO objects.
> + if (AddressCells == 2) {
> + for (Index = 0; Index < GicCCmObjDesc->Count; Index++) {
> + // GicR is discribed by the CM_ARM_GIC_REDIST_INFO object.
> + GicCInfo[Index].GICRBaseAddress = 0;
> + GicCInfo[Index].PhysicalBaseAddress = (GicCValue == NULL) ? 0 :
> + fdt64_to_cpu (*(UINT64*)GicCValue);
> + GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
> + fdt64_to_cpu (*(UINT64*)GicHValue);
> + GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
> + fdt64_to_cpu (*(UINT64*)GicVValue);
> + }
> + } else {
> + for (Index = 0; Index < GicCCmObjDesc->Count; Index++) {
> + // GicR is discribed by the CM_ARM_GIC_REDIST_INFO object.
> + GicCInfo[Index].GICRBaseAddress = 0;
> + GicCInfo[Index].PhysicalBaseAddress = (GicCValue == NULL) ? 0 :
> + fdt32_to_cpu (*(UINT32*)GicCValue);
> + GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
> + fdt32_to_cpu (*(UINT32*)GicHValue);
> + GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
> + fdt32_to_cpu (*(UINT32*)GicVValue);
> + }
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/** CM_ARM_GICC_INFO parser function.
> +
> + This parser expects FdtBranch to be the "\cpus" node node.
> + At most one CmObj is created.
> + The following structure is populated:
> + typedef struct CmArmGicCInfo {
> + UINT32 CPUInterfaceNumber; // {Populated}
> + UINT32 AcpiProcessorUid; // {Populated}
> + UINT32 Flags; // {Populated}
> + UINT32 ParkingProtocolVersion; // {default = 0}
> + UINT32 PerformanceInterruptGsiv; // {default = 0}
> + UINT64 ParkedAddress; // {default = 0}
> + UINT64 PhysicalBaseAddress; // {Populated}
> + UINT64 GICV; // {Populated}
> + UINT64 GICH; // {Populated}
> + UINT32 VGICMaintenanceInterrupt; // {Populated}
> + UINT64 GICRBaseAddress; // {default = 0}
> + UINT64 MPIDR; // {Populated}
> + UINT8 ProcessorPowerEfficiencyClass; // {default = 0}
> + UINT16 SpeOverflowInterrupt; // {default = 0}
> + UINT32 ProximityDomain; // {default = 0}
> + UINT32 ClockDomain; // {default = 0}
> + UINT32 AffinityFlags; // {default = 0}
> + } CM_ARM_GICC_INFO;
> +
> + The pmu information can be found in the pmu node. There is no support
> + for now.
> +
> + A parser parses a Device Tree to populate a specific CmObj type. None,
> + one or many CmObj can be created by the parser.
> + The created CmObj are then handed to the parser's caller through the
> + HW_INFO_ADD_OBJECT interface.
> + This can also be a dispatcher. I.e. a function that not parsing a
> + Device Tree but calling other parsers.
> +
> + @param [in] FdtParserHandle A handle to the parser instance.
> + @param [in] FdtBranch When searching for DT node name, restrict
> + the search to this Device Tree branch.
> +
> + @retval EFI_SUCCESS The function completed successfully.
> + @retval EFI_ABORTED An error occurred.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_NOT_FOUND Not found.
> + @retval EFI_UNSUPPORTED Unsupported.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ArmGicCInfoParser (
> + IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
> + IN INT32 FdtBranch
> + )
> +{
> + EFI_STATUS Status;
> + INT32 IntcNode;
> + UINT32 GicVersion;
> + CM_OBJ_DESCRIPTOR * NewCmObjDesc;
> + VOID * Fdt;
> +
> + if (FdtParserHandle == NULL) {
> + ASSERT (0);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Fdt = FdtParserHandle->Fdt;
> + NewCmObjDesc = NULL;
> +
> + // The FdtBranch points to the Cpus Node.
> + // Get the interrupt-controller node associated to the "cpus" node.
> + Status = FdtGetIntcParentNode (Fdt, FdtBranch, &IntcNode);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + if (Status == EFI_NOT_FOUND) {
> + // Should have found the node.
> + Status = EFI_ABORTED;
> + }
> + goto exit_handler;
[SAMI] Return directly from here as memory for NewCmObjDescis not yet
allocated.
> + }
> +
> + Status = GetGicVersion (Fdt, IntcNode, &GicVersion);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + goto exit_handler;
[SAMI] Return directly from here as memory for NewCmObjDescis not yet
allocated.
> + }
> +
> + // Parse the "cpus" nodes and its children "cpu" nodes,
> + // and create a CM_OBJ_DESCRIPTOR.
> + Status = CpusNodeParser (Fdt, FdtBranch, GicVersion, &NewCmObjDesc);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // Parse the interrupt-controller node according to the Gic version.
> + switch (GicVersion) {
> + case 2:
> + {
> + Status = GicCv2IntcNodeParser (Fdt, IntcNode, NewCmObjDesc);
> + break;
> + }
> + case 3:
> + {
> + Status = GicCv3IntcNodeParser (Fdt, IntcNode, NewCmObjDesc);
> + break;
> + }
> + default:
> + {
> + // Unsupported Gic version.
> + ASSERT (0);
> + Status = EFI_UNSUPPORTED;
> + }
> + }
> +
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + goto exit_handler;
> + }
> +
> + // Parse the Gic information common to Gic v2 and v3.
> + Status = GicCIntcNodeParser (Fdt, IntcNode, NewCmObjDesc);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + goto exit_handler;
> + }
> +
> + // Add all the CmObjs to the Configuration Manager.
> + Status = AddMultipleCmObj (FdtParserHandle, NewCmObjDesc, 0, NULL);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + goto exit_handler;
> + }
> +
> +exit_handler:
> + FreeCmObjDesc (NewCmObjDesc);
> + return Status;
> +}
> diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.h
> new file mode 100644
> index 000000000000..10e6b03c541f
> --- /dev/null
> +++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.h
> @@ -0,0 +1,67 @@
> +/** @file
> + Arm Gic cpu parser.
> +
> + Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + @par Reference(s):
> + - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic.yaml
> + - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
> +**/
> +
> +#ifndef ARM_GICC_PARSER_H_
> +#define ARM_GICC_PARSER_H_
> +
> +/** CM_ARM_GICC_INFO parser function.
> +
> + This parser expects FdtBranch to be the "\cpus" node node.
> + At most one CmObj is created.
> + The following structure is populated:
> + typedef struct CmArmGicCInfo {
> + UINT32 CPUInterfaceNumber; // {Populated}
> + UINT32 AcpiProcessorUid; // {Populated}
> + UINT32 Flags; // {Populated}
> + UINT32 ParkingProtocolVersion; // {default = 0}
> + UINT32 PerformanceInterruptGsiv; // {default = 0}
> + UINT64 ParkedAddress; // {default = 0}
> + UINT64 PhysicalBaseAddress; // {Populated}
> + UINT64 GICV; // {Populated}
> + UINT64 GICH; // {Populated}
> + UINT32 VGICMaintenanceInterrupt; // {Populated}
> + UINT64 GICRBaseAddress; // {default = 0}
> + UINT64 MPIDR; // {Populated}
> + UINT8 ProcessorPowerEfficiencyClass; // {default = 0}
> + UINT16 SpeOverflowInterrupt; // {default = 0}
> + UINT32 ProximityDomain; // {default = 0}
> + UINT32 ClockDomain; // {default = 0}
> + UINT32 AffinityFlags; // {default = 0}
> + } CM_ARM_GICC_INFO;
> +
> + The pmu information can be found in the pmu node. There is no support
> + for now.
> +
> + A parser parses a Device Tree to populate a specific CmObj type. None,
> + one or many CmObj can be created by the parser.
> + The created CmObj are then handed to the parser's caller through the
> + HW_INFO_ADD_OBJECT interface.
> + This can also be a dispatcher. I.e. a function that not parsing a
> + Device Tree but calling other parsers.
> +
> + @param [in] FdtParserHandle A handle to the parser instance.
> + @param [in] FdtBranch When searching for DT node name, restrict
> + the search to this Device Tree branch.
> +
> + @retval EFI_SUCCESS The function completed successfully.
> + @retval EFI_ABORTED An error occurred.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_NOT_FOUND Not found.
> + @retval EFI_UNSUPPORTED Unsupported.
> +**/
> +EFI_STATUS
> +EFIAPI
> +ArmGicCInfoParser (
> + IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
> + IN INT32 FdtBranch
> + );
> +
> +#endif // ARM_GICC_PARSER_H_
next prev parent reply other threads:[~2021-11-05 14:28 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-23 12:38 [PATCH v1 00/14] Implement a FdtHwInfoParserLib PierreGondois
2021-06-23 12:38 ` [PATCH v1 01/14] DynamicTablesPkg: Definition for HwInfoParser interface PierreGondois
2021-06-23 12:38 ` [PATCH v1 02/14] DynamicTablesPkg: FdtHwInfoParser: CM Object descriptor helper PierreGondois
2021-11-05 14:27 ` Sami Mujawar
2021-06-23 12:38 ` [PATCH v1 03/14] DynamicTablesPkg: FdtHwInfoParser: Add FDT utility functions PierreGondois
2021-11-05 14:27 ` Sami Mujawar
2021-06-23 12:38 ` [PATCH v1 04/14] DynamicTablesPkg: FdtHwInfoParser: Add Boot Arch parser PierreGondois
2021-06-23 12:38 ` [PATCH v1 05/14] DynamicTablesPkg: FdtHwInfoParser: Generic Timer Parser PierreGondois
2021-06-23 12:38 ` [PATCH v1 06/14] DynamicTablesPkg: FdtHwInfoParser: Add Serial port parser PierreGondois
2021-11-05 14:27 ` Sami Mujawar
2021-11-18 10:11 ` PierreGondois
2021-06-23 12:38 ` [PATCH v1 07/14] DynamicTablesPkg: FdtHwInfoParser: Add GICC parser PierreGondois
2021-11-05 14:28 ` Sami Mujawar [this message]
2021-06-23 12:38 ` [PATCH v1 08/14] DynamicTablesPkg: FdtHwInfoParser: Add GICD parser PierreGondois
2021-06-23 12:38 ` [PATCH v1 09/14] DynamicTablesPkg: FdtHwInfoParser: Add MSI Frame parser PierreGondois
2021-06-23 12:38 ` [PATCH v1 10/14] DynamicTablesPkg: FdtHwInfoParser: Add ITS parser PierreGondois
2021-06-23 12:38 ` [PATCH v1 11/14] DynamicTablesPkg: FdtHwInfoParser: Add GICR parser PierreGondois
2021-06-23 12:38 ` [PATCH v1 12/14] DynamicTablesPkg: FdtHwInfoParser: Add GIC dispatcher PierreGondois
2021-06-23 12:38 ` [PATCH v1 13/14] DynamicTablesPkg: FdtHwInfoParser: Add PCI config parser PierreGondois
2021-06-23 12:38 ` [PATCH v1 14/14] DynamicTablesPkg: Add FdtHwInfoParser library PierreGondois
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=bd9bcc7a-a0c9-c513-1d3c-42404a5bd1d3@arm.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox