[alsa-devel] [PATCH 0/4] ASoC: rsnd: fixup interrupt / spin lock issue
Hi Mark, Vinod Cc Laurent
These patches fixup unknown interrupt issue which was reported by Hiep-san in v4.1-rcX kernel. It was not happened in v4.0 because ARM platform side couldn't use DMA transfer.
--------- Unable to handle kernel NULL pointer dereference at virtual address 00000048 pgd = edfac000 [00000048] *pgd=6e0f0831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] SMP ARM CPU: 0 PID: 2009 Comm: aplay Not tainted 4.1.0-rc2-dirty #4 Hardware name: Generic R8A7790 (Flattened Device Tree) ... --------
Renesas sound driver had 2 issues. [1] spin lock was unlocked un-expected timing [2] HW restart (when error timing) is called without spin lock
In our environment, it was difficult to reproduce this error, because it happens in very rare timing. But I noticed it is easy to reproduce it if I added this setting.
[Kernel hacking] - [Lock Debugging] - all ON
And we decided this error has gone by these tests.
Test1: reproduce error
1. start / stop sound playback in 100 times 2. count error 3. test above in 10 sets
result: 100% error happen. In average, this error happens once during 5 playbacks.
Test2: apply these fixup patces, and retry Test1
result: 0 error happen.
Kuninori Morimoto (4): 1) dmaengine: rcar-dmac: fixup spinlock in rcar-dmac 2) ASoC: rsnd: indicate unknown HW start 3) ASoC: rsnd: add rsnd_dai_stream_quit() 4) ASoC: rsnd: spin lock for interrupt handler
drivers/dma/sh/rcar-dmac.c | 55 +++++++++++++++++++++++++++++++------------------------ sound/soc/sh/rcar/core.c | 25 ++++++++++++++++++------- sound/soc/sh/rcar/rsnd.h | 3 +-- sound/soc/sh/rcar/src.c | 11 ++++++++--- sound/soc/sh/rcar/ssi.c | 18 ++++++++++++++---- 5 files changed, 72 insertions(+), 40 deletions(-)
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Current rcar-dmac driver is using spin_lock_irq() / spin_unlock_irq() in some functions. But, some other driver might call DMAEngine API during interrupt disabled. In such case, rcar-dmac side spin_unlock_irq() forcefully allows all interrupts. Therefore, other driver receives unexpected interruption, and its exclusive access control will be broken. This patch replaces spin_lock_irq() to spin_lock_irqsave(), and spin_unlock_irq() to spin_unlock_irqrestore().
Reported-by: Cao Minh Hiep cm-hiep@jinso.co.jp Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Tested-by: Keita Kobayashi keita.kobayashi.ym@renesas.com --- drivers/dma/sh/rcar-dmac.c | 55 ++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 24 deletions(-)
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index a18d16c..6a5d4b9 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -465,6 +465,7 @@ static dma_cookie_t rcar_dmac_tx_submit(struct dma_async_tx_descriptor *tx) static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp) { struct rcar_dmac_desc_page *page; + unsigned long flags; LIST_HEAD(list); unsigned int i;
@@ -482,10 +483,10 @@ static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp) list_add_tail(&desc->node, &list); }
- spin_lock_irq(&chan->lock); + spin_lock_irqsave(&chan->lock, flags); list_splice_tail(&list, &chan->desc.free); list_add_tail(&page->node, &chan->desc.pages); - spin_unlock_irq(&chan->lock); + spin_unlock_irqrestore(&chan->lock, flags);
return 0; } @@ -516,6 +517,7 @@ static void rcar_dmac_desc_put(struct rcar_dmac_chan *chan, static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan) { struct rcar_dmac_desc *desc, *_desc; + unsigned long flags; LIST_HEAD(list);
/* @@ -524,9 +526,9 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan) * list_for_each_entry_safe, isn't safe if we release the channel lock * around the rcar_dmac_desc_put() call. */ - spin_lock_irq(&chan->lock); + spin_lock_irqsave(&chan->lock, flags); list_splice_init(&chan->desc.wait, &list); - spin_unlock_irq(&chan->lock); + spin_unlock_irqrestore(&chan->lock, flags);
list_for_each_entry_safe(desc, _desc, &list, node) { if (async_tx_test_ack(&desc->async_tx)) { @@ -539,9 +541,9 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan) return;
/* Put the remaining descriptors back in the wait list. */ - spin_lock_irq(&chan->lock); + spin_lock_irqsave(&chan->lock, flags); list_splice(&list, &chan->desc.wait); - spin_unlock_irq(&chan->lock); + spin_unlock_irqrestore(&chan->lock, flags); }
/* @@ -556,12 +558,13 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan) static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan) { struct rcar_dmac_desc *desc; + unsigned long flags; int ret;
/* Recycle acked descriptors before attempting allocation. */ rcar_dmac_desc_recycle_acked(chan);
- spin_lock_irq(&chan->lock); + spin_lock_irqsave(&chan->lock, flags);
while (list_empty(&chan->desc.free)) { /* @@ -570,17 +573,17 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan) * allocated descriptors. If the allocation fails return an * error. */ - spin_unlock_irq(&chan->lock); + spin_unlock_irqrestore(&chan->lock, flags); ret = rcar_dmac_desc_alloc(chan, GFP_NOWAIT); if (ret < 0) return NULL; - spin_lock_irq(&chan->lock); + spin_lock_irqsave(&chan->lock, flags); }
desc = list_first_entry(&chan->desc.free, struct rcar_dmac_desc, node); list_del(&desc->node);
- spin_unlock_irq(&chan->lock); + spin_unlock_irqrestore(&chan->lock, flags);
return desc; } @@ -593,6 +596,7 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan) static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp) { struct rcar_dmac_desc_page *page; + unsigned long flags; LIST_HEAD(list); unsigned int i;
@@ -606,10 +610,10 @@ static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp) list_add_tail(&chunk->node, &list); }
- spin_lock_irq(&chan->lock); + spin_lock_irqsave(&chan->lock, flags); list_splice_tail(&list, &chan->desc.chunks_free); list_add_tail(&page->node, &chan->desc.pages); - spin_unlock_irq(&chan->lock); + spin_unlock_irqrestore(&chan->lock, flags);
return 0; } @@ -627,9 +631,10 @@ static struct rcar_dmac_xfer_chunk * rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan) { struct rcar_dmac_xfer_chunk *chunk; + unsigned long flags; int ret;
- spin_lock_irq(&chan->lock); + spin_lock_irqsave(&chan->lock, flags);
while (list_empty(&chan->desc.chunks_free)) { /* @@ -638,18 +643,18 @@ rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan) * allocated descriptors. If the allocation fails return an * error. */ - spin_unlock_irq(&chan->lock); + spin_unlock_irqrestore(&chan->lock, flags); ret = rcar_dmac_xfer_chunk_alloc(chan, GFP_NOWAIT); if (ret < 0) return NULL; - spin_lock_irq(&chan->lock); + spin_lock_irqsave(&chan->lock, flags); }
chunk = list_first_entry(&chan->desc.chunks_free, struct rcar_dmac_xfer_chunk, node); list_del(&chunk->node);
- spin_unlock_irq(&chan->lock); + spin_unlock_irqrestore(&chan->lock, flags);
return chunk; } @@ -964,12 +969,13 @@ static void rcar_dmac_free_chan_resources(struct dma_chan *chan) struct rcar_dmac *dmac = to_rcar_dmac(chan->device); struct rcar_dmac_desc_page *page, *_page; struct rcar_dmac_desc *desc; + unsigned long flags; LIST_HEAD(list);
/* Protect against ISR */ - spin_lock_irq(&rchan->lock); + spin_lock_irqsave(&rchan->lock, flags); rcar_dmac_chan_halt(rchan); - spin_unlock_irq(&rchan->lock); + spin_unlock_irqrestore(&rchan->lock, flags);
/* Now no new interrupts will occur */
@@ -1351,8 +1357,9 @@ static irqreturn_t rcar_dmac_isr_channel_thread(int irq, void *dev) { struct rcar_dmac_chan *chan = dev; struct rcar_dmac_desc *desc; + unsigned long flags;
- spin_lock_irq(&chan->lock); + spin_lock_irqsave(&chan->lock, flags);
/* For cyclic transfers notify the user after every chunk. */ if (chan->desc.running && chan->desc.running->cyclic) { @@ -1364,9 +1371,9 @@ static irqreturn_t rcar_dmac_isr_channel_thread(int irq, void *dev) callback_param = desc->async_tx.callback_param;
if (callback) { - spin_unlock_irq(&chan->lock); + spin_unlock_irqrestore(&chan->lock, flags); callback(callback_param); - spin_lock_irq(&chan->lock); + spin_lock_irqsave(&chan->lock, flags); } }
@@ -1381,20 +1388,20 @@ static irqreturn_t rcar_dmac_isr_channel_thread(int irq, void *dev) list_del(&desc->node);
if (desc->async_tx.callback) { - spin_unlock_irq(&chan->lock); + spin_unlock_irqrestore(&chan->lock, flags); /* * We own the only reference to this descriptor, we can * safely dereference it without holding the channel * lock. */ desc->async_tx.callback(desc->async_tx.callback_param); - spin_lock_irq(&chan->lock); + spin_lock_irqsave(&chan->lock, flags); }
list_add_tail(&desc->node, &chan->desc.wait); }
- spin_unlock_irq(&chan->lock); + spin_unlock_irqrestore(&chan->lock, flags);
/* Recycle all acked descriptors. */ rcar_dmac_desc_recycle_acked(chan);
Hi Morimoto-san,
Thank you for the patch.
On Wednesday 20 May 2015 03:46:19 Kuninori Morimoto wrote:
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Current rcar-dmac driver is using spin_lock_irq() / spin_unlock_irq() in some functions. But, some other driver might call DMAEngine API during interrupt disabled. In such case, rcar-dmac side spin_unlock_irq() forcefully allows all interrupts. Therefore, other driver receives unexpected interruption, and its exclusive access control will be broken. This patch replaces spin_lock_irq() to spin_lock_irqsave(), and spin_unlock_irq() to spin_unlock_irqrestore().
I would have sworn I had fixed the issue already :-/ Sorry about it.
I believe (part of) the issue should be fixed in the DMA engine API by splitting descriptor allocation to non-atomic context, but that's a longer term solution of course, out of scope for this series.
The patch looks good, please see below for a couple of comments.
Reported-by: Cao Minh Hiep cm-hiep@jinso.co.jp Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Tested-by: Keita Kobayashi keita.kobayashi.ym@renesas.com
drivers/dma/sh/rcar-dmac.c | 55 +++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 24 deletions(-)
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index a18d16c..6a5d4b9 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c
[snip]
@@ -964,12 +969,13 @@ static void rcar_dmac_free_chan_resources(struct dma_chan *chan) struct rcar_dmac *dmac = to_rcar_dmac(chan->device); struct rcar_dmac_desc_page *page, *_page; struct rcar_dmac_desc *desc;
unsigned long flags; LIST_HEAD(list);
/* Protect against ISR */
- spin_lock_irq(&rchan->lock);
- spin_lock_irqsave(&rchan->lock, flags);
The .device_free_chan_resources() can't be called with interrupts disabled, so we should be safe with spin_lock_irq() here. However, as the function isn't called in a performance-critical path, I'm fine with spin_lock_irqsave() too.
rcar_dmac_chan_halt(rchan);
- spin_unlock_irq(&rchan->lock);
spin_unlock_irqrestore(&rchan->lock, flags);
/* Now no new interrupts will occur */
@@ -1351,8 +1357,9 @@ static irqreturn_t rcar_dmac_isr_channel_thread(int irq, void *dev) { struct rcar_dmac_chan *chan = dev; struct rcar_dmac_desc *desc;
- unsigned long flags;
- spin_lock_irq(&chan->lock);
- spin_lock_irqsave(&chan->lock, flags);
Isn't the threaded IRQ handler called in a thread with interrupts enabled by definition ? spin_lock_irq() should thus be safe here. You could, however, convince me that spin_lock_irqsave() won't make much of a difference performance-wise, and would allow avoiding future similar bugs.
/* For cyclic transfers notify the user after every chunk. */ if (chan->desc.running && chan->desc.running->cyclic) { @@ -1364,9 +1371,9 @@ static irqreturn_t rcar_dmac_isr_channel_thread(int irq, void *dev) callback_param = desc->async_tx.callback_param;
if (callback) {
spin_unlock_irq(&chan->lock);
spin_unlock_irqrestore(&chan->lock, flags); callback(callback_param);
spin_lock_irq(&chan->lock);
} }spin_lock_irqsave(&chan->lock, flags);
@@ -1381,20 +1388,20 @@ static irqreturn_t rcar_dmac_isr_channel_thread(int irq, void *dev) list_del(&desc->node);
if (desc->async_tx.callback) {
spin_unlock_irq(&chan->lock);
spin_unlock_irqrestore(&chan->lock, flags); /* * We own the only reference to this descriptor, we can * safely dereference it without holding the channel * lock. */ desc->async_tx.callback(desc->async_tx.callback_param);
spin_lock_irq(&chan->lock);
spin_lock_irqsave(&chan->lock, flags);
}
list_add_tail(&desc->node, &chan->desc.wait); }
- spin_unlock_irq(&chan->lock);
spin_unlock_irqrestore(&chan->lock, flags);
/* Recycle all acked descriptors. */ rcar_dmac_desc_recycle_acked(chan);
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
rsnd_ssi_hw_stop() should be called after rsnd_ssi_hw_start(). This patch indicates unknown hw_stop as error
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Tested-by: Keita Kobayashi keita.kobayashi.ym@renesas.com --- sound/soc/sh/rcar/ssi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 5b89723..927ac52 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -232,8 +232,10 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi) struct device *dev = rsnd_priv_to_dev(priv); u32 cr;
- if (0 == ssi->usrcnt) /* stop might be called without start */ + if (0 == ssi->usrcnt) { + dev_err(dev, "%s called without starting\n", __func__); return; + }
ssi->usrcnt--;
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Current Renesas R-Car sound driver calls rsnd_dai_stream_init() when start, but it didn't call paired function. This patch adds rsnd_dai_stream_quit() for it. This is prepare for interrupt error status check feature support.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Tested-by: Keita Kobayashi keita.kobayashi.ym@renesas.com --- sound/soc/sh/rcar/core.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 405cacd..2b7323c 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -315,7 +315,7 @@ void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte) } }
-static int rsnd_dai_stream_init(struct rsnd_dai_stream *io, +static void rsnd_dai_stream_init(struct rsnd_dai_stream *io, struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -327,8 +327,11 @@ static int rsnd_dai_stream_init(struct rsnd_dai_stream *io, runtime->channels * samples_to_bytes(runtime, 1); io->next_period_byte = io->byte_per_period; +}
- return 0; +static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io) +{ + io->substream = NULL; }
static @@ -363,9 +366,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) { case SNDRV_PCM_TRIGGER_START: - ret = rsnd_dai_stream_init(io, substream); - if (ret < 0) - goto dai_trigger_end; + rsnd_dai_stream_init(io, substream);
ret = rsnd_platform_call(priv, dai, start, ssi_id); if (ret < 0) @@ -391,6 +392,8 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, ret = rsnd_platform_call(priv, dai, stop, ssi_id); if (ret < 0) goto dai_trigger_end; + + rsnd_dai_stream_quit(io); break; default: ret = -EINVAL;
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Renesas R-Car driver interrupt handler was not locked before. But now, SSI/SRC interrupt handler calls restart function which should be called under spin lock. Below error might happen witout this patch.
Unable to handle kernel NULL pointer dereference at virtual address 00000048 pgd = edfac000 [00000048] *pgd=6e0f0831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] SMP ARM CPU: 0 PID: 2009 Comm: aplay Not tainted 4.1.0-rc2-dirty #4 Hardware name: Generic R8A7790 (Flattened Device Tree) task: eeac9040 ti: eebe8000 task.ti: eebe8000 PC is at rsnd_get_adinr+0x28/0x60 LR is at rsnd_src_ssiu_start+0xdc/0x19c pc : [<c0409790>] lr : [<c040c068>] psr: a0000193 sp : eebe9e58 ip : eebe9e68 fp : eebe9e64 r10: c06ed9d0 r9 : ee919d10 r8 : 00000001 r7 : 00000001 r6 : ee1cb090 r5 : 00000000 r4 : edcaa418 r3 : 00000000 r2 : eea8ce00 r1 : 80000193 r0 : edcaa418 ...
Reported-by: Cao Minh Hiep cm-hiep@jinso.co.jp Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Tested-by: Keita Kobayashi keita.kobayashi.ym@renesas.com --- sound/soc/sh/rcar/core.c | 12 ++++++++++-- sound/soc/sh/rcar/rsnd.h | 3 +-- sound/soc/sh/rcar/src.c | 11 ++++++++--- sound/soc/sh/rcar/ssi.c | 14 +++++++++++--- 4 files changed, 30 insertions(+), 10 deletions(-)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 2b7323c..d460d2a 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -170,6 +170,14 @@ void rsnd_mod_quit(struct rsnd_mod *mod) clk_unprepare(mod->clk); }
+int rsnd_mod_is_working(struct rsnd_mod *mod) +{ + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + + /* see rsnd_dai_stream_init/quit() */ + return !!io->substream; +} + /* * settting function */ @@ -362,7 +370,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, int ret; unsigned long flags;
- rsnd_lock(priv, flags); + spin_lock_irqsave(&priv->lock, flags);
switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -400,7 +408,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, }
dai_trigger_end: - rsnd_unlock(priv, flags); + spin_unlock_irqrestore(&priv->lock, flags);
return ret; } diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 4e6de68..03ff071 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -303,6 +303,7 @@ int rsnd_mod_init(struct rsnd_mod *mod, int id); void rsnd_mod_quit(struct rsnd_mod *mod); char *rsnd_mod_name(struct rsnd_mod *mod); +int rsnd_mod_is_working(struct rsnd_mod *mod); struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod);
/* @@ -449,8 +450,6 @@ struct rsnd_priv { #define rsnd_priv_to_pdev(priv) ((priv)->pdev) #define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) #define rsnd_priv_to_info(priv) ((priv)->info) -#define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags) -#define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
/* * rsnd_kctrl diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 3beb32e..fbe9166 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -673,10 +673,13 @@ static int _rsnd_src_stop_gen2(struct rsnd_mod *mod) static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data) { struct rsnd_mod *mod = data; - struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + + spin_lock(&priv->lock);
- if (!io) - return IRQ_NONE; + /* ignore all cases if not working */ + if (!rsnd_mod_is_working(mod)) + goto rsnd_src_interrupt_gen2_out;
if (rsnd_src_error_record_gen2(mod)) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); @@ -692,6 +695,8 @@ static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data) else dev_warn(dev, "no more SRC restart\n"); } +rsnd_src_interrupt_gen2_out: + spin_unlock(&priv->lock);
return IRQ_HANDLED; } diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 927ac52..50fa392 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -423,10 +423,15 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); int is_dma = rsnd_ssi_is_dma_mode(mod); - u32 status = rsnd_mod_read(mod, SSISR); + u32 status; + + spin_lock(&priv->lock);
- if (!io) - return IRQ_NONE; + /* ignore all cases if not working */ + if (!rsnd_mod_is_working(mod)) + goto rsnd_ssi_interrupt_out; + + status = rsnd_mod_read(mod, SSISR);
/* PIO only */ if (!is_dma && (status & DIRQ)) { @@ -466,6 +471,9 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
rsnd_ssi_record_error(ssi, status);
+rsnd_ssi_interrupt_out: + spin_unlock(&priv->lock); + return IRQ_HANDLED; }
Hi All
On 2015年05月20日 12:45, Kuninori Morimoto wrote:
Kuninori Morimoto (4): 1) dmaengine: rcar-dmac: fixup spinlock in rcar-dmac 2) ASoC: rsnd: indicate unknown HW start 3) ASoC: rsnd: add rsnd_dai_stream_quit() 4) ASoC: rsnd: spin lock for interrupt handler
drivers/dma/sh/rcar-dmac.c | 55 +++++++++++++++++++++++++++++++------------------------ sound/soc/sh/rcar/core.c | 25 ++++++++++++++++++------- sound/soc/sh/rcar/rsnd.h | 3 +-- sound/soc/sh/rcar/src.c | 11 ++++++++--- sound/soc/sh/rcar/ssi.c | 18 ++++++++++++++---- 5 files changed, 72 insertions(+), 40 deletions(-)
I have just patched these patches and tested them. I tested 40 times with playback and recode (for 4 times restart x 10 times playback and record), It works very well without any problems. I mean these patches fixed our bug of kernel panic when playback.
Tested by: Cao Minh Hiep cm-hiep@jinso.co.jp
Best Regards, Cao Minh Hiep.
participants (3)
-
Cao Minh Hiep
-
Kuninori Morimoto
-
Laurent Pinchart