summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonio Nino Diaz <antonio.ninodiaz@arm.com>2017-01-26 17:45:15 +0000
committerSandrine Bailleux <sandrine.bailleux@arm.com>2017-02-07 16:45:34 +0000
commit285ff6cc8d01e24940b654c1c67dc38c5ab931b5 (patch)
tree8392ab1970d5215cd80f4d5a8c3ad9edeac381c1
parent6e975fe64714457dd70ec4faf482010a5d69e0d2 (diff)
Allow IRQ handler to handle spurious IRQs
Modify the IRQ handler so that tests can specify a spurious IRQ handler. This type of interrupt is only generated by GICv2 implementations when the config registers are set up in certain ways, so this patch also adds new helper functions to access said registers. Change-Id: I81b21651046d2b8c4c069f27aec61a2969441730 Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
-rw-r--r--drivers/arm/gic/gic_v2.c21
-rw-r--r--include/drivers/arm/gic_v2.h10
-rw-r--r--include/lib/irq.h3
-rw-r--r--lib/irq/irq.c27
4 files changed, 55 insertions, 6 deletions
diff --git a/drivers/arm/gic/gic_v2.c b/drivers/arm/gic/gic_v2.c
index 6612f62..4225ac9 100644
--- a/drivers/arm/gic/gic_v2.c
+++ b/drivers/arm/gic/gic_v2.c
@@ -96,6 +96,12 @@ void gicd_write_itargetsr(unsigned int base,
mmio_write_32(base + GICD_ITARGETSR + (n << 2), val);
}
+void gicd_write_itargetsr_byte(unsigned int base,
+ unsigned int interrupt_id, unsigned int val)
+{
+ mmio_write_8(base + GICD_ITARGETSR + interrupt_id, val);
+}
+
void gicd_write_cpendsgir(unsigned int base,
unsigned int interrupt_id, unsigned int val)
{
@@ -276,6 +282,14 @@ void gicv2_set_itargetsr(unsigned int num, unsigned int core_pos)
gicd_set_itargetsr(gicd_base_addr, num, gic_cpu_id);
}
+void gicv2_set_itargetsr_value(unsigned int num, unsigned int val)
+{
+ assert(gicd_base_addr);
+ assert(IS_SPI(num));
+
+ gicd_write_itargetsr_byte(gicd_base_addr, num, val);
+}
+
void gicv2_gicd_set_isenabler(unsigned int num)
{
assert(gicd_base_addr);
@@ -312,6 +326,13 @@ unsigned int gicv2_gicd_get_ispendr(unsigned int interrupt_id)
return !!(ispendr & (1 << bit_pos));
}
+void gicv2_gicd_set_ispendr(unsigned int interrupt_id)
+{
+ assert(gicd_base_addr);
+ assert(IS_PPI(interrupt_id) || IS_SPI(interrupt_id));
+ gicd_set_ispendr(gicd_base_addr, interrupt_id);
+}
+
void gicv2_gicd_set_icpendr(unsigned int interrupt_id)
{
assert(gicd_base_addr);
diff --git a/include/drivers/arm/gic_v2.h b/include/drivers/arm/gic_v2.h
index 2959a99..5752703 100644
--- a/include/drivers/arm/gic_v2.h
+++ b/include/drivers/arm/gic_v2.h
@@ -246,6 +246,11 @@ void gicv2_init(uintptr_t gicc_base, uintptr_t gicd_base);
void gicv2_gicc_write_eoir(unsigned int val);
/*
+ * Set the bit corresponding to `interrupt_id` in the GICD ISPENDR register.
+ */
+void gicv2_gicd_set_ispendr(unsigned int interrupt_id);
+
+/*
* Set the bit corresponding to `interrupt_id` in the GICD ICPENDR register.
*/
void gicv2_gicd_set_icpendr(unsigned int interrupt_id);
@@ -276,6 +281,11 @@ void gicv2_gicd_set_isenabler(unsigned int num);
void gicv2_set_itargetsr(unsigned int num, unsigned int core_pos);
/*
+ * Set the target of interrupt ID `num` to the desired core mask.
+ */
+void gicv2_set_itargetsr_value(unsigned int num, unsigned int val);
+
+/*
* Send SGI with ID `sgi_id` to core with index `core_pos`.
*/
void gicv2_send_sgi(unsigned int sgi_id, unsigned int core_pos);
diff --git a/include/lib/irq.h b/include/lib/irq.h
index 2939ec8..60d4fa4 100644
--- a/include/lib/irq.h
+++ b/include/lib/irq.h
@@ -50,6 +50,9 @@ typedef struct {
irq_handler_t handler;
} spi_desc;
+/* Keep track of the IRQ handler registered for a spurious interrupt */
+typedef irq_handler_t spurious_desc;
+
/*
* PPIs and SGIs are interrupts that are private to a GIC CPU interface. These
* interrupts are banked in the GIC Distributor. Therefore, each CPU can
diff --git a/lib/irq/irq.c b/lib/irq/irq.c
index e966ffc..ea47399 100644
--- a/lib/irq/irq.c
+++ b/lib/irq/irq.c
@@ -50,6 +50,7 @@
static spi_desc spi_desc_table[PLAT_MAX_SPI_OFFSET_ID];
static ppi_desc ppi_desc_table[PLATFORM_CORE_COUNT][MAX_PPI_ID + 1];
static sgi_desc sgi_desc_table[PLATFORM_CORE_COUNT][MAX_SGI_ID + 1];
+static spurious_desc spurious_desc_handler;
/*
* For a given SPI, the associated IRQ handler is common to all CPUs.
@@ -124,9 +125,15 @@ static int tftf_irq_update_handler(unsigned int irq_num,
if (IS_PPI(irq_num)) {
cur_handler = &ppi_desc_table[linear_id][irq_num].handler;
- } else /* SGI */ {
- assert(IS_SGI(irq_num));
+ } else if (IS_SGI(irq_num)) {
cur_handler = &sgi_desc_table[linear_id][irq_num].handler;
+ } else {
+ /*
+ * The only possibility is for it to be a spurious
+ * interrupt.
+ */
+ assert(irq_num == GIC_SPURIOUS_INTERRUPT);
+ cur_handler = &spurious_desc_handler;
}
}
@@ -194,19 +201,26 @@ int tftf_irq_handler_dispatcher(void)
if (IS_PPI(irq_num)) {
handler = &ppi_desc_table[linear_id][irq_num].handler;
irq_data = &irq_num;
- } else /* SGI */ {
- assert(IS_SGI(irq_num));
+ } else if (IS_SGI(irq_num)) {
handler = &sgi_desc_table[linear_id][irq_num].handler;
-
sgi_data.irq_id = irq_num;
irq_data = &sgi_data;
+ } else {
+ /*
+ * The only possibility is for it to be a spurious
+ * interrupt.
+ */
+ assert(irq_num == GIC_SPURIOUS_INTERRUPT);
+ handler = &spurious_desc_handler;
}
}
+
if (*handler != NULL)
rc = (*handler)(irq_data);
/* Mark the processing of the interrupt as complete */
- arm_gic_end_of_intr(raw_iar);
+ if (irq_num != GIC_SPURIOUS_INTERRUPT)
+ arm_gic_end_of_intr(raw_iar);
return rc;
}
@@ -216,5 +230,6 @@ void tftf_irq_setup(void)
memset(spi_desc_table, 0, sizeof(spi_desc_table));
memset(ppi_desc_table, 0, sizeof(ppi_desc_table));
memset(sgi_desc_table, 0, sizeof(sgi_desc_table));
+ memset(&spurious_desc_handler, 0, sizeof(spurious_desc_handler));
init_spinlock(&spi_lock);
}