summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/raspberrypi/irq
diff options
context:
space:
mode:
authorPavel Pisa <pisa@cmp.felk.cvut.cz>2016-07-23 12:10:34 +0200
committerPavel Pisa <pisa@cmp.felk.cvut.cz>2016-10-02 10:40:35 +0200
commit78627fe2825d19f810c60d4b2a42aea717712d7f (patch)
tree92abe21cda94b951a9ed025c796a6b002b0162bf /c/src/lib/libbsp/arm/raspberrypi/irq
parentarm/raspberrypi: remove duplicate setup of IRQ handler in the main ARM except... (diff)
downloadrtems-78627fe2825d19f810c60d4b2a42aea717712d7f.tar.bz2
arm/raspberrypi: change interrupt dispatch and enable to generic vector id based approach.
Using conditional branches to find bits is extremely inefficient and for asynchronous delivery of different interrupt sources lead to total confusion of branch prediction unit. Updates #2783
Diffstat (limited to 'c/src/lib/libbsp/arm/raspberrypi/irq')
-rw-r--r--c/src/lib/libbsp/arm/raspberrypi/irq/irq.c133
1 files changed, 90 insertions, 43 deletions
diff --git a/c/src/lib/libbsp/arm/raspberrypi/irq/irq.c b/c/src/lib/libbsp/arm/raspberrypi/irq/irq.c
index ce5b363f5d..e654d077c9 100644
--- a/c/src/lib/libbsp/arm/raspberrypi/irq/irq.c
+++ b/c/src/lib/libbsp/arm/raspberrypi/irq/irq.c
@@ -1,5 +1,5 @@
/**
- * @file
+ * @file irq.c
*
* @ingroup raspberrypi_interrupt
*
@@ -7,6 +7,8 @@
*/
/*
+ * Copyright (c) 2014 Andre Marques <andre.lousa.marques at gmail.com>
+ *
* Copyright (c) 2009
* embedded brains GmbH
* Obere Lagerstr. 30
@@ -27,78 +29,123 @@
#include <bsp/raspberrypi.h>
#include <bsp/linker-symbols.h>
#include <bsp/mmu.h>
+#include <rtems/bspIo.h>
+#include <strings.h>
+
+typedef struct {
+ unsigned long enable_reg_addr;
+ unsigned long disable_reg_addr;
+} bcm2835_irq_ctrl_reg_t;
+
+static const bcm2835_irq_ctrl_reg_t bcm2835_irq_ctrl_reg_table[] = {
+ { BCM2835_IRQ_ENABLE1, BCM2835_IRQ_DISABLE1 },
+ { BCM2835_IRQ_ENABLE2, BCM2835_IRQ_DISABLE2 },
+ { BCM2835_IRQ_ENABLE_BASIC, BCM2835_IRQ_DISABLE_BASIC }
+};
+
+static inline const bcm2835_irq_ctrl_reg_t *
+bsp_vector_to_reg(rtems_vector_number vector)
+{
+ return bcm2835_irq_ctrl_reg_table + (vector >> 5);
+}
+
+static inline uint32_t
+bsp_vector_to_mask(rtems_vector_number vector)
+{
+ return 1 << (vector & 0x1f);
+}
+
+static const int bcm2835_irq_speedup_table[] =
+{
+ /* 0 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 0,
+ /* 1 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 1,
+ /* 2 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 2,
+ /* 3 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 3,
+ /* 4 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 4,
+ /* 5 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 5,
+ /* 6 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 6,
+ /* 7 */ BCM2835_IRQ_ID_BASIC_BASE_ID + 7,
+ /* 8 */ -1, /* One or more bits set in pending register 1 */
+ /* 9 */ -2, /* One or more bits set in pending register 2 */
+ /* 10 */ 7, /* GPU IRQ 7 */
+ /* 11 */ 9, /* GPU IRQ 9 */
+ /* 12 */ 10, /* GPU IRQ 10 */
+ /* 13 */ 18, /* GPU IRQ 18 */
+ /* 14 */ 19, /* GPU IRQ 19 */
+ /* 15 */ 53, /* GPU IRQ 53 */
+ /* 16 */ 54, /* GPU IRQ 54 */
+ /* 17 */ 55, /* GPU IRQ 55 */
+ /* 18 */ 56, /* GPU IRQ 56 */
+ /* 19 */ 57, /* GPU IRQ 57 */
+ /* 20 */ 62, /* GPU IRQ 62 */
+};
/*
-** Determine the source of the interrupt and dispatch the correct handler.
-*/
+ * Define which basic peding register (BCM2835_IRQ_BASIC) bits
+ * should be processed through bcm2835_irq_speedup_table
+ */
+
+#define BCM2835_IRQ_BASIC_SPEEDUP_USED_BITS 0x1ffcff
+
+/*
+ * Determine the source of the interrupt and dispatch the correct handler.
+ */
void bsp_interrupt_dispatch(void)
{
- rtems_vector_number vector = 255;
+ unsigned int pend;
+ unsigned int pend_bit;
- /* ARM timer */
- if (BCM2835_REG(BCM2835_IRQ_BASIC) && 0x1)
- {
- vector = BCM2835_IRQ_ID_TIMER_0;
+ rtems_vector_number vector = 255;
- }
- /* UART 0 */
- else if ( BCM2835_REG(BCM2835_IRQ_BASIC) && BCM2835_BIT(19))
- {
- vector = BCM2835_IRQ_ID_UART;
+ pend = BCM2835_REG(BCM2835_IRQ_BASIC);
+ if ( pend & BCM2835_IRQ_BASIC_SPEEDUP_USED_BITS ) {
+ pend_bit = ffs(pend) - 1;
+ vector = bcm2835_irq_speedup_table[pend_bit];
+ } else {
+ pend = BCM2835_REG(BCM2835_IRQ_PENDING1);
+ if ( pend != 0 ) {
+ pend_bit = ffs(pend) - 1;
+ vector = pend_bit;
+ } else {
+ pend = BCM2835_REG(BCM2835_IRQ_PENDING2);
+ if ( pend != 0 ) {
+ pend_bit = ffs(pend) - 1;
+ vector = pend_bit + 32;
+ }
+ }
}
if ( vector < 255 )
{
bsp_interrupt_handler_dispatch(vector);
}
-
}
rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
{
- rtems_interrupt_level level;
-
- rtems_interrupt_disable(level);
+ if ( vector > BSP_INTERRUPT_VECTOR_MAX )
+ return RTEMS_INVALID_ID;
- /* ARM Timer */
- if ( vector == BCM2835_IRQ_ID_TIMER_0 )
- {
- BCM2835_REG(BCM2835_IRQ_ENABLE_BASIC) = 0x1;
- }
- /* UART 0 */
- else if ( vector == BCM2835_IRQ_ID_UART )
- {
- BCM2835_REG(BCM2835_IRQ_ENABLE2) = BCM2835_BIT(25);
-
- }
- rtems_interrupt_enable(level);
+ BCM2835_REG(bsp_vector_to_reg(vector)->enable_reg_addr) =
+ bsp_vector_to_mask(vector);
return RTEMS_SUCCESSFUL;
}
rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
{
- rtems_interrupt_level level;
+ if ( vector > BSP_INTERRUPT_VECTOR_MAX )
+ return RTEMS_INVALID_ID;
- rtems_interrupt_disable(level);
-
- if ( vector == BCM2835_IRQ_ID_TIMER_0 )
- {
- BCM2835_REG(BCM2835_IRQ_DISABLE_BASIC) = 0x1;
- }
- else if ( vector == BCM2835_IRQ_ID_UART )
- {
- BCM2835_REG(BCM2835_IRQ_DISABLE2) = BCM2835_BIT(25);
- }
- rtems_interrupt_enable(level);
+ BCM2835_REG(bsp_vector_to_reg(vector)->disable_reg_addr) =
+ bsp_vector_to_mask(vector);
return RTEMS_SUCCESSFUL;
}
-
void bsp_interrupt_handler_default(rtems_vector_number vector)
{
- printk("spurious interrupt: %u\n", vector);
+ printk("spurious interrupt: %lu\n", vector);
}
rtems_status_code bsp_interrupt_facility_initialize(void)