Commit 02299d98 authored by Kuninori Morimoto's avatar Kuninori Morimoto Committed by Mark Brown

ASoC: rsnd: spin lock for interrupt handler

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: default avatarCao Minh Hiep <cm-hiep@jinso.co.jp>
Signed-off-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Tested-by: default avatarKeita Kobayashi <keita.kobayashi.ym@renesas.com>
Tested by: Cao Minh Hiep <cm-hiep@jinso.co.jp>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent e8a07d60
...@@ -170,6 +170,14 @@ void rsnd_mod_quit(struct rsnd_mod *mod) ...@@ -170,6 +170,14 @@ void rsnd_mod_quit(struct rsnd_mod *mod)
clk_unprepare(mod->clk); 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 * settting function
*/ */
...@@ -362,7 +370,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -362,7 +370,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
int ret; int ret;
unsigned long flags; unsigned long flags;
rsnd_lock(priv, flags); spin_lock_irqsave(&priv->lock, flags);
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
...@@ -400,7 +408,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -400,7 +408,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
} }
dai_trigger_end: dai_trigger_end:
rsnd_unlock(priv, flags); spin_unlock_irqrestore(&priv->lock, flags);
return ret; return ret;
} }
......
...@@ -303,6 +303,7 @@ int rsnd_mod_init(struct rsnd_mod *mod, ...@@ -303,6 +303,7 @@ int rsnd_mod_init(struct rsnd_mod *mod,
int id); int id);
void rsnd_mod_quit(struct rsnd_mod *mod); void rsnd_mod_quit(struct rsnd_mod *mod);
char *rsnd_mod_name(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); struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod);
/* /*
...@@ -449,8 +450,6 @@ struct rsnd_priv { ...@@ -449,8 +450,6 @@ struct rsnd_priv {
#define rsnd_priv_to_pdev(priv) ((priv)->pdev) #define rsnd_priv_to_pdev(priv) ((priv)->pdev)
#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) #define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev))
#define rsnd_priv_to_info(priv) ((priv)->info) #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 * rsnd_kctrl
......
...@@ -673,10 +673,13 @@ static int _rsnd_src_stop_gen2(struct rsnd_mod *mod) ...@@ -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) static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
{ {
struct rsnd_mod *mod = 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) /* ignore all cases if not working */
return IRQ_NONE; if (!rsnd_mod_is_working(mod))
goto rsnd_src_interrupt_gen2_out;
if (rsnd_src_error_record_gen2(mod)) { if (rsnd_src_error_record_gen2(mod)) {
struct rsnd_priv *priv = rsnd_mod_to_priv(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) ...@@ -692,6 +695,8 @@ static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
else else
dev_warn(dev, "no more SRC restart\n"); dev_warn(dev, "no more SRC restart\n");
} }
rsnd_src_interrupt_gen2_out:
spin_unlock(&priv->lock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -423,10 +423,15 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) ...@@ -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_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
int is_dma = rsnd_ssi_is_dma_mode(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) /* ignore all cases if not working */
return IRQ_NONE; if (!rsnd_mod_is_working(mod))
goto rsnd_ssi_interrupt_out;
status = rsnd_mod_read(mod, SSISR);
/* PIO only */ /* PIO only */
if (!is_dma && (status & DIRQ)) { if (!is_dma && (status & DIRQ)) {
...@@ -466,6 +471,9 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) ...@@ -466,6 +471,9 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
rsnd_ssi_record_error(ssi, status); rsnd_ssi_record_error(ssi, status);
rsnd_ssi_interrupt_out:
spin_unlock(&priv->lock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
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