GIC: Allow specifying interrupt properties
authorJeenu Viswambharan <jeenu.viswambharan@arm.com>
Fri, 22 Sep 2017 07:32:09 +0000 (08:32 +0100)
committerJeenu Viswambharan <jeenu.viswambharan@arm.com>
Mon, 16 Oct 2017 15:50:02 +0000 (16:50 +0100)
The GIC driver initialization currently allows an array of interrupts to
be configured as secure. Future use cases would require more interrupt
configuration other than just security, such as priority.

This patch introduces a new interrupt property array as part of both
GICv2 and GICv3 driver data. The platform can populate the array with
interrupt numbers and respective properties. The corresponding driver
initialization iterates through the array, and applies interrupt
configuration as required.

This capability, and the current way of supplying array (or arrays, in
case of GICv3) of secure interrupts, are however mutually exclusive.
Henceforth, the platform should supply either:

  - A list of interrupts to be mapped as secure (the current way).
    Platforms that do this will continue working as they were. With this
    patch, this scheme is deprecated.

  - A list of interrupt properties (properties include interrupt group).
    Individual interrupt properties are specified via. descriptors of
    type 'interrupt_prop_desc_t', which can be populated with the macro
    INTR_PROP_DESC().

A run time assert checks that the platform doesn't specify both.

Henceforth the old scheme of providing list of secure interrupts is
deprecated. When built with ERROR_DEPRECATED=1, GIC drivers will require
that the interrupt properties are supplied instead of an array of secure
interrupts.

Add a section to firmware design about configuring secure interrupts.

Fixes ARM-software/tf-issues#262

Change-Id: I8eec29e72eb69dbb6bce77879febf32c95376942
Signed-off-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
12 files changed:
docs/firmware-design.rst
drivers/arm/gic/v2/gicv2_helpers.c
drivers/arm/gic/v2/gicv2_main.c
drivers/arm/gic/v2/gicv2_private.h
drivers/arm/gic/v3/gicv3_helpers.c
drivers/arm/gic/v3/gicv3_main.c
drivers/arm/gic/v3/gicv3_private.h
include/bl31/interrupt_mgmt.h
include/common/interrupt_props.h [new file with mode: 0644]
include/drivers/arm/gic_common.h
include/drivers/arm/gicv2.h
include/drivers/arm/gicv3.h

index 997d29b879d6df78d97514e7847e028bcb965ac1..aeb883ab7a255485bc67f9731a2214ba248dd98b 100644 (file)
@@ -1161,6 +1161,56 @@ In other words, the reset handler should be able to detect whether an action has
 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
 ---------------------------------
 
index 26930769b16cbd70f85b4e1d89e0fb776555005f..0df50fb008d897eddb83aa488ffa731b625dd80f 100644 (file)
@@ -9,6 +9,7 @@
 #include <assert.h>
 #include <debug.h>
 #include <gic_common.h>
+#include <interrupt_props.h>
 #include "../common/gic_common_private.h"
 #include "gicv2_private.h"
 
@@ -112,6 +113,7 @@ void gicv2_spis_configure_defaults(uintptr_t gicd_base)
                gicd_write_icfgr(gicd_base, index, 0);
 }
 
+#if !ERROR_DEPRECATED
 /*******************************************************************************
  * Helper function to configure secure G0 SPIs.
  ******************************************************************************/
@@ -145,7 +147,49 @@ void gicv2_secure_spis_configure(uintptr_t gicd_base,
        }
 
 }
+#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.
  ******************************************************************************/
@@ -193,3 +237,66 @@ void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,
        /* 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);
+}
index 59b6632329c9f6007f6f889d39783f3761ed0b8c..25296a63e4e66501b70837b395e1846ce897ace3 100644 (file)
@@ -10,6 +10,7 @@
 #include <debug.h>
 #include <gic_common.h>
 #include <gicv2.h>
+#include <interrupt_props.h>
 #include <spinlock.h>
 #include "../common/gic_common_private.h"
 #include "gicv2_private.h"
@@ -73,11 +74,21 @@ void gicv2_pcpu_distif_init(void)
 {
        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 @@ void gicv2_distif_init(void)
 
        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 @@ void gicv2_distif_init(void)
        /* 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 @@ void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data)
        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 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);
+#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);
+
+               /* 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);
index 70f05976868d90c546ad01bf6621ad298e007bd0..25600deba37d930aadcdd6a2a414b5d6fd9f13df 100644 (file)
  * 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);
 
 /*******************************************************************************
index 33dbe2c8ea8a981255fa99e1bdbd5c5f892d12cd..2522695682517452fee5ab94db761b78586f99a2 100644 (file)
@@ -9,6 +9,7 @@
 #include <assert.h>
 #include <debug.h>
 #include <gic_common.h>
+#include <interrupt_props.h>
 #include "../common/gic_common_private.h"
 #include "gicv3_private.h"
 
@@ -364,6 +365,7 @@ void gicv3_spis_configure_defaults(uintptr_t gicd_base)
                gicd_write_icfgr(gicd_base, index, 0);
 }
 
+#if !ERROR_DEPRECATED
 /*******************************************************************************
  * Helper function to configure secure G0 and G1S SPIs.
  ******************************************************************************/
