Commit fc529fee authored by Jeenu Viswambharan's avatar Jeenu Viswambharan
Browse files

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: default avatarYousuf A <yousuf.sait@arm.com>
Signed-off-by: default avatarJeenu Viswambharan <jeenu.viswambharan@arm.com>
parent 8db978b5
...@@ -217,6 +217,32 @@ In case of ARM standard platforms using GIC, the implementation of the API ...@@ -217,6 +217,32 @@ In case of ARM standard platforms using GIC, the implementation of the API
inserts barrier to make memory updates visible before raising SGI, then writes inserts barrier to make memory updates visible before raising SGI, then writes
to appropriate *SGI Register* in order to raise the EL3 SGI. to appropriate *SGI Register* in order to raise the EL3 SGI.
Function: void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode, u_register_t mpidr); [optional]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
Argument : unsigned int
Argument : unsigned int
Argument : u_register_t
Return : void
This API should set the routing mode of Share Peripheral Interrupt (SPI)
specified by first parameter ``id`` to that specified by the second parameter
``routing_mode``.
The ``routing_mode`` parameter can be one of:
- ``INTR_ROUTING_MODE_ANY`` means the interrupt can be routed to any PE in the
system. The ``mpidr`` parameter is ignored in this case.
- ``INTR_ROUTING_MODE_PE`` means the interrupt is routed to the PE whose MPIDR
value is specified by the parameter ``mpidr``.
In case of ARM standard platforms using GIC, the implementation of the API
writes to the GIC *Target Register* (GICv2) or *Route Register* (GICv3) to set
the routing.
---- ----
*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.* *Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
/* /*
* 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 * SPDX-License-Identifier: BSD-3-Clause
*/ */
...@@ -72,15 +72,6 @@ void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val) ...@@ -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); 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 * Get the current CPU bit mask from GICD_ITARGETSR0
******************************************************************************/ ******************************************************************************/
......
...@@ -403,3 +403,38 @@ void gicv2_raise_sgi(int sgi_num, int proc_num) ...@@ -403,3 +403,38 @@ void gicv2_raise_sgi(int sgi_num, int proc_num)
dsbishst(); dsbishst();
gicd_write_sgir(driver_data->gicd_base, sgir_val); 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);
}
...@@ -34,6 +34,17 @@ static inline unsigned int gicd_read_pidr2(uintptr_t base) ...@@ -34,6 +34,17 @@ static inline unsigned int gicd_read_pidr2(uintptr_t base)
/******************************************************************************* /*******************************************************************************
* GIC Distributor interface accessors for writing entire registers * 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) static inline void gicd_write_sgir(uintptr_t base, unsigned int val)
{ {
mmio_write_32(base + GICD_SGIR, val); mmio_write_32(base + GICD_SGIR, val);
......
...@@ -999,3 +999,41 @@ void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target) ...@@ -999,3 +999,41 @@ void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target)
write_icc_sgi0r_el1(sgi_val); write_icc_sgi0r_el1(sgi_val);
isb(); 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();
}
}
}
/* /*
* Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
* *
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
...@@ -17,6 +17,11 @@ ...@@ -17,6 +17,11 @@
#define INTR_TYPE_NS U(2) #define INTR_TYPE_NS U(2)
#define MAX_INTR_TYPES U(3) #define MAX_INTR_TYPES U(3)
#define INTR_TYPE_INVAL MAX_INTR_TYPES #define INTR_TYPE_INVAL MAX_INTR_TYPES
/* Interrupt routing modes */
#define INTR_ROUTING_MODE_PE 0
#define INTR_ROUTING_MODE_ANY 1
/* /*
* Constant passed to the interrupt handler in the 'id' field when the * Constant passed to the interrupt handler in the 'id' field when the
* framework does not read the gic registers to determine the interrupt id. * framework does not read the gic registers to determine the interrupt id.
......
...@@ -74,6 +74,7 @@ ...@@ -74,6 +74,7 @@
#define ISACTIVER_SHIFT 5 #define ISACTIVER_SHIFT 5
#define ICACTIVER_SHIFT ISACTIVER_SHIFT #define ICACTIVER_SHIFT ISACTIVER_SHIFT
#define IPRIORITYR_SHIFT 2 #define IPRIORITYR_SHIFT 2
#define ITARGETSR_SHIFT 2
#define ICFGR_SHIFT 4 #define ICFGR_SHIFT 4
#define NSACR_SHIFT 4 #define NSACR_SHIFT 4
......
...@@ -171,6 +171,7 @@ void gicv2_disable_interrupt(unsigned int id); ...@@ -171,6 +171,7 @@ void gicv2_disable_interrupt(unsigned int id);
void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority); void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority);
void gicv2_set_interrupt_type(unsigned int id, unsigned int type); void gicv2_set_interrupt_type(unsigned int id, unsigned int type);
void gicv2_raise_sgi(int sgi_num, int proc_num); void gicv2_raise_sgi(int sgi_num, int proc_num);
void gicv2_set_spi_routing(unsigned int id, int proc_num);
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* __GICV2_H__ */ #endif /* __GICV2_H__ */
...@@ -75,6 +75,9 @@ ...@@ -75,6 +75,9 @@
#define IROUTER_IRM_SHIFT 31 #define IROUTER_IRM_SHIFT 31
#define IROUTER_IRM_MASK 0x1 #define IROUTER_IRM_MASK 0x1
#define GICV3_IRM_PE 0
#define GICV3_IRM_ANY 1
#define NUM_OF_DIST_REGS 30 #define NUM_OF_DIST_REGS 30
/******************************************************************************* /*******************************************************************************
...@@ -382,6 +385,8 @@ void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num, ...@@ -382,6 +385,8 @@ void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num, void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
unsigned int group); unsigned int group);
void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target); void gicv3_raise_secure_g0_sgi(int sgi_num, u_register_t target);
void gicv3_set_spi_routing(unsigned int id, unsigned int irm,
u_register_t mpidr);
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* __GICV3_H__ */ #endif /* __GICV3_H__ */
...@@ -83,6 +83,8 @@ int plat_ic_has_interrupt_type(unsigned int type); ...@@ -83,6 +83,8 @@ int plat_ic_has_interrupt_type(unsigned int type);
void plat_ic_set_interrupt_type(unsigned int id, unsigned int type); void plat_ic_set_interrupt_type(unsigned int id, unsigned int type);
void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority); void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority);
void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target); void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target);
void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
u_register_t mpidr);
/******************************************************************************* /*******************************************************************************
* Optional common functions (may be overridden) * Optional common functions (may be overridden)
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#pragma weak plat_ic_set_interrupt_priority #pragma weak plat_ic_set_interrupt_priority
#pragma weak plat_ic_set_interrupt_type #pragma weak plat_ic_set_interrupt_type
#pragma weak plat_ic_raise_el3_sgi #pragma weak plat_ic_raise_el3_sgi
#pragma weak plat_ic_set_spi_routing
/* /*
* This function returns the highest priority pending interrupt at * This function returns the highest priority pending interrupt at
...@@ -240,3 +241,24 @@ void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target) ...@@ -240,3 +241,24 @@ void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
assert(0); assert(0);
#endif #endif
} }
void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
u_register_t mpidr)
{
int proc_num = 0;
switch (routing_mode) {
case INTR_ROUTING_MODE_PE:
proc_num = plat_core_pos_by_mpidr(mpidr);
assert(proc_num >= 0);
break;
case INTR_ROUTING_MODE_ANY:
/* Bit mask selecting all 8 CPUs as candidates */
proc_num = -1;
break;
default:
assert(0);
}
gicv2_set_spi_routing(id, proc_num);
}
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#pragma weak plat_ic_set_interrupt_priority #pragma weak plat_ic_set_interrupt_priority
#pragma weak plat_ic_set_interrupt_type #pragma weak plat_ic_set_interrupt_type
#pragma weak plat_ic_raise_el3_sgi #pragma weak plat_ic_raise_el3_sgi
#pragma weak plat_ic_set_spi_routing
CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) && CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) &&
(INTR_TYPE_NS == INTR_GROUP1NS) && (INTR_TYPE_NS == INTR_GROUP1NS) &&
...@@ -229,6 +230,26 @@ void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target) ...@@ -229,6 +230,26 @@ void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
gicv3_raise_secure_g0_sgi(sgi_num, target); gicv3_raise_secure_g0_sgi(sgi_num, target);
} }
void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
u_register_t mpidr)
{
unsigned int irm = 0;
switch (routing_mode) {
case INTR_ROUTING_MODE_PE:
assert(plat_core_pos_by_mpidr(mpidr) >= 0);
irm = GICV3_IRM_PE;
break;
case INTR_ROUTING_MODE_ANY:
irm = GICV3_IRM_ANY;
break;
default:
assert(0);
}
gicv3_set_spi_routing(id, irm, mpidr);
}
#endif #endif
#ifdef IMAGE_BL32 #ifdef IMAGE_BL32
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment