diff mbox series

[edk2,3/4] ArmPkg/ArmGicDxe: Expose HardwareInterrupt2 protocol

Message ID 20170921162345.11724-4-evan.lloyd@arm.com
State New
Headers show
Series None | expand

Commit Message

Evan Lloyd Sept. 21, 2017, 4:23 p.m. UTC
From: Ard Biesheuvel <ard.biesheuvel@linaro.org>


The existing HardwareInterrupt protocol lacked a means to configure the
level/edge properties of an interrupt.  The new HardwareInterrupt2
protocol introduced this capability.
This patch updates the GIC drivers to provide the new interfaces.
The changes comprise:
  Update to use HardwareInterrupt2 protocol
  Additions to register info in ArmGicLib.h
  Added new functionality (GetTriggerType and SetTriggerType)

The requirement for this change derives from a problem detected on ARM
Juno boards, but the change is of generic (ARM) relevance.

This commit is in response to review on the mailing list and, as
suggested there, rolls Girish's updates onto Ard's original example.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Signed-off-by: Girish Pathak <girish.pathak@arm.com>

Signed-off-by: Evan Lloyd <evan.lloyd@arm.com>

Tested-by: Girish Pathak <girish.pathak@arm.com>

---

Notes:
    376_irqtype_v4
      [Leif Lindholm]
      - Fixed continuation line indent
      - Moved EFI_D_ERROR changes out
      - Replaced MmioBitFieldRead32
      - Fixed indent and parentheses

 ArmPkg/Drivers/ArmGic/ArmGicDxe.inf       |   3 +-
 ArmPkg/Drivers/ArmGic/ArmGicDxe.h         |  23 ++++
 ArmPkg/Include/Library/ArmGicLib.h        |  11 +-
 ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c   |  43 ++++++
 ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c | 137 ++++++++++++++++++++
 ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c | 136 +++++++++++++++++++
 6 files changed, 351 insertions(+), 2 deletions(-)

-- 
Guid("CE165669-3EF3-493F-B85D-6190EE5B9759")

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Comments

Leif Lindholm Oct. 5, 2017, 8:15 p.m. UTC | #1
On Thu, Sep 21, 2017 at 05:23:43PM +0100, evan.lloyd@arm.com wrote:
> From: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> 

> The existing HardwareInterrupt protocol lacked a means to configure the

> level/edge properties of an interrupt.  The new HardwareInterrupt2

> protocol introduced this capability.

> This patch updates the GIC drivers to provide the new interfaces.

> The changes comprise:

>   Update to use HardwareInterrupt2 protocol

>   Additions to register info in ArmGicLib.h

>   Added new functionality (GetTriggerType and SetTriggerType)

> 

> The requirement for this change derives from a problem detected on ARM

> Juno boards, but the change is of generic (ARM) relevance.

> 

> This commit is in response to review on the mailing list and, as

> suggested there, rolls Girish's updates onto Ard's original example.

> 

> Contributed-under: TianoCore Contribution Agreement 1.0


This patch has lagged: Ard, are you happy to confirm this one could be
updated to 1.1?

/
    Leif

> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> Signed-off-by: Girish Pathak <girish.pathak@arm.com>

> Signed-off-by: Evan Lloyd <evan.lloyd@arm.com>

> Tested-by: Girish Pathak <girish.pathak@arm.com>

> ---

> 

> Notes:

>     376_irqtype_v4

>       [Leif Lindholm]

>       - Fixed continuation line indent

>       - Moved EFI_D_ERROR changes out

>       - Replaced MmioBitFieldRead32

>       - Fixed indent and parentheses

> 

>  ArmPkg/Drivers/ArmGic/ArmGicDxe.inf       |   3 +-

>  ArmPkg/Drivers/ArmGic/ArmGicDxe.h         |  23 ++++

>  ArmPkg/Include/Library/ArmGicLib.h        |  11 +-

>  ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c   |  43 ++++++

>  ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c | 137 ++++++++++++++++++++

>  ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c | 136 +++++++++++++++++++

>  6 files changed, 351 insertions(+), 2 deletions(-)

> 

> diff --git a/ArmPkg/Drivers/ArmGic/ArmGicDxe.inf b/ArmPkg/Drivers/ArmGic/ArmGicDxe.inf

> index e554301c4b28022c805f69242cf6ee979d19abc2..d5921533fb68fa32c3e0705b05930700ee81da07 100644

> --- a/ArmPkg/Drivers/ArmGic/ArmGicDxe.inf

> +++ b/ArmPkg/Drivers/ArmGic/ArmGicDxe.inf

> @@ -1,7 +1,7 @@

>  #/** @file

>  #

>  #  Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>

> -#  Copyright (c) 2012 - 2015, ARM Ltd. All rights reserved.<BR>

> +#  Copyright (c) 2012 - 2017, ARM Ltd. All rights reserved.<BR>

>  #

>  #  This program and the accompanying materials

>  #  are licensed and made available under the terms and conditions of the BSD License

> @@ -48,6 +48,7 @@ [LibraryClasses]

>  

>  [Protocols]

>    gHardwareInterruptProtocolGuid

> +  gHardwareInterrupt2ProtocolGuid

>    gEfiCpuArchProtocolGuid

>  

>  [Pcd.common]

> diff --git a/ArmPkg/Drivers/ArmGic/ArmGicDxe.h b/ArmPkg/Drivers/ArmGic/ArmGicDxe.h

> index 76945282d9b9bbf6da872a408a56387ee321a3b5..610ffacc7eb025011f87ad5e6e457a610bd570a9 100644

