[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(&regs->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(&regs->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