The GIC Redistributor (GICR) structure is part of the Multiple APIC Description Table (MADT) that enables the discovery of GIC Redistributor base addresses by providing the Physical Base Address of a page range containing the GIC Redistributors. More than one GICR Structure may be presented in the MADT. The GICR structures should only be used when describing GIC version 3 or higher. The GIC Redistributor information is described in the platform Device Tree, the bindings for which can be found at: - linux/Documentation/devicetree/bindings/interrupt-controller/ arm,gic-v3.yaml The FdtHwInfoParser implements a GIC Redistributor Parser that parses the platform Device Tree to create CM_ARM_GIC_REDIST_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 table. Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com> Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
		
			
				
	
	
		
			239 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Arm Gic Redistributor 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-v3.yaml
 | 
						|
**/
 | 
						|
 | 
						|
#include "CmObjectDescUtility.h"
 | 
						|
#include "FdtHwInfoParser.h"
 | 
						|
#include "Gic/ArmGicDispatcher.h"
 | 
						|
#include "Gic/ArmGicRParser.h"
 | 
						|
 | 
						|
/** Parse a Gic compatible interrupt-controller node,
 | 
						|
    extracting GicR information.
 | 
						|
 | 
						|
  This parser is valid for Gic v3 and higher.
 | 
						|
 | 
						|
  @param [in]  FdtParserHandle  A handle to the parser instance.
 | 
						|
  @param [in]  GicIntcNode      Offset of a Gic compatible
 | 
						|
                                interrupt-controller node.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             The function completed successfully.
 | 
						|
  @retval EFI_ABORTED             An error occurred.
 | 
						|
  @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
GicRIntcNodeParser (
 | 
						|
  IN  CONST FDT_HW_INFO_PARSER_HANDLE  FdtParserHandle,
 | 
						|
  IN        INT32                      GicIntcNode
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  UINT32                  Index;
 | 
						|
  UINT32                  RedistReg;
 | 
						|
  UINT32                  RegSize;
 | 
						|
  INT32                   AddressCells;
 | 
						|
  INT32                   SizeCells;
 | 
						|
  CONST UINT8             *Data;
 | 
						|
  INT32                   DataSize;
 | 
						|
  CM_ARM_GIC_REDIST_INFO  GicRInfo;
 | 
						|
  VOID                    *Fdt;
 | 
						|
 | 
						|
  if (FdtParserHandle == NULL) {
 | 
						|
    ASSERT (0);
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Fdt = FdtParserHandle->Fdt;
 | 
						|
 | 
						|
  Status = FdtGetParentAddressInfo (
 | 
						|
             Fdt,
 | 
						|
             GicIntcNode,
 | 
						|
             &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.
 | 
						|
  // It indicates the number of GicR.
 | 
						|
  Data = fdt_getprop (Fdt, GicIntcNode, "#redistributor-regions", &DataSize);
 | 
						|
  if ((Data != NULL) && (DataSize == sizeof (UINT32))) {
 | 
						|
    // If available, must be on one cell.
 | 
						|
    RedistReg = fdt32_to_cpu (*(UINT32 *)Data);
 | 
						|
  } else {
 | 
						|
    // The DT Spec says GicR is mandatory so we will
 | 
						|
    // always have one.
 | 
						|
    RedistReg = 1;
 | 
						|
  }
 | 
						|
 | 
						|
  /*
 | 
						|
    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
 | 
						|
 | 
						|
    Example:
 | 
						|
      interrupt-controller@2c010000 {
 | 
						|
        compatible = "arm,gic-v3";
 | 
						|
        #interrupt-cells = <4>;
 | 
						|
        #address-cells = <1>;
 | 
						|
        #size-cells = <1>;
 | 
						|
        ranges;
 | 
						|
        interrupt-controller;
 | 
						|
        redistributor-stride = <0x0 0x40000>;  // 256kB stride
 | 
						|
        #redistributor-regions = <2>;
 | 
						|
        reg = <0x2c010000 0x10000>,  // GICD
 | 
						|
              <0x2d000000 0x800000>,  // GICR 1: CPUs 0-31
 | 
						|
              <0x2e000000 0x800000>,  // GICR 2: CPUs 32-63
 | 
						|
              <0x2c040000 0x2000>,  // GICC
 | 
						|
              <0x2c060000 0x2000>,  // GICH
 | 
						|
              <0x2c080000 0x2000>;  // GICV
 | 
						|
        interrupts = <1 9 4>;
 | 
						|
        ...
 | 
						|
      }
 | 
						|
  */
 | 
						|
  RegSize = (AddressCells + SizeCells) * sizeof (UINT32);
 | 
						|
  Data    = fdt_getprop (Fdt, GicIntcNode, "reg", &DataSize);
 | 
						|
  if ((Data == NULL)  ||
 | 
						|
      (DataSize < 0)  ||
 | 
						|
      ((DataSize % RegSize) != 0))
 | 
						|
  {
 | 
						|
    // If error or wrong size.
 | 
						|
    ASSERT (0);
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  Data += GET_DT_REG_ADDRESS_OFFSET (1, AddressCells, SizeCells)
 | 
						|
          * sizeof (UINT32);
 | 
						|
  for (Index = 0; Index < RedistReg; Index++) {
 | 
						|
    ZeroMem (&GicRInfo, sizeof (CM_ARM_GIC_REDIST_INFO));
 | 
						|
 | 
						|
    if (AddressCells == 2) {
 | 
						|
      GicRInfo.DiscoveryRangeBaseAddress = fdt64_to_cpu (*(UINT64 *)Data);
 | 
						|
    } else {
 | 
						|
      GicRInfo.DiscoveryRangeBaseAddress = fdt32_to_cpu (*(UINT32 *)Data);
 | 
						|
    }
 | 
						|
 | 
						|
    Data += sizeof (UINT32) * AddressCells;
 | 
						|
 | 
						|
    if (SizeCells == 2) {
 | 
						|
      GicRInfo.DiscoveryRangeLength = (UINT32)fdt64_to_cpu (*(UINT64 *)Data);
 | 
						|
    } else {
 | 
						|
      GicRInfo.DiscoveryRangeLength = fdt32_to_cpu (*(UINT32 *)Data);
 | 
						|
    }
 | 
						|
 | 
						|
    // Add the CmObj to the Configuration Manager.
 | 
						|
    Status = AddSingleCmObj (
 | 
						|
               FdtParserHandle,
 | 
						|
               CREATE_CM_ARM_OBJECT_ID (EArmObjGicRedistributorInfo),
 | 
						|
               &GicRInfo,
 | 
						|
               sizeof (CM_ARM_GIC_REDIST_INFO),
 | 
						|
               NULL
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      ASSERT (0);
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    Data += sizeof (UINT32) * SizeCells;
 | 
						|
  } // for
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/** CM_ARM_GIC_REDIST_INFO parser function.
 | 
						|
 | 
						|
  This parser expects FdtBranch to be a Gic interrupt-controller node.
 | 
						|
  Gic version must be v3 or higher.
 | 
						|
  typedef struct CmArmGicRedistInfo {
 | 
						|
    UINT64  DiscoveryRangeBaseAddress;        // {Populated}
 | 
						|
    UINT32  DiscoveryRangeLength;             // {Populated}
 | 
						|
  } CM_ARM_GIC_REDIST_INFO;
 | 
						|
 | 
						|
  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
 | 
						|
ArmGicRInfoParser (
 | 
						|
  IN  CONST FDT_HW_INFO_PARSER_HANDLE  FdtParserHandle,
 | 
						|
  IN        INT32                      FdtBranch
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT32      GicVersion;
 | 
						|
  VOID        *Fdt;
 | 
						|
 | 
						|
  if (FdtParserHandle == NULL) {
 | 
						|
    ASSERT (0);
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Fdt = FdtParserHandle->Fdt;
 | 
						|
 | 
						|
  if (!FdtNodeHasProperty (Fdt, FdtBranch, "interrupt-controller")) {
 | 
						|
    ASSERT (0);
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  // Get the Gic version of the interrupt-controller.
 | 
						|
  Status = GetGicVersion (Fdt, FdtBranch, &GicVersion);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    ASSERT (0);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (GicVersion < 3) {
 | 
						|
    ASSERT (0);
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = GicRIntcNodeParser (FdtParserHandle, FdtBranch);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  return Status;
 | 
						|
}
 |