From 1ea73e2b5ff669c9cc0284519da02f47d7676a63 Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Thu, 11 May 2017 13:43:53 +0200 Subject: leon, grtc: SMP support by using spin-locks --- 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 3cceb60c86..c01d7d8391 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 #include -#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); } -- cgit v1.2.3