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:
Ville Juven 2025-04-22 12:25:06 +03:00 committed by Xiang Xiao
parent 53d7fab355
commit 72bba3b2ee
2 changed files with 47 additions and 1 deletions

View file

@ -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)

View file

@ -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);