2014-10-27 11:30:53 +01:00
|
|
|
/** @file
|
|
|
|
*
|
2019-02-22 20:43:28 +01:00
|
|
|
* Copyright (c) 2011-2018, ARM Limited. All rights reserved.
|
2014-10-27 11:30:53 +01:00
|
|
|
*
|
2019-04-04 01:03:18 +02:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause-Patent
|
2014-10-27 11:30:53 +01:00
|
|
|
*
|
|
|
|
**/
|
|
|
|
|
2015-07-28 22:44:27 +02:00
|
|
|
#include <Library/ArmGicLib.h>
|
|
|
|
|
2014-10-27 11:30:53 +01:00
|
|
|
#include "ArmGicDxe.h"
|
|
|
|
|
|
|
|
#define ARM_GIC_DEFAULT_PRIORITY 0x80
|
|
|
|
|
|
|
|
extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol;
|
2016-09-01 18:21:56 +02:00
|
|
|
extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol;
|
2014-10-27 11:30:53 +01:00
|
|
|
|
|
|
|
STATIC UINTN mGicDistributorBase;
|
2015-02-16 11:21:06 +01:00
|
|
|
STATIC UINTN mGicRedistributorsBase;
|
2014-10-27 11:30:53 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
Enable interrupt source Source.
|
|
|
|
|
|
|
|
@param This Instance pointer for this protocol
|
|
|
|
@param Source Hardware source of the interrupt
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Source interrupt enabled.
|
|
|
|
@retval EFI_DEVICE_ERROR Hardware could not be programmed.
|
|
|
|
|
|
|
|
**/
|
2017-02-15 17:54:29 +01:00
|
|
|
STATIC
|
2014-10-27 11:30:53 +01:00
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
GicV3EnableInterruptSource (
|
|
|
|
IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
|
|
|
|
IN HARDWARE_INTERRUPT_SOURCE Source
|
|
|
|
)
|
|
|
|
{
|
2016-04-23 16:39:59 +02:00
|
|
|
if (Source >= mGicNumInterrupts) {
|
2014-10-27 11:30:53 +01:00
|
|
|
ASSERT(FALSE);
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2015-02-16 11:23:42 +01:00
|
|
|
ArmGicEnableInterrupt (mGicDistributorBase, mGicRedistributorsBase, Source);
|
2014-10-27 11:30:53 +01:00
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Disable interrupt source Source.
|
|
|
|
|
|
|
|
@param This Instance pointer for this protocol
|
|
|
|
@param Source Hardware source of the interrupt
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Source interrupt disabled.
|
|
|
|
@retval EFI_DEVICE_ERROR Hardware could not be programmed.
|
|
|
|
|
|
|
|
**/
|
2017-02-15 17:54:29 +01:00
|
|
|
STATIC
|
2014-10-27 11:30:53 +01:00
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
GicV3DisableInterruptSource (
|
|
|
|
IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
|
|
|
|
IN HARDWARE_INTERRUPT_SOURCE Source
|
|
|
|
)
|
|
|
|
{
|
2016-04-23 16:39:59 +02:00
|
|
|
if (Source >= mGicNumInterrupts) {
|
2014-10-27 11:30:53 +01:00
|
|
|
ASSERT(FALSE);
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2015-02-16 11:23:42 +01:00
|
|
|
ArmGicDisableInterrupt (mGicDistributorBase, mGicRedistributorsBase, Source);
|
2014-10-27 11:30:53 +01:00
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Return current state of interrupt source Source.
|
|
|
|
|
|
|
|
@param This Instance pointer for this protocol
|
|
|
|
@param Source Hardware source of the interrupt
|
|
|
|
@param InterruptState TRUE: source enabled, FALSE: source disabled.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS InterruptState is valid
|
|
|
|
@retval EFI_DEVICE_ERROR InterruptState is not valid
|
|
|
|
|
|
|
|
**/
|
2017-02-15 17:54:29 +01:00
|
|
|
STATIC
|
2014-10-27 11:30:53 +01:00
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
GicV3GetInterruptSourceState (
|
|
|
|
IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
|
|
|
|
IN HARDWARE_INTERRUPT_SOURCE Source,
|
|
|
|
IN BOOLEAN *InterruptState
|
|
|
|
)
|
|
|
|
{
|
2016-04-23 16:39:59 +02:00
|
|
|
if (Source >= mGicNumInterrupts) {
|
2014-10-27 11:30:53 +01:00
|
|
|
ASSERT(FALSE);
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2017-02-15 17:54:29 +01:00
|
|
|
*InterruptState = ArmGicIsInterruptEnabled (
|
|
|
|
mGicDistributorBase,
|
|
|
|
mGicRedistributorsBase,
|
|
|
|
Source
|
|
|
|
);
|
2014-10-27 11:30:53 +01:00
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Signal to the hardware that the End Of Interrupt state
|
|
|
|
has been reached.
|
|
|
|
|
|
|
|
@param This Instance pointer for this protocol
|
|
|
|
@param Source Hardware source of the interrupt
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Source interrupt EOI'ed.
|
|
|
|
@retval EFI_DEVICE_ERROR Hardware could not be programmed.
|
|
|
|
|
|
|
|
**/
|
2017-02-15 17:54:29 +01:00
|
|
|
STATIC
|
2014-10-27 11:30:53 +01:00
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
GicV3EndOfInterrupt (
|
|
|
|
IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
|
|
|
|
IN HARDWARE_INTERRUPT_SOURCE Source
|
|
|
|
)
|
|
|
|
{
|
2016-04-23 16:39:59 +02:00
|
|
|
if (Source >= mGicNumInterrupts) {
|
2014-10-27 11:30:53 +01:00
|
|
|
ASSERT(FALSE);
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
ArmGicV3EndOfInterrupt (Source);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
|
|
|
|
|
|
|
|
@param InterruptType Defines the type of interrupt or exception that
|
2017-02-15 17:54:29 +01:00
|
|
|
occurred on the processor. This parameter is
|
|
|
|
processor architecture specific.
|
2014-10-27 11:30:53 +01:00
|
|
|
@param SystemContext A pointer to the processor context when
|
|
|
|
the interrupt occurred on the processor.
|
|
|
|
|
|
|
|
@return None
|
|
|
|
|
|
|
|
**/
|
2017-02-15 17:54:29 +01:00
|
|
|
STATIC
|
2014-10-27 11:30:53 +01:00
|
|
|
VOID
|
|
|
|
EFIAPI
|
|
|
|
GicV3IrqInterruptHandler (
|
|
|
|
IN EFI_EXCEPTION_TYPE InterruptType,
|
|
|
|
IN EFI_SYSTEM_CONTEXT SystemContext
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINT32 GicInterrupt;
|
|
|
|
HARDWARE_INTERRUPT_HANDLER InterruptHandler;
|
|
|
|
|
|
|
|
GicInterrupt = ArmGicV3AcknowledgeInterrupt ();
|
|
|
|
|
|
|
|
// Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the
|
|
|
|
// number of interrupt (ie: Spurious interrupt).
|
|
|
|
if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) >= mGicNumInterrupts) {
|
|
|
|
// The special interrupt do not need to be acknowledge
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];
|
|
|
|
if (InterruptHandler != NULL) {
|
|
|
|
// Call the registered interrupt handler.
|
|
|
|
InterruptHandler (GicInterrupt, SystemContext);
|
|
|
|
} else {
|
2017-02-15 17:54:29 +01:00
|
|
|
DEBUG ((DEBUG_ERROR, "Spurious GIC interrupt: 0x%x\n", GicInterrupt));
|
2016-08-08 15:46:00 +02:00
|
|
|
GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol, GicInterrupt);
|
2014-10-27 11:30:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The protocol instance produced by this driver
|
|
|
|
EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol = {
|
|
|
|
RegisterInterruptSource,
|
|
|
|
GicV3EnableInterruptSource,
|
|
|
|
GicV3DisableInterruptSource,
|
|
|
|
GicV3GetInterruptSourceState,
|
|
|
|
GicV3EndOfInterrupt
|
|
|
|
};
|
|
|
|
|
2016-09-01 18:21:56 +02:00
|
|
|
/**
|
|
|
|
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
|
|
|
|
};
|
|
|
|
|
2014-10-27 11:30:53 +01:00
|
|
|
/**
|
|
|
|
Shutdown our hardware
|
|
|
|
|
|
|
|
DXE Core will disable interrupts and turn off the timer and disable interrupts
|
|
|
|
after all the event handlers have run.
|
|
|
|
|
|
|
|
@param[in] Event The Event that is being processed
|
|
|
|
@param[in] Context Event Context
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
EFIAPI
|
|
|
|
GicV3ExitBootServicesEvent (
|
|
|
|
IN EFI_EVENT Event,
|
|
|
|
IN VOID *Context
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN Index;
|
|
|
|
|
|
|
|
// Acknowledge all pending interrupts
|
|
|
|
for (Index = 0; Index < mGicNumInterrupts; Index++) {
|
|
|
|
GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Index = 0; Index < mGicNumInterrupts; Index++) {
|
|
|
|
GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol, Index);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disable Gic Interface
|
|
|
|
ArmGicV3DisableInterruptInterface ();
|
|
|
|
|
|
|
|
// Disable Gic Distributor
|
|
|
|
ArmGicDisableDistributor (mGicDistributorBase);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Initialize the state information for the CPU Architectural Protocol
|
|
|
|
|
|
|
|
@param ImageHandle of the loaded driver
|
|
|
|
@param SystemTable Pointer to the System Table
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Protocol registered
|
|
|
|
@retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
|
|
|
|
@retval EFI_DEVICE_ERROR Hardware problems
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
GicV3DxeInitialize (
|
|
|
|
IN EFI_HANDLE ImageHandle,
|
|
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN Index;
|
2015-02-16 11:23:42 +01:00
|
|
|
UINT64 CpuTarget;
|
|
|
|
UINT64 MpId;
|
2014-10-27 11:30:53 +01:00
|
|
|
|
2017-02-15 17:54:29 +01:00
|
|
|
// Make sure the Interrupt Controller Protocol is not already installed in
|
|
|
|
// the system.
|
2014-10-27 11:30:53 +01:00
|
|
|
ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
|
|
|
|
|
2016-09-05 13:38:20 +02:00
|
|
|
mGicDistributorBase = PcdGet64 (PcdGicDistributorBase);
|
|
|
|
mGicRedistributorsBase = PcdGet64 (PcdGicRedistributorsBase);
|
2015-02-16 11:21:06 +01:00
|
|
|
mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);
|
2014-10-27 11:30:53 +01:00
|
|
|
|
2015-02-16 11:27:02 +01:00
|
|
|
// We will be driving this GIC in native v3 mode, i.e., with Affinity
|
|
|
|
// Routing enabled. So ensure that the ARE bit is set.
|
|
|
|
if (!FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {
|
|
|
|
MmioOr32 (mGicDistributorBase + ARM_GIC_ICDDCR, ARM_GIC_ICDDCR_ARE);
|
|
|
|
}
|
|
|
|
|
2014-10-27 11:30:53 +01:00
|
|
|
for (Index = 0; Index < mGicNumInterrupts; Index++) {
|
|
|
|
GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index);
|
|
|
|
|
|
|
|
// Set Priority
|
2020-12-16 14:25:21 +01:00
|
|
|
ArmGicSetInterruptPriority (
|
|
|
|
mGicDistributorBase,
|
|
|
|
mGicRedistributorsBase,
|
|
|
|
Index,
|
|
|
|
ARM_GIC_DEFAULT_PRIORITY
|
2014-10-27 11:30:53 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Targets the interrupts to the Primary Cpu
|
|
|
|
|
2015-02-25 19:42:36 +01:00
|
|
|
if (FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {
|
2017-02-15 17:54:29 +01:00
|
|
|
// Only Primary CPU will run this code. We can identify our GIC CPU ID by
|
|
|
|
// reading the GIC Distributor Target register. The 8 first
|
|
|
|
// GICD_ITARGETSRn are banked to each connected CPU. These 8 registers
|
|
|
|
// hold the CPU targets fields for interrupts 0-31. More Info in the GIC
|
|
|
|
// Specification about "Interrupt Processor Targets Registers"
|
|
|
|
|
|
|
|
// Read the first Interrupt Processor Targets Register (that corresponds
|
|
|
|
// to the 4 first SGIs)
|
2015-02-25 19:42:36 +01:00
|
|
|
CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR);
|
|
|
|
|
2017-02-15 17:54:29 +01:00
|
|
|
// The CPU target is a bit field mapping each CPU to a GIC CPU Interface.
|
|
|
|
// This value is 0 when we run on a uniprocessor platform.
|
2015-02-25 19:42:36 +01:00
|
|
|
if (CpuTarget != 0) {
|
|
|
|
// The 8 first Interrupt Processor Targets Registers are read-only
|
|
|
|
for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) {
|
2017-02-15 17:54:29 +01:00
|
|
|
MmioWrite32 (
|
|
|
|
mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4),
|
|
|
|
CpuTarget
|
|
|
|
);
|
2015-02-25 19:42:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
MpId = ArmReadMpidr ();
|
2017-02-15 17:54:29 +01:00
|
|
|
CpuTarget = MpId &
|
|
|
|
(ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2 | ARM_CORE_AFF3);
|
|
|
|
|
|
|
|
if ((MmioRead32 (
|
|
|
|
mGicDistributorBase + ARM_GIC_ICDDCR
|
|
|
|
) & ARM_GIC_ICDDCR_DS) != 0) {
|
2015-02-16 11:23:42 +01:00
|
|
|
|
2016-06-22 16:23:57 +02:00
|
|
|
// If the Disable Security (DS) control bit is set, we are dealing with a
|
|
|
|
// GIC that has only one security state. In this case, let's assume we are
|
|
|
|
// executing in non-secure state (which is appropriate for DXE modules)
|
|
|
|
// and that no other firmware has performed any configuration on the GIC.
|
|
|
|
// This means we need to reconfigure all interrupts to non-secure Group 1
|
|
|
|
// first.
|
2017-02-15 17:54:29 +01:00
|
|
|
|
|
|
|
MmioWrite32 (
|
|
|
|
mGicRedistributorsBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDISR,
|
|
|
|
0xffffffff
|
|
|
|
);
|
2016-06-22 16:23:57 +02:00
|
|
|
|
|
|
|
for (Index = 32; Index < mGicNumInterrupts; Index += 32) {
|
2017-02-15 17:54:29 +01:00
|
|
|
MmioWrite32 (
|
|
|
|
mGicDistributorBase + ARM_GIC_ICDISR + Index / 8,
|
|
|
|
0xffffffff
|
|
|
|
);
|
2016-06-22 16:23:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-25 19:42:36 +01:00
|
|
|
// Route the SPIs to the primary CPU. SPIs start at the INTID 32
|
|
|
|
for (Index = 0; Index < (mGicNumInterrupts - 32); Index++) {
|
2019-02-22 20:43:28 +01:00
|
|
|
MmioWrite64 (
|
2017-02-15 17:54:29 +01:00
|
|
|
mGicDistributorBase + ARM_GICD_IROUTER + (Index * 8),
|
ArmPkg/ArmGicDxe: Fix GICv3 interrupt routing mode bug
Setting GICD_IROUTERn.IRM and GICD_IROUTERn.{Aff3,Aff2,Aff1,Aff0}
at the same time is nonsensical (see 8.9.13 in the GICv3 spec, which
says of GICD_IROUTERn.IRM that "When this bit is set to 1,
GICD_IROUTER<n>.{Aff3,Aff2,Aff1,Aff0} are UNKNOWN"). There is also no
guarantee that IRM is implemented (see GICD_TYPER.No1N which indicates
whether the implementation supports this or not).
Let's thus not set this bit, as we want all SPIs to be delivered to the
same CPU, and not be broadcast to all of them.
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ming Huang <ming.huang@linaro.org>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
2018-10-29 05:57:08 +01:00
|
|
|
CpuTarget
|
2017-02-15 17:54:29 +01:00
|
|
|
);
|
2015-02-25 19:42:36 +01:00
|
|
|
}
|
2014-10-27 11:30:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set binary point reg to 0x7 (no preemption)
|
|
|
|
ArmGicV3SetBinaryPointer (0x7);
|
|
|
|
|
|
|
|
// Set priority mask reg to 0xff to allow all priorities through
|
|
|
|
ArmGicV3SetPriorityMask (0xff);
|
|
|
|
|
|
|
|
// Enable gic cpu interface
|
|
|
|
ArmGicV3EnableInterruptInterface ();
|
|
|
|
|
|
|
|
// Enable gic distributor
|
|
|
|
ArmGicEnableDistributor (mGicDistributorBase);
|
|
|
|
|
|
|
|
Status = InstallAndRegisterInterruptService (
|
2017-02-15 17:54:29 +01:00
|
|
|
&gHardwareInterruptV3Protocol,
|
2016-09-01 18:21:56 +02:00
|
|
|
&gHardwareInterrupt2V3Protocol,
|
2017-02-15 17:54:29 +01:00
|
|
|
GicV3IrqInterruptHandler,
|
|
|
|
GicV3ExitBootServicesEvent
|
|
|
|
);
|
2014-10-27 11:30:53 +01:00
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|