> --- a/ArmPkg/Drivers/ArmGic/ArmGicDxe.h

> +++ b/ArmPkg/Drivers/ArmGic/ArmGicDxe.h

> @@ -24,6 +24,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

>  

>  #include <Protocol/Cpu.h>

>  #include <Protocol/HardwareInterrupt.h>

> +#include <Protocol/HardwareInterrupt2.h>

>  

>  extern UINTN                        mGicNumInterrupts;

>  extern HARDWARE_INTERRUPT_HANDLER  *gRegisteredInterruptHandlers;

> @@ -32,6 +33,7 @@ extern HARDWARE_INTERRUPT_HANDLER  *gRegisteredInterruptHandlers;

>  EFI_STATUS

>  InstallAndRegisterInterruptService (

>    IN EFI_HARDWARE_INTERRUPT_PROTOCOL   *InterruptProtocol,

> +  IN EFI_HARDWARE_INTERRUPT2_PROTOCOL  *Interrupt2Protocol,

>    IN EFI_CPU_INTERRUPT_HANDLER          InterruptHandler,

>    IN EFI_EVENT_NOTIFY                   ExitBootServicesEvent

>    );

> @@ -58,4 +60,25 @@ GicV3DxeInitialize (

>    IN EFI_SYSTEM_TABLE   *SystemTable

>    );

>  

> +

> +// Shared code

> +

> +/**

> +  Calculate GICD_ICFGRn base address and corresponding bit

> +  field Int_config[1] of the GIC distributor register.

> +

> +  @param Source       Hardware source of the interrupt.

> +  @param RegAddress   Corresponding GICD_ICFGRn base address.

> +  @param Config1Bit   Bit number of F Int_config[1] bit in the register.

> +

> +  @retval EFI_SUCCESS       Source interrupt supported.

> +  @retval EFI_UNSUPPORTED   Source interrupt is not supported.

> +**/

> +EFI_STATUS

> +GicGetDistributorIcfgBaseAndBit (

> +  IN HARDWARE_INTERRUPT_SOURCE             Source,

> +  OUT UINTN                               *RegAddress,

> +  OUT UINTN                               *Config1Bit

> +  );

> +

>  #endif

> diff --git a/ArmPkg/Include/Library/ArmGicLib.h b/ArmPkg/Include/Library/ArmGicLib.h

> index a4ede82bc6c07733f880a12fff54001590a0518a..4b21ea9e4e76cb83c0c3421c1d9d88b456192687 100644

> --- a/ArmPkg/Include/Library/ArmGicLib.h

> +++ b/ArmPkg/Include/Library/ArmGicLib.h

> @@ -49,8 +49,17 @@

>  #define ARM_GIC_ICDDCR_ARE      (1 << 4) // Affinity Routing Enable (ARE)

>  #define ARM_GIC_ICDDCR_DS       (1 << 6) // Disable Security (DS)

>  

> +// GICD_ICDICFR bits

> +#define ARM_GIC_ICDICFR_WIDTH            32   // ICDICFR is a 32 bit register

> +#define ARM_GIC_ICDICFR_BYTES            (ARM_GIC_ICDICFR_WIDTH / 8)

> +#define ARM_GIC_ICDICFR_F_WIDTH          2    // Each F field is 2 bits

> +#define ARM_GIC_ICDICFR_F_STRIDE         16   // (32/2) F fields per register

> +#define ARM_GIC_ICDICFR_F_CONFIG1_BIT    1    // Bit number within F field

> +#define ARM_GIC_ICDICFR_LEVEL_TRIGGERED  0x0  // Level triggered interrupt

> +#define ARM_GIC_ICDICFR_EDGE_TRIGGERED   0x1  // Edge triggered interrupt

> +

> +

>  // GIC Redistributor

> -

>  #define ARM_GICR_CTLR_FRAME_SIZE    SIZE_64KB

>  #define ARM_GICR_SGI_PPI_FRAME_SIZE SIZE_64KB

>  

> diff --git a/ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c b/ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c

> index 7ca3ca8f52afe52c827ca82b749b665184813fc1..bff8d983cf02f7fd1fa6165824cb6556cdea5c6f 100644

> --- a/ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c

> +++ b/ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c

> @@ -39,6 +39,46 @@ UINTN mGicNumInterrupts                 = 0;

>  

>  HARDWARE_INTERRUPT_HANDLER  *gRegisteredInterruptHandlers = NULL;

>  

> +

> +/**

> +  Calculate GICD_ICFGRn base address and corresponding bit

> +  field Int_config[1] of the GIC distributor register.

> +

> +  @param Source       Hardware source of the interrupt.

> +  @param RegAddress   Corresponding GICD_ICFGRn base address.

> +  @param Config1Bit   Bit number of F Int_config[1] bit in the register.

> +

> +  @retval EFI_SUCCESS       Source interrupt supported.

> +  @retval EFI_UNSUPPORTED   Source interrupt is not supported.

> +**/

> +EFI_STATUS

> +GicGetDistributorIcfgBaseAndBit (

> +  IN HARDWARE_INTERRUPT_SOURCE             Source,

> +  OUT UINTN                               *RegAddress,

> +  OUT UINTN                               *Config1Bit

> +  )

