]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
ASoC: stm32: spdifrx: fix inconsistent lock state
authorOlivier Moysan <olivier.moysan@st.com>
Wed, 4 Dec 2019 15:43:31 +0000 (16:43 +0100)
committerKhalid Elmously <khalid.elmously@canonical.com>
Fri, 14 Feb 2020 05:29:37 +0000 (00:29 -0500)
BugLink: https://bugs.launchpad.net/bugs/1861934
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: 03e4d5d56fa5 ("ASoC: stm32: Add SPDIFRX support")
Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Link: https://lore.kernel.org/r/20191204154333.7152-2-olivier.moysan@st.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
sound/soc/stm/stm32_spdifrx.c

index b9bdefcd3e104a7f138803200be77b51648c1802..efcbee35743a990d8aaa114438e32c7a81e0c1c6 100644 (file)
@@ -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,