[rtems commit] leon, gr1553rt: adding SMP protection

Daniel Hellstrom danielh at rtems.org
Tue Nov 21 09:29:14 UTC 2017


Module:    rtems
Branch:    master
Commit:    4d7e4bb2139439e676a9131cad3b1a9aa04037ae
Changeset: http://git.rtems.org/rtems/commit/?id=4d7e4bb2139439e676a9131cad3b1a9aa04037ae

Author:    Daniel Hellstrom <daniel at gaisler.com>
Date:      Thu Nov 16 16:46:47 2017 +0100

leon, gr1553rt: adding SMP protection

Add device spin-lock around internal data structures. Since the driver
provides a low-level C API accessing the descriptors the application
still needs to implement part of the SMP synchonization needed between
Interrupt handler and tasks.

Close #2355.

---

 c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c | 182 ++++++++++----------------
 1 file changed, 69 insertions(+), 113 deletions(-)

diff --git a/c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c b/c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c
index 22378bf..932e849 100644
--- a/c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c
+++ b/c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c
@@ -25,17 +25,16 @@
 #define GR1553RT_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
 #define GR1553RT_READ_REG(adr) (*(volatile uint32_t *)(adr))
 
-#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)
+#define SPIN_FREE(lock) rtems_interrupt_lock_destroy(lock)
 
 /* Software representation of one hardware descriptor */
 struct gr1553rt_sw_bd {
@@ -74,6 +73,7 @@ struct gr1553rt_priv {
 	/* Software State */
 	int started;
 	struct gr1553rt_cfg cfg;
+	SPIN_DECLARE(devlock);
 
 	/* Handle to GR1553B RT device layer */
 	struct drvmgr_dev **pdev;
@@ -313,7 +313,7 @@ int gr1553rt_bd_init(
 	unsigned short bdid;
 	struct gr1553rt_bd *bd;
 	unsigned int nextbd, dataptr;
-	IRQ_GLOBAL_PREPARE(oldLevel);
+	SPIN_IRQFLAGS(irqflags);
 
 	if ( entry_no >= list->bd_cnt )
 		return -1;
@@ -353,12 +353,12 @@ int gr1553rt_bd_init(
 			);
 	}
 
-	/* Get current status, and clear */
-	IRQ_GLOBAL_DISABLE(oldLevel);
+	/* Init BD */
+	SPIN_LOCK_IRQ(&priv->devlock, irqflags);
 	bd->ctrl = flags & GR1553RT_BD_FLAGS_IRQEN;
 	bd->dptr = (unsigned int)dptr;
 	bd->next = nextbd;
-	IRQ_GLOBAL_ENABLE(oldLevel);
+	SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
 
 	return 0;	
 }
@@ -374,7 +374,7 @@ int gr1553rt_bd_update(
 	unsigned short bdid;
 	struct gr1553rt_bd *bd;
 	unsigned int tmp, dataptr;
-	IRQ_GLOBAL_PREPARE(oldLevel);
+	SPIN_IRQFLAGS(irqflags);
 
 	if ( entry_no >= list->bd_cnt )
 		return -1;
@@ -400,8 +400,8 @@ int gr1553rt_bd_update(
 		}
 	}
 
-	/* Get current status, and clear */
-	IRQ_GLOBAL_DISABLE(oldLevel);
+	/* Get current values and then set new values in BD */
+	SPIN_LOCK_IRQ(&priv->devlock, irqflags);
 	/* READ/WRITE Status/Control word */
 	if ( status ) {
 		tmp = bd->ctrl;
@@ -418,7 +418,7 @@ int gr1553rt_bd_update(
 		}
 		*dptr = (uint16_t *)tmp;
 	}
-	IRQ_GLOBAL_ENABLE(oldLevel);
+	SPIN_LOCK_IRQ(&priv->devlock, irqflags);
 
 	return 0;
 }
