From fa9db4230aef4411cc6c56557f0c407326421876 Mon Sep 17 00:00:00 2001 From: Jeenu Viswambharan Date: Fri, 22 Sep 2017 08:32:09 +0100 Subject: [PATCH] GICv2: Add driver API to set PE target mask The PE target mask is used to translate linear PE index (returned by platform core position) to a bit mask used when targeting interrupts to a PE, viz. when raising SGIs and routing SPIs. The platform shall: - Populate the driver data with a pointer to array that's to contain per-PE target masks. - Invoke the new driver API 'gicv2_set_pe_target_mask()' during per-CPU initialization so that the driver populates the target mask for that CPU. Platforms that don't intend to target interrupts or raise SGIs need not populate this. Change-Id: Ic0db54da86915e9dccd82fff51479bc3c1fdc968 Signed-off-by: Jeenu Viswambharan --- drivers/arm/gic/v2/gicv2_main.c | 23 +++++++++++++++++++++++ include/drivers/arm/gicv2.h | 26 ++++++++++++++++++-------- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c index 7759a551..28266807 100644 --- a/drivers/arm/gic/v2/gicv2_main.c +++ b/drivers/arm/gic/v2/gicv2_main.c @@ -252,3 +252,26 @@ unsigned int gicv2_get_running_priority(void) return gicc_read_rpr(driver_data->gicc_base); } + +/******************************************************************************* + * This function sets the GICv2 target mask pattern for the current PE. The PE + * target mask is used to translate linear PE index (returned by platform core + * position) to a bit mask used when targeting interrupts to a PE, viz. when + * raising SGIs and routing SPIs. + ******************************************************************************/ +void gicv2_set_pe_target_mask(unsigned int proc_num) +{ + assert(driver_data); + assert(driver_data->gicd_base); + assert(driver_data->target_masks); + assert(proc_num < GICV2_MAX_TARGET_PE); + assert(proc_num < driver_data->target_masks_num); + + /* Return if the target mask is already populated */ + if (driver_data->target_masks[proc_num]) + return; + + /* Read target register corresponding to this CPU */ + driver_data->target_masks[proc_num] = + gicv2_get_cpuif_id(driver_data->gicd_base); +} diff --git a/include/drivers/arm/gicv2.h b/include/drivers/arm/gicv2.h index 1ef0779b..c91cc1b0 100644 --- a/include/drivers/arm/gicv2.h +++ b/include/drivers/arm/gicv2.h @@ -13,6 +13,9 @@ /* Interrupt IDs reported by the HPPIR and IAR registers */ #define PENDING_G1_INTID 1022 +/* GICv2 can only target up to 8 PEs */ +#define GICV2_MAX_TARGET_PE 8 + /******************************************************************************* * GICv2 specific Distributor interface register offsets and constants. ******************************************************************************/ @@ -103,23 +106,29 @@ * in order to initialize the GICv2 driver. The attributes are described * below. * - * 1. The 'gicd_base' field contains the base address of the Distributor - * interface programmer's view. + * The 'gicd_base' field contains the base address of the Distributor interface + * programmer's view. + * + * The 'gicc_base' field contains the base address of the CPU Interface + * programmer's view. * - * 2. The 'gicc_base' field contains the base address of the CPU Interface - * programmer's view. + * The 'g0_interrupt_array' field is a pointer to an array in which each + * entry corresponds to an ID of a Group 0 interrupt. * - * 3. The 'g0_interrupt_array' field is a pointer to an array in which each - * entry corresponds to an ID of a Group 0 interrupt. + * The 'g0_interrupt_num' field contains the number of entries in the + * 'g0_interrupt_array'. * - * 4. The 'g0_interrupt_num' field contains the number of entries in the - * 'g0_interrupt_array'. + * The 'target_masks' is a pointer to an array containing 'target_masks_num' + * elements. The GIC driver will populate the array with per-PE target mask to + * use to when targeting interrupts. ******************************************************************************/ typedef struct gicv2_driver_data { uintptr_t gicd_base; uintptr_t gicc_base; unsigned int g0_interrupt_num; const unsigned int *g0_interrupt_array; + unsigned int *target_masks; + unsigned int target_masks_num; } gicv2_driver_data_t; /******************************************************************************* @@ -137,6 +146,7 @@ unsigned int gicv2_acknowledge_interrupt(void); 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); #endif /* __ASSEMBLY__ */ #endif /* __GICV2_H__ */ -- 2.30.2