diff options
author | Peter Ujfalusi <peter.ujfalusi@ti.com> | 2019-08-13 06:45:32 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-08-15 10:07:43 -0400 |
commit | 72b745e3ad65deac94ea4eb83262c52ba3ffdb5b (patch) | |
tree | a5850d63c1e97e8fc8d4a6e1f29b8d6e181b112a /sound/soc/soc-pcm.c | |
parent | 12f0bfadf69bb154052722e7e4e5cd1639044c76 (diff) |
ASoC: core: Move pcm_mutex up to card level from snd_soc_pcm_runtime
The pcm_mutex is used to prevent concurrent execution of snd_pcm_ops
callbacks. This works fine most of the cases but it can not handle setups
when the same DAI is used by different rtd, for example:
pcm3168a have two DAIs: one for Playback and one for Capture.
If the codec is connected to a single CPU DAI we need to have two dai_link
to support both playback and capture.
In this case the snd_pcm_ops callbacks can be executed in parallel causing
unexpected races in DAI drivers.
By moving the pcm_mutex up to card level this can be solved
while - hopefully - not breaking other setups.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Tested-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20190813104532.16669-1-peter.ujfalusi@ti.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/soc-pcm.c')
-rw-r--r-- | sound/soc/soc-pcm.c | 36 |
1 files changed, 18 insertions, 18 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index da657c8179cc..e163dde5eab1 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -36,7 +36,7 @@ | |||
36 | * Increments the active count for all the DAIs and components attached to a PCM | 36 | * Increments the active count for all the DAIs and components attached to a PCM |
37 | * runtime. Should typically be called when a stream is opened. | 37 | * runtime. Should typically be called when a stream is opened. |
38 | * | 38 | * |
39 | * Must be called with the rtd->pcm_mutex being held | 39 | * Must be called with the rtd->card->pcm_mutex being held |
40 | */ | 40 | */ |
41 | void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) | 41 | void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) |
42 | { | 42 | { |
@@ -44,7 +44,7 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) | |||
44 | struct snd_soc_dai *codec_dai; | 44 | struct snd_soc_dai *codec_dai; |
45 | int i; | 45 | int i; |
46 | 46 | ||
47 | lockdep_assert_held(&rtd->pcm_mutex); | 47 | lockdep_assert_held(&rtd->card->pcm_mutex); |
48 | 48 | ||
49 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 49 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
50 | cpu_dai->playback_active++; | 50 | cpu_dai->playback_active++; |
@@ -72,7 +72,7 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) | |||
72 | * Decrements the active count for all the DAIs and components attached to a PCM | 72 | * Decrements the active count for all the DAIs and components attached to a PCM |
73 | * runtime. Should typically be called when a stream is closed. | 73 | * runtime. Should typically be called when a stream is closed. |
74 | * | 74 | * |
75 | * Must be called with the rtd->pcm_mutex being held | 75 | * Must be called with the rtd->card->pcm_mutex being held |
76 | */ | 76 | */ |
77 | void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) | 77 | void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) |
78 | { | 78 | { |
@@ -80,7 +80,7 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) | |||
80 | struct snd_soc_dai *codec_dai; | 80 | struct snd_soc_dai *codec_dai; |
81 | int i; | 81 | int i; |
82 | 82 | ||
83 | lockdep_assert_held(&rtd->pcm_mutex); | 83 | lockdep_assert_held(&rtd->card->pcm_mutex); |
84 | 84 | ||
85 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 85 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
86 | cpu_dai->playback_active--; | 86 | cpu_dai->playback_active--; |
@@ -506,7 +506,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
506 | pm_runtime_get_sync(component->dev); | 506 | pm_runtime_get_sync(component->dev); |
507 | } | 507 | } |
508 | 508 | ||
509 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 509 | mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); |
510 | 510 | ||
511 | /* startup the audio subsystem */ | 511 | /* startup the audio subsystem */ |
512 | ret = snd_soc_dai_startup(cpu_dai, substream); | 512 | ret = snd_soc_dai_startup(cpu_dai, substream); |
@@ -604,7 +604,7 @@ dynamic: | |||
604 | 604 | ||
605 | snd_soc_runtime_activate(rtd, substream->stream); | 605 | snd_soc_runtime_activate(rtd, substream->stream); |
606 | 606 | ||
607 | mutex_unlock(&rtd->pcm_mutex); | 607 | mutex_unlock(&rtd->card->pcm_mutex); |
608 | return 0; | 608 | return 0; |
609 | 609 | ||
610 | config_err: | 610 | config_err: |
@@ -623,7 +623,7 @@ component_err: | |||
623 | 623 | ||
624 | snd_soc_dai_shutdown(cpu_dai, substream); | 624 | snd_soc_dai_shutdown(cpu_dai, substream); |
625 | out: | 625 | out: |
626 | mutex_unlock(&rtd->pcm_mutex); | 626 | mutex_unlock(&rtd->card->pcm_mutex); |
627 | 627 | ||
628 | for_each_rtdcom(rtd, rtdcom) { | 628 | for_each_rtdcom(rtd, rtdcom) { |
629 | component = rtdcom->component; | 629 | component = rtdcom->component; |
@@ -653,7 +653,7 @@ static void close_delayed_work(struct work_struct *work) | |||
653 | container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); | 653 | container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); |
654 | struct snd_soc_dai *codec_dai = rtd->codec_dais[0]; | 654 | struct snd_soc_dai *codec_dai = rtd->codec_dais[0]; |
655 | 655 | ||
656 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 656 | mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); |
657 | 657 | ||
658 | dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n", | 658 | dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n", |
659 | codec_dai->driver->playback.stream_name, | 659 | codec_dai->driver->playback.stream_name, |
@@ -667,7 +667,7 @@ static void close_delayed_work(struct work_struct *work) | |||
667 | SND_SOC_DAPM_STREAM_STOP); | 667 | SND_SOC_DAPM_STREAM_STOP); |
668 | } | 668 | } |
669 | 669 | ||
670 | mutex_unlock(&rtd->pcm_mutex); | 670 | mutex_unlock(&rtd->card->pcm_mutex); |
671 | } | 671 | } |
672 | 672 | ||
673 | static void codec2codec_close_delayed_work(struct work_struct *work) | 673 | static void codec2codec_close_delayed_work(struct work_struct *work) |
@@ -694,7 +694,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
694 | struct snd_soc_dai *codec_dai; | 694 | struct snd_soc_dai *codec_dai; |
695 | int i; | 695 | int i; |
696 | 696 | ||
697 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 697 | mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); |
698 | 698 | ||
699 | snd_soc_runtime_deactivate(rtd, substream->stream); | 699 | snd_soc_runtime_deactivate(rtd, substream->stream); |
700 | 700 | ||
@@ -738,7 +738,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
738 | SND_SOC_DAPM_STREAM_STOP); | 738 | SND_SOC_DAPM_STREAM_STOP); |
739 | } | 739 | } |
740 | 740 | ||
741 | mutex_unlock(&rtd->pcm_mutex); | 741 | mutex_unlock(&rtd->card->pcm_mutex); |
742 | 742 | ||
743 | for_each_rtdcom(rtd, rtdcom) { | 743 | for_each_rtdcom(rtd, rtdcom) { |
744 | component = rtdcom->component; | 744 | component = rtdcom->component; |
@@ -771,7 +771,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
771 | struct snd_soc_dai *codec_dai; | 771 | struct snd_soc_dai *codec_dai; |
772 | int i, ret = 0; | 772 | int i, ret = 0; |
773 | 773 | ||
774 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 774 | mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); |
775 | 775 | ||
776 | if (rtd->dai_link->ops->prepare) { | 776 | if (rtd->dai_link->ops->prepare) { |
777 | ret = rtd->dai_link->ops->prepare(substream); | 777 | ret = rtd->dai_link->ops->prepare(substream); |
@@ -826,7 +826,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
826 | snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream); | 826 | snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream); |
827 | 827 | ||
828 | out: | 828 | out: |
829 | mutex_unlock(&rtd->pcm_mutex); | 829 | mutex_unlock(&rtd->card->pcm_mutex); |
830 | return ret; | 830 | return ret; |
831 | } | 831 | } |
832 | 832 | ||
@@ -876,7 +876,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
876 | struct snd_soc_dai *codec_dai; | 876 | struct snd_soc_dai *codec_dai; |
877 | int i, ret = 0; | 877 | int i, ret = 0; |
878 | 878 | ||
879 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 879 | mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); |
880 | if (rtd->dai_link->ops->hw_params) { | 880 | if (rtd->dai_link->ops->hw_params) { |
881 | ret = rtd->dai_link->ops->hw_params(substream, params); | 881 | ret = rtd->dai_link->ops->hw_params(substream, params); |
882 | if (ret < 0) { | 882 | if (ret < 0) { |
@@ -962,7 +962,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
962 | if (ret) | 962 | if (ret) |
963 | goto component_err; | 963 | goto component_err; |
964 | out: | 964 | out: |
965 | mutex_unlock(&rtd->pcm_mutex); | 965 | mutex_unlock(&rtd->card->pcm_mutex); |
966 | return ret; | 966 | return ret; |
967 | 967 | ||
968 | component_err: | 968 | component_err: |
@@ -986,7 +986,7 @@ codec_err: | |||
986 | if (rtd->dai_link->ops->hw_free) | 986 | if (rtd->dai_link->ops->hw_free) |
987 | rtd->dai_link->ops->hw_free(substream); | 987 | rtd->dai_link->ops->hw_free(substream); |
988 | 988 | ||
989 | mutex_unlock(&rtd->pcm_mutex); | 989 | mutex_unlock(&rtd->card->pcm_mutex); |
990 | return ret; | 990 | return ret; |
991 | } | 991 | } |
992 | 992 | ||
@@ -1001,7 +1001,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
1001 | bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | 1001 | bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
1002 | int i; | 1002 | int i; |
1003 | 1003 | ||
1004 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 1004 | mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); |
1005 | 1005 | ||
1006 | /* clear the corresponding DAIs parameters when going to be inactive */ | 1006 | /* clear the corresponding DAIs parameters when going to be inactive */ |
1007 | if (cpu_dai->active == 1) { | 1007 | if (cpu_dai->active == 1) { |
@@ -1043,7 +1043,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
1043 | 1043 | ||
1044 | snd_soc_dai_hw_free(cpu_dai, substream); | 1044 | snd_soc_dai_hw_free(cpu_dai, substream); |
1045 | 1045 | ||
1046 | mutex_unlock(&rtd->pcm_mutex); | 1046 | mutex_unlock(&rtd->card->pcm_mutex); |
1047 | return 0; | 1047 | return 0; |
1048 | } | 1048 | } |
1049 | 1049 | ||