diff --git a/docs/firmware-design.rst b/docs/firmware-design.rst index 997d29b..aeb883a 100644 --- a/docs/firmware-design.rst +++ b/docs/firmware-design.rst @@ -1161,6 +1161,56 @@ already been performed and act as appropriate. Possible courses of actions are, e.g. skip the action the second time, or undo/redo it. +Configuring secure interrupts +----------------------------- + +The GIC driver is responsible for performing initial configuration of secure +interrupts on the platform. To this end, the platform is expected to provide the +GIC driver (either GICv2 or GICv3, as selected by the platform) with the +interrupt configuration during the driver initialisation. + +There are two ways to specify secure interrupt configuration: + +#. Array of secure interrupt properties: In this scheme, in both GICv2 and GICv3 + driver data structures, the ``interrupt_props`` member points to an array of + interrupt properties. Each element of the array specifies the interrupt + number and its configuration, viz. priority, group, configuration. Each + element of the array shall be populated by the macro ``INTR_PROP_DESC()``. + The macro takes the following arguments: + + - 10-bit interrupt number, + + - 8-bit interrupt priority, + + - Interrupt type (one of ``INTR_TYPE_EL3``, ``INTR_TYPE_S_EL1``, + ``INTR_TYPE_NS``), + + - Interrupt configuration (either ``GIC_INTR_CFG_LEVEL`` or + ``GIC_INTR_CFG_EDGE``). + +#. Array of secure interrupts: In this scheme, the GIC driver is provided an + array of secure interrupt numbers. The GIC driver, at the time of + initialisation, iterates through the array and assigns each interrupt + the appropriate group. + + - For the GICv2 driver, in ``gicv2_driver_data`` structure, the + ``g0_interrupt_array`` member of the should point to the array of + interrupts to be assigned to *Group 0*, and the ``g0_interrupt_num`` + member of the should be set to the number of interrupts in the array. + + - For the GICv3 driver, in ``gicv3_driver_data`` structure: + + - The ``g0_interrupt_array`` member of the should point to the array of + interrupts to be assigned to *Group 0*, and the ``g0_interrupt_num`` + member of the should be set to the number of interrupts in the array. + + - The ``g1s_interrupt_array`` member of the should point to the array of + interrupts to be assigned to *Group 1 Secure*, and the + ``g1s_interrupt_num`` member of the should be set to the number of + interrupts in the array. + + **Note that this scheme is deprecated.** + CPU specific operations framework --------------------------------- diff --git a/drivers/arm/gic/v2/gicv2_helpers.c b/drivers/arm/gic/v2/gicv2_helpers.c index 2693076..0df50fb 100644 --- a/drivers/arm/gic/v2/gicv2_helpers.c +++ b/drivers/arm/gic/v2/gicv2_helpers.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "../common/gic_common_private.h" #include "gicv2_private.h" @@ -112,6 +113,7 @@ gicd_write_icfgr(gicd_base, index, 0); } +#if !ERROR_DEPRECATED /******************************************************************************* * Helper function to configure secure G0 SPIs. ******************************************************************************/ @@ -145,8 +147,50 @@ } } +#endif /******************************************************************************* + * Helper function to configure properties of secure G0 SPIs. + ******************************************************************************/ +void gicv2_secure_spis_configure_props(uintptr_t gicd_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num) +{ + unsigned int i; + const interrupt_prop_t *prop_desc; + + /* Make sure there's a valid property array */ + assert(interrupt_props_num != 0 ? (uintptr_t) interrupt_props : 1); + + for (i = 0; i < interrupt_props_num; i++) { + prop_desc = &interrupt_props[i]; + + if (prop_desc->intr_num < MIN_SPI_ID) + continue; + + /* Configure this interrupt as a secure interrupt */ + assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); + gicd_clr_igroupr(gicd_base, prop_desc->intr_num); + + /* Set the priority of this interrupt */ + gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, + prop_desc->intr_pri); + + /* Target the secure interrupts to primary CPU */ + gicd_set_itargetsr(gicd_base, prop_desc->intr_num, + gicv2_get_cpuif_id(gicd_base)); + + /* Set interrupt configuration */ + gicd_set_icfgr(gicd_base, prop_desc->intr_num, + prop_desc->intr_cfg); + + /* Enable this interrupt */ + gicd_set_isenabler(gicd_base, prop_desc->intr_num); + } +} + +#if !ERROR_DEPRECATED +/******************************************************************************* * Helper function to configure secure G0 SGIs and PPIs. ******************************************************************************/ void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base, @@ -193,3 +237,66 @@ /* Enable the Group 0 SGIs and PPIs */ gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); } +#endif + +/******************************************************************************* + * Helper function to configure properties of secure G0 SGIs and PPIs. + ******************************************************************************/ +void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num) +{ + unsigned int i; + uint32_t sec_ppi_sgi_mask = 0; + const interrupt_prop_t *prop_desc; + + /* Make sure there's a valid property array */ + assert(interrupt_props_num != 0 ? (uintptr_t) interrupt_props : 1); + + /* + * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a + * more scalable approach as it avoids clearing the enable bits in the + * GICD_CTLR. + */ + gicd_write_icenabler(gicd_base, 0, ~0); + + /* Setup the default PPI/SGI priorities doing four at a time */ + for (i = 0; i < MIN_SPI_ID; i += 4) + gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL); + + for (i = 0; i < interrupt_props_num; i++) { + prop_desc = &interrupt_props[i]; + + if (prop_desc->intr_num >= MIN_SPI_ID) + continue; + + /* Configure this interrupt as a secure interrupt */ + assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); + + /* + * Set interrupt configuration for PPIs. Configuration for SGIs + * are ignored. + */ + if ((prop_desc->intr_num >= MIN_PPI_ID) && + (prop_desc->intr_num < MIN_SPI_ID)) { + gicd_set_icfgr(gicd_base, prop_desc->intr_num, + prop_desc->intr_cfg); + } + + /* We have an SGI or a PPI. They are Group0 at reset */ + sec_ppi_sgi_mask |= (1u << prop_desc->intr_num); + + /* Set the priority of this interrupt */ + gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, + prop_desc->intr_pri); + } + + /* + * Invert the bitmask to create a mask for non-secure PPIs and SGIs. + * Program the GICD_IGROUPR0 with this bit mask. + */ + gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); + + /* Enable the Group 0 SGIs and PPIs */ + gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); +} diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c index 59b6632..25296a6 100644 --- a/drivers/arm/gic/v2/gicv2_main.c +++ b/drivers/arm/gic/v2/gicv2_main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "../common/gic_common_private.h" #include "gicv2_private.h" @@ -73,11 +74,21 @@ { assert(driver_data); assert(driver_data->gicd_base); - assert(driver_data->g0_interrupt_array); - gicv2_secure_ppi_sgi_setup(driver_data->gicd_base, - driver_data->g0_interrupt_num, - driver_data->g0_interrupt_array); +#if !ERROR_DEPRECATED + if (driver_data->interrupt_props != NULL) { +#endif + gicv2_secure_ppi_sgi_setup_props(driver_data->gicd_base, + driver_data->interrupt_props, + driver_data->interrupt_props_num); +#if !ERROR_DEPRECATED + } else { + assert(driver_data->g0_interrupt_array); + gicv2_secure_ppi_sgi_setup(driver_data->gicd_base, + driver_data->g0_interrupt_num, + driver_data->g0_interrupt_array); + } +#endif } /******************************************************************************* @@ -91,7 +102,6 @@ assert(driver_data); assert(driver_data->gicd_base); - assert(driver_data->g0_interrupt_array); /* Disable the distributor before going further */ ctlr = gicd_read_ctlr(driver_data->gicd_base); @@ -101,10 +111,22 @@ /* Set the default attribute of all SPIs */ gicv2_spis_configure_defaults(driver_data->gicd_base); - /* Configure the G0 SPIs */ - gicv2_secure_spis_configure(driver_data->gicd_base, - driver_data->g0_interrupt_num, - driver_data->g0_interrupt_array); +#if !ERROR_DEPRECATED + if (driver_data->interrupt_props != NULL) { +#endif + gicv2_secure_spis_configure_props(driver_data->gicd_base, + driver_data->interrupt_props, + driver_data->interrupt_props_num); +#if !ERROR_DEPRECATED + } else { + assert(driver_data->g0_interrupt_array); + + /* Configure the G0 SPIs */ + gicv2_secure_spis_configure(driver_data->gicd_base, + driver_data->g0_interrupt_num, + driver_data->g0_interrupt_array); + } +#endif /* Re-enable the secure SPIs now that they have been configured */ gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT); @@ -120,19 +142,26 @@ assert(plat_driver_data->gicd_base); assert(plat_driver_data->gicc_base); - /* - * The platform should provide a list of atleast one type of - * interrupts - */ - assert(plat_driver_data->g0_interrupt_array); +#if !ERROR_DEPRECATED + if (plat_driver_data->interrupt_props == NULL) { + /* Interrupt properties array size must be 0 */ + assert(plat_driver_data->interrupt_props_num == 0); - /* - * If there are no interrupts of a particular type, then the number of - * interrupts of that type should be 0 and vice-versa. - */ - assert(plat_driver_data->g0_interrupt_array ? - plat_driver_data->g0_interrupt_num : - plat_driver_data->g0_interrupt_num == 0); + /* The platform should provide a list of secure interrupts */ + assert(plat_driver_data->g0_interrupt_array); + + /* + * If there are no interrupts of a particular type, then the + * number of interrupts of that type should be 0 and vice-versa. + */ + assert(plat_driver_data->g0_interrupt_array ? + plat_driver_data->g0_interrupt_num : + plat_driver_data->g0_interrupt_num == 0); + } +#else + assert(plat_driver_data->interrupt_props != NULL); + assert(plat_driver_data->interrupt_props_num > 0); +#endif /* Ensure that this is a GICv2 system */ gic_version = gicd_read_pidr2(plat_driver_data->gicd_base); diff --git a/drivers/arm/gic/v2/gicv2_private.h b/drivers/arm/gic/v2/gicv2_private.h index 70f0597..25600de 100644 --- a/drivers/arm/gic/v2/gicv2_private.h +++ b/drivers/arm/gic/v2/gicv2_private.h @@ -15,12 +15,20 @@ * Private function prototypes ******************************************************************************/ void gicv2_spis_configure_defaults(uintptr_t gicd_base); +#if !ERROR_DEPRECATED void gicv2_secure_spis_configure(uintptr_t gicd_base, unsigned int num_ints, const unsigned int *sec_intr_list); void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base, unsigned int num_ints, const unsigned int *sec_intr_list); +#endif +void gicv2_secure_spis_configure_props(uintptr_t gicd_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num); +void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num); unsigned int gicv2_get_cpuif_id(uintptr_t base); /******************************************************************************* diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c index 33dbe2c..2522695 100644 --- a/drivers/arm/gic/v3/gicv3_helpers.c +++ b/drivers/arm/gic/v3/gicv3_helpers.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "../common/gic_common_private.h" #include "gicv3_private.h" @@ -364,6 +365,7 @@ gicd_write_icfgr(gicd_base, index, 0); } +#if !ERROR_DEPRECATED /******************************************************************************* * Helper function to configure secure G0 and G1S SPIs. ******************************************************************************/ @@ -410,6 +412,63 @@ } } +#endif + +/******************************************************************************* + * Helper function to configure properties of secure SPIs + ******************************************************************************/ +unsigned int gicv3_secure_spis_configure_props(uintptr_t gicd_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num) +{ + unsigned int i; + const interrupt_prop_t *current_prop; + unsigned long long gic_affinity_val; + unsigned int ctlr_enable = 0; + + /* Make sure there's a valid property array */ + assert(interrupt_props != NULL); + assert(interrupt_props_num > 0); + + for (i = 0; i < interrupt_props_num; i++) { + current_prop = &interrupt_props[i]; + + if (current_prop->intr_num < MIN_SPI_ID) + continue; + + /* Configure this interrupt as a secure interrupt */ + gicd_clr_igroupr(gicd_base, current_prop->intr_num); + + /* Configure this interrupt as G0 or a G1S interrupt */ + assert((current_prop->intr_grp == INTR_GROUP0) || + (current_prop->intr_grp == INTR_GROUP1S)); + if (current_prop->intr_grp == INTR_GROUP1S) { + gicd_set_igrpmodr(gicd_base, current_prop->intr_num); + ctlr_enable |= CTLR_ENABLE_G1S_BIT; + } else { + gicd_clr_igrpmodr(gicd_base, current_prop->intr_num); + ctlr_enable |= CTLR_ENABLE_G0_BIT; + } + + /* Set interrupt configuration */ + gicd_set_icfgr(gicd_base, current_prop->intr_num, + current_prop->intr_cfg); + + /* Set the priority of this interrupt */ + gicd_set_ipriorityr(gicd_base, current_prop->intr_num, + current_prop->intr_pri); + + /* Target SPIs to the primary CPU */ + gic_affinity_val = gicd_irouter_val_from_mpidr(read_mpidr(), 0); + gicd_write_irouter(gicd_base, current_prop->intr_num, + gic_affinity_val); + + /* Enable this interrupt */ + gicd_set_isenabler(gicd_base, current_prop->intr_num); + } + + return ctlr_enable; +} /******************************************************************************* * Helper function to configure the default attributes of SPIs. @@ -439,6 +498,7 @@ gicr_write_icfgr1(gicr_base, 0); } +#if !ERROR_DEPRECATED /******************************************************************************* * Helper function to configure secure G0 and G1S SPIs. ******************************************************************************/ @@ -476,3 +536,54 @@ } } } +#endif + +/******************************************************************************* + * Helper function to configure properties of secure G0 and G1S PPIs and SGIs. + ******************************************************************************/ +void gicv3_secure_ppi_sgi_configure_props(uintptr_t gicr_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num) +{ + unsigned int i; + const interrupt_prop_t *current_prop; + + /* Make sure there's a valid property array */ + assert(interrupt_props != NULL); + assert(interrupt_props_num > 0); + + for (i = 0; i < interrupt_props_num; i++) { + current_prop = &interrupt_props[i]; + + if (current_prop->intr_num >= MIN_SPI_ID) + continue; + + /* Configure this interrupt as a secure interrupt */ + gicr_clr_igroupr0(gicr_base, current_prop->intr_num); + + /* Configure this interrupt as G0 or a G1S interrupt */ + assert((current_prop->intr_grp == INTR_GROUP0) || + (current_prop->intr_grp == INTR_GROUP1S)); + if (current_prop->intr_grp == INTR_GROUP1S) + gicr_set_igrpmodr0(gicr_base, current_prop->intr_num); + else + gicr_clr_igrpmodr0(gicr_base, current_prop->intr_num); + + /* Set the priority of this interrupt */ + gicr_set_ipriorityr(gicr_base, current_prop->intr_num, + current_prop->intr_pri); + + /* + * Set interrupt configuration for PPIs. Configuration for SGIs + * are ignored. + */ + if ((current_prop->intr_num >= MIN_PPI_ID) && + (current_prop->intr_num < MIN_SPI_ID)) { + gicr_set_icfgr1(gicr_base, current_prop->intr_num, + current_prop->intr_cfg); + } + + /* Enable this interrupt */ + gicr_set_isenabler0(gicr_base, current_prop->intr_num); + } +} diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index 0f50f6d..8c4f508 100644 --- a/drivers/arm/gic/v3/gicv3_main.c +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "gicv3_private.h" @@ -66,23 +67,33 @@ assert(IS_IN_EL3()); - /* - * The platform should provide a list of at least one type of - * interrupts - */ - assert(plat_driver_data->g0_interrupt_array || - plat_driver_data->g1s_interrupt_array); +#if !ERROR_DEPRECATED + if (plat_driver_data->interrupt_props == NULL) { + /* Interrupt properties array size must be 0 */ + assert(plat_driver_data->interrupt_props_num == 0); - /* - * If there are no interrupts of a particular type, then the number of - * interrupts of that type should be 0 and vice-versa. - */ - assert(plat_driver_data->g0_interrupt_array ? - plat_driver_data->g0_interrupt_num : - plat_driver_data->g0_interrupt_num == 0); - assert(plat_driver_data->g1s_interrupt_array ? - plat_driver_data->g1s_interrupt_num : - plat_driver_data->g1s_interrupt_num == 0); + /* + * The platform should provide a list of at least one type of + * interrupt. + */ + assert(plat_driver_data->g0_interrupt_array || + plat_driver_data->g1s_interrupt_array); + + /* + * If there are no interrupts of a particular type, then the + * number of interrupts of that type should be 0 and vice-versa. + */ + assert(plat_driver_data->g0_interrupt_array ? + plat_driver_data->g0_interrupt_num : + plat_driver_data->g0_interrupt_num == 0); + assert(plat_driver_data->g1s_interrupt_array ? + plat_driver_data->g1s_interrupt_num : + plat_driver_data->g1s_interrupt_num == 0); + } +#else + assert(plat_driver_data->interrupt_props != NULL); + assert(plat_driver_data->interrupt_props_num > 0); +#endif /* Check for system register support */ #ifdef AARCH32 @@ -148,8 +159,6 @@ assert(gicv3_driver_data); assert(gicv3_driver_data->gicd_base); - assert(gicv3_driver_data->g1s_interrupt_array || - gicv3_driver_data->g0_interrupt_array); assert(IS_IN_EL3()); @@ -171,23 +180,37 @@ /* Set the default attribute of all SPIs */ gicv3_spis_configure_defaults(gicv3_driver_data->gicd_base); - /* Configure the G1S SPIs */ - if (gicv3_driver_data->g1s_interrupt_array) { - gicv3_secure_spis_configure(gicv3_driver_data->gicd_base, +#if !ERROR_DEPRECATED + if (gicv3_driver_data->interrupt_props != NULL) { +#endif + bitmap = gicv3_secure_spis_configure_props( + gicv3_driver_data->gicd_base, + gicv3_driver_data->interrupt_props, + gicv3_driver_data->interrupt_props_num); +#if !ERROR_DEPRECATED + } else { + assert(gicv3_driver_data->g1s_interrupt_array || + gicv3_driver_data->g0_interrupt_array); + + /* Configure the G1S SPIs */ + if (gicv3_driver_data->g1s_interrupt_array) { + gicv3_secure_spis_configure(gicv3_driver_data->gicd_base, gicv3_driver_data->g1s_interrupt_num, gicv3_driver_data->g1s_interrupt_array, INTR_GROUP1S); - bitmap |= CTLR_ENABLE_G1S_BIT; - } + bitmap |= CTLR_ENABLE_G1S_BIT; + } - /* Configure the G0 SPIs */ - if (gicv3_driver_data->g0_interrupt_array) { - gicv3_secure_spis_configure(gicv3_driver_data->gicd_base, + /* Configure the G0 SPIs */ + if (gicv3_driver_data->g0_interrupt_array) { + gicv3_secure_spis_configure(gicv3_driver_data->gicd_base, gicv3_driver_data->g0_interrupt_num, gicv3_driver_data->g0_interrupt_array, INTR_GROUP0); - bitmap |= CTLR_ENABLE_G0_BIT; + bitmap |= CTLR_ENABLE_G0_BIT; + } } +#endif /* Enable the secure SPIs now that they have been configured */ gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE); @@ -207,8 +230,6 @@ assert(gicv3_driver_data->rdistif_base_addrs); assert(gicv3_driver_data->gicd_base); assert(gicd_read_ctlr(gicv3_driver_data->gicd_base) & CTLR_ARE_S_BIT); - assert(gicv3_driver_data->g1s_interrupt_array || - gicv3_driver_data->g0_interrupt_array); assert(IS_IN_EL3()); @@ -220,21 +241,34 @@ /* Set the default attribute of all SGIs and PPIs */ gicv3_ppi_sgi_configure_defaults(gicr_base); - /* Configure the G1S SGIs/PPIs */ - if (gicv3_driver_data->g1s_interrupt_array) { - gicv3_secure_ppi_sgi_configure(gicr_base, +#if !ERROR_DEPRECATED + if (gicv3_driver_data->interrupt_props != NULL) { +#endif + gicv3_secure_ppi_sgi_configure_props(gicr_base, + gicv3_driver_data->interrupt_props, + gicv3_driver_data->interrupt_props_num); +#if !ERROR_DEPRECATED + } else { + assert(gicv3_driver_data->g1s_interrupt_array || + gicv3_driver_data->g0_interrupt_array); + + /* Configure the G1S SGIs/PPIs */ + if (gicv3_driver_data->g1s_interrupt_array) { + gicv3_secure_ppi_sgi_configure(gicr_base, gicv3_driver_data->g1s_interrupt_num, gicv3_driver_data->g1s_interrupt_array, INTR_GROUP1S); - } + } - /* Configure the G0 SGIs/PPIs */ - if (gicv3_driver_data->g0_interrupt_array) { - gicv3_secure_ppi_sgi_configure(gicr_base, + /* Configure the G0 SGIs/PPIs */ + if (gicv3_driver_data->g0_interrupt_array) { + gicv3_secure_ppi_sgi_configure(gicr_base, gicv3_driver_data->g0_interrupt_num, gicv3_driver_data->g0_interrupt_array, INTR_GROUP0); + } } +#endif } /******************************************************************************* diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h index 43529c5..a5093d0 100644 --- a/drivers/arm/gic/v3/gicv3_private.h +++ b/drivers/arm/gic/v3/gicv3_private.h @@ -85,6 +85,7 @@ ******************************************************************************/ void gicv3_spis_configure_defaults(uintptr_t gicd_base); void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base); +#if !ERROR_DEPRECATED void gicv3_secure_spis_configure(uintptr_t gicd_base, unsigned int num_ints, const unsigned int *sec_intr_list, @@ -93,6 +94,13 @@ unsigned int num_ints, const unsigned int *sec_intr_list, unsigned int int_grp); +#endif +void gicv3_secure_ppi_sgi_configure_props(uintptr_t gicr_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num); +unsigned int gicv3_secure_spis_configure_props(uintptr_t gicd_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num); void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs, unsigned int rdistif_num, uintptr_t gicr_base, diff --git a/include/bl31/interrupt_mgmt.h b/include/bl31/interrupt_mgmt.h index 4f5a601..cccad3a 100644 --- a/include/bl31/interrupt_mgmt.h +++ b/include/bl31/interrupt_mgmt.h @@ -98,6 +98,8 @@ #ifndef __ASSEMBLY__ +#include + /* Prototype for defining a handler for an interrupt type */ typedef uint64_t (*interrupt_type_handler_t)(uint32_t id, uint32_t flags, diff --git a/include/common/interrupt_props.h b/include/common/interrupt_props.h new file mode 100644 index 0000000..9786b40 --- /dev/null +++ b/include/common/interrupt_props.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __INTERRUPT_PROPS_H__ +#define __INTERRUPT_PROPS_H__ + +#ifndef __ASSEMBLY__ + +/* Create an interrupt property descriptor from various interrupt properties */ +#define INTR_PROP_DESC(num, pri, grp, cfg) \ + { \ + .intr_num = num, \ + .intr_pri = pri, \ + .intr_grp = grp, \ + .intr_cfg = cfg, \ + } + +typedef struct interrupt_prop { + unsigned int intr_num:10; + unsigned int intr_pri:8; + unsigned int intr_grp:2; + unsigned int intr_cfg:2; +} interrupt_prop_t; + +#endif /* __ASSEMBLY__ */ +#endif /* __INTERRUPT_PROPS_H__ */ diff --git a/include/drivers/arm/gic_common.h b/include/drivers/arm/gic_common.h index f7fc8ce..9e126a8 100644 --- a/include/drivers/arm/gic_common.h +++ b/include/drivers/arm/gic_common.h @@ -29,6 +29,10 @@ /* Constant to indicate a spurious interrupt in all GIC versions */ #define GIC_SPURIOUS_INTERRUPT 1023 +/* Interrupt configurations */ +#define GIC_INTR_CFG_LEVEL 0 +#define GIC_INTR_CFG_EDGE 1 + /* Constants to categorise priorities */ #define GIC_HIGHEST_SEC_PRIORITY 0 #define GIC_LOWEST_SEC_PRIORITY 127 diff --git a/include/drivers/arm/gicv2.h b/include/drivers/arm/gicv2.h index 9b8510a..6e8322e 100644 --- a/include/drivers/arm/gicv2.h +++ b/include/drivers/arm/gicv2.h @@ -116,6 +116,7 @@ #ifndef __ASSEMBLY__ +#include #include /******************************************************************************* @@ -130,23 +131,37 @@ * 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. + * The 'g0_interrupt_array' field is a pointer to an array in which each entry + * corresponds to an ID of a Group 0 interrupt. This field is ignored when + * 'interrupt_props' field is used. This field is deprecated. * * The 'g0_interrupt_num' field contains the number of entries in the - * 'g0_interrupt_array'. + * 'g0_interrupt_array'. This field is ignored when 'interrupt_props' field is + * used. This field is deprecated. * * 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. + * + * The 'interrupt_props' field is a pointer to an array that enumerates secure + * interrupts and their properties. If this field is not NULL, both + * 'g0_interrupt_array' and 'g1s_interrupt_array' fields are ignored. + * + * The 'interrupt_props_num' field contains the number of entries in the + * 'interrupt_props' array. If this field is non-zero, 'g0_interrupt_num' is + * ignored. ******************************************************************************/ typedef struct gicv2_driver_data { uintptr_t gicd_base; uintptr_t gicc_base; +#if !ERROR_DEPRECATED unsigned int g0_interrupt_num; const unsigned int *g0_interrupt_array; +#endif unsigned int *target_masks; unsigned int target_masks_num; + const interrupt_prop_t *interrupt_props; + unsigned int interrupt_props_num; } gicv2_driver_data_t; /******************************************************************************* diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h index 95b6e3b..b2e4d4c 100644 --- a/include/drivers/arm/gicv3.h +++ b/include/drivers/arm/gicv3.h @@ -7,8 +7,6 @@ #ifndef __GICV3_H__ #define __GICV3_H__ -#include "utils_def.h" - /******************************************************************************* * GICv3 miscellaneous definitions ******************************************************************************/ @@ -212,6 +210,7 @@ #ifndef __ASSEMBLY__ #include +#include #include #include #include @@ -251,53 +250,70 @@ * GICv3 IP. It is used by the platform port to specify these attributes in order * to initialise the GICV3 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. * - * 2. The 'gicr_base' field contains the base address of the Re-distributor - * interface programmer's view. + * The 'gicr_base' field contains the base address of the Re-distributor + * interface programmer's view. * - * 3. The 'g0_interrupt_array' field is a ponter to an array in which each - * entry corresponds to an ID of a Group 0 interrupt. + * The 'g0_interrupt_array' field is a pointer to an array in which each entry + * corresponds to an ID of a Group 0 interrupt. This field is ignored when + * 'interrupt_props' field is used. This field is deprecated. * - * 4. The 'g0_interrupt_num' field contains the number of entries in the - * 'g0_interrupt_array'. + * The 'g0_interrupt_num' field contains the number of entries in the + * 'g0_interrupt_array'. This field is ignored when 'interrupt_props' field is + * used. This field is deprecated. * - * 5. The 'g1s_interrupt_array' field is a ponter to an array in which each - * entry corresponds to an ID of a Group 1 interrupt. + * The 'g1s_interrupt_array' field is a pointer to an array in which each entry + * corresponds to an ID of a Group 1 interrupt. This field is ignored when + * 'interrupt_props' field is used. This field is deprecated. * - * 6. The 'g1s_interrupt_num' field contains the number of entries in the - * 'g1s_interrupt_array'. + * The 'g1s_interrupt_num' field contains the number of entries in the + * 'g1s_interrupt_array'. This field must be 0 if 'interrupt_props' field is + * used. This field is ignored when 'interrupt_props' field is used. This field + * is deprecated. * - * 7. The 'rdistif_num' field contains the number of Redistributor interfaces - * the GIC implements. This is equal to the number of CPUs or CPU interfaces - * instantiated in the GIC. + * The 'interrupt_props' field is a pointer to an array that enumerates secure + * interrupts and their properties. If this field is not NULL, both + * 'g0_interrupt_array' and 'g1s_interrupt_array' fields are ignored. * - * 8. The 'rdistif_base_addrs' field is a pointer to an array that has an entry - * for storing the base address of the Redistributor interface frame of each - * CPU in the system. The size of the array = 'rdistif_num'. The base - * addresses are detected during driver initialisation. + * The 'interrupt_props_num' field contains the number of entries in the + * 'interrupt_props' array. If this field is non-zero, both 'g0_interrupt_num' + * and 'g1s_interrupt_num' are ignored. * - * 9. The 'mpidr_to_core_pos' field is a pointer to a hash function which the - * driver will use to convert an MPIDR value to a linear core index. This - * index will be used for accessing the 'rdistif_base_addrs' array. This is - * an optional field. A GICv3 implementation maps each MPIDR to a linear core - * index as well. This mapping can be found by reading the "Affinity Value" - * and "Processor Number" fields in the GICR_TYPER. It is IMP. DEF. if the - * "Processor Numbers" are suitable to index into an array to access core - * specific information. If this not the case, the platform port must provide - * a hash function. Otherwise, the "Processor Number" field will be used to - * access the array elements. + * The 'rdistif_num' field contains the number of Redistributor interfaces the + * GIC implements. This is equal to the number of CPUs or CPU interfaces + * instantiated in the GIC. + * + * The 'rdistif_base_addrs' field is a pointer to an array that has an entry for + * storing the base address of the Redistributor interface frame of each CPU in + * the system. The size of the array = 'rdistif_num'. The base addresses are + * detected during driver initialisation. + * + * The 'mpidr_to_core_pos' field is a pointer to a hash function which the + * driver will use to convert an MPIDR value to a linear core index. This index + * will be used for accessing the 'rdistif_base_addrs' array. This is an + * optional field. A GICv3 implementation maps each MPIDR to a linear core index + * as well. This mapping can be found by reading the "Affinity Value" and + * "Processor Number" fields in the GICR_TYPER. It is IMP. DEF. if the + * "Processor Numbers" are suitable to index into an array to access core + * specific information. If this not the case, the platform port must provide a + * hash function. Otherwise, the "Processor Number" field will be used to access + * the array elements. ******************************************************************************/ typedef unsigned int (*mpidr_hash_fn)(u_register_t mpidr); typedef struct gicv3_driver_data { uintptr_t gicd_base; uintptr_t gicr_base; +#if !ERROR_DEPRECATED unsigned int g0_interrupt_num; unsigned int g1s_interrupt_num; const unsigned int *g0_interrupt_array; const unsigned int *g1s_interrupt_array; +#endif + const interrupt_prop_t *interrupt_props; + unsigned int interrupt_props_num; unsigned int rdistif_num; uintptr_t *rdistif_base_addrs; mpidr_hash_fn mpidr_to_core_pos;