@@ -410,6 +412,63 @@ void gicv3_secure_spis_configure(uintptr_t gicd_base,
        }
 
 }
+#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 @@ void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base)
        gicr_write_icfgr1(gicr_base, 0);
 }
 
+#if !ERROR_DEPRECATED
 /*******************************************************************************
  * Helper function to configure secure G0 and G1S SPIs.
  ******************************************************************************/
@@ -476,3 +536,54 @@ void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base,
                }
        }
 }
+#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);
+       }
+}
index 0f50f6d763257b85b21685b249d06590dbd5c11d..8c4f508472ab6c63f1d92bdae3f06a7299af29ee 100644 (file)
@@ -9,6 +9,7 @@
 #include <assert.h>
 #include <debug.h>
 #include <gicv3.h>
+#include <interrupt_props.h>
 #include <spinlock.h>
 #include "gicv3_private.h"
 
@@ -66,23 +67,33 @@ void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
 
        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 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);
+#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);
+
+               /*
+                * 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 @@ void gicv3_distif_init(void)
 
        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 @@ void gicv3_distif_init(void)
        /* 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 @@ void gicv3_rdistif_init(unsigned int proc_num)
        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 @@ void gicv3_rdistif_init(unsigned int proc_num)
        /* 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
 }
 
 /*******************************************************************************
index 43529c5a539a858287c1853f42c0c1ae1b9e8219..a5093d0c747e7c7bbc2c561564907abab485c801 100644 (file)
@@ -85,6 +85,7 @@ void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri);
  ******************************************************************************/
 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 @@ void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base,
                                        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,
index 4f5a6013a4cec9f54eddd893d7626b0d20a98af8..cccad3add1c4132814b2315ff797290e1bd180f4 100644 (file)
@@ -98,6 +98,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <stdint.h>
+
 /* 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 (file)
index 0000000..9786b40
--- /dev/null
@@ -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__ */
index f7fc8ceb64cd02e4288279cfec440e53ef7869e9..9e126a854b41e1c3630f0c8bb06b5d43b518fd40 100644 (file)
 /* 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
index 9b8510aabeee91c73c7a16b704a845e3948ed2ab..6e8322e1b864876e73c76fa0d5c6f50c620a9aa5 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+#include <interrupt_props.h>
 #include <stdint.h>
 
 /*******************************************************************************
  * 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;
 
 /*******************************************************************************
index 95b6e3bb9bd6946087a864d5ac63b971d5b64883..b2e4d4c5e91885b4d5dcf1b8c8bff0084225fccf 100644 (file)
@@ -7,8 +7,6 @@
 #ifndef __GICV3_H__
 #define __GICV3_H__
 
-#include "utils_def.h"
-
 /*******************************************************************************
  * GICv3 miscellaneous definitions
  ******************************************************************************/
 #ifndef __ASSEMBLY__
 
 #include <gic_common.h>
+#include <interrupt_props.h>
 #include <stdint.h>
 #include <types.h>
 #include <utils_def.h>
  * 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.
+ *
+ * The 'gicr_base' field contains the base address of the Re-distributor
+ * 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. This field is ignored when
+ * 'interrupt_props' field is used. This field is deprecated.
  *
- * 2. The 'gicr_base' field contains the base address of the Re-distributor
- *    interface programmer's view.
+ * 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.
  *
- * 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 '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.
  *
- * 4. The 'g0_interrupt_num' field contains the number of entries in the
- *    'g0_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.
  *
- * 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 '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.
  *
- * 6. The 'g1s_interrupt_num' field contains the number of entries in the
- *    'g1s_interrupt_array'.
+ * 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.
  *
- * 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 '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.
  *
- * 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 '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.
  *
- * 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 '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;