summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/pci/gr_701.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/pci/gr_701.c')
-rw-r--r--c/src/lib/libbsp/sparc/shared/pci/gr_701.c67
1 files changed, 50 insertions, 17 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/pci/gr_701.c b/c/src/lib/libbsp/sparc/shared/pci/gr_701.c
index 40a0a2560e..a6c9ebcd5c 100644
--- a/c/src/lib/libbsp/sparc/shared/pci/gr_701.c
+++ b/c/src/lib/libbsp/sparc/shared/pci/gr_701.c
@@ -23,6 +23,7 @@
#include <bsp.h>
#include <rtems/bspIo.h>
+#include <rtems/score/isrlock.h> /* spin-lock */
#include <pci.h>
#include <pci/access.h>
@@ -37,6 +38,16 @@
#include <bsp/gr_701.h>
+/* map via rtems_interrupt_lock_* API: */
+#define SPIN_DECLARE(lock) RTEMS_INTERRUPT_LOCK_MEMBER(lock)
+#define SPIN_INIT(lock, name) rtems_interrupt_lock_initialize(lock, name)
+#define SPIN_LOCK(lock, level) rtems_interrupt_lock_acquire_isr(lock, &level)
+#define SPIN_LOCK_IRQ(lock, level) rtems_interrupt_lock_acquire(lock, &level)
+#define SPIN_UNLOCK(lock, level) rtems_interrupt_lock_release_isr(lock, &level)
+#define SPIN_UNLOCK_IRQ(lock, level) rtems_interrupt_lock_release(lock, &level)
+#define SPIN_IRQFLAGS(k) rtems_interrupt_lock_context k
+#define SPIN_ISR_IRQFLAGS(k) SPIN_IRQFLAGS(k)
+
/* Offset from 0x80000000 (dual bus version) */
#define AHB1_BASE_ADDR 0x80000000
#define AHB1_IOAREA_BASE_ADDR 0x80100000
@@ -87,8 +98,9 @@ struct pci_bridge_regs {
/* Private data structure for driver */
struct gr701_priv {
/* Driver management */
- struct drvmgr_dev *dev;
+ struct drvmgr_dev *dev;
char prefix[16];
+ SPIN_DECLARE(devlock);
struct pci_bridge_regs *pcib;
struct amba_bridge_regs *ambab;
@@ -200,7 +212,9 @@ void gr701_interrupt(void *arg)
struct gr701_priv *priv = arg;
unsigned int status;
int irq = 0;
+ SPIN_ISR_IRQFLAGS(irqflags);
+ SPIN_LOCK(&priv->devlock, irqflags);
while ( (status=priv->pcib->istatus) != 0 ) {
priv->interrupt_cnt++; /* An interrupt was generated */
irq = status;
@@ -208,6 +222,7 @@ void gr701_interrupt(void *arg)
/* ACK interrupt */
priv->pcib->istatus = 0;
}
+ SPIN_UNLOCK(&priv->devlock, irqflags);
/* ACK interrupt, this is because PCI is Level, so the IRQ Controller still drives the IRQ. */
if ( irq )
@@ -347,6 +362,12 @@ int gr701_init1(struct drvmgr_dev *dev)
if ((bar0_size == 0) || (bar1_size == 0))
return DRVMGR_ENORES;
+ /* Initialize spin-lock for this PCI perihperal device. This is to
+ * protect the Interrupt Controller Registers. The genirq layer is
+ * protecting its own internals and ISR dispatching.
+ */
+ SPIN_INIT(&priv->devlock, priv->prefix);
+
priv->genirq = genirq_init(16);
if ( priv->genirq == NULL ) {
free(priv);
@@ -410,12 +431,17 @@ int ambapp_gr701_int_register(
void *arg)
{
struct gr701_priv *priv = dev->parent->dev->priv;
- rtems_interrupt_level level;
+ SPIN_IRQFLAGS(irqflags);
int status;
+ void *h;
+
+ h = genirq_alloc_handler(handler, arg);
+ if ( h == NULL )
+ return DRVMGR_FAIL;
- rtems_interrupt_disable(level);
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
- status = genirq_register(priv->genirq, irq, handler, arg);
+ status = genirq_register(priv->genirq, irq, h);
if ( status == 0 ) {
/* Clear IRQ for first registered handler */
priv->pcib->iclear = (1<<irq);
@@ -423,7 +449,8 @@ int ambapp_gr701_int_register(
status = 0;
if (status != 0) {
- rtems_interrupt_enable(level);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+ genirq_free_handler(h);
return DRVMGR_FAIL;
}
@@ -434,7 +461,7 @@ int ambapp_gr701_int_register(
} else if ( status == 1 )
status = DRVMGR_OK;
- rtems_interrupt_enable(level);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
return status;
}
@@ -446,10 +473,11 @@ int ambapp_gr701_int_unregister(
void *arg)
{
struct gr701_priv *priv = dev->parent->dev->priv;
- rtems_interrupt_level level;
+ SPIN_IRQFLAGS(irqflags);
int status;
+ void *handler;
- rtems_interrupt_disable(level);
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
status = genirq_disable(priv->genirq, irq, isr, arg);
if ( status == 0 ) {
@@ -457,11 +485,16 @@ int ambapp_gr701_int_unregister(
priv->pcib->imask &= ~(1<<irq); /* mask interrupt source */
}
- status = genirq_unregister(priv->genirq, irq, isr, arg);
- if ( status != 0 )
+ handler = genirq_unregister(priv->genirq, irq, isr, arg);
+ if ( handler == NULL )
status = DRVMGR_FAIL;
+ else
+ status = DRVMGR_OK;
+
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
- rtems_interrupt_enable(level);
+ if (handler)
+ genirq_free_handler(handler);
return status;
}
@@ -471,19 +504,19 @@ int ambapp_gr701_int_unmask(
int irq)
{
struct gr701_priv *priv = dev->parent->dev->priv;
- rtems_interrupt_level level;
+ SPIN_IRQFLAGS(irqflags);
DBG("GR-701 IRQ %d: enable\n", irq);
if ( genirq_check(priv->genirq, irq) )
return DRVMGR_FAIL;
- rtems_interrupt_disable(level);
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
/* Enable IRQ */
priv->pcib->imask |= (1<<irq); /* unmask interrupt source */
- rtems_interrupt_enable(level);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
return DRVMGR_OK;
}
@@ -493,19 +526,19 @@ int ambapp_gr701_int_mask(
int irq)
{
struct gr701_priv *priv = dev->parent->dev->priv;
- rtems_interrupt_level level;
+ SPIN_IRQFLAGS(irqflags);
DBG("GR-701 IRQ %d: disable\n", irq);
if ( genirq_check(priv->genirq, irq) )
return DRVMGR_FAIL;
- rtems_interrupt_disable(level);
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
/* Disable IRQ */
priv->pcib->imask &= ~(1<<irq); /* mask interrupt source */
- rtems_interrupt_enable(level);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
return DRVMGR_OK;
}