[edk2-devel] [PATCH v1 07/14] DynamicTablesPkg: FdtHwInfoParser: Add GICC parser

Sami Mujawar sami.mujawar at arm.com
Fri Nov 5 14:28:04 UTC 2021


Hi Pierre,

Please find my feedback inline marked [SAMI].

Regards,

Sami Mujawar

On 23/06/2021 01:38 PM, Pierre.Gondois at arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois at 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 processor’s 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 at arm.com>
> Signed-off-by: Sami Mujawar <sami.mujawar at 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_



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#83402): https://edk2.groups.io/g/devel/message/83402
Mute This Topic: https://groups.io/mt/83736633/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-






More information about the edk2-devel-archive mailing list