Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5063469c authored by Olivier Moysan's avatar Olivier Moysan Committed by Greg Kroah-Hartman
Browse files

ASoC: stm32: spdifrx: fix inconsistent lock state



commit 2859b1784031b5709446af8f6039c467f136e67d upstream.

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.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 57f633cf
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -313,6 +313,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;
@@ -320,7 +321,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++;

@@ -353,7 +354,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;
}
@@ -361,11 +362,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;
	}

@@ -384,7 +386,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_CSR, &reg);

	spin_unlock(&spdifrx->lock);
	spin_unlock_irqrestore(&spdifrx->lock, flags);
}

static int stm32_spdifrx_dma_ctrl_register(struct device *dev,