From: Kuninori Morimoto <kuninori.morimoto.gx@xxxxxxxxxxx> clk_prepare_enable/unprepare() uses mutex inside, and it uses __schedule(). Then, raw_spin_lock/unlock_irq() is called, and it breaks Renesas sound driver's spin lock irq. This patch moves clk_prepare_enable/unprepare to probe/remove function. Special thanks to Das Biju. Reported-by: Das Biju <biju.das@xxxxxxxxxxxxxx> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@xxxxxxxxxxx> --- - it should goes to linus/master too sound/soc/sh/rcar/core.c | 14 ++++++++++++++ sound/soc/sh/rcar/dvc.c | 20 +++++++------------- sound/soc/sh/rcar/rsnd.h | 4 ++-- sound/soc/sh/rcar/src.c | 18 ++++++++++++------ sound/soc/sh/rcar/ssi.c | 25 ++++++++++++++++--------- 5 files changed, 51 insertions(+), 30 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 8d67042..398eb8f 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -157,6 +157,20 @@ void rsnd_mod_init(struct rsnd_mod *mod, mod->clk = clk; } +int rsnd_mod_probe(struct rsnd_mod *mod, + struct rsnd_priv *priv) +{ + return clk_prepare_enable(mod->clk); +} + +int rsnd_mod_remove(struct rsnd_mod *mod, + struct rsnd_priv *priv) +{ + clk_disable_unprepare(mod->clk); + + return 0; +} + /* * settting function */ diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index aeeef13..8f7558c 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -123,11 +123,16 @@ static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); + int ret; + + ret = rsnd_mod_probe(mod, priv); + if (ret) + return ret; dev_dbg(dev, "%s[%d] (Gen2) is probed\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); - return 0; + return ret; } static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod, @@ -141,7 +146,7 @@ static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod, rsnd_kctrl_remove(dvc->rup); rsnd_kctrl_remove(dvc->rdown); - return 0; + return rsnd_mod_remove(mod, priv); } static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, @@ -166,8 +171,6 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, return -EINVAL; } - rsnd_mod_hw_start(dvc_mod); - /* * fixme * it doesn't support CTU/MIX @@ -191,14 +194,6 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, return 0; } -static int rsnd_dvc_quit(struct rsnd_mod *mod, - struct rsnd_priv *priv) -{ - rsnd_mod_hw_stop(mod); - - return 0; -} - static int rsnd_dvc_start(struct rsnd_mod *mod, struct rsnd_priv *priv) { @@ -286,7 +281,6 @@ static struct rsnd_mod_ops rsnd_dvc_ops = { .probe = rsnd_dvc_probe_gen2, .remove = rsnd_dvc_remove_gen2, .init = rsnd_dvc_init, - .quit = rsnd_dvc_quit, .start = rsnd_dvc_start, .stop = rsnd_dvc_stop, .pcm_new = rsnd_dvc_pcm_new, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 5f35af7..49ea11b 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -285,9 +285,9 @@ struct rsnd_mod { #define rsnd_mod_to_dma(mod) (&(mod)->dma) #define rsnd_mod_to_io(mod) ((mod)->io) #define rsnd_mod_id(mod) ((mod)->id) -#define rsnd_mod_hw_start(mod) clk_prepare_enable((mod)->clk) -#define rsnd_mod_hw_stop(mod) clk_disable_unprepare((mod)->clk) +int rsnd_mod_probe(struct rsnd_mod *mod, struct rsnd_priv *priv); +int rsnd_mod_remove(struct rsnd_mod *mod, struct rsnd_priv *priv); void rsnd_mod_init(struct rsnd_mod *mod, struct rsnd_mod_ops *ops, struct clk *clk, diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index cc93f32..327771a 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -292,8 +292,6 @@ static int rsnd_src_init(struct rsnd_mod *mod) { struct rsnd_src *src = rsnd_mod_to_src(mod); - rsnd_mod_hw_start(mod); - src->err = 0; /* @@ -311,8 +309,6 @@ static int rsnd_src_quit(struct rsnd_mod *mod, struct rsnd_src *src = rsnd_mod_to_src(mod); struct device *dev = rsnd_priv_to_dev(priv); - rsnd_mod_hw_stop(mod); - if (src->err) dev_warn(dev, "%s[%d] under/over flow err = %d\n", rsnd_mod_name(mod), rsnd_mod_id(mod), src->err); @@ -464,11 +460,16 @@ static int rsnd_src_probe_gen1(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); + int ret; + + ret = rsnd_mod_probe(mod, priv); + if (ret) + return ret; dev_dbg(dev, "%s[%d] (Gen1) is probed\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); - return 0; + return ret; } static int rsnd_src_init_gen1(struct rsnd_mod *mod, @@ -519,6 +520,7 @@ static struct rsnd_mod_ops rsnd_src_gen1_ops = { .name = SRC_NAME, .dma_req = rsnd_src_dma_req, .probe = rsnd_src_probe_gen1, + .remove = rsnd_mod_remove, .init = rsnd_src_init_gen1, .quit = rsnd_src_quit, .start = rsnd_src_start_gen1, @@ -734,6 +736,10 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, if (ret) goto rsnd_src_probe_gen2_fail; + ret = rsnd_mod_probe(mod, priv); + if (ret) + goto rsnd_src_probe_gen2_fail; + dev_dbg(dev, "%s[%d] (Gen2) is probed\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); @@ -751,7 +757,7 @@ static int rsnd_src_remove_gen2(struct rsnd_mod *mod, { rsnd_dma_quit(rsnd_mod_to_dma(mod)); - return 0; + return rsnd_mod_remove(mod, priv); } static int rsnd_src_init_gen2(struct rsnd_mod *mod, diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 060d3d2..dd49559 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -186,8 +186,6 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, u32 cr; if (0 == ssi->usrcnt) { - rsnd_mod_hw_start(&ssi->mod); - if (rsnd_rdai_is_clk_master(rdai)) { if (rsnd_ssi_clk_from_parent(ssi)) rsnd_ssi_hw_start(ssi->parent, io); @@ -258,8 +256,6 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi) else rsnd_ssi_master_clk_stop(ssi); } - - rsnd_mod_hw_stop(&ssi->mod); } dev_dbg(dev, "%s[%d] hw stopped\n", @@ -445,12 +441,18 @@ static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, rsnd_ssi_interrupt, IRQF_SHARED, dev_name(dev), ssi); - if (ret) + if (ret) { dev_err(dev, "%s[%d] (PIO) request interrupt failed\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); - else - dev_dbg(dev, "%s[%d] (PIO) is probed\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); + return ret; + } + + ret = rsnd_mod_probe(mod, priv); + if (ret) + return ret; + + dev_dbg(dev, "%s[%d] (PIO) is probed\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); return ret; } @@ -458,6 +460,7 @@ static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, static struct rsnd_mod_ops rsnd_ssi_pio_ops = { .name = SSI_NAME, .probe = rsnd_ssi_pio_probe, + .remove = rsnd_mod_remove, .init = rsnd_ssi_init, .quit = rsnd_ssi_quit, .start = rsnd_ssi_start, @@ -485,6 +488,10 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, if (ret) goto rsnd_ssi_dma_probe_fail; + ret = rsnd_mod_probe(mod, priv); + if (ret) + goto rsnd_ssi_dma_probe_fail; + dev_dbg(dev, "%s[%d] (DMA) is probed\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); @@ -509,7 +516,7 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, /* PIO will request IRQ again */ devm_free_irq(dev, irq, ssi); - return 0; + return rsnd_mod_remove(mod, priv); } static int rsnd_ssi_fallback(struct rsnd_mod *mod, -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html