Message ID | 20170921162345.11724-4-evan.lloyd@arm.com |
---|---|
State | New |
Headers | show |
Series | None | expand |
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
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
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 --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 );