summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/irq
diff options
context:
space:
mode:
authorDaniel Hellstrom <daniel@gaisler.com>2015-02-23 13:02:39 +0100
committerDaniel Hellstrom <daniel@gaisler.com>2015-04-17 01:10:17 +0200
commit3bb41226e0941b86d58ecb97f7d292677de573c8 (patch)
tree907aa270343f7c6d1bc08bf73288fb9b10da6197 /c/src/lib/libbsp/sparc/shared/irq
parentLEON: added network device configuration helper function (diff)
downloadrtems-3bb41226e0941b86d58ecb97f7d292677de573c8.tar.bz2
LEON: added new drivers to the LEON2/LEON3 BSPs
Most drivers use the Driver Manager for device probing, they work on AMBA-over-PCI systems if PCI is big-endian. New APIs: * GPIO Library, interfaced to GRGPIO * GENIRQ, Generic interrupt service implementation helper New GRLIB Drivers: * ACTEL 1553 RT, user interface is similar to 1553 BRM driver * GR1553 (1553 BC, RT and BM core) * AHBSTAT (AHB error status core) * GRADCDAC (Core interfacing to ADC/DAC hardware) * GRGPIO (GPIO port accessed from GPIO Library) * MCTRL (Memory controller settings configuration) * GRETH (10/100/1000 Ethernet driver using Driver manager) * GRPWM (Pulse Width Modulation core) * SPICTRL (SPI master interface) * GRSPW_ROUTER (SpaceWire Router AMBA configuration interface) * GRCTM (SpaceCraft on-board Time Management core) * SPWCUC (Time distribution over SpaceWire) * GRTC (SpaceCraft up-link Tele core) * GRTM (SpaceCraft down-link Tele Metry core) GR712RC ASIC specific interfaces: * GRASCS * CANMUX (select between OCCAN and SATCAN) * SATCAN * SLINK
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/irq')
-rw-r--r--c/src/lib/libbsp/sparc/shared/irq/genirq.c241
1 files changed, 241 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/irq/genirq.c b/c/src/lib/libbsp/sparc/shared/irq/genirq.c
new file mode 100644
index 0000000000..782ebf8a5f
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/irq/genirq.c
@@ -0,0 +1,241 @@
+/*
+ * Generic interrupt helpers mainly for GRLIB PCI peripherals
+ *
+ * COPYRIGHT (c) 2008.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <stdlib.h>
+#include <string.h>
+#include <genirq.h>
+
+struct genirq_handler_entry {
+ struct genirq_handler_entry *next; /* Next ISR entry for this IRQ number */
+ genirq_handler isr; /* ISR function called upon IRQ */
+ void *arg; /* custom argument to ISR */
+ int enabled; /* Inidicates if IRQ is enabled */
+};
+
+struct genirq_irq_entry {
+ struct genirq_handler_entry *head;
+ struct genirq_stats stats;
+};
+
+struct genirq_priv {
+ /* Maximum number of interrupt */
+ int genirq_max;
+ /* IRQ Table index N reflect IRQ number N */
+ struct genirq_irq_entry genirq_table[1]; /* Length depends on */
+};
+
+genirq_t genirq_init(int number_of_irqs)
+{
+ int size;
+ struct genirq_priv *priv;
+
+ size = sizeof(int) +
+ number_of_irqs * sizeof(struct genirq_irq_entry);
+
+ priv = (struct genirq_priv *)malloc(size);
+ if ( !priv )
+ return NULL;
+ memset(priv, 0, size);
+ priv->genirq_max = number_of_irqs - 1;
+ return priv;
+}
+
+void genirq_destroy(genirq_t d)
+{
+ struct genirq_priv *priv = d;
+ struct genirq_irq_entry *irqentry;
+ struct genirq_handler_entry *isrentry, *tmp;
+ int i;
+
+ /* Free all registered interrupts */
+ for ( i=0; i<priv->genirq_max; i++) {
+ irqentry = &priv->genirq_table[i];
+ isrentry = irqentry->head;
+ while ( isrentry ) {
+ tmp = isrentry;
+ isrentry = isrentry->next;
+ free(tmp);
+ }
+ }
+
+ free(priv);
+}
+
+int genirq_check(genirq_t d, int irq)
+{
+ struct genirq_priv *priv = d;
+
+ if ( (irq <= 0) || (irq > priv->genirq_max) )
+ return -1;
+ else
+ return 0;
+}
+
+int genirq_register(genirq_t d, int irq, genirq_handler isr, void *arg)
+{
+ struct genirq_priv *priv = d;
+ struct genirq_irq_entry *irqentry;
+ struct genirq_handler_entry *isrentry, *newentry;
+ rtems_interrupt_level level;
+
+ if ( genirq_check(d, irq) )
+ return -1;
+
+ newentry = malloc(sizeof(*newentry));
+ if ( !newentry )
+ return -1;
+
+ /* Initialize ISR entry */
+ newentry->isr = isr;
+ newentry->arg = arg;
+ newentry->enabled = 0;
+
+ rtems_interrupt_disable(level);
+
+ /* Insert new ISR entry first into table */
+ irqentry = &priv->genirq_table[irq];
+ isrentry = irqentry->head;
+ irqentry->head = newentry;
+ newentry->next = isrentry;
+
+ rtems_interrupt_enable(level);
+
+ if ( isrentry )
+ return 1; /* This is the first handler on this IRQ */
+ return 0;
+}
+
+int genirq_unregister(genirq_t d, int irq, genirq_handler isr, void *arg)
+{
+ struct genirq_priv *priv = d;
+ struct genirq_irq_entry *irqentry;
+ struct genirq_handler_entry *isrentry, **prev;
+ rtems_interrupt_level level;
+ int ret;
+
+ if ( genirq_check(d, irq) )
+ return -1;
+
+ /* Remove isr[arg] from ISR list */
+ irqentry = &priv->genirq_table[irq];
+ ret = -1;
+
+ rtems_interrupt_disable(level);
+
+ prev = &irqentry->head;
+ isrentry = irqentry->head;
+ while ( isrentry ) {
+ if ( (isrentry->arg == arg) && (isrentry->isr == isr) ) {
+ /* Found ISR, remove it from list */
+ if ( isrentry->enabled ) {
+ /* Can not remove enabled ISRs, disable first */
+ ret = 1;
+ break;
+ }
+ *prev = isrentry->next;
+ ret = 0;
+ break;
+ }
+ prev = &isrentry->next;
+ isrentry = isrentry->next;
+ }
+
+ rtems_interrupt_enable(level);
+
+ return ret;
+}
+
+/* Enables or Disables ISR handler. Internal function to reduce footprint
+ * of enable/disable functions.
+ *
+ * \param action 1=enable, 0=disable ISR
+ */
+int genirq_set_active(struct genirq_priv *priv, int irq, genirq_handler isr, void *arg, int action)
+{
+ struct genirq_irq_entry *irqentry;
+ struct genirq_handler_entry *isrentry, *e = NULL;
+ int enabled;
+
+ if ( genirq_check(priv, irq) )
+ return -1;
+
+ /* Find isr[arg] in ISR list */
+ irqentry = &priv->genirq_table[irq];
+ enabled = 0;
+
+ isrentry = irqentry->head;
+ while ( isrentry ) {
+ if ( (isrentry->arg == arg) && (isrentry->isr == isr) ) {
+ /* Found ISR */
+ if ( isrentry->enabled == action ) {
+ /* The ISR is already enabled or disabled
+ * depending on request, neccessary actions
+ * were taken last time the same action was
+ * requested.
+ */
+ return 1;
+ }
+ e = isrentry;
+ } else {
+ enabled += isrentry->enabled;
+ }
+ isrentry = isrentry->next;
+ }
+
+ if ( !e )
+ return -1;
+
+ e->enabled = action;
+
+ return enabled;
+}
+
+int genirq_enable(genirq_t d, int irq, genirq_handler isr, void *arg)
+{
+ struct genirq_priv *priv = d;
+ return genirq_set_active(priv, irq, isr, arg, 1);
+}
+
+int genirq_disable(genirq_t d, int irq, genirq_handler isr, void *arg)
+{
+ struct genirq_priv *priv = d;
+ return genirq_set_active(priv, irq, isr, arg, 0);
+}
+
+void genirq_doirq(genirq_t d, int irq)
+{
+ struct genirq_priv *priv = d;
+ struct genirq_irq_entry *irqentry;
+ struct genirq_handler_entry *isrentry;
+ int enabled;
+
+ irqentry = &priv->genirq_table[irq];
+ irqentry->stats.irq_cnt++;
+
+ enabled = 0;
+
+ isrentry = irqentry->head;
+ while ( isrentry ) {
+ if ( isrentry->enabled ) {
+ enabled = 1;
+ /* Call the ISR */
+ isrentry->isr(isrentry->arg);
+ }
+ isrentry = isrentry->next;
+ }
+
+ /* Was the IRQ an IRQ without source? */
+ if ( enabled == 0 ) {
+ /* This should not happen */
+ printk("Spurious IRQ happened on IRQ %d\n", irq);
+ }
+}