In current spdifrx driver locks may be requested as follows: - request lock on iec capture control, when starting synchronization. - request lock in interrupt context, when spdifrx stop is called from IRQ handler.
Take lock with IRQs disabled, to avoid the possible deadlock.
Lockdep report: [ 74.278059] ================================ [ 74.282306] WARNING: inconsistent lock state [ 74.290120] -------------------------------- ... [ 74.314373] CPU0 [ 74.314377] ---- [ 74.314381] lock(&(&spdifrx->lock)->rlock); [ 74.314396] <Interrupt> [ 74.314400] lock(&(&spdifrx->lock)->rlock);
Fixes: 03e4d5d56fa5 ("ASoC: stm32: Add SPDIFRX support")
Signed-off-by: Olivier Moysan olivier.moysan@st.com --- sound/soc/stm/stm32_spdifrx.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index 3fd28ee01675..9c6beb610c17 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -320,6 +320,7 @@ static void stm32_spdifrx_dma_ctrl_stop(struct stm32_spdifrx_data *spdifrx) static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) { int cr, cr_mask, imr, ret; + unsigned long flags;
/* Enable IRQs */ imr = SPDIFRX_IMR_IFEIE | SPDIFRX_IMR_SYNCDIE | SPDIFRX_IMR_PERRIE; @@ -327,7 +328,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) if (ret) return ret;
- spin_lock(&spdifrx->lock); + spin_lock_irqsave(&spdifrx->lock, flags);
spdifrx->refcount++;
@@ -362,7 +363,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) "Failed to start synchronization\n"); }
- spin_unlock(&spdifrx->lock); + spin_unlock_irqrestore(&spdifrx->lock, flags);
return ret; } @@ -370,11 +371,12 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) { int cr, cr_mask, reg; + unsigned long flags;
- spin_lock(&spdifrx->lock); + spin_lock_irqsave(&spdifrx->lock, flags);
if (--spdifrx->refcount) { - spin_unlock(&spdifrx->lock); + spin_unlock_irqrestore(&spdifrx->lock, flags); return; }
@@ -393,7 +395,7 @@ static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) regmap_read(spdifrx->regmap, STM32_SPDIFRX_DR, ®); regmap_read(spdifrx->regmap, STM32_SPDIFRX_CSR, ®);
- spin_unlock(&spdifrx->lock); + spin_unlock_irqrestore(&spdifrx->lock, flags); }
static int stm32_spdifrx_dma_ctrl_register(struct device *dev,