diff options
-rw-r--r-- | drivers/arm/gic/gic_v2.c | 21 | ||||
-rw-r--r-- | include/drivers/arm/gic_v2.h | 10 | ||||
-rw-r--r-- | include/lib/irq.h | 3 | ||||
-rw-r--r-- | lib/irq/irq.c | 27 |
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); } |