diff --git a/docs/platform-interrupt-controller-API.rst b/docs/platform-interrupt-controller-API.rst index 795c08562..c14f00530 100644 --- a/docs/platform-interrupt-controller-API.rst +++ b/docs/platform-interrupt-controller-API.rst @@ -292,6 +292,22 @@ inserts to order memory updates before updating mask, then writes to the GIC *Priority Mask Register*, and make sure memory updates are visible before potential trigger due to mask update. +Function: unsigned int plat_ic_get_interrupt_id(unsigned int raw); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : unsigned int + +This API should extract and return the interrupt number from the raw value +obtained by the acknowledging the interrupt (read using +``plat_ic_acknowledge_interrupt()``). If the interrupt ID is invalid, this API +should return ``INTR_ID_UNAVAILABLE``. + +In case of ARM standard platforms using GIC, the implementation of the API +masks out the interrupt ID field from the acknowledged value from GIC. + ---- *Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.* diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst index f0a8aaf30..af933fdbc 100644 --- a/docs/porting-guide.rst +++ b/docs/porting-guide.rst @@ -2479,14 +2479,17 @@ Function : plat\_ic\_acknowledge\_interrupt() [mandatory] Return : uint32_t This API is used by the CPU to indicate to the platform IC that processing of -the highest pending interrupt has begun. It should return the id of the -interrupt which is being processed. +the highest pending interrupt has begun. It should return the raw, unmodified +value obtained from the interrupt controller when acknowledging an interrupt. +The actual interrupt number shall be extracted from this raw value using the API +`plat_ic_get_interrupt_id()`__. + +.. __: platform-interrupt-controller-API.rst#function-unsigned-int-plat-ic-get-interrupt-id-unsigned-int-raw-optional This function in ARM standard platforms using GICv2, reads the *Interrupt Acknowledge Register* (``GICC_IAR``). This changes the state of the highest priority pending interrupt from pending to active in the interrupt controller. -It returns the value read from the ``GICC_IAR``. This value is the id of the -interrupt whose state has been changed. +It returns the value read from the ``GICC_IAR``, unmodified. In the case of ARM standard platforms using GICv3, if the API is invoked from EL3, the function reads the system register ``ICC_IAR0_EL1``, *Interrupt @@ -2494,7 +2497,7 @@ Acknowledge Register group 0*. If the API is invoked from S-EL1, the function reads the system register ``ICC_IAR1_EL1``, *Interrupt Acknowledge Register group 1*. The read changes the state of the highest pending interrupt from pending to active in the interrupt controller. The value read is returned -and is the id of the interrupt whose state has been changed. +unmodified. The TSP uses this API to start processing of the secure physical timer interrupt. diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h index b2e4d4c5e..f2a53712e 100644 --- a/include/drivers/arm/gicv3.h +++ b/include/drivers/arm/gicv3.h @@ -245,6 +245,9 @@ #define GICR_NUM_REGS(reg_name) \ DIV_ROUND_UP_2EVAL(TOTAL_PCPU_INTR_NUM, (1 << reg_name ## _SHIFT)) +/* Interrupt ID mask for HPPIR, AHPPIR, IAR and AIAR CPU Interface registers */ +#define INT_ID_MASK 0xffffff + /******************************************************************************* * This structure describes some of the implementation defined attributes of the * GICv3 IP. It is used by the platform port to specify these attributes in order diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h index 068d7aab2..086e5e6ae 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -90,6 +90,7 @@ void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode, void plat_ic_set_interrupt_pending(unsigned int id); void plat_ic_clear_interrupt_pending(unsigned int id); unsigned int plat_ic_set_priority_mask(unsigned int mask); +unsigned int plat_ic_get_interrupt_id(unsigned int raw); /******************************************************************************* * Optional common functions (may be overridden) diff --git a/plat/common/plat_gicv2.c b/plat/common/plat_gicv2.c index 05fabcab1..38e1a61e7 100644 --- a/plat/common/plat_gicv2.c +++ b/plat/common/plat_gicv2.c @@ -277,3 +277,13 @@ unsigned int plat_ic_set_priority_mask(unsigned int mask) { return gicv2_set_pmr(mask); } + +unsigned int plat_ic_get_interrupt_id(unsigned int raw) +{ + unsigned int id = (raw & INT_ID_MASK); + + if (id == GIC_SPURIOUS_INTERRUPT) + id = INTR_ID_UNAVAILABLE; + + return id; +} diff --git a/plat/common/plat_gicv3.c b/plat/common/plat_gicv3.c index 52ceb6a7c..030eea723 100644 --- a/plat/common/plat_gicv3.c +++ b/plat/common/plat_gicv3.c @@ -271,6 +271,14 @@ unsigned int plat_ic_set_priority_mask(unsigned int mask) { return gicv3_set_pmr(mask); } + +unsigned int plat_ic_get_interrupt_id(unsigned int raw) +{ + unsigned int id = (raw & INT_ID_MASK); + + return (gicv3_is_intr_id_special_identifier(id) ? + INTR_ID_UNAVAILABLE : id); +} #endif #ifdef IMAGE_BL32