From 4d7e4bb2139439e676a9131cad3b1a9aa04037ae Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Thu, 16 Nov 2017 16:46:47 +0100 Subject: 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 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; icfg->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) -- cgit v1.2.3