@@ -431,12 +431,12 @@ int gr1553rt_irq_err
 	)
 {
 	struct gr1553rt_priv *priv = rt;
-	IRQ_GLOBAL_PREPARE(oldLevel);
+	SPIN_IRQFLAGS(irqflags);
 
-	IRQ_GLOBAL_DISABLE(oldLevel);
+	SPIN_LOCK_IRQ(&priv->devlock, irqflags);
 	priv->irq_err.func = func;
 	priv->irq_err.data = data;
-	IRQ_GLOBAL_ENABLE(oldLevel);
+	SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
 
 	return 0;
 }
@@ -449,12 +449,12 @@ int gr1553rt_irq_mc
 	)
 {
 	struct gr1553rt_priv *priv = rt;
-	IRQ_GLOBAL_PREPARE(oldLevel);
+	SPIN_IRQFLAGS(irqflags);
 
-	IRQ_GLOBAL_DISABLE(oldLevel);
+	SPIN_LOCK_IRQ(&priv->devlock, irqflags);
 	priv->irq_mc.func = func;
 	priv->irq_mc.data = data;
-	IRQ_GLOBAL_ENABLE(oldLevel);
+	SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
 
 	return 0;
 }
@@ -469,9 +469,9 @@ int gr1553rt_irq_sa
 	)
 {
 	struct gr1553rt_priv *priv = rt;
-	IRQ_GLOBAL_PREPARE(oldLevel);
+	SPIN_IRQFLAGS(irqflags);
 
-	IRQ_GLOBAL_DISABLE(oldLevel);
+	SPIN_LOCK_IRQ(&priv->devlock, irqflags);
 	if ( tx ) {
 		priv->irq_tx[subadr].func = func;
 		priv->irq_tx[subadr].data = data;
@@ -479,7 +479,7 @@ int gr1553rt_irq_sa
 		priv->irq_rx[subadr].func = func;
 		priv->irq_rx[subadr].data = data;
 	}
-	IRQ_GLOBAL_ENABLE(oldLevel);
+	SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
 
 	return 0;
 }
@@ -493,10 +493,11 @@ void gr1553rt_isr(void *data)
 	unsigned int *last, *curr, entry, hwbd;
 	int type, samc, mcode, subadr;
 	int listid;
-	struct gr1553rt_irq *isr;
-	struct gr1553rt_irqerr *isrerr;
-	struct gr1553rt_irqmc *isrmc;
+	struct gr1553rt_irq *pisr, isr;
+	struct gr1553rt_irqerr isrerr;
+	struct gr1553rt_irqmc isrmc;
 	unsigned int irq;
+	SPIN_ISR_IRQFLAGS(irqflags);
 
 	/* Ack IRQ before reading current write pointer, but after
 	 * reading current IRQ pointer. This is because RT_EVIRQ
@@ -516,9 +517,12 @@ void gr1553rt_isr(void *data)
 		return;
 
 	if ( irq & (GR1553B_IRQ_RTTE|GR1553B_IRQ_RTD) ) {
-		isrerr = &priv->irq_err;
-		if ( isrerr->func ) {
-			isrerr->func(irq, isrerr->data);
+		/* copy func and arg while owning lock */
+		SPIN_LOCK(&priv->devlock, irqflags);
+		isrerr = priv->irq_err;
+		SPIN_UNLOCK(&priv->devlock, irqflags);
+		if ( isrerr.func ) {
+			isrerr.func(irq, isrerr.data);
 		}
 
 		/* Stop Hardware and enter non-started mode. This will
@@ -556,42 +560,51 @@ void gr1553rt_isr(void *data)
 					/* Receive */
 					listid = priv->subadrs[subadr].rxlistid;
 					hwbd = priv->sas_cpu[subadr].rxptr;
-					isr = &priv->irq_rx[subadr];
+					pisr = &priv->irq_rx[subadr];
 				} else {
 					/* Transmit */
 					listid = priv->subadrs[subadr].txlistid;
 					hwbd = priv->sas_cpu[subadr].txptr;
-					isr = &priv->irq_tx[subadr];
+					pisr = &priv->irq_tx[subadr];
 				}
 
 				index = ((unsigned int)hwbd - (unsigned int)
 					priv->bds_hw)/sizeof(struct gr1553rt_bd);
 
+				/* copy func and arg while owning lock */
+				SPIN_LOCK(&priv->devlock, irqflags);
+				isr = *pisr;
+				SPIN_UNLOCK(&priv->devlock, irqflags);
+
 				/* Call user ISR of RX/TX transfer */
-				if ( isr->func ) {
-					isr->func(
+				if ( isr.func ) {
+					isr.func(
 						priv->lists[listid],
 						entry,
 						priv->swbds[index].this_next,
-						isr->data
+						isr.data
 						);
 				}
 			} else if ( type == 0x2) {
 				/* Modecode */
 				mcode = samc;
-				isrmc = &priv->irq_mc;
+
+				/* copy func and arg while owning lock */
+				SPIN_LOCK(&priv->devlock, irqflags);
+				isrmc = priv->irq_mc;
+				SPIN_UNLOCK(&priv->devlock, irqflags);
 
 				/* Call user ISR of ModeCodes RX/TX */
-				if ( isrmc->func ) {
-					isrmc->func(
+				if ( isrmc.func ) {
+					isrmc.func(
 						mcode,
 						entry,
-						isrmc->data
+						isrmc.data
 						);
 				}
 			} else {
 				/* ERROR OF SOME KIND, EVLOG OVERWRITTEN? */
-				exit(-1);
+				rtems_fatal_error_occurred(RTEMS_IO_ERROR);
 			}
 		}
 
@@ -637,66 +650,6 @@ int gr1553rt_indication(void *rt, int subadr, int *txeno, int *rxeno)
 	return 0;
 }
 
-#if 0
-int gr1553rt_bd_irq(
-	struct gr1553rt_list *list,
-	unsigned short entry_no,
-	void (*func)(struct gr1553rt_list *list, int entry, void *data),
-	void *data
-	)
-{
-	struct gr1553rt_priv *priv = list->rt;
-	int irqid;
-	int ret;
-	IRQ_GLOBAL_PREPARE(oldLevel);
-
-	if ( entry_no == 0xffff ) {
-		/* Default interrupt for all list entries without
-		 * assigned IRQ function.
-		 */
-		list->irqs[0].func = func;
-		list->irqs[0].data = data;
-		return 0;
-	}
-
-	if ( entry_no >= list->bd_cnt ) {
-		return -1;
-	}
-
-	bdid = list->bds[entry_no];
-	irqid = priv->swbds[bdid].irqid;
-
-	ret = 0;
-	IRQ_GLOBAL_DISABLE(oldLevel);
-	if ( (irqid != 0) && (func == 0) ) {
-		/* Unassign IRQ function */
-		list->irqs[irqid].func = NULL;
-		list->irqs[irqid].data = NULL;
-		irqid = 0; /* Disable IRQ (default handler) */
-	} else if ( priv->swbds[bdid].irqid != 0 ) {
-		/* reassign IRQ function */
-		list->irqs[irqid].func = func;
-		list->irqs[irqid].data = data;
-	} else {
-		/* Find free IRQ spot. If no free irqid=0 (general IRQ) */
-		ret = -1;
-		for (i=0; i<list->cfg->maxirq; i++) {
-			if ( list->irqs[i].func == NULL ) {
-				irqid = i;
-				list->irqs[i].func = func;
-				list->irqs[i].data = data;
-				ret = 0;
-				break;
-			}
-		}
-	}
-	priv->swbds[bdid].irqid = irqid;
-	IRQ_GLOBAL_ENABLE(oldLevel);
-
-	return ret;
-}
-#endif
-
 void gr1553rt_hw_stop(struct gr1553rt_priv *priv);
 
 void gr1553rt_register(void)
@@ -731,6 +684,8 @@ void *gr1553rt_open(int minor)
 	pnpinfo = &ambadev->info;
 	priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
 
+	SPIN_INIT(&priv->devlock, "gr1553rt");
+
 	/* Start with default configuration */
 	/*priv->cfg = gr1553rt_default_config;*/
 
@@ -766,6 +721,7 @@ void gr1553rt_close(void *rt)
 
 	/* Free dynamically allocated buffers if any */
 	gr1553rt_sw_free(priv);
+	SPIN_FREE(&priv->devlock);
 
 	/* Return RT/BC device */
 	gr1553_rt_close(priv->pdev);
@@ -1025,7 +981,7 @@ int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
 int gr1553rt_start(void *rt)
 {
 	struct gr1553rt_priv *priv = rt;
-	IRQ_GLOBAL_PREPARE(oldLevel);
+	SPIN_IRQFLAGS(irqflags);
 
 	if ( priv->started )
 		return -1;
@@ -1054,7 +1010,7 @@ int gr1553rt_start(void *rt)
 	priv->regs->rt_evirq = 0;
 
 	/* Clear and old IRQ flag and Enable IRQ */
-	IRQ_GLOBAL_DISABLE(oldLevel);
+	SPIN_LOCK_IRQ(&priv->devlock, irqflags);
 	priv->regs->irq = GR1553B_IRQ_RTEV|GR1553B_IRQ_RTD|GR1553B_IRQ_RTTE;
 	priv->regs->imask |= GR1553B_IRQEN_RTEVE | GR1553B_IRQEN_RTDE |
 			GR1553B_IRQEN_RTTEE;
@@ -1066,7 +1022,7 @@ int gr1553rt_start(void *rt)
 
 	/* Tell software RT is started */
 	priv->started = 1;
-	IRQ_GLOBAL_ENABLE(oldLevel);
+	SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
 
 	return 0;
 }
@@ -1074,9 +1030,9 @@ int gr1553rt_start(void *rt)
 void gr1553rt_stop(void *rt)
 {
 	struct gr1553rt_priv *priv = rt;
-	IRQ_GLOBAL_PREPARE(oldLevel);
+	SPIN_IRQFLAGS(irqflags);
 
-	IRQ_GLOBAL_DISABLE(oldLevel);
+	SPIN_LOCK_IRQ(&priv->devlock, irqflags);
 
 	/* Stop Hardware */
 	gr1553rt_hw_stop(priv);
@@ -1084,7 +1040,7 @@ void gr1553rt_stop(void *rt)
 	/* Software state */
 	priv->started = 0;
 
-	IRQ_GLOBAL_ENABLE(oldLevel);
+	SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
 }
 
 void gr1553rt_sa_schedule(
@@ -1164,9 +1120,9 @@ void gr1553rt_status(void *rt, struct gr1553rt_status *status)
 	struct gr1553rt_priv *priv = rt;
 	struct gr1553b_regs *regs = priv->regs;
 	unsigned int tmp;
-	IRQ_GLOBAL_PREPARE(oldLevel);
+	SPIN_IRQFLAGS(irqflags);
 
-	IRQ_GLOBAL_DISABLE(oldLevel);
+	SPIN_LOCK_IRQ(&priv->devlock, irqflags);
 	status->status = regs->rt_stat;
 	status->bus_status = regs->rt_stat2;
 
@@ -1178,7 +1134,7 @@ void gr1553rt_status(void *rt, struct gr1553rt_status *status)
 	status->time_res = tmp >> 16;
 	status->time = tmp & 0xffff;
 
-	IRQ_GLOBAL_ENABLE(oldLevel);
+	SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
 }
 
 void gr1553rt_list_sa(struct gr1553rt_list *list, int *subadr, int *tx)



More information about the vc mailing list