forked from Imagelibrary/rtems
leon, grcan: fixed race on interrupt mask register
There was a potential read-modify-write race on the interrupt mask (imr) register between the ISR and user functions.
This commit is contained in:
committed by
Daniel Hellstrom
parent
5d367c56cf
commit
057496906f
@@ -1712,6 +1712,7 @@ int grcan_set_afilter(void *d, const struct grcan_filter *filter)
|
|||||||
int grcan_set_sfilter(void *d, const struct grcan_filter *filter)
|
int grcan_set_sfilter(void *d, const struct grcan_filter *filter)
|
||||||
{
|
{
|
||||||
struct grcan_priv *pDev = d;
|
struct grcan_priv *pDev = d;
|
||||||
|
SPIN_IRQFLAGS(oldLevel);
|
||||||
|
|
||||||
FUNCDBG();
|
FUNCDBG();
|
||||||
|
|
||||||
@@ -1721,13 +1722,17 @@ int grcan_set_sfilter(void *d, const struct grcan_filter *filter)
|
|||||||
pDev->sfilter.mask = 0;
|
pDev->sfilter.mask = 0;
|
||||||
|
|
||||||
/* disable Sync interrupt */
|
/* disable Sync interrupt */
|
||||||
|
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
|
||||||
pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~(GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ);
|
pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~(GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ);
|
||||||
|
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
|
||||||
}else{
|
}else{
|
||||||
/* Save filter */
|
/* Save filter */
|
||||||
pDev->sfilter = *filter;
|
pDev->sfilter = *filter;
|
||||||
|
|
||||||
/* Enable Sync interrupt */
|
/* Enable Sync interrupt */
|
||||||
|
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
|
||||||
pDev->regs->imr = READ_REG(&pDev->regs->imr) | (GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ);
|
pDev->regs->imr = READ_REG(&pDev->regs->imr) | (GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ);
|
||||||
|
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
|
||||||
}
|
}
|
||||||
/* Set Sync RX/TX filter */
|
/* Set Sync RX/TX filter */
|
||||||
grcan_hw_sync(pDev->regs,&pDev->sfilter);
|
grcan_hw_sync(pDev->regs,&pDev->sfilter);
|
||||||
@@ -1756,6 +1761,7 @@ static void grcan_interrupt(void *arg)
|
|||||||
struct grcan_priv *pDev = arg;
|
struct grcan_priv *pDev = arg;
|
||||||
unsigned int status = READ_REG(&pDev->regs->pimsr);
|
unsigned int status = READ_REG(&pDev->regs->pimsr);
|
||||||
unsigned int canstat = READ_REG(&pDev->regs->stat);
|
unsigned int canstat = READ_REG(&pDev->regs->stat);
|
||||||
|
SPIN_ISR_IRQFLAGS(irqflags);
|
||||||
|
|
||||||
/* Spurious IRQ call? */
|
/* Spurious IRQ call? */
|
||||||
if ( !status && !canstat )
|
if ( !status && !canstat )
|
||||||
@@ -1777,8 +1783,10 @@ static void grcan_interrupt(void *arg)
|
|||||||
* that is blocked in read/write calls and stop futher calls
|
* that is blocked in read/write calls and stop futher calls
|
||||||
* to read/write until user has called ioctl(fd,START,0).
|
* to read/write until user has called ioctl(fd,START,0).
|
||||||
*/
|
*/
|
||||||
|
SPIN_LOCK(&pDev->devlock, irqflags);
|
||||||
pDev->started = 0;
|
pDev->started = 0;
|
||||||
grcan_hw_stop(pDev); /* this mask all IRQ sources */
|
grcan_hw_stop(pDev); /* this mask all IRQ sources */
|
||||||
|
SPIN_UNLOCK(&pDev->devlock, irqflags);
|
||||||
status=0x1ffff; /* clear all interrupts */
|
status=0x1ffff; /* clear all interrupts */
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -1803,13 +1811,17 @@ static void grcan_interrupt(void *arg)
|
|||||||
if ( status & GRCAN_RXIRQ_IRQ ){
|
if ( status & GRCAN_RXIRQ_IRQ ){
|
||||||
/* RX IRQ pointer interrupt */
|
/* RX IRQ pointer interrupt */
|
||||||
/*printk("RxIrq 0x%x\n",status);*/
|
/*printk("RxIrq 0x%x\n",status);*/
|
||||||
|
SPIN_LOCK(&pDev->devlock, irqflags);
|
||||||
pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_RXIRQ_IRQ;
|
pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_RXIRQ_IRQ;
|
||||||
|
SPIN_UNLOCK(&pDev->devlock, irqflags);
|
||||||
rtems_semaphore_release(pDev->rx_sem);
|
rtems_semaphore_release(pDev->rx_sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( status & GRCAN_TXIRQ_IRQ ){
|
if ( status & GRCAN_TXIRQ_IRQ ){
|
||||||
/* TX IRQ pointer interrupt */
|
/* TX IRQ pointer interrupt */
|
||||||
|
SPIN_LOCK(&pDev->devlock, irqflags);
|
||||||
pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXIRQ_IRQ;
|
pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXIRQ_IRQ;
|
||||||
|
SPIN_UNLOCK(&pDev->devlock, irqflags);
|
||||||
rtems_semaphore_release(pDev->tx_sem);
|
rtems_semaphore_release(pDev->tx_sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1824,7 +1836,9 @@ static void grcan_interrupt(void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( status & GRCAN_TXEMPTY_IRQ ){
|
if ( status & GRCAN_TXEMPTY_IRQ ){
|
||||||
|
SPIN_LOCK(&pDev->devlock, irqflags);
|
||||||
pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXEMPTY_IRQ;
|
pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRCAN_TXEMPTY_IRQ;
|
||||||
|
SPIN_UNLOCK(&pDev->devlock, irqflags);
|
||||||
rtems_semaphore_release(pDev->txempty_sem);
|
rtems_semaphore_release(pDev->txempty_sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user