Commit 2859b178 authored by Olivier Moysan's avatar Olivier Moysan Committed by Mark Brown

ASoC: stm32: spdifrx: fix inconsistent lock state

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: 03e4d5d5 ("ASoC: stm32: Add SPDIFRX support")
Signed-off-by: default avatarOlivier Moysan <olivier.moysan@st.com>
Link: https://lore.kernel.org/r/20191204154333.7152-2-olivier.moysan@st.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 07d22a9b
...@@ -320,6 +320,7 @@ static void stm32_spdifrx_dma_ctrl_stop(struct stm32_spdifrx_data *spdifrx) ...@@ -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) static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx)
{ {
int cr, cr_mask, imr, ret; int cr, cr_mask, imr, ret;
unsigned long flags;
/* Enable IRQs */ /* Enable IRQs */
imr = SPDIFRX_IMR_IFEIE | SPDIFRX_IMR_SYNCDIE | SPDIFRX_IMR_PERRIE; 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) ...@@ -327,7 +328,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx)
if (ret) if (ret)
return ret; return ret;
spin_lock(&spdifrx->lock); spin_lock_irqsave(&spdifrx->lock, flags);
spdifrx->refcount++; spdifrx->refcount++;
...@@ -362,7 +363,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) ...@@ -362,7 +363,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx)
"Failed to start synchronization\n"); "Failed to start synchronization\n");
} }
spin_unlock(&spdifrx->lock); spin_unlock_irqrestore(&spdifrx->lock, flags);
return ret; return ret;
} }
...@@ -370,11 +371,12 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) ...@@ -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) static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx)
{ {
int cr, cr_mask, reg; int cr, cr_mask, reg;
unsigned long flags;
spin_lock(&spdifrx->lock); spin_lock_irqsave(&spdifrx->lock, flags);
if (--spdifrx->refcount) { if (--spdifrx->refcount) {
spin_unlock(&spdifrx->lock); spin_unlock_irqrestore(&spdifrx->lock, flags);
return; return;
} }
...@@ -393,7 +395,7 @@ static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) ...@@ -393,7 +395,7 @@ static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx)
regmap_read(spdifrx->regmap, STM32_SPDIFRX_DR, &reg); regmap_read(spdifrx->regmap, STM32_SPDIFRX_DR, &reg);
regmap_read(spdifrx->regmap, STM32_SPDIFRX_CSR, &reg); regmap_read(spdifrx->regmap, STM32_SPDIFRX_CSR, &reg);
spin_unlock(&spdifrx->lock); spin_unlock_irqrestore(&spdifrx->lock, flags);
} }
static int stm32_spdifrx_dma_ctrl_register(struct device *dev, static int stm32_spdifrx_dma_ctrl_register(struct device *dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment