Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb3893e1 authored by Sriranjan Srikantam's avatar Sriranjan Srikantam Committed by Stephen Boyd
Browse files

ASoC: Add locking in DAPM widget power update



While playback and capture is done concurrently the dapm widget
data is accessed parallelly which results in data corruption and
kernel panic. Fix this problem by serializing the stream event
operation by adding lock

dapm_seq_run will invoke dapm power sequence for pre-sorted list
of widgets to be powered up. Kernel panic issue is observed
during stability runs with the above sequence caused by null
pointer dereference in dapm_seq_run_coalesced. Fix kernel panic
issue by checking for valid snd_soc_dapm_context pointer in
dapm_seq_run before invoking dapm_seq_run_coalesced

Widget list in dapm is getting corrupted during concurrent
use cases where dapm_power_widget is accessed. This corruption
is resulting in kernel crash in dapm. Fix the issue by adding
protection in dapm_power_widgets API.

Change-Id: I49d19860277726cf3152e104ab40627fd56c021c
CRs-Fixed: 388785
Signed-off-by: default avatarSriranjan Srikantam <cssrika@codeaurora.org>
Signed-off-by: default avatarGopikrishnaiah Anandan <agopik@codeaurora.org>

Conflicts:

	include/sound/soc.h
parent d2837197
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -994,6 +994,7 @@ struct snd_soc_card {
	struct list_head list;
	struct mutex mutex;
	struct mutex dapm_mutex;
	struct mutex dapm_power_mutex;

	bool instantiated;

+1 −1
Original line number Diff line number Diff line
@@ -3665,7 +3665,7 @@ int snd_soc_register_card(struct snd_soc_card *card)
	card->instantiated = 0;
	mutex_init(&card->mutex);
	mutex_init(&card->dapm_mutex);

	mutex_init(&card->dapm_power_mutex);
	ret = snd_soc_instantiate_card(card);
	if (ret != 0)
		soc_cleanup_card_debugfs(card);
+4 −4
Original line number Diff line number Diff line
@@ -1377,7 +1377,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
		/* Do we need to apply any queued changes? */
		if (sort[w->id] != cur_sort || w->reg != cur_reg ||
		    w->dapm != cur_dapm || w->subseq != cur_subseq) {
			if (!list_empty(&pending))
			if (cur_dapm && !list_empty(&pending))
				dapm_seq_run_coalesced(cur_dapm, &pending);

			if (cur_dapm && cur_dapm->seq_notifier) {
@@ -1437,7 +1437,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
				"ASoC: Failed to apply widget power: %d\n", ret);
	}

	if (!list_empty(&pending))
	if (cur_dapm && !list_empty(&pending))
		dapm_seq_run_coalesced(cur_dapm, &pending);

	if (cur_dapm && cur_dapm->seq_notifier) {
@@ -1652,7 +1652,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
	enum snd_soc_bias_level bias;

	trace_snd_soc_dapm_start(card);

	mutex_lock(&dapm->card->dapm_power_mutex);
	list_for_each_entry(d, &card->dapm_list, list) {
		if (d->idle_bias_off)
			d->target_bias_level = SND_SOC_BIAS_OFF;
@@ -1753,7 +1753,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
	pop_dbg(dapm->dev, card->pop_time,
		"DAPM sequencing finished, waiting %dms\n", card->pop_time);
	pop_wait(card->pop_time);

	mutex_unlock(&dapm->card->dapm_power_mutex);
	trace_snd_soc_dapm_done(card);

	return 0;