> +{

> +  UINTN                  RegIndex;

> +  UINTN                  Field;

> +

> +  if (Source >= mGicNumInterrupts) {

> +    ASSERT(Source < mGicNumInterrupts);

> +    return EFI_UNSUPPORTED;

> +  }

> +

> +  RegIndex = Source / ARM_GIC_ICDICFR_F_STRIDE;  // NOTE: truncation is significant

> +  Field = Source % ARM_GIC_ICDICFR_F_STRIDE;

> +  *RegAddress = PcdGet64 (PcdGicDistributorBase)

> +                + ARM_GIC_ICDICFR

> +                + (ARM_GIC_ICDICFR_BYTES * RegIndex);

> +  *Config1Bit = ((Field * ARM_GIC_ICDICFR_F_WIDTH)

> +                 + ARM_GIC_ICDICFR_F_CONFIG1_BIT);

> +

> +  return EFI_SUCCESS;

> +}

> +

> +

> +

>  /**

>    Register Handler for the specified interrupt source.

>  

> @@ -84,6 +124,7 @@ RegisterInterruptSource (

>  EFI_STATUS

>  InstallAndRegisterInterruptService (

>    IN EFI_HARDWARE_INTERRUPT_PROTOCOL   *InterruptProtocol,

> +  IN EFI_HARDWARE_INTERRUPT2_PROTOCOL  *Interrupt2Protocol,

>    IN EFI_CPU_INTERRUPT_HANDLER          InterruptHandler,

>    IN EFI_EVENT_NOTIFY                   ExitBootServicesEvent

>    )

> @@ -103,6 +144,8 @@ InstallAndRegisterInterruptService (

>                    &gHardwareInterruptHandle,

>                    &gHardwareInterruptProtocolGuid,

>                    InterruptProtocol,

> +                  &gHardwareInterrupt2ProtocolGuid,

> +                  Interrupt2Protocol,

>                    NULL

>                    );

>    if (EFI_ERROR (Status)) {

> diff --git a/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c b/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c

> index 3d5d034efbb1bf2e1e84841cab4175bc607845c2..7717ebe75330562db61a30ab4e5c5ad559c5f201 100644

> --- a/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c

> +++ b/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c

> @@ -29,6 +29,7 @@ Abstract:

>  #define ARM_GIC_DEFAULT_PRIORITY  0x80

>  

>  extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol;

> +extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol;

>  

>  STATIC UINT32 mGicInterruptInterfaceBase;

>  STATIC UINT32 mGicDistributorBase;

> @@ -198,6 +199,141 @@ EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol = {

>    GicV2EndOfInterrupt

>  };

>  

> +/**

> +  Get interrupt trigger type of an interrupt

> +

> +  @param This          Instance pointer for this protocol

> +  @param Source        Hardware source of the interrupt.

> +  @param TriggerType   Returns interrupt trigger type.

> +

> +  @retval EFI_SUCCESS       Source interrupt supported.

> +  @retval EFI_UNSUPPORTED   Source interrupt is not supported.

> +**/

> +STATIC

> +EFI_STATUS

> +EFIAPI

> +GicV2GetTriggerType (

> +  IN  EFI_HARDWARE_INTERRUPT2_PROTOCOL      *This,

> +  IN  HARDWARE_INTERRUPT_SOURCE              Source,

> +  OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE  *TriggerType

> +  )

> +{

> +  UINTN                   RegAddress;

> +  UINTN                   Config1Bit;

> +  EFI_STATUS              Status;

> +

> +  Status = GicGetDistributorIcfgBaseAndBit (

> +              Source,

> +              &RegAddress,

> +              &Config1Bit

> +              );

> +

> +  if (EFI_ERROR (Status)) {

> +    return Status;

> +  }

> +

> +  if ((MmioRead32 (RegAddress) & (1 << Config1Bit)) == 0) {

> +     *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH;

> +  } else {

> +     *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING;

> +  }

> +

> +  return EFI_SUCCESS;

> +}

> +

> +/**

> +  Set interrupt trigger type of an interrupt

> +

> +  @param This          Instance pointer for this protocol

> +  @param Source        Hardware source of the interrupt.

> +  @param TriggerType   Interrupt trigger type.

> +

> +  @retval EFI_SUCCESS       Source interrupt supported.

> +  @retval EFI_UNSUPPORTED   Source interrupt is not supported.

> +**/

> +STATIC

> +EFI_STATUS

> +EFIAPI

> +GicV2SetTriggerType (

> +  IN  EFI_HARDWARE_INTERRUPT2_PROTOCOL      *This,

> +  IN  HARDWARE_INTERRUPT_SOURCE             Source,

> +  IN  EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE  TriggerType

> +  )

