summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);
}