diff --git a/docs/platform-interrupt-controller-API.rst b/docs/platform-interrupt-controller-API.rst index a94a90c75..d0a2ad276 100644 --- a/docs/platform-interrupt-controller-API.rst +++ b/docs/platform-interrupt-controller-API.rst @@ -66,6 +66,21 @@ as a Software Generated Interrupt. Software Generated Interrupts are raised by explicit programming by software, and are typically used in inter-PE communication. Secure SGIs are reserved for use by Secure world software. +Function: unsigned int plat_ic_get_interrupt_active(unsigned int id); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : int + +This API should return the *active* status of the interrupt ID specified by the +first parameter, ``id``. + +In case of ARM standard platforms using GIC, the implementation of the API reads +the GIC *Set Active Register* to read and return the active status of the +interrupt. + ---- *Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.* diff --git a/drivers/arm/gic/common/gic_common.c b/drivers/arm/gic/common/gic_common.c index 6535813f9..71155a970 100644 --- a/drivers/arm/gic/common/gic_common.c +++ b/drivers/arm/gic/common/gic_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -273,6 +273,14 @@ void gicd_set_icpendr(uintptr_t base, unsigned int id) gicd_write_icpendr(base, id, (1 << bit_num)); } +unsigned int gicd_get_isactiver(uintptr_t base, unsigned int id) +{ + unsigned int bit_num = id & ((1 << ISACTIVER_SHIFT) - 1); + unsigned int reg_val = gicd_read_isactiver(base, id); + + return (reg_val >> bit_num) & 0x1; +} + void gicd_set_isactiver(uintptr_t base, unsigned int id) { unsigned bit_num = id & ((1 << ISACTIVER_SHIFT) - 1); diff --git a/drivers/arm/gic/common/gic_common_private.h b/drivers/arm/gic/common/gic_common_private.h index 2077cc464..8b96b37bb 100644 --- a/drivers/arm/gic/common/gic_common_private.h +++ b/drivers/arm/gic/common/gic_common_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -73,6 +73,7 @@ void gicd_set_isenabler(uintptr_t base, unsigned int id); void gicd_set_icenabler(uintptr_t base, unsigned int id); void gicd_set_ispendr(uintptr_t base, unsigned int id); void gicd_set_icpendr(uintptr_t base, unsigned int id); +unsigned int gicd_get_isactiver(uintptr_t base, unsigned int id); void gicd_set_isactiver(uintptr_t base, unsigned int id); void gicd_set_icactiver(uintptr_t base, unsigned int id); void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri); diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c index 28266807c..e33353a88 100644 --- a/drivers/arm/gic/v2/gicv2_main.c +++ b/drivers/arm/gic/v2/gicv2_main.c @@ -275,3 +275,16 @@ void gicv2_set_pe_target_mask(unsigned int proc_num) driver_data->target_masks[proc_num] = gicv2_get_cpuif_id(driver_data->gicd_base); } + +/******************************************************************************* + * This function returns the active status of the interrupt (either because the + * state is active, or active and pending). + ******************************************************************************/ +unsigned int gicv2_get_interrupt_active(unsigned int id) +{ + assert(driver_data); + assert(driver_data->gicd_base); + assert(id <= MAX_SPI_ID); + + return gicd_get_isactiver(driver_data->gicd_base, id); +} diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c index 73ad060f6..81d50ad45 100644 --- a/drivers/arm/gic/v3/gicv3_helpers.c +++ b/drivers/arm/gic/v3/gicv3_helpers.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -171,6 +171,18 @@ void gicr_set_isenabler0(uintptr_t base, unsigned int id) gicr_write_isenabler0(base, (1 << bit_num)); } +/* + * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor + * ISACTIVER0. + */ +unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ISACTIVER_SHIFT) - 1); + unsigned int reg_val = gicr_read_isactiver0(base); + + return (reg_val >> bit_num) & 0x1; +} + /* * Accessor to set the byte corresponding to interrupt ID * in GIC Re-distributor IPRIORITYR. diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index 7e7574306..08cf0957d 100644 --- a/drivers/arm/gic/v3/gicv3_main.c +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -778,3 +778,30 @@ unsigned int gicv3_get_running_priority(void) { return read_icc_rpr_el1(); } + +/******************************************************************************* + * This function checks if the interrupt identified by id is active (whether the + * state is either active, or active and pending). The proc_num is used if the + * interrupt is SGI or PPI and programs the corresponding Redistributor + * interface. + ******************************************************************************/ +unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num) +{ + unsigned int value; + + assert(gicv3_driver_data); + assert(gicv3_driver_data->gicd_base); + assert(proc_num < gicv3_driver_data->rdistif_num); + assert(gicv3_driver_data->rdistif_base_addrs); + assert(id <= MAX_SPI_ID); + + if (id < MIN_SPI_ID) { + /* For SGIs and PPIs */ + value = gicr_get_isactiver0( + gicv3_driver_data->rdistif_base_addrs[proc_num], id); + } else { + value = gicd_get_isactiver(gicv3_driver_data->gicd_base, id); + } + + return value; +} diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h index 59298edf2..bb8ad9ae8 100644 --- a/drivers/arm/gic/v3/gicv3_private.h +++ b/drivers/arm/gic/v3/gicv3_private.h @@ -67,6 +67,7 @@ void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val); unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id); unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id); unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id); +unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id); void gicd_set_igrpmodr(uintptr_t base, unsigned int id); void gicr_set_igrpmodr0(uintptr_t base, unsigned int id); void gicr_set_isenabler0(uintptr_t base, unsigned int id); diff --git a/include/drivers/arm/gicv2.h b/include/drivers/arm/gicv2.h index c91cc1b04..2b4612637 100644 --- a/include/drivers/arm/gicv2.h +++ b/include/drivers/arm/gicv2.h @@ -147,6 +147,7 @@ void gicv2_end_of_interrupt(unsigned int id); unsigned int gicv2_get_interrupt_group(unsigned int id); unsigned int gicv2_get_running_priority(void); void gicv2_set_pe_target_mask(unsigned int proc_num); +unsigned int gicv2_get_interrupt_active(unsigned int id); #endif /* __ASSEMBLY__ */ #endif /* __GICV2_H__ */ diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h index 4548a87c8..ec272ea7c 100644 --- a/include/drivers/arm/gicv3.h +++ b/include/drivers/arm/gicv3.h @@ -350,6 +350,7 @@ void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx); unsigned int gicv3_get_running_priority(void); +unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num); #endif /* __ASSEMBLY__ */ #endif /* __GICV3_H__ */ diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h index f00db0db2..e4fb6a9f9 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -76,6 +76,7 @@ unsigned int plat_ic_get_running_priority(void); int plat_ic_is_spi(unsigned int id); int plat_ic_is_ppi(unsigned int id); int plat_ic_is_sgi(unsigned int id); +unsigned int plat_ic_get_interrupt_active(unsigned int id); /******************************************************************************* * Optional common functions (may be overridden) diff --git a/plat/common/plat_gicv2.c b/plat/common/plat_gicv2.c index 7d91f7922..5a92b66b9 100644 --- a/plat/common/plat_gicv2.c +++ b/plat/common/plat_gicv2.c @@ -24,6 +24,7 @@ #pragma weak plat_ic_is_spi #pragma weak plat_ic_is_ppi #pragma weak plat_ic_is_sgi +#pragma weak plat_ic_get_interrupt_active /* * This function returns the highest priority pending interrupt at @@ -147,3 +148,8 @@ int plat_ic_is_sgi(unsigned int id) { return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID); } + +unsigned int plat_ic_get_interrupt_active(unsigned int id) +{ + return gicv2_get_interrupt_active(id); +} diff --git a/plat/common/plat_gicv3.c b/plat/common/plat_gicv3.c index 5a6021c4a..abb3f1d16 100644 --- a/plat/common/plat_gicv3.c +++ b/plat/common/plat_gicv3.c @@ -30,6 +30,7 @@ #pragma weak plat_ic_is_spi #pragma weak plat_ic_is_ppi #pragma weak plat_ic_is_sgi +#pragma weak plat_ic_get_interrupt_active CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) && (INTR_TYPE_NS == INTR_GROUP1NS) && @@ -180,6 +181,11 @@ int plat_ic_is_sgi(unsigned int id) { return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID); } + +unsigned int plat_ic_get_interrupt_active(unsigned int id) +{ + return gicv3_get_interrupt_active(id, plat_my_core_pos()); +} #endif #ifdef IMAGE_BL32