> +{

> +  UINTN                   RegAddress;

> +  UINTN                   Config1Bit;

> +  UINT32                  Value;

> +  EFI_STATUS              Status;

> +  BOOLEAN                 SourceEnabled;

> +

> +  if (   (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)

> +      && (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH)) {

> +          DEBUG ((DEBUG_ERROR, "Invalid interrupt trigger type: %d\n", \

> +                  TriggerType));

> +          ASSERT (FALSE);

> +          return EFI_UNSUPPORTED;

> +  }

> +

> +  Status = GicGetDistributorIcfgBaseAndBit (

> +             Source,

> +             &RegAddress,

> +             &Config1Bit

> +             );

> +

> +  if (EFI_ERROR (Status)) {

> +    return Status;

> +  }

> +

> +  Status = GicV2GetInterruptSourceState (

> +             (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,

> +             Source,

> +             &SourceEnabled

> +             );

> +

> +  if (EFI_ERROR (Status)) {

> +    return Status;

> +  }

> +

> +  Value = (TriggerType == EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)

> +          ?  ARM_GIC_ICDICFR_EDGE_TRIGGERED

> +          :  ARM_GIC_ICDICFR_LEVEL_TRIGGERED;

> +

> +  // Before changing the value, we must disable the interrupt,

> +  // otherwise GIC behavior is UNPREDICTABLE.

> +  if (SourceEnabled) {

> +    GicV2DisableInterruptSource (

> +      (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,

> +      Source

> +      );

> +  }

> +

> +  MmioAndThenOr32 (

> +    RegAddress,

> +    ~(0x1 << Config1Bit),

> +    Value << Config1Bit

> +    );

> +

> +  // Restore interrupt state

> +  if (SourceEnabled) {

> +    GicV2EnableInterruptSource (

> +      (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,

> +      Source

> +      );

> +  }

> +

> +  return EFI_SUCCESS;

> +}

> +

> +EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol = {

> +  (HARDWARE_INTERRUPT2_REGISTER)RegisterInterruptSource,

> +  (HARDWARE_INTERRUPT2_ENABLE)GicV2EnableInterruptSource,

> +  (HARDWARE_INTERRUPT2_DISABLE)GicV2DisableInterruptSource,

> +  (HARDWARE_INTERRUPT2_INTERRUPT_STATE)GicV2GetInterruptSourceState,

> +  (HARDWARE_INTERRUPT2_END_OF_INTERRUPT)GicV2EndOfInterrupt,

> +  GicV2GetTriggerType,

> +  GicV2SetTriggerType

> +};

> +

>  /**

>    Shutdown our hardware

>  

> @@ -321,6 +457,7 @@ GicV2DxeInitialize (

>  

>    Status = InstallAndRegisterInterruptService (

>               &gHardwareInterruptV2Protocol,

> +             &gHardwareInterrupt2V2Protocol,

>               GicV2IrqInterruptHandler,

>               GicV2ExitBootServicesEvent

>               );

> diff --git a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c

> index 50b51ffcf57b23b110899c7c55237cf85b61d196..01154848f4439af3e87e89cf796f3d69ce4a0c4a 100644

> --- a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c

> +++ b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c

> @@ -19,6 +19,7 @@

>  #define ARM_GIC_DEFAULT_PRIORITY  0x80

>  

>  extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol;

> +extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol;

>  

>  STATIC UINTN mGicDistributorBase;

>  STATIC UINTN mGicRedistributorsBase;

> @@ -192,6 +193,140 @@ EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol = {

>    GicV3EndOfInterrupt

>  };

>  

> +/**

> +  Get interrupt trigger type of an interrupt

> +

> +  @param This          Instance pointer for this protocol

> +  @param Source        Hardware source of the interrupt.

> +  @param TriggerType   Returns interrupt trigger type.

> +

> +  @retval EFI_SUCCESS       Source interrupt supported.

> +  @retval EFI_UNSUPPORTED   Source interrupt is not supported.

> +**/

> +STATIC

> +EFI_STATUS

> +EFIAPI

> +GicV3GetTriggerType (

> +  IN  EFI_HARDWARE_INTERRUPT2_PROTOCOL      *This,

> +  IN  HARDWARE_INTERRUPT_SOURCE             Source,

> +  OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE  *TriggerType

> +  )

> +{

> +  UINTN                   RegAddress;

> +  UINTN                   Config1Bit;

> +  EFI_STATUS              Status;

> +

> +  Status = GicGetDistributorIcfgBaseAndBit (

> +             Source,

> +             &RegAddress,

> +             &Config1Bit

> +             );

> +

> +  if (EFI_ERROR (Status)) {

> +    return Status;

> +  }

> +

> +  if ((MmioRead32 (RegAddress) & (1 << Config1Bit)) == 0) {

> +     *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH;

> +  } else {

> +     *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING;

> +  }

> +

> +  return EFI_SUCCESS;

> +}

> +

> +/**

> +  Set interrupt trigger type of an interrupt

> +

> +  @param This          Instance pointer for this protocol

> +  @param Source        Hardware source of the interrupt.

> +  @param TriggerType   Interrupt trigger type.

> +

> +  @retval EFI_SUCCESS       Source interrupt supported.

> +  @retval EFI_UNSUPPORTED   Source interrupt is not supported.

> +**/

> +STATIC

> +EFI_STATUS

> +EFIAPI

> +GicV3SetTriggerType (

> +  IN  EFI_HARDWARE_INTERRUPT2_PROTOCOL      *This,

> +  IN  HARDWARE_INTERRUPT_SOURCE             Source,

> +  IN  EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE  TriggerType

> +  )

> +{

> +  UINTN                   RegAddress;

> +  UINTN                   Config1Bit;

> +  UINT32                  Value;

> +  EFI_STATUS              Status;

> +  BOOLEAN                 SourceEnabled;

> +

> +  if (   (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)

> +      && (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH)) {

> +          DEBUG ((DEBUG_ERROR, "Invalid interrupt trigger type: %d\n", \

> +                 TriggerType));

> +          ASSERT (FALSE);

> +          return EFI_UNSUPPORTED;

> +  }

> +

> +  Status = GicGetDistributorIcfgBaseAndBit (

> +             Source,

> +             &RegAddress,

> +             &Config1Bit

> +             );

> +

> +  if (EFI_ERROR (Status)) {

> +    return Status;

> +  }

> +

> +  Status = GicV3GetInterruptSourceState (

> +             (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,

> +             Source,

> +             &SourceEnabled

> +             );

> +

> +  if (EFI_ERROR (Status)) {

> +    return Status;

> +  }

> +

> +  Value = (TriggerType == EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)

> +          ?  ARM_GIC_ICDICFR_EDGE_TRIGGERED

> +          :  ARM_GIC_ICDICFR_LEVEL_TRIGGERED;

> +

> +  // Before changing the value, we must disable the interrupt,

> +  // otherwise GIC behavior is UNPREDICTABLE.

> +  if (SourceEnabled) {

> +    GicV3DisableInterruptSource (

> +      (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,

> +      Source

> +      );

> +  }

> +

> +  MmioAndThenOr32 (

> +    RegAddress,

> +    ~(0x1 << Config1Bit),

> +    Value << Config1Bit

> +    );

> +  // Restore interrupt state

> +  if (SourceEnabled) {

> +    GicV3EnableInterruptSource (

> +      (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,

> +      Source

> +      );

> +  }

> +

> +  return EFI_SUCCESS;

> +}

> +

> +EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol = {

> +  (HARDWARE_INTERRUPT2_REGISTER)RegisterInterruptSource,

> +  (HARDWARE_INTERRUPT2_ENABLE)GicV3EnableInterruptSource,

> +  (HARDWARE_INTERRUPT2_DISABLE)GicV3DisableInterruptSource,

> +  (HARDWARE_INTERRUPT2_INTERRUPT_STATE)GicV3GetInterruptSourceState,

> +  (HARDWARE_INTERRUPT2_END_OF_INTERRUPT)GicV3EndOfInterrupt,

> +  GicV3GetTriggerType,

> +  GicV3SetTriggerType

> +};

> +

>  /**

>    Shutdown our hardware

>  

> @@ -353,6 +488,7 @@ GicV3DxeInitialize (

>  

>    Status = InstallAndRegisterInterruptService (

>               &gHardwareInterruptV3Protocol,

> +             &gHardwareInterrupt2V3Protocol,

>               GicV3IrqInterruptHandler,

>               GicV3ExitBootServicesEvent

>               );

> -- 

> Guid("CE165669-3EF3-493F-B85D-6190EE5B9759")

> 

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Ard Biesheuvel Oct. 5, 2017, 8:15 p.m. UTC | #2
On 5 October 2017 at 21:15, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Thu, Sep 21, 2017 at 05:23:43PM +0100, evan.lloyd@arm.com wrote:

>> From: Ard Biesheuvel <ard.biesheuvel@linaro.org>

>>

>> The existing HardwareInterrupt protocol lacked a means to configure the

>> level/edge properties of an interrupt.  The new HardwareInterrupt2

>> protocol introduced this capability.

>> This patch updates the GIC drivers to provide the new interfaces.

>> The changes comprise:

>>   Update to use HardwareInterrupt2 protocol

>>   Additions to register info in ArmGicLib.h

>>   Added new functionality (GetTriggerType and SetTriggerType)

>>

>> The requirement for this change derives from a problem detected on ARM

>> Juno boards, but the change is of generic (ARM) relevance.

>>

>> This commit is in response to review on the mailing list and, as

>> suggested there, rolls Girish's updates onto Ard's original example.

>>

>> Contributed-under: TianoCore Contribution Agreement 1.0

>

> This patch has lagged: Ard, are you happy to confirm this one could be

> updated to 1.1?

>


Absolutely.
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Leif Lindholm Oct. 5, 2017, 8:25 p.m. UTC | #3
On Thu, Oct 05, 2017 at 09:15:41PM +0100, Ard Biesheuvel wrote:
> On 5 October 2017 at 21:15, Leif Lindholm <leif.lindholm@linaro.org> wrote:

> > On Thu, Sep 21, 2017 at 05:23:43PM +0100, evan.lloyd@arm.com wrote:

> >> From: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> >>

> >> The existing HardwareInterrupt protocol lacked a means to configure the

> >> level/edge properties of an interrupt.  The new HardwareInterrupt2

> >> protocol introduced this capability.

> >> This patch updates the GIC drivers to provide the new interfaces.

> >> The changes comprise:

> >>   Update to use HardwareInterrupt2 protocol

> >>   Additions to register info in ArmGicLib.h

> >>   Added new functionality (GetTriggerType and SetTriggerType)

> >>

> >> The requirement for this change derives from a problem detected on ARM

> >> Juno boards, but the change is of generic (ARM) relevance.

> >>

> >> This commit is in response to review on the mailing list and, as

> >> suggested there, rolls Girish's updates onto Ard's original example.

> >>

> >> Contributed-under: TianoCore Contribution Agreement 1.0

> >

> > This patch has lagged: Ard, are you happy to confirm this one could be

> > updated to 1.1?

> >

> 

> Absolutely.


Many thanks: series pushed as fe4049471b..baee8efb36

/
    Leif
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
diff mbox series

Patch

diff --git a/ArmPkg/Drivers/ArmGic/ArmGicDxe.inf b/ArmPkg/Drivers/ArmGic/ArmGicDxe.inf
index e554301c4b28022c805f69242cf6ee979d19abc2..d5921533fb68fa32c3e0705b05930700ee81da07 100644
--- a/ArmPkg/Drivers/ArmGic/ArmGicDxe.inf
+++ b/ArmPkg/Drivers/ArmGic/ArmGicDxe.inf
@@ -1,7 +1,7 @@ 
 #/** @file
 #
 #  Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
-#  Copyright (c) 2012 - 2015, ARM Ltd. All rights reserved.<BR>
+#  Copyright (c) 2012 - 2017, ARM Ltd. All rights reserved.<BR>
 #
 #  This program and the accompanying materials
 #  are licensed and made available under the terms and conditions of the BSD License
@@ -48,6 +48,7 @@  [LibraryClasses]
 
 [Protocols]
   gHardwareInterruptProtocolGuid
+  gHardwareInterrupt2ProtocolGuid
   gEfiCpuArchProtocolGuid
 
 [Pcd.common]
diff --git a/ArmPkg/Drivers/ArmGic/ArmGicDxe.h b/ArmPkg/Drivers/ArmGic/ArmGicDxe.h
index 76945282d9b9bbf6da872a408a56387ee321a3b5..610ffacc7eb025011f87ad5e6e457a610bd570a9 100644
--- a/ArmPkg/Drivers/ArmGic/ArmGicDxe.h
+++ b/ArmPkg/Drivers/ArmGic/ArmGicDxe.h
@@ -24,6 +24,7 @@  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 
 #include <Protocol/Cpu.h>
 #include <Protocol/HardwareInterrupt.h>
+#include <Protocol/HardwareInterrupt2.h>
 
 extern UINTN                        mGicNumInterrupts;
 extern HARDWARE_INTERRUPT_HANDLER  *gRegisteredInterruptHandlers;
@@ -32,6 +33,7 @@  extern HARDWARE_INTERRUPT_HANDLER  *gRegisteredInterruptHandlers;
 EFI_STATUS
 InstallAndRegisterInterruptService (
   IN EFI_HARDWARE_INTERRUPT_PROTOCOL   *InterruptProtocol,
+  IN EFI_HARDWARE_INTERRUPT2_PROTOCOL  *Interrupt2Protocol,
   IN EFI_CPU_INTERRUPT_HANDLER          InterruptHandler,
   IN EFI_EVENT_NOTIFY                   ExitBootServicesEvent
   );
@@ -58,4 +60,25 @@  GicV3DxeInitialize (
   IN EFI_SYSTEM_TABLE   *SystemTable
   );
 
+
+// Shared code
+
+/**
+  Calculate GICD_ICFGRn base address and corresponding bit
+  field Int_config[1] of the GIC distributor register.
+
+  @param Source       Hardware source of the interrupt.
+  @param RegAddress   Corresponding GICD_ICFGRn base address.
+  @param Config1Bit   Bit number of F Int_config[1] bit in the register.
+
+  @retval EFI_SUCCESS       Source interrupt supported.
+  @retval EFI_UNSUPPORTED   Source interrupt is not supported.
+**/
+EFI_STATUS
+GicGetDistributorIcfgBaseAndBit (
+  IN HARDWARE_INTERRUPT_SOURCE             Source,
+  OUT UINTN                               *RegAddress,
+  OUT UINTN                               *Config1Bit
+  );
+
 #endif
diff --git a/ArmPkg/Include/Library/ArmGicLib.h b/ArmPkg/Include/Library/ArmGicLib.h
index a4ede82bc6c07733f880a12fff54001590a0518a..4b21ea9e4e76cb83c0c3421c1d9d88b456192687 100644
--- a/ArmPkg/Include/Library/ArmGicLib.h
+++ b/ArmPkg/Include/Library/ArmGicLib.h
@@ -49,8 +49,17 @@ 
 #define ARM_GIC_ICDDCR_ARE      (1 << 4) // Affinity Routing Enable (ARE)
 #define ARM_GIC_ICDDCR_DS       (1 << 6) // Disable Security (DS)
 
+// GICD_ICDICFR bits
+#define ARM_GIC_ICDICFR_WIDTH            32   // ICDICFR is a 32 bit register
+#define ARM_GIC_ICDICFR_BYTES            (ARM_GIC_ICDICFR_WIDTH / 8)
+#define ARM_GIC_ICDICFR_F_WIDTH          2    // Each F field is 2 bits
+#define ARM_GIC_ICDICFR_F_STRIDE         16   // (32/2) F fields per register
+#define ARM_GIC_ICDICFR_F_CONFIG1_BIT    1    // Bit number within F field
+#define ARM_GIC_ICDICFR_LEVEL_TRIGGERED  0x0  // Level triggered interrupt
+#define ARM_GIC_ICDICFR_EDGE_TRIGGERED   0x1  // Edge triggered interrupt
+
+
 // GIC Redistributor
-
 #define ARM_GICR_CTLR_FRAME_SIZE    SIZE_64KB
 #define ARM_GICR_SGI_PPI_FRAME_SIZE SIZE_64KB
 
diff --git a/ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c b/ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c
index 7ca3ca8f52afe52c827ca82b749b665184813fc1..bff8d983cf02f7fd1fa6165824cb6556cdea5c6f 100644
--- a/ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c
+++ b/ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c
@@ -39,6 +39,46 @@  UINTN mGicNumInterrupts                 = 0;
 
 HARDWARE_INTERRUPT_HANDLER  *gRegisteredInterruptHandlers = NULL;
 
+
+/**
+  Calculate GICD_ICFGRn base address and corresponding bit
+  field Int_config[1] of the GIC distributor register.
+
+  @param Source       Hardware source of the interrupt.
+  @param RegAddress   Corresponding GICD_ICFGRn base address.
+  @param Config1Bit   Bit number of F Int_config[1] bit in the register.
+
+  @retval EFI_SUCCESS       Source interrupt supported.
+  @retval EFI_UNSUPPORTED   Source interrupt is not supported.
+**/
+EFI_STATUS
+GicGetDistributorIcfgBaseAndBit (
+  IN HARDWARE_INTERRUPT_SOURCE             Source,
+  OUT UINTN                               *RegAddress,
+  OUT UINTN                               *Config1Bit
+  )
+{
+  UINTN                  RegIndex;
+  UINTN                  Field;
+
+  if (Source >= mGicNumInterrupts) {
+    ASSERT(Source < mGicNumInterrupts);
+    return EFI_UNSUPPORTED;
+  }
+
+  RegIndex = Source / ARM_GIC_ICDICFR_F_STRIDE;  // NOTE: truncation is significant
+  Field = Source % ARM_GIC_ICDICFR_F_STRIDE;
+  *RegAddress = PcdGet64 (PcdGicDistributorBase)
+                + ARM_GIC_ICDICFR
+                + (ARM_GIC_ICDICFR_BYTES * RegIndex);
+  *Config1Bit = ((Field * ARM_GIC_ICDICFR_F_WIDTH)
+                 + ARM_GIC_ICDICFR_F_CONFIG1_BIT);
+
+  return EFI_SUCCESS;
+}
+
+
+
 /**
   Register Handler for the specified interrupt source.
 
@@ -84,6 +124,7 @@  RegisterInterruptSource (
 EFI_STATUS
 InstallAndRegisterInterruptService (
   IN EFI_HARDWARE_INTERRUPT_PROTOCOL   *InterruptProtocol,
+  IN EFI_HARDWARE_INTERRUPT2_PROTOCOL  *Interrupt2Protocol,
   IN EFI_CPU_INTERRUPT_HANDLER          InterruptHandler,
   IN EFI_EVENT_NOTIFY                   ExitBootServicesEvent
   )
@@ -103,6 +144,8 @@  InstallAndRegisterInterruptService (
                   &gHardwareInterruptHandle,
                   &gHardwareInterruptProtocolGuid,
                   InterruptProtocol,
+                  &gHardwareInterrupt2ProtocolGuid,
+                  Interrupt2Protocol,
                   NULL
                   );
   if (EFI_ERROR (Status)) {
diff --git a/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c b/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c
index 3d5d034efbb1bf2e1e84841cab4175bc607845c2..7717ebe75330562db61a30ab4e5c5ad559c5f201 100644
--- a/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c
+++ b/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c
@@ -29,6 +29,7 @@  Abstract:
 #define ARM_GIC_DEFAULT_PRIORITY  0x80
 
 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol;
+extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol;
 
 STATIC UINT32 mGicInterruptInterfaceBase;
 STATIC UINT32 mGicDistributorBase;
@@ -198,6 +199,141 @@  EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol = {
   GicV2EndOfInterrupt
 };
 
+/**
+  Get interrupt trigger type of an interrupt
+
+  @param This          Instance pointer for this protocol
+  @param Source        Hardware source of the interrupt.
+  @param TriggerType   Returns interrupt trigger type.
+
+  @retval EFI_SUCCESS       Source interrupt supported.
+  @retval EFI_UNSUPPORTED   Source interrupt is not supported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV2GetTriggerType (
+  IN  EFI_HARDWARE_INTERRUPT2_PROTOCOL      *This,
+  IN  HARDWARE_INTERRUPT_SOURCE              Source,
+  OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE  *TriggerType
+  )
+{
+  UINTN                   RegAddress;
+  UINTN                   Config1Bit;
+  EFI_STATUS              Status;
+
+  Status = GicGetDistributorIcfgBaseAndBit (
+              Source,
+              &RegAddress,
+              &Config1Bit
+              );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if ((MmioRead32 (RegAddress) & (1 << Config1Bit)) == 0) {
+     *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH;
+  } else {
+     *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set interrupt trigger type of an interrupt
+
+  @param This          Instance pointer for this protocol
+  @param Source        Hardware source of the interrupt.
+  @param TriggerType   Interrupt trigger type.
+
+  @retval EFI_SUCCESS       Source interrupt supported.
+  @retval EFI_UNSUPPORTED   Source interrupt is not supported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV2SetTriggerType (
+  IN  EFI_HARDWARE_INTERRUPT2_PROTOCOL      *This,
+  IN  HARDWARE_INTERRUPT_SOURCE             Source,
+  IN  EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE  TriggerType
+  )
+{
+  UINTN                   RegAddress;
+  UINTN                   Config1Bit;
+  UINT32                  Value;
+  EFI_STATUS              Status;
+  BOOLEAN                 SourceEnabled;
+
+  if (   (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)
+      && (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH)) {
+          DEBUG ((DEBUG_ERROR, "Invalid interrupt trigger type: %d\n", \
+                  TriggerType));
+          ASSERT (FALSE);
+          return EFI_UNSUPPORTED;
+  }
+
+  Status = GicGetDistributorIcfgBaseAndBit (
+             Source,
+             &RegAddress,
+             &Config1Bit
+             );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = GicV2GetInterruptSourceState (
+             (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,
+             Source,
+             &SourceEnabled
+             );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Value = (TriggerType == EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)
+          ?  ARM_GIC_ICDICFR_EDGE_TRIGGERED
+          :  ARM_GIC_ICDICFR_LEVEL_TRIGGERED;
+
+  // Before changing the value, we must disable the interrupt,
+  // otherwise GIC behavior is UNPREDICTABLE.
+  if (SourceEnabled) {
+    GicV2DisableInterruptSource (
+      (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,
+      Source
+      );
+  }
+
+  MmioAndThenOr32 (
+    RegAddress,
+    ~(0x1 << Config1Bit),
+    Value << Config1Bit
+    );
+
+  // Restore interrupt state
+  if (SourceEnabled) {
+    GicV2EnableInterruptSource (
+      (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,
+      Source
+      );
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol = {
+  (HARDWARE_INTERRUPT2_REGISTER)RegisterInterruptSource,
+  (HARDWARE_INTERRUPT2_ENABLE)GicV2EnableInterruptSource,
+  (HARDWARE_INTERRUPT2_DISABLE)GicV2DisableInterruptSource,
+  (HARDWARE_INTERRUPT2_INTERRUPT_STATE)GicV2GetInterruptSourceState,
+  (HARDWARE_INTERRUPT2_END_OF_INTERRUPT)GicV2EndOfInterrupt,
+  GicV2GetTriggerType,
+  GicV2SetTriggerType
+};
+
 /**
   Shutdown our hardware
 
@@ -321,6 +457,7 @@  GicV2DxeInitialize (
 
   Status = InstallAndRegisterInterruptService (
              &gHardwareInterruptV2Protocol,
+             &gHardwareInterrupt2V2Protocol,
              GicV2IrqInterruptHandler,
              GicV2ExitBootServicesEvent
              );
diff --git a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
index 50b51ffcf57b23b110899c7c55237cf85b61d196..01154848f4439af3e87e89cf796f3d69ce4a0c4a 100644
--- a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
+++ b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
@@ -19,6 +19,7 @@ 
 #define ARM_GIC_DEFAULT_PRIORITY  0x80
 
 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol;
+extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol;
 
 STATIC UINTN mGicDistributorBase;
 STATIC UINTN mGicRedistributorsBase;
@@ -192,6 +193,140 @@  EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol = {
   GicV3EndOfInterrupt
 };
 
+/**
+  Get interrupt trigger type of an interrupt
+
+  @param This          Instance pointer for this protocol
+  @param Source        Hardware source of the interrupt.
+  @param TriggerType   Returns interrupt trigger type.
+
+  @retval EFI_SUCCESS       Source interrupt supported.
+  @retval EFI_UNSUPPORTED   Source interrupt is not supported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV3GetTriggerType (
+  IN  EFI_HARDWARE_INTERRUPT2_PROTOCOL      *This,
+  IN  HARDWARE_INTERRUPT_SOURCE             Source,
+  OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE  *TriggerType
+  )
+{
+  UINTN                   RegAddress;
+  UINTN                   Config1Bit;
+  EFI_STATUS              Status;
+
+  Status = GicGetDistributorIcfgBaseAndBit (
+             Source,
+             &RegAddress,
+             &Config1Bit
+             );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if ((MmioRead32 (RegAddress) & (1 << Config1Bit)) == 0) {
+     *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH;
+  } else {
+     *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set interrupt trigger type of an interrupt
+
+  @param This          Instance pointer for this protocol
+  @param Source        Hardware source of the interrupt.
+  @param TriggerType   Interrupt trigger type.
+
+  @retval EFI_SUCCESS       Source interrupt supported.
+  @retval EFI_UNSUPPORTED   Source interrupt is not supported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicV3SetTriggerType (
+  IN  EFI_HARDWARE_INTERRUPT2_PROTOCOL      *This,
+  IN  HARDWARE_INTERRUPT_SOURCE             Source,
+  IN  EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE  TriggerType
+  )
+{
+  UINTN                   RegAddress;
+  UINTN                   Config1Bit;
+  UINT32                  Value;
+  EFI_STATUS              Status;
+  BOOLEAN                 SourceEnabled;
+
+  if (   (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)
+      && (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH)) {
+          DEBUG ((DEBUG_ERROR, "Invalid interrupt trigger type: %d\n", \
+                 TriggerType));
+          ASSERT (FALSE);
+          return EFI_UNSUPPORTED;
+  }
+
+  Status = GicGetDistributorIcfgBaseAndBit (
+             Source,
+             &RegAddress,
+             &Config1Bit
+             );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = GicV3GetInterruptSourceState (
+             (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,
+             Source,
+             &SourceEnabled
+             );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Value = (TriggerType == EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)
+          ?  ARM_GIC_ICDICFR_EDGE_TRIGGERED
+          :  ARM_GIC_ICDICFR_LEVEL_TRIGGERED;
+
+  // Before changing the value, we must disable the interrupt,
+  // otherwise GIC behavior is UNPREDICTABLE.
+  if (SourceEnabled) {
+    GicV3DisableInterruptSource (
+      (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,
+      Source
+      );
+  }
+
+  MmioAndThenOr32 (
+    RegAddress,
+    ~(0x1 << Config1Bit),
+    Value << Config1Bit
+    );
+  // Restore interrupt state
+  if (SourceEnabled) {
+    GicV3EnableInterruptSource (
+      (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,
+      Source
+      );
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol = {
+  (HARDWARE_INTERRUPT2_REGISTER)RegisterInterruptSource,
+  (HARDWARE_INTERRUPT2_ENABLE)GicV3EnableInterruptSource,
+  (HARDWARE_INTERRUPT2_DISABLE)GicV3DisableInterruptSource,
+  (HARDWARE_INTERRUPT2_INTERRUPT_STATE)GicV3GetInterruptSourceState,
+  (HARDWARE_INTERRUPT2_END_OF_INTERRUPT)GicV3EndOfInterrupt,
+  GicV3GetTriggerType,
+  GicV3SetTriggerType
+};
+
 /**
   Shutdown our hardware
 
@@ -353,6 +488,7 @@  GicV3DxeInitialize (
 
   Status = InstallAndRegisterInterruptService (
              &gHardwareInterruptV3Protocol,
+             &gHardwareInterrupt2V3Protocol,
              GicV3IrqInterruptHandler,
              GicV3ExitBootServicesEvent
              );