diff options
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.c | 76 |
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; } |