From fc529fee720de5fef8388c52bfefcb807ac764b0 Mon Sep 17 00:00:00 2001 From: Jeenu Viswambharan Date: Fri, 22 Sep 2017 08:32:09 +0100 Subject: GIC: Add API to set interrupt routing SPIs can be routed to either a specific PE, or to any one of all available PEs. API documentation updated. Change-Id: I28675f634568aaf4ea1aa8aa7ebf25b419a963ed Co-authored-by: Yousuf A Signed-off-by: Jeenu Viswambharan --- drivers/arm/gic/v2/gicv2_helpers.c | 11 +---------- drivers/arm/gic/v2/gicv2_main.c | 35 +++++++++++++++++++++++++++++++++++ drivers/arm/gic/v2/gicv2_private.h | 11 +++++++++++ drivers/arm/gic/v3/gicv3_main.c | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/arm/gic/v2/gicv2_helpers.c b/drivers/arm/gic/v2/gicv2_helpers.c index 7cdbc27c..26930769 100644 --- a/drivers/arm/gic/v2/gicv2_helpers.c +++ b/drivers/arm/gic/v2/gicv2_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 */ @@ -72,15 +72,6 @@ void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val) mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val); } -/* - * Accessor to write the GIC Distributor ITARGETSR corresponding to the - * interrupt `id`. - */ -void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target) -{ - mmio_write_8(base + GICD_ITARGETSR + id, target & GIC_TARGET_CPU_MASK); -} - /******************************************************************************* * Get the current CPU bit mask from GICD_ITARGETSR0 ******************************************************************************/ diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c index b59e4586..f0b902cf 100644 --- a/drivers/arm/gic/v2/gicv2_main.c +++ b/drivers/arm/gic/v2/gicv2_main.c @@ -403,3 +403,38 @@ void gicv2_raise_sgi(int sgi_num, int proc_num) dsbishst(); gicd_write_sgir(driver_data->gicd_base, sgir_val); } + +/******************************************************************************* + * This function sets the interrupt routing for the given SPI interrupt id. + * The interrupt routing is specified in routing mode. The proc_num parameter is + * linear index of the PE to target SPI. When proc_num < 0, the SPI may target + * all PEs. + ******************************************************************************/ +void gicv2_set_spi_routing(unsigned int id, int proc_num) +{ + int target; + + assert(driver_data); + assert(driver_data->gicd_base); + + assert(id >= MIN_SPI_ID && id <= MAX_SPI_ID); + + /* + * Target masks array must have been supplied, and the core position + * should be valid. + */ + assert(driver_data->target_masks); + assert(proc_num < GICV2_MAX_TARGET_PE); + assert(proc_num < driver_data->target_masks_num); + + if (proc_num < 0) { + /* Target all PEs */ + target = GIC_TARGET_CPU_MASK; + } else { + /* Don't route interrupt if the mask hasn't been populated */ + target = driver_data->target_masks[proc_num]; + assert(target != 0); + } + + gicd_set_itargetsr(driver_data->gicd_base, id, target); +} diff --git a/drivers/arm/gic/v2/gicv2_private.h b/drivers/arm/gic/v2/gicv2_private.h index 915fc3a7..70f05976 100644 --- a/drivers/arm/gic/v2/gicv2_private.h +++ b/drivers/arm/gic/v2/gicv2_private.h @@ -34,6 +34,17 @@ static inline unsigned int gicd_read_pidr2(uintptr_t base) /******************************************************************************* * GIC Distributor interface accessors for writing entire registers ******************************************************************************/ +static inline unsigned int gicd_get_itargetsr(uintptr_t base, unsigned int id) +{ + return mmio_read_8(base + GICD_ITARGETSR + id); +} + +static inline void gicd_set_itargetsr(uintptr_t base, unsigned int id, + unsigned int target) +{ + mmio_write_8(base + GICD_ITARGETSR + id, target & GIC_TARGET_CPU_MASK); +} + static inline void gicd_write_sgir(uintptr_t base, unsigned int val) { mmio_write_32(base + GICD_SGIR, val); diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index a5067322..c81ba950 100644 --- a/drivers/arm/gic/v3/gicv3_main.c +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -999,3 +999,41 @@ void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target) write_icc_sgi0r_el1(sgi_val); isb(); } + +/******************************************************************************* + * This function sets the interrupt routing for the given SPI interrupt id. + * The interrupt routing is specified in routing mode and mpidr. + * + * The routing mode can be either of: + * - GICV3_IRM_ANY + * - GICV3_IRM_PE + * + * The mpidr is the affinity of the PE to which the interrupt will be routed, + * and is ignored for routing mode GICV3_IRM_ANY. + ******************************************************************************/ +void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr) +{ + unsigned long long aff; + uint64_t router; + + assert(gicv3_driver_data); + assert(gicv3_driver_data->gicd_base); + + assert((irm == GICV3_IRM_ANY) || (irm == GICV3_IRM_PE)); + assert(id >= MIN_SPI_ID && id <= MAX_SPI_ID); + + aff = gicd_irouter_val_from_mpidr(mpidr, irm); + gicd_write_irouter(gicv3_driver_data->gicd_base, id, aff); + + /* + * In implementations that do not require 1 of N distribution of SPIs, + * IRM might be RAZ/WI. Read back and verify IRM bit. + */ + if (irm == GICV3_IRM_ANY) { + router = gicd_read_irouter(gicv3_driver_data->gicd_base, id); + if (!((router >> IROUTER_IRM_SHIFT) & IROUTER_IRM_MASK)) { + ERROR("GICv3 implementation doesn't support routing ANY\n"); + panic(); + } + } +} -- cgit v1.2.3