From 979225f4eed00d631bb57ebd09068edd91b8df7b Mon Sep 17 00:00:00 2001 From: Jeenu Viswambharan Date: Fri, 22 Sep 2017 08:32:09 +0100 Subject: [PATCH] GIC: Add APIs to enable and disable interrupt API documentation updated. Change-Id: Ice7511f8df5356851001d2f7dc2a46cfe318f9ba Co-authored-by: Yousuf A Signed-off-by: Jeenu Viswambharan --- docs/platform-interrupt-controller-API.rst | 30 ++++++++++ drivers/arm/gic/v2/gicv2_main.c | 34 ++++++++++++ drivers/arm/gic/v3/gicv3_helpers.c | 11 ++++ drivers/arm/gic/v3/gicv3_main.c | 64 ++++++++++++++++++++++ drivers/arm/gic/v3/gicv3_private.h | 1 + include/drivers/arm/gicv2.h | 2 + include/drivers/arm/gicv3.h | 2 + include/plat/common/platform.h | 2 + plat/common/plat_gicv2.c | 12 ++++ plat/common/plat_gicv3.c | 12 ++++ 10 files changed, 170 insertions(+) diff --git a/docs/platform-interrupt-controller-API.rst b/docs/platform-interrupt-controller-API.rst index d0a2ad276..bea1a64b5 100644 --- a/docs/platform-interrupt-controller-API.rst +++ b/docs/platform-interrupt-controller-API.rst @@ -81,6 +81,36 @@ 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. +Function: void plat_ic_enable_interrupt(unsigned int id); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : void + +This API should enable the interrupt ID specified by the first parameter, +``id``. PEs in the system are expected to receive only enabled interrupts. + +In case of ARM standard platforms using GIC, the implementation of the API +inserts barrier to make memory updates visible before enabling interrupt, and +then writes to GIC *Set Enable Register* to enable the interrupt. + +Function: void plat_ic_disable_interrupt(unsigned int id); [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : unsigned int + Return : void + +This API should disable the interrupt ID specified by the first parameter, +``id``. PEs in the system are not expected to receive disabled interrupts. + +In case of ARM standard platforms using GIC, the implementation of the API +writes to GIC *Clear Enable Register* to disable the interrupt, and inserts +barrier to make memory updates visible afterwards. + ---- *Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.* diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c index e33353a88..e0058ad13 100644 --- a/drivers/arm/gic/v2/gicv2_main.c +++ b/drivers/arm/gic/v2/gicv2_main.c @@ -288,3 +288,37 @@ unsigned int gicv2_get_interrupt_active(unsigned int id) return gicd_get_isactiver(driver_data->gicd_base, id); } + +/******************************************************************************* + * This function enables the interrupt identified by id. + ******************************************************************************/ +void gicv2_enable_interrupt(unsigned int id) +{ + assert(driver_data); + assert(driver_data->gicd_base); + assert(id <= MAX_SPI_ID); + + /* + * Ensure that any shared variable updates depending on out of band + * interrupt trigger are observed before enabling interrupt. + */ + dsbishst(); + gicd_set_isenabler(driver_data->gicd_base, id); +} + +/******************************************************************************* + * This function disables the interrupt identified by id. + ******************************************************************************/ +void gicv2_disable_interrupt(unsigned int id) +{ + assert(driver_data); + assert(driver_data->gicd_base); + assert(id <= MAX_SPI_ID); + + /* + * Disable interrupt, and ensure that any shared variable updates + * depending on out of band interrupt trigger are observed afterwards. + */ + gicd_set_icenabler(driver_data->gicd_base, id); + dsbishst(); +} diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c index 81d50ad45..ee874f92f 100644 --- a/drivers/arm/gic/v3/gicv3_helpers.c +++ b/drivers/arm/gic/v3/gicv3_helpers.c @@ -171,6 +171,17 @@ 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 + * ICENABLER0. + */ +void gicr_set_icenabler0(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ICENABLER_SHIFT) - 1); + + gicr_write_icenabler0(base, (1 << bit_num)); +} + /* * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor * ISACTIVER0. diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index 08cf0957d..b3231993e 100644 --- a/drivers/arm/gic/v3/gicv3_main.c +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -805,3 +805,67 @@ unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num) return value; } + +/******************************************************************************* + * This function enables the interrupt identified by id. The proc_num + * is used if the interrupt is SGI or PPI, and programs the corresponding + * Redistributor interface. + ******************************************************************************/ +void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num) +{ + 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); + + /* + * Ensure that any shared variable updates depending on out of band + * interrupt trigger are observed before enabling interrupt. + */ + dsbishst(); + if (id < MIN_SPI_ID) { + /* For SGIs and PPIs */ + gicr_set_isenabler0( + gicv3_driver_data->rdistif_base_addrs[proc_num], + id); + } else { + gicd_set_isenabler(gicv3_driver_data->gicd_base, id); + } +} + +/******************************************************************************* + * This function disables the interrupt identified by id. The proc_num + * is used if the interrupt is SGI or PPI, and programs the corresponding + * Redistributor interface. + ******************************************************************************/ +void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num) +{ + 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); + + /* + * Disable interrupt, and ensure that any shared variable updates + * depending on out of band interrupt trigger are observed afterwards. + */ + if (id < MIN_SPI_ID) { + /* For SGIs and PPIs */ + gicr_set_icenabler0( + gicv3_driver_data->rdistif_base_addrs[proc_num], + id); + + /* Write to clear enable requires waiting for pending writes */ + gicr_wait_for_pending_write( + gicv3_driver_data->rdistif_base_addrs[proc_num]); + } else { + gicd_set_icenabler(gicv3_driver_data->gicd_base, id); + + /* Write to clear enable requires waiting for pending writes */ + gicd_wait_for_pending_write(gicv3_driver_data->gicd_base); + } + + dsbishst(); +} diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h index bb8ad9ae8..19fce2e73 100644 --- a/drivers/arm/gic/v3/gicv3_private.h +++ b/drivers/arm/gic/v3/gicv3_private.h @@ -71,6 +71,7 @@ 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); +void gicr_set_icenabler0(uintptr_t base, unsigned int id); void gicr_set_igroupr0(uintptr_t base, unsigned int id); void gicd_clr_igrpmodr(uintptr_t base, unsigned int id); void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id); diff --git a/include/drivers/arm/gicv2.h b/include/drivers/arm/gicv2.h index 2b4612637..0af1a25e2 100644 --- a/include/drivers/arm/gicv2.h +++ b/include/drivers/arm/gicv2.h @@ -148,6 +148,8 @@ 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); +void gicv2_enable_interrupt(unsigned int id); +void gicv2_disable_interrupt(unsigned int id); #endif /* __ASSEMBLY__ */ #endif /* __GICV2_H__ */ diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h index ec272ea7c..6e6a47b97 100644 --- a/include/drivers/arm/gicv3.h +++ b/include/drivers/arm/gicv3.h @@ -351,6 +351,8 @@ void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ct unsigned int gicv3_get_running_priority(void); unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num); +void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num); +void gicv3_disable_interrupt(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 e4fb6a9f9..671aa61e8 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -77,6 +77,8 @@ 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); +void plat_ic_disable_interrupt(unsigned int id); +void plat_ic_enable_interrupt(unsigned int id); /******************************************************************************* * Optional common functions (may be overridden) diff --git a/plat/common/plat_gicv2.c b/plat/common/plat_gicv2.c index 5a92b66b9..2591805de 100644 --- a/plat/common/plat_gicv2.c +++ b/plat/common/plat_gicv2.c @@ -25,6 +25,8 @@ #pragma weak plat_ic_is_ppi #pragma weak plat_ic_is_sgi #pragma weak plat_ic_get_interrupt_active +#pragma weak plat_ic_enable_interrupt +#pragma weak plat_ic_disable_interrupt /* * This function returns the highest priority pending interrupt at @@ -153,3 +155,13 @@ unsigned int plat_ic_get_interrupt_active(unsigned int id) { return gicv2_get_interrupt_active(id); } + +void plat_ic_enable_interrupt(unsigned int id) +{ + gicv2_enable_interrupt(id); +} + +void plat_ic_disable_interrupt(unsigned int id) +{ + gicv2_disable_interrupt(id); +} diff --git a/plat/common/plat_gicv3.c b/plat/common/plat_gicv3.c index abb3f1d16..2a1f0f5c5 100644 --- a/plat/common/plat_gicv3.c +++ b/plat/common/plat_gicv3.c @@ -31,6 +31,8 @@ #pragma weak plat_ic_is_ppi #pragma weak plat_ic_is_sgi #pragma weak plat_ic_get_interrupt_active +#pragma weak plat_ic_enable_interrupt +#pragma weak plat_ic_disable_interrupt CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) && (INTR_TYPE_NS == INTR_GROUP1NS) && @@ -186,6 +188,16 @@ unsigned int plat_ic_get_interrupt_active(unsigned int id) { return gicv3_get_interrupt_active(id, plat_my_core_pos()); } + +void plat_ic_enable_interrupt(unsigned int id) +{ + gicv3_enable_interrupt(id, plat_my_core_pos()); +} + +void plat_ic_disable_interrupt(unsigned int id) +{ + gicv3_disable_interrupt(id, plat_my_core_pos()); +} #endif #ifdef IMAGE_BL32