aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2015-05-20 23:50:23 -0400
committerMark Brown <broonie@kernel.org>2015-05-22 09:15:26 -0400
commit02299d9875bab5b1e9d87ce9ae4aecf537eb12a4 (patch)
treefd8540f53112e7ed217aa6d95b2b9047a25af101
parente8a07d60c932efbd44bee50e3fa95f133b8c28be (diff)
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: 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> Tested by: Cao Minh Hiep <cm-hiep@jinso.co.jp> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/sh/rcar/core.c12
-rw-r--r--sound/soc/sh/rcar/rsnd.h3
-rw-r--r--sound/soc/sh/rcar/src.c11
-rw-r--r--sound/soc/sh/rcar/ssi.c14
4 files changed, 30 insertions, 10 deletions
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 2b7323c92994..d460d2aa82ee 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)
170 clk_unprepare(mod->clk); 170 clk_unprepare(mod->clk);
171} 171}
172 172
173int rsnd_mod_is_working(struct rsnd_mod *mod)
174{
175 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
176
177 /* see rsnd_dai_stream_init/quit() */
178 return !!io->substream;
179}
180
173/* 181/*
174 * settting function 182 * settting function
175 */ 183 */
@@ -362,7 +370,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
362 int ret; 370 int ret;
363 unsigned long flags; 371 unsigned long flags;
364 372
365 rsnd_lock(priv, flags); 373 spin_lock_irqsave(&priv->lock, flags);
366 374
367 switch (cmd) { 375 switch (cmd) {
368 case SNDRV_PCM_TRIGGER_START: 376 case SNDRV_PCM_TRIGGER_START:
@@ -400,7 +408,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
400 } 408 }
401 409
402dai_trigger_end: 410dai_trigger_end:
403 rsnd_unlock(priv, flags); 411 spin_unlock_irqrestore(&priv->lock, flags);
404 412
405 return ret; 413 return ret;
406} 414}
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 4e6de6804cfb..03ff071d012f 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,
303 int id); 303 int id);
304void rsnd_mod_quit(struct rsnd_mod *mod); 304void rsnd_mod_quit(struct rsnd_mod *mod);
305char *rsnd_mod_name(struct rsnd_mod *mod); 305char *rsnd_mod_name(struct rsnd_mod *mod);
306int rsnd_mod_is_working(struct rsnd_mod *mod);
306struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod); 307struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod);
307 308
308/* 309/*
@@ -449,8 +450,6 @@ struct rsnd_priv {
449#define rsnd_priv_to_pdev(priv) ((priv)->pdev) 450#define rsnd_priv_to_pdev(priv) ((priv)->pdev)
450#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) 451#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev))
451#define rsnd_priv_to_info(priv) ((priv)->info) 452#define rsnd_priv_to_info(priv) ((priv)->info)
452#define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags)
453#define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
454 453
455/* 454/*
456 * rsnd_kctrl 455 * rsnd_kctrl
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 3beb32eb412a..fbe9166e26d1 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)
673static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data) 673static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
674{ 674{
675 struct rsnd_mod *mod = data; 675 struct rsnd_mod *mod = data;
676 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); 676 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
677
678 spin_lock(&priv->lock);
677 679
678 if (!io) 680 /* ignore all cases if not working */
679 return IRQ_NONE; 681 if (!rsnd_mod_is_working(mod))
682 goto rsnd_src_interrupt_gen2_out;
680 683
681 if (rsnd_src_error_record_gen2(mod)) { 684 if (rsnd_src_error_record_gen2(mod)) {
682 struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 685 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 else 695 else
693 dev_warn(dev, "no more SRC restart\n"); 696 dev_warn(dev, "no more SRC restart\n");
694 } 697 }
698rsnd_src_interrupt_gen2_out:
699 spin_unlock(&priv->lock);
695 700
696 return IRQ_HANDLED; 701 return IRQ_HANDLED;
697} 702}
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 927ac52a6d1e..50fa3928a003 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)
423 struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 423 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
424 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); 424 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
425 int is_dma = rsnd_ssi_is_dma_mode(mod); 425 int is_dma = rsnd_ssi_is_dma_mode(mod);
426 u32 status = rsnd_mod_read(mod, SSISR); 426 u32 status;
427
428 spin_lock(&priv->lock);
427 429
428 if (!io) 430 /* ignore all cases if not working */
429 return IRQ_NONE; 431 if (!rsnd_mod_is_working(mod))
432 goto rsnd_ssi_interrupt_out;
433
434 status = rsnd_mod_read(mod, SSISR);
430 435
431 /* PIO only */ 436 /* PIO only */
432 if (!is_dma && (status & DIRQ)) { 437 if (!is_dma && (status & DIRQ)) {
@@ -466,6 +471,9 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
466 471
467 rsnd_ssi_record_error(ssi, status); 472 rsnd_ssi_record_error(ssi, status);
468 473
474rsnd_ssi_interrupt_out:
475 spin_unlock(&priv->lock);
476
469 return IRQ_HANDLED; 477 return IRQ_HANDLED;
470} 478}
471 479