summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/pci/gr_cpci_gr740.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/pci/gr_cpci_gr740.c')
-rw-r--r--c/src/lib/libbsp/sparc/shared/pci/gr_cpci_gr740.c76
1 files changed, 55 insertions, 21 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/pci/gr_cpci_gr740.c b/c/src/lib/libbsp/sparc/shared/pci/gr_cpci_gr740.c
index 3ba55c5442..7ff7206199 100644
--- a/c/src/lib/libbsp/sparc/shared/pci/gr_cpci_gr740.c
+++ b/c/src/lib/libbsp/sparc/shared/pci/gr_cpci_gr740.c
@@ -33,6 +33,7 @@
#include <bsp.h>
#include <rtems/bspIo.h>
+#include <rtems/score/isrlock.h> /* spin-lock */
#include <pci.h>
#include <ambapp.h>
@@ -45,6 +46,16 @@
#include <bsp/gr_cpci_gr740.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)
+
/* Determines which PCI address the AHB masters on the GR740 board will
* access when accessing the AHB to PCI window, it should be set so that the
* masters can access the HOST RAM.
@@ -98,7 +109,8 @@ struct gr740_grcg_regs {
struct gr_cpci_gr740_priv {
/* Driver management */
struct drvmgr_dev *dev;
- char prefix[20];
+ char prefix[16];
+ SPIN_DECLARE(devlock);
/* PCI */
pci_dev_t pcidev;
@@ -213,10 +225,13 @@ void gr_cpci_gr740_isr(void *arg)
struct gr_cpci_gr740_priv *priv = arg;
unsigned int status, tmp;
int irq, eirq;
+ SPIN_ISR_IRQFLAGS(irqflags);
+
tmp = status = priv->irq->ipend;
/* DBG("GR-CPCI-GR740: IRQ 0x%x\n",status); */
+ SPIN_LOCK(&priv->devlock, irqflags);
for(irq = 0; irq < 32; irq++) {
if (status & (1 << irq)) {
if (irq == priv->eirq) {
@@ -235,6 +250,7 @@ void gr_cpci_gr740_isr(void *arg)
break;
}
}
+ SPIN_UNLOCK(&priv->devlock, irqflags);
/* ACK interrupt, this is because PCI is Level, so the IRQ Controller
* still drives the IRQ
@@ -461,11 +477,11 @@ int gr_cpci_gr740_init1(struct drvmgr_dev *dev)
/* Generate Device prefix */
- strcpy(priv->prefix, "/dev/gr7400");
- priv->prefix[10] += dev->minor_drv;
+ strcpy(priv->prefix, "/dev/gr740_0");
+ priv->prefix[11] += dev->minor_drv;
mkdir(priv->prefix, S_IRWXU | S_IRWXG | S_IRWXO);
- priv->prefix[11] = '/';
- priv->prefix[12] = '\0';
+ priv->prefix[12] = '/';
+ priv->prefix[13] = '\0';
priv->devinfo = devinfo = (struct pci_dev_info *)dev->businfo;
priv->pcidev = devinfo->pcidev;
@@ -485,6 +501,12 @@ int gr_cpci_gr740_init1(struct drvmgr_dev *dev)
}
printf(" IRQ: %d\n\n\n", devinfo->irq);
+ /* 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);
+
/* Let user override which PCI address the AHB masters of the
* GR740 board access when doing DMA to HOST RAM. The AHB masters
* access the PCI Window of the AMBA bus, the MSB 2-bits of that address
@@ -576,12 +598,17 @@ int ambapp_gr740_int_register(
void *arg)
{
struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
- rtems_interrupt_level level;
+ SPIN_IRQFLAGS(irqflags);
int status;
+ void *h;
- rtems_interrupt_disable(level);
+ h = genirq_alloc_handler(handler, arg);
+ if ( h == NULL )
+ return DRVMGR_FAIL;
- status = genirq_register(priv->genirq, irq, handler, arg);
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+
+ status = genirq_register(priv->genirq, irq, h);
if (status == 0) {
/* Clear IRQ for first registered handler */
priv->irq->iclear = (1<<irq);
@@ -589,7 +616,8 @@ int ambapp_gr740_int_register(
status = 0;
if (status != 0) {
- rtems_interrupt_enable(level);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+ genirq_free_handler(h);
return DRVMGR_FAIL;
}
@@ -600,7 +628,7 @@ int ambapp_gr740_int_register(
} else if ( status == 1 )
status = 0;
- rtems_interrupt_enable(level);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
return status;
}
@@ -612,10 +640,11 @@ int ambapp_gr740_int_unregister(
void *arg)
{
struct gr_cpci_gr740_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 ) {
@@ -623,11 +652,16 @@ int ambapp_gr740_int_unregister(
priv->irq->mask[0] &= ~(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;
}
@@ -637,19 +671,19 @@ int ambapp_gr740_int_unmask(
int irq)
{
struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
- rtems_interrupt_level level;
+ SPIN_IRQFLAGS(irqflags);
DBG("GR740 IRQ %d: unmask\n", irq);
if ( genirq_check(priv->genirq, irq) )
return DRVMGR_EINVAL;
- rtems_interrupt_disable(level);
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
/* Enable IRQ for first enabled handler only */
priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
- rtems_interrupt_enable(level);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
return DRVMGR_OK;
}
@@ -659,19 +693,19 @@ int ambapp_gr740_int_mask(
int irq)
{
struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
- rtems_interrupt_level level;
+ SPIN_IRQFLAGS(irqflags);
DBG("GR740 IRQ %d: mask\n", irq);
if ( genirq_check(priv->genirq, irq) )
return DRVMGR_EINVAL;
- rtems_interrupt_disable(level);
+ SPIN_LOCK_IRQ(&priv->devlock, irqflags);
/* Disable/mask IRQ */
priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
- rtems_interrupt_enable(level);
+ SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
return DRVMGR_OK;
}