mpfs_emmcsd/coremmc.c: Fix interrupt handling in SMP mode
In SMP mode one CPU can be executing the MMC interrupt while another CPU disables (e.g. via watchdog timeout). As it is disabled the other CPU assumes it's safe to start configuring the device after this. This causes a leak in the driver's private data as well as a mutual exclusion leak on the device itself. Fix this by aborting any triggered interrupt by checking whether it's even enabled. Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This commit is contained in:
parent
53d7fab355
commit
72bba3b2ee
2 changed files with 47 additions and 1 deletions
|
|
@ -654,7 +654,7 @@ static void mpfs_recvfifo(struct mpfs_dev_s *priv)
|
|||
}
|
||||
}
|
||||
|
||||
mcinfo("Read all\n");
|
||||
mcinfo("Read all\n");
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -818,6 +818,22 @@ static int mpfs_coremmc_wrcomplete_interrupt(int irq, void *context,
|
|||
|
||||
DEBUGASSERT(priv != NULL);
|
||||
|
||||
#ifdef CONFIG_SPINLOCK
|
||||
spin_lock(&priv->lock);
|
||||
|
||||
/* Check if the write complete event is enabled */
|
||||
|
||||
if ((priv->waitevents & SDIOWAIT_WRCOMPLETE) == 0)
|
||||
{
|
||||
spin_unlock(&priv->lock);
|
||||
return OK;
|
||||
}
|
||||
|
||||
spin_unlock(&priv->lock);
|
||||
#endif
|
||||
|
||||
/* Note: the spin lock must NOT be held when calling mpfs_endwait */
|
||||
|
||||
mpfs_endwait(priv, SDIOWAIT_WRCOMPLETE);
|
||||
|
||||
return OK;
|
||||
|
|
@ -846,6 +862,22 @@ static int mpfs_coremmc_interrupt(int irq, void *context, void *arg)
|
|||
|
||||
DEBUGASSERT(priv != NULL);
|
||||
|
||||
#ifdef CONFIG_SPINLOCK
|
||||
spin_lock(&priv->lock);
|
||||
|
||||
/* Check if any of the interrupt sources are even enabled */
|
||||
|
||||
if (priv->xfrmask == 0 && priv->waitmask == 0 && priv->xfr_blkmask == 0)
|
||||
{
|
||||
spin_unlock(&priv->lock);
|
||||
return OK;
|
||||
}
|
||||
|
||||
spin_unlock(&priv->lock);
|
||||
#endif
|
||||
|
||||
/* Note: the spin lock must NOT be held when calling mpfs_endtransfer */
|
||||
|
||||
status = getreg8(MPFS_COREMMC_ISR);
|
||||
|
||||
if (priv->multiblock)
|
||||
|
|
|
|||
|
|
@ -986,6 +986,20 @@ static int mpfs_emmcsd_interrupt(int irq, void *context, void *arg)
|
|||
|
||||
DEBUGASSERT(priv != NULL);
|
||||
|
||||
#ifdef CONFIG_SPINLOCK
|
||||
spin_lock(&priv->lock);
|
||||
|
||||
/* Check if any of the interrupt sources are even enabled */
|
||||
|
||||
if (priv->xfrmask == 0 && priv->waitmask == 0 && priv->xfr_blkmask == 0)
|
||||
{
|
||||
spin_unlock(&priv->lock);
|
||||
return OK;
|
||||
}
|
||||
|
||||
spin_unlock(&priv->lock);
|
||||
#endif
|
||||
|
||||
status = getreg32(MPFS_EMMCSD_SRS12);
|
||||
|
||||
mcinfo("status: %08" PRIx32 "\n", status);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue