diff options
author | Jiada Wang <jiada_wang@mentor.com> | 2018-09-03 03:08:58 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2018-09-03 09:28:59 -0400 |
commit | 4d230d12710646788af581ba0155d83ab48b955c (patch) | |
tree | 20747680d7257215c96a8daee54cb894c22c47e0 /sound | |
parent | 7aa09ff24301535491cd4de1b93107ee91449a12 (diff) |
ASoC: rsnd: fixup not to call clk_get/set under non-atomic
Clocking operations clk_get/set_rate, are non-atomic,
they shouldn't be called in soc_pcm_trigger() which is atomic.
Following issue was found due to execution of clk_get_rate() causes
sleep in soc_pcm_trigger(), which shouldn't be blocked.
We can reproduce this issue by following
> enable CONFIG_DEBUG_ATOMIC_SLEEP=y
> compile, and boot
> mount -t debugfs none /sys/kernel/debug
> while true; do cat /sys/kernel/debug/clk/clk_summary > /dev/null; done &
> while true; do aplay xxx; done
This patch adds support to .prepare callback, and moves non-atomic
clocking operations to it. As .prepare is non-atomic, it is always
called before trigger_start/trigger_stop.
BUG: sleeping function called from invalid context at kernel/locking/mutex.c:620
in_atomic(): 1, irqs_disabled(): 128, pid: 2242, name: aplay
INFO: lockdep is turned off.
irq event stamp: 5964
hardirqs last enabled at (5963): [<ffff200008e59e40>] mutex_lock_nested+0x6e8/0x6f0
hardirqs last disabled at (5964): [<ffff200008e623f0>] _raw_spin_lock_irqsave+0x24/0x68
softirqs last enabled at (5502): [<ffff200008081838>] __do_softirq+0x560/0x10c0
softirqs last disabled at (5495): [<ffff2000080c2e78>] irq_exit+0x160/0x25c
Preemption disabled at:[ 62.904063] [<ffff200008be4d48>] snd_pcm_stream_lock+0xb4/0xc0
CPU: 2 PID: 2242 Comm: aplay Tainted: G B C 4.9.54+ #186
Hardware name: Renesas Salvator-X board based on r8a7795 (DT)
Call trace:
[<ffff20000808fe48>] dump_backtrace+0x0/0x37c
[<ffff2000080901d8>] show_stack+0x14/0x1c
[<ffff2000086f4458>] dump_stack+0xfc/0x154
[<ffff2000081134a0>] ___might_sleep+0x57c/0x58c
[<ffff2000081136b8>] __might_sleep+0x208/0x21c
[<ffff200008e5980c>] mutex_lock_nested+0xb4/0x6f0
[<ffff2000087cac74>] clk_prepare_lock+0xb0/0x184
[<ffff2000087cb094>] clk_core_get_rate+0x14/0x54
[<ffff2000087cb0f4>] clk_get_rate+0x20/0x34
[<ffff20000113aa00>] rsnd_adg_ssi_clk_try_start+0x158/0x4f8 [snd_soc_rcar]
[<ffff20000113da00>] rsnd_ssi_init+0x668/0x7a0 [snd_soc_rcar]
[<ffff200001133ff4>] rsnd_soc_dai_trigger+0x4bc/0xcf8 [snd_soc_rcar]
[<ffff200008c1af24>] soc_pcm_trigger+0x2a4/0x2d4
Fixes: e7d850dd10f4 ("ASoC: rsnd: use mod base common method on SSI-parent")
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
Signed-off-by: Timo Wischer <twischer@de.adit-jv.com>
[Kuninori: tidyup for upstream]
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Tested-by: Hiroyuki Yokoyama <hiroyuki.yokoyama.vx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Cc: stable@vger.kernel.org
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/sh/rcar/core.c | 11 | ||||
-rw-r--r-- | sound/soc/sh/rcar/rsnd.h | 7 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 16 |
3 files changed, 28 insertions, 6 deletions
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f8425d8b44d2..b35f5509cfe2 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
@@ -958,12 +958,23 @@ static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, | |||
958 | rsnd_dai_stream_quit(io); | 958 | rsnd_dai_stream_quit(io); |
959 | } | 959 | } |
960 | 960 | ||
961 | static int rsnd_soc_dai_prepare(struct snd_pcm_substream *substream, | ||
962 | struct snd_soc_dai *dai) | ||
963 | { | ||
964 | struct rsnd_priv *priv = rsnd_dai_to_priv(dai); | ||
965 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | ||
966 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | ||
967 | |||
968 | return rsnd_dai_call(prepare, io, priv); | ||
969 | } | ||
970 | |||
961 | static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { | 971 | static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { |
962 | .startup = rsnd_soc_dai_startup, | 972 | .startup = rsnd_soc_dai_startup, |
963 | .shutdown = rsnd_soc_dai_shutdown, | 973 | .shutdown = rsnd_soc_dai_shutdown, |
964 | .trigger = rsnd_soc_dai_trigger, | 974 | .trigger = rsnd_soc_dai_trigger, |
965 | .set_fmt = rsnd_soc_dai_set_fmt, | 975 | .set_fmt = rsnd_soc_dai_set_fmt, |
966 | .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, | 976 | .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, |
977 | .prepare = rsnd_soc_dai_prepare, | ||
967 | }; | 978 | }; |
968 | 979 | ||
969 | void rsnd_parse_connect_common(struct rsnd_dai *rdai, | 980 | void rsnd_parse_connect_common(struct rsnd_dai *rdai, |
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 96d93330b1e1..8f7a0abfa751 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h | |||
@@ -280,6 +280,9 @@ struct rsnd_mod_ops { | |||
280 | int (*nolock_stop)(struct rsnd_mod *mod, | 280 | int (*nolock_stop)(struct rsnd_mod *mod, |
281 | struct rsnd_dai_stream *io, | 281 | struct rsnd_dai_stream *io, |
282 | struct rsnd_priv *priv); | 282 | struct rsnd_priv *priv); |
283 | int (*prepare)(struct rsnd_mod *mod, | ||
284 | struct rsnd_dai_stream *io, | ||
285 | struct rsnd_priv *priv); | ||
283 | }; | 286 | }; |
284 | 287 | ||
285 | struct rsnd_dai_stream; | 288 | struct rsnd_dai_stream; |
@@ -309,6 +312,7 @@ struct rsnd_mod { | |||
309 | * H 0: fallback | 312 | * H 0: fallback |
310 | * H 0: hw_params | 313 | * H 0: hw_params |
311 | * H 0: pointer | 314 | * H 0: pointer |
315 | * H 0: prepare | ||
312 | */ | 316 | */ |
313 | #define __rsnd_mod_shift_nolock_start 0 | 317 | #define __rsnd_mod_shift_nolock_start 0 |
314 | #define __rsnd_mod_shift_nolock_stop 0 | 318 | #define __rsnd_mod_shift_nolock_stop 0 |
@@ -323,6 +327,7 @@ struct rsnd_mod { | |||
323 | #define __rsnd_mod_shift_fallback 28 /* always called */ | 327 | #define __rsnd_mod_shift_fallback 28 /* always called */ |
324 | #define __rsnd_mod_shift_hw_params 28 /* always called */ | 328 | #define __rsnd_mod_shift_hw_params 28 /* always called */ |
325 | #define __rsnd_mod_shift_pointer 28 /* always called */ | 329 | #define __rsnd_mod_shift_pointer 28 /* always called */ |
330 | #define __rsnd_mod_shift_prepare 28 /* always called */ | ||
326 | 331 | ||
327 | #define __rsnd_mod_add_probe 0 | 332 | #define __rsnd_mod_add_probe 0 |
328 | #define __rsnd_mod_add_remove 0 | 333 | #define __rsnd_mod_add_remove 0 |
@@ -337,6 +342,7 @@ struct rsnd_mod { | |||
337 | #define __rsnd_mod_add_fallback 0 | 342 | #define __rsnd_mod_add_fallback 0 |
338 | #define __rsnd_mod_add_hw_params 0 | 343 | #define __rsnd_mod_add_hw_params 0 |
339 | #define __rsnd_mod_add_pointer 0 | 344 | #define __rsnd_mod_add_pointer 0 |
345 | #define __rsnd_mod_add_prepare 0 | ||
340 | 346 | ||
341 | #define __rsnd_mod_call_probe 0 | 347 | #define __rsnd_mod_call_probe 0 |
342 | #define __rsnd_mod_call_remove 0 | 348 | #define __rsnd_mod_call_remove 0 |
@@ -351,6 +357,7 @@ struct rsnd_mod { | |||
351 | #define __rsnd_mod_call_pointer 0 | 357 | #define __rsnd_mod_call_pointer 0 |
352 | #define __rsnd_mod_call_nolock_start 0 | 358 | #define __rsnd_mod_call_nolock_start 0 |
353 | #define __rsnd_mod_call_nolock_stop 1 | 359 | #define __rsnd_mod_call_nolock_stop 1 |
360 | #define __rsnd_mod_call_prepare 0 | ||
354 | 361 | ||
355 | #define rsnd_mod_to_priv(mod) ((mod)->priv) | 362 | #define rsnd_mod_to_priv(mod) ((mod)->priv) |
356 | #define rsnd_mod_name(mod) ((mod)->ops->name) | 363 | #define rsnd_mod_name(mod) ((mod)->ops->name) |
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 8304e4ec9242..3f880ec66459 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c | |||
@@ -283,7 +283,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, | |||
283 | if (rsnd_ssi_is_multi_slave(mod, io)) | 283 | if (rsnd_ssi_is_multi_slave(mod, io)) |
284 | return 0; | 284 | return 0; |
285 | 285 | ||
286 | if (ssi->usrcnt > 1) { | 286 | if (ssi->rate) { |
287 | if (ssi->rate != rate) { | 287 | if (ssi->rate != rate) { |
288 | dev_err(dev, "SSI parent/child should use same rate\n"); | 288 | dev_err(dev, "SSI parent/child should use same rate\n"); |
289 | return -EINVAL; | 289 | return -EINVAL; |
@@ -434,7 +434,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, | |||
434 | struct rsnd_priv *priv) | 434 | struct rsnd_priv *priv) |
435 | { | 435 | { |
436 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 436 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
437 | int ret; | ||
438 | 437 | ||
439 | if (!rsnd_ssi_is_run_mods(mod, io)) | 438 | if (!rsnd_ssi_is_run_mods(mod, io)) |
440 | return 0; | 439 | return 0; |
@@ -443,10 +442,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, | |||
443 | 442 | ||
444 | rsnd_mod_power_on(mod); | 443 | rsnd_mod_power_on(mod); |
445 | 444 | ||
446 | ret = rsnd_ssi_master_clk_start(mod, io); | ||
447 | if (ret < 0) | ||
448 | return ret; | ||
449 | |||
450 | rsnd_ssi_config_init(mod, io); | 445 | rsnd_ssi_config_init(mod, io); |
451 | 446 | ||
452 | rsnd_ssi_register_setup(mod); | 447 | rsnd_ssi_register_setup(mod); |
@@ -852,6 +847,13 @@ static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod, | |||
852 | return 0; | 847 | return 0; |
853 | } | 848 | } |
854 | 849 | ||
850 | static int rsnd_ssi_prepare(struct rsnd_mod *mod, | ||
851 | struct rsnd_dai_stream *io, | ||
852 | struct rsnd_priv *priv) | ||
853 | { | ||
854 | return rsnd_ssi_master_clk_start(mod, io); | ||
855 | } | ||
856 | |||
855 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | 857 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { |
856 | .name = SSI_NAME, | 858 | .name = SSI_NAME, |
857 | .probe = rsnd_ssi_common_probe, | 859 | .probe = rsnd_ssi_common_probe, |
@@ -864,6 +866,7 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | |||
864 | .pointer = rsnd_ssi_pio_pointer, | 866 | .pointer = rsnd_ssi_pio_pointer, |
865 | .pcm_new = rsnd_ssi_pcm_new, | 867 | .pcm_new = rsnd_ssi_pcm_new, |
866 | .hw_params = rsnd_ssi_hw_params, | 868 | .hw_params = rsnd_ssi_hw_params, |
869 | .prepare = rsnd_ssi_prepare, | ||
867 | }; | 870 | }; |
868 | 871 | ||
869 | static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, | 872 | static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, |
@@ -940,6 +943,7 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | |||
940 | .pcm_new = rsnd_ssi_pcm_new, | 943 | .pcm_new = rsnd_ssi_pcm_new, |
941 | .fallback = rsnd_ssi_fallback, | 944 | .fallback = rsnd_ssi_fallback, |
942 | .hw_params = rsnd_ssi_hw_params, | 945 | .hw_params = rsnd_ssi_hw_params, |
946 | .prepare = rsnd_ssi_prepare, | ||
943 | }; | 947 | }; |
944 | 948 | ||
945 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) | 949 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) |