summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Hellstrom <daniel@gaisler.com>2017-11-16 16:46:47 +0100
committerDaniel Hellstrom <daniel@gaisler.com>2017-11-21 10:28:02 +0100
commit4d7e4bb2139439e676a9131cad3b1a9aa04037ae (patch)
tree175283239c2b61e96a1807d44558b4a5f011a9f4
parentposix: _POSIX_Threads_Get_sched_param_sporadic() (diff)
downloadrtems-4d7e4bb2139439e676a9131cad3b1a9aa04037ae.tar.bz2
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.
-rw-r--r--c/src/lib/libbsp/sparc/shared/1553/gr1553rt.c182
1 files 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 22378bf88c..932e8494f1 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)