forked from Imagelibrary/rtems
leon, grtc: SMP support by using spin-locks
This commit is contained in:
@@ -23,17 +23,20 @@
|
|||||||
#include <ambapp.h>
|
#include <ambapp.h>
|
||||||
#include <bsp/grtc.h>
|
#include <bsp/grtc.h>
|
||||||
|
|
||||||
#ifndef IRQ_GLOBAL_PREPARE
|
/* map via rtems_interrupt_lock_* API: */
|
||||||
#define IRQ_GLOBAL_PREPARE(level) rtems_interrupt_level level
|
#define SPIN_DECLARE(lock) RTEMS_INTERRUPT_LOCK_MEMBER(lock)
|
||||||
#endif
|
#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)
|
||||||
|
|
||||||
#ifndef IRQ_GLOBAL_DISABLE
|
/* turn on/off local CPU's interrupt to ensure HW timing - not SMP safe. */
|
||||||
#define IRQ_GLOBAL_DISABLE(level) rtems_interrupt_disable(level)
|
#define IRQ_LOCAL_DECLARE(_level) rtems_interrupt_level _level
|
||||||
#endif
|
#define IRQ_LOCAL_DISABLE(_level) rtems_interrupt_local_disable(_level)
|
||||||
|
#define IRQ_LOCAL_ENABLE(_level) rtems_interrupt_local_enable(_level)
|
||||||
#ifndef IRQ_GLOBAL_ENABLE
|
|
||||||
#define IRQ_GLOBAL_ENABLE(level) rtems_interrupt_enable(level)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
@@ -236,6 +239,7 @@ struct grtc_priv {
|
|||||||
char devName[32]; /* Device Name */
|
char devName[32]; /* Device Name */
|
||||||
struct grtc_regs *regs; /* TC Hardware Register MAP */
|
struct grtc_regs *regs; /* TC Hardware Register MAP */
|
||||||
int irq; /* IRQ number of TC core */
|
int irq; /* IRQ number of TC core */
|
||||||
|
SPIN_DECLARE(devlock); /* spin-lock of registers */
|
||||||
|
|
||||||
int major; /* Driver major */
|
int major; /* Driver major */
|
||||||
int minor; /* Device Minor */
|
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);
|
sprintf(priv->devName, "/dev/%sgrtc%d", prefix, dev->minor_bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SPIN_INIT(&priv->devlock, priv->devName);
|
||||||
|
|
||||||
/* Register Device */
|
/* Register Device */
|
||||||
status = rtems_io_register_name(priv->devName, grtc_driver_io_major, dev->minor_drv);
|
status = rtems_io_register_name(priv->devName, grtc_driver_io_major, dev->minor_drv);
|
||||||
if (status != RTEMS_SUCCESSFUL) {
|
if (status != RTEMS_SUCCESSFUL) {
|
||||||
@@ -703,9 +709,12 @@ static int grtc_start(struct grtc_priv *pDev)
|
|||||||
return 0;
|
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;
|
struct grtc_regs *regs = pDev->regs;
|
||||||
|
SPIN_IRQFLAGS(irqflags);
|
||||||
|
|
||||||
|
SPIN_LOCK_IRQ(&pDev->devlock, irqflags);
|
||||||
|
|
||||||
/* Disable the receiver */
|
/* Disable the receiver */
|
||||||
regs->cor = GRTC_SEB;
|
regs->cor = GRTC_SEB;
|
||||||
@@ -717,6 +726,14 @@ static void grtc_stop(struct grtc_priv *pDev)
|
|||||||
|
|
||||||
DBG("GRTC: STOPPED\n");
|
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) */
|
/* Flush semaphores in case a thread is stuck waiting for CLTUs (RX data) */
|
||||||
rtems_semaphore_flush(pDev->sem_rx);
|
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 avail;
|
||||||
int ret;
|
int ret;
|
||||||
IRQ_GLOBAL_PREPARE(oldLevel);
|
SPIN_IRQFLAGS(irqflags);
|
||||||
|
|
||||||
FUNCDBG();
|
FUNCDBG();
|
||||||
|
|
||||||
if ( count < 1 )
|
if ( count < 1 )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
IRQ_GLOBAL_DISABLE(oldLevel);
|
SPIN_LOCK_IRQ(&pDev->devlock, irqflags);
|
||||||
|
|
||||||
/* Enable interrupts when receiving CLTUs, Also clear old pending CLTUs store
|
/* Enable interrupts when receiving CLTUs, Also clear old pending CLTUs store
|
||||||
* interrupts.
|
* interrupts.
|
||||||
@@ -747,7 +764,7 @@ static int grtc_wait_data(struct grtc_priv *pDev, int count, rtems_interval time
|
|||||||
if ( avail < count ) {
|
if ( avail < count ) {
|
||||||
/* Wait for interrupt. */
|
/* Wait for interrupt. */
|
||||||
|
|
||||||
IRQ_GLOBAL_ENABLE(oldLevel);
|
SPIN_UNLOCK_IRQ(&pDev->devlock, irqflags);
|
||||||
|
|
||||||
if ( timeout == 0 ){
|
if ( timeout == 0 ){
|
||||||
timeout = RTEMS_NO_TIMEOUT;
|
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.
|
* which should cancel this operation.
|
||||||
* RTEMS_OBJECT_WAS_DELETED, RTEMS_INVALID_ID = driver error.
|
* RTEMS_OBJECT_WAS_DELETED, RTEMS_INVALID_ID = driver error.
|
||||||
*/
|
*/
|
||||||
IRQ_GLOBAL_DISABLE(oldLevel);
|
SPIN_LOCK_IRQ(&pDev->devlock, irqflags);
|
||||||
}else{
|
}else{
|
||||||
ret = RTEMS_SUCCESSFUL;
|
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 */
|
/* Disable interrupts when receiving CLTUs */
|
||||||
pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRTC_INT_CS;
|
pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRTC_INT_CS;
|
||||||
|
|
||||||
IRQ_GLOBAL_ENABLE(oldLevel);
|
SPIN_UNLOCK_IRQ(&pDev->devlock, irqflags);
|
||||||
|
|
||||||
return ret;
|
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;
|
pDev = (struct grtc_priv *)dev->priv;
|
||||||
|
|
||||||
if ( pDev->running ){
|
if ( pDev->running ){
|
||||||
grtc_stop(pDev);
|
grtc_stop(pDev, 0);
|
||||||
pDev->running = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset core */
|
/* 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_list *frmlist;
|
||||||
struct grtc_ioc_stats *stats;
|
struct grtc_ioc_stats *stats;
|
||||||
unsigned int mem;
|
unsigned int mem;
|
||||||
|
IRQ_LOCAL_DECLARE(oldLevel);
|
||||||
IRQ_GLOBAL_PREPARE(oldLevel);
|
|
||||||
|
|
||||||
FUNCDBG();
|
FUNCDBG();
|
||||||
|
|
||||||
@@ -1575,8 +1590,7 @@ static rtems_device_driver grtc_ioctl(rtems_device_major_number major, rtems_dev
|
|||||||
return RTEMS_RESOURCE_IN_USE;
|
return RTEMS_RESOURCE_IN_USE;
|
||||||
}
|
}
|
||||||
drvmgr_interrupt_unregister(pDev->dev, 0, grtc_interrupt, pDev);
|
drvmgr_interrupt_unregister(pDev->dev, 0, grtc_interrupt, pDev);
|
||||||
grtc_stop(pDev);
|
grtc_stop(pDev, 0);
|
||||||
pDev->running = 0;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GRTC_IOC_ISSTARTED:
|
case GRTC_IOC_ISSTARTED:
|
||||||
@@ -1716,15 +1730,17 @@ static rtems_device_driver grtc_ioctl(rtems_device_major_number major, rtems_dev
|
|||||||
if ( !hwregs ) {
|
if ( !hwregs ) {
|
||||||
return RTEMS_INVALID_NAME;
|
return RTEMS_INVALID_NAME;
|
||||||
}
|
}
|
||||||
/* We disable interrupt in order to get a snapshot of the registers */
|
/* We disable interrupt on the local CPU in order to get a
|
||||||
IRQ_GLOBAL_DISABLE(oldLevel);
|
* snapshot of the registers.
|
||||||
|
*/
|
||||||
|
IRQ_LOCAL_DISABLE(oldLevel);
|
||||||
hwregs->sir = READ_REG(&pDev->regs->sir);
|
hwregs->sir = READ_REG(&pDev->regs->sir);
|
||||||
hwregs->far = READ_REG(&pDev->regs->far);
|
hwregs->far = READ_REG(&pDev->regs->far);
|
||||||
hwregs->clcw1 = READ_REG(&pDev->regs->clcw1);
|
hwregs->clcw1 = READ_REG(&pDev->regs->clcw1);
|
||||||
hwregs->clcw2 = READ_REG(&pDev->regs->clcw2);
|
hwregs->clcw2 = READ_REG(&pDev->regs->clcw2);
|
||||||
hwregs->phir = READ_REG(&pDev->regs->phir);
|
hwregs->phir = READ_REG(&pDev->regs->phir);
|
||||||
hwregs->str = READ_REG(&pDev->regs->str);
|
hwregs->str = READ_REG(&pDev->regs->str);
|
||||||
IRQ_GLOBAL_ENABLE(oldLevel);
|
IRQ_LOCAL_ENABLE(oldLevel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GRTC_IOC_GET_STATS:
|
case GRTC_IOC_GET_STATS:
|
||||||
@@ -1897,6 +1913,7 @@ static void grtc_interrupt(void *arg)
|
|||||||
struct grtc_priv *pDev = arg;
|
struct grtc_priv *pDev = arg;
|
||||||
struct grtc_regs *regs = pDev->regs;
|
struct grtc_regs *regs = pDev->regs;
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
|
SPIN_ISR_IRQFLAGS(irqflags);
|
||||||
|
|
||||||
/* Clear interrupt by reading it */
|
/* Clear interrupt by reading it */
|
||||||
status = READ_REG(®s->pisr);
|
status = READ_REG(®s->pisr);
|
||||||
@@ -1906,36 +1923,36 @@ static void grtc_interrupt(void *arg)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if ( status & GRTC_INT_OV ){
|
if ( status & GRTC_INT_OV ){
|
||||||
|
|
||||||
/* Stop core (Disable receiver, interrupts), set overrun condition,
|
/* Stop core (Disable receiver, interrupts), set overrun condition,
|
||||||
* Flush semaphore if thread waiting for data in grtc_wait_data().
|
* Flush semaphore if thread waiting for data in grtc_wait_data().
|
||||||
*/
|
*/
|
||||||
pDev->overrun_condition = 1;
|
grtc_stop(pDev, 1);
|
||||||
|
|
||||||
grtc_stop(pDev);
|
|
||||||
|
|
||||||
/* No need to handle the reset of interrupts, we are still */
|
/* No need to handle the reset of interrupts, we are still */
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( status & GRTC_INT_CS ){
|
if ( status & GRTC_INT_CS ){
|
||||||
|
SPIN_LOCK(&pDev->devlock, irqflags);
|
||||||
|
|
||||||
if ( (pDev->blocking==GRTC_BLKMODE_COMPLETE) && pDev->timeout ){
|
if ( (pDev->blocking==GRTC_BLKMODE_COMPLETE) && pDev->timeout ){
|
||||||
/* Signal to thread only if enough data is available */
|
/* Signal to thread only if enough data is available */
|
||||||
if ( pDev->wait_for_nbytes > grtc_data_avail(pDev) ){
|
if ( pDev->wait_for_nbytes > grtc_data_avail(pDev) ){
|
||||||
/* Not enough data available */
|
/* Not enough data available */
|
||||||
goto procceed_processing_interrupts;
|
goto procceed_processing_interrupts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enough data is available which means that we should wake
|
/* Enough data is available which means that we should
|
||||||
* up thread sleeping.
|
* wake up the thread sleeping.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable further CLTUs Stored interrupts, no point until thread waiting for them
|
/* Disable further CLTUs Stored interrupts, no point until
|
||||||
* say it want to wait for more.
|
* thread waiting for them says it want to wait for more.
|
||||||
*/
|
*/
|
||||||
regs->imr = READ_REG(®s->imr) & ~GRTC_INT_CS;
|
regs->imr = READ_REG(®s->imr) & ~GRTC_INT_CS;
|
||||||
|
SPIN_UNLOCK(&pDev->devlock, irqflags);
|
||||||
|
|
||||||
/* Signal Semaphore to wake waiting thread in read() */
|
/* Signal Semaphore to wake waiting thread in read() */
|
||||||
rtems_semaphore_release(pDev->sem_rx);
|
rtems_semaphore_release(pDev->sem_rx);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user