[PATCH 29/32] leon, grtc: SMP support by using spin-locks
Daniel Hellstrom
daniel at gaisler.com
Thu May 11 14:26:14 UTC 2017
---
c/src/lib/libbsp/sparc/shared/tmtc/grtc.c | 91 ++++++++++++++++++-------------
1 file changed, 54 insertions(+), 37 deletions(-)
diff --git a/c/src/lib/libbsp/sparc/shared/tmtc/grtc.c b/c/src/lib/libbsp/sparc/shared/tmtc/grtc.c
index 3cceb60..c01d7d8 100644
--- a/c/src/lib/libbsp/sparc/shared/tmtc/grtc.c
+++ b/c/src/lib/libbsp/sparc/shared/tmtc/grtc.c
@@ -23,17 +23,20 @@
#include <ambapp.h>
#include <bsp/grtc.h>
-#ifndef IRQ_GLOBAL_PREPARE
- #define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
-#endif
-
-#ifndef IRQ_GLOBAL_DISABLE
- #define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
-#endif
-
-#ifndef IRQ_GLOBAL_ENABLE
- #define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
-#endif
+/* 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)
+
+/* turn on/off local CPU's interrupt to ensure HW timing - not SMP safe. */
+#define IRQ_LOCAL_DECLARE(_level) rtems_interrupt_level _level
+#define IRQ_LOCAL_DISABLE(_level) rtems_interrupt_local_disable(_level)
+#define IRQ_LOCAL_ENABLE(_level) rtems_interrupt_local_enable(_level)
/*
#define DEBUG
@@ -236,6 +239,7 @@ struct grtc_priv {
char devName[32]; /* Device Name */
struct grtc_regs *regs; /* TC Hardware Register MAP */
int irq; /* IRQ number of TC core */
+ SPIN_DECLARE(devlock); /* spin-lock of registers */
int major; /* Driver major */
int minor; /* Device Minor */
@@ -398,6 +402,8 @@ static int grtc_init3(struct drvmgr_dev *dev)
sprintf(priv->devName, "/dev/%sgrtc%d", prefix, dev->minor_bus);
}
+ SPIN_INIT(&priv->devlock, priv->devName);
+
/* Register Device */
status = rtems_io_register_name(priv->devName, grtc_driver_io_major, dev->minor_drv);
if (status != RTEMS_SUCCESSFUL) {
@@ -703,9 +709,12 @@ static int grtc_start(struct grtc_priv *pDev)
return 0;
}
-static void grtc_stop(struct grtc_priv *pDev)
+static void grtc_stop(struct grtc_priv *pDev, int overrun)
{
struct grtc_regs *regs = pDev->regs;
+ SPIN_IRQFLAGS(irqflags);
+
+ SPIN_LOCK_IRQ(&pDev->devlock, irqflags);
/* Disable the receiver */
regs->cor = GRTC_SEB;
@@ -717,6 +726,14 @@ static void grtc_stop(struct grtc_priv *pDev)
DBG("GRTC: STOPPED\n");
+ if (overrun) {
+ pDev->overrun_condition = 1;
+ } else {
+ pDev->running = 0;
+ }
+
+ SPIN_UNLOCK_IRQ(&pDev->devlock, irqflags);
+
/* Flush semaphores in case a thread is stuck waiting for CLTUs (RX data) */
rtems_semaphore_flush(pDev->sem_rx);
}
@@ -728,14 +745,14 @@ static int grtc_wait_data(struct grtc_priv *pDev, int count, rtems_interval time
{
int avail;
int ret;
- IRQ_GLOBAL_PREPARE(oldLevel);
+ SPIN_IRQFLAGS(irqflags);
FUNCDBG();
if ( count < 1 )
return 0;
- IRQ_GLOBAL_DISABLE(oldLevel);
+ SPIN_LOCK_IRQ(&pDev->devlock, irqflags);
/* Enable interrupts when receiving CLTUs, Also clear old pending CLTUs store
* interrupts.
@@ -747,7 +764,7 @@ static int grtc_wait_data(struct grtc_priv *pDev, int count, rtems_interval time
if ( avail < count ) {
/* Wait for interrupt. */
- IRQ_GLOBAL_ENABLE(oldLevel);
+ SPIN_UNLOCK_IRQ(&pDev->devlock, irqflags);
if ( timeout == 0 ){
timeout = RTEMS_NO_TIMEOUT;
@@ -759,7 +776,7 @@ static int grtc_wait_data(struct grtc_priv *pDev, int count, rtems_interval time
* which should cancel this operation.
* RTEMS_OBJECT_WAS_DELETED, RTEMS_INVALID_ID = driver error.
*/
- IRQ_GLOBAL_DISABLE(oldLevel);
+ SPIN_LOCK_IRQ(&pDev->devlock, irqflags);
}else{
ret = RTEMS_SUCCESSFUL;
}
@@ -767,7 +784,7 @@ static int grtc_wait_data(struct grtc_priv *pDev, int count, rtems_interval time
/* Disable interrupts when receiving CLTUs */
pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRTC_INT_CS;
- IRQ_GLOBAL_ENABLE(oldLevel);
+ SPIN_UNLOCK_IRQ(&pDev->devlock, irqflags);
return ret;
}
@@ -845,8 +862,7 @@ static rtems_device_driver grtc_close(rtems_device_major_number major, rtems_dev
pDev = (struct grtc_priv *)dev->priv;
if ( pDev->running ){
- grtc_stop(pDev);
- pDev->running = 0;
+ grtc_stop(pDev, 0);
}
/* Reset core */
@@ -1542,8 +1558,7 @@ static rtems_device_driver grtc_ioctl(rtems_device_major_number major, rtems_dev
struct grtc_list *frmlist;
struct grtc_ioc_stats *stats;
unsigned int mem;
-
- IRQ_GLOBAL_PREPARE(oldLevel);
+ IRQ_LOCAL_DECLARE(oldLevel);
FUNCDBG();
@@ -1575,8 +1590,7 @@ static rtems_device_driver grtc_ioctl(rtems_device_major_number major, rtems_dev
return RTEMS_RESOURCE_IN_USE;
}
drvmgr_interrupt_unregister(pDev->dev, 0, grtc_interrupt, pDev);
- grtc_stop(pDev);
- pDev->running = 0;
+ grtc_stop(pDev, 0);
break;
case GRTC_IOC_ISSTARTED:
@@ -1716,15 +1730,17 @@ static rtems_device_driver grtc_ioctl(rtems_device_major_number major, rtems_dev
if ( !hwregs ) {
return RTEMS_INVALID_NAME;
}
- /* We disable interrupt in order to get a snapshot of the registers */
- IRQ_GLOBAL_DISABLE(oldLevel);
+ /* We disable interrupt on the local CPU in order to get a
+ * snapshot of the registers.
+ */
+ IRQ_LOCAL_DISABLE(oldLevel);
hwregs->sir = READ_REG(&pDev->regs->sir);
hwregs->far = READ_REG(&pDev->regs->far);
hwregs->clcw1 = READ_REG(&pDev->regs->clcw1);
hwregs->clcw2 = READ_REG(&pDev->regs->clcw2);
hwregs->phir = READ_REG(&pDev->regs->phir);
hwregs->str = READ_REG(&pDev->regs->str);
- IRQ_GLOBAL_ENABLE(oldLevel);
+ IRQ_LOCAL_ENABLE(oldLevel);
break;
case GRTC_IOC_GET_STATS:
@@ -1897,6 +1913,7 @@ static void grtc_interrupt(void *arg)
struct grtc_priv *pDev = arg;
struct grtc_regs *regs = pDev->regs;
unsigned int status;
+ SPIN_ISR_IRQFLAGS(irqflags);
/* Clear interrupt by reading it */
status = READ_REG(®s->pisr);
@@ -1906,36 +1923,36 @@ static void grtc_interrupt(void *arg)
return;
if ( status & GRTC_INT_OV ){
-
/* Stop core (Disable receiver, interrupts), set overrun condition,
* Flush semaphore if thread waiting for data in grtc_wait_data().
*/
- pDev->overrun_condition = 1;
-
- grtc_stop(pDev);
+ grtc_stop(pDev, 1);
/* No need to handle the reset of interrupts, we are still */
goto out;
}
if ( status & GRTC_INT_CS ){
+ SPIN_LOCK(&pDev->devlock, irqflags);
+
if ( (pDev->blocking==GRTC_BLKMODE_COMPLETE) && pDev->timeout ){
/* Signal to thread only if enough data is available */
if ( pDev->wait_for_nbytes > grtc_data_avail(pDev) ){
/* Not enough data available */
goto procceed_processing_interrupts;
}
-
- /* Enough data is available which means that we should wake
- * up thread sleeping.
+
+ /* Enough data is available which means that we should
+ * wake up the thread sleeping.
*/
}
-
- /* Disable further CLTUs Stored interrupts, no point until thread waiting for them
- * say it want to wait for more.
+
+ /* Disable further CLTUs Stored interrupts, no point until
+ * thread waiting for them says it want to wait for more.
*/
regs->imr = READ_REG(®s->imr) & ~GRTC_INT_CS;
-
+ SPIN_UNLOCK(&pDev->devlock, irqflags);
+
/* Signal Semaphore to wake waiting thread in read() */
rtems_semaphore_release(pDev->sem_rx);
}
--
2.7.4
More information about the devel
mailing list