diff mbox series

[5.11,019/775] ALSA: pcm: Call sync_stop at disconnection

Message ID 20210301161202.665328301@linuxfoundation.org
State New
Headers show
Series None | expand

Commit Message

Greg Kroah-Hartman March 1, 2021, 4:03 p.m. UTC
From: Takashi Iwai <tiwai@suse.de>

commit 29bb274e94974669acb5186a75538f20df1508b6 upstream.

The PCM core should perform the sync for the pending stop operations
at disconnection.  Otherwise it may lead to unexpected access.

Currently the old user of sync_stop, USB-audio driver, has its own
sync, so this isn't needed, but it's better to guarantee the sync in
the PCM core level.

This patch adds the missing sync_stop call at PCM disconnection
callback.  It also assures the IRQ sync if it's specified in the
card.  snd_pcm_sync_stop() is slightly modified to be called also for
any PCM substream object now.

Fixes: 1e850beea278 ("ALSA: pcm: Add the support for sync-stop operation")
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20210206203656.15959-2-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 sound/core/init.c       |    4 ++++
 sound/core/pcm.c        |    4 ++++
 sound/core/pcm_local.h  |    1 +
 sound/core/pcm_native.c |   16 ++++++++--------
 4 files changed, 17 insertions(+), 8 deletions(-)
diff mbox series

Patch

--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -14,6 +14,7 @@ 
 #include <linux/ctype.h>
 #include <linux/pm.h>
 #include <linux/completion.h>
+#include <linux/interrupt.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -416,6 +417,9 @@  int snd_card_disconnect(struct snd_card
 	/* notify all devices that we are disconnected */
 	snd_device_disconnect_all(card);
 
+	if (card->sync_irq > 0)
+		synchronize_irq(card->sync_irq);
+
 	snd_info_card_disconnect(card);
 	if (card->registered) {
 		device_del(&card->card_dev);
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -1111,6 +1111,10 @@  static int snd_pcm_dev_disconnect(struct
 		}
 	}
 
+	for (cidx = 0; cidx < 2; cidx++)
+		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
+			snd_pcm_sync_stop(substream, false);
+
 	pcm_call_notify(pcm, n_disconnect);
 	for (cidx = 0; cidx < 2; cidx++) {
 		snd_unregister_device(&pcm->streams[cidx].dev);
--- a/sound/core/pcm_local.h
+++ b/sound/core/pcm_local.h
@@ -63,6 +63,7 @@  static inline void snd_pcm_timer_done(st
 
 void __snd_pcm_xrun(struct snd_pcm_substream *substream);
 void snd_pcm_group_init(struct snd_pcm_group *group);
+void snd_pcm_sync_stop(struct snd_pcm_substream *substream, bool sync_irq);
 
 #ifdef CONFIG_SND_DMA_SGBUF
 struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -583,13 +583,13 @@  static inline void snd_pcm_timer_notify(
 #endif
 }
 
-static void snd_pcm_sync_stop(struct snd_pcm_substream *substream)
+void snd_pcm_sync_stop(struct snd_pcm_substream *substream, bool sync_irq)
 {
-	if (substream->runtime->stop_operating) {
+	if (substream->runtime && substream->runtime->stop_operating) {
 		substream->runtime->stop_operating = false;
-		if (substream->ops->sync_stop)
+		if (substream->ops && substream->ops->sync_stop)
 			substream->ops->sync_stop(substream);
-		else if (substream->pcm->card->sync_irq > 0)
+		else if (sync_irq && substream->pcm->card->sync_irq > 0)
 			synchronize_irq(substream->pcm->card->sync_irq);
 	}
 }
@@ -686,7 +686,7 @@  static int snd_pcm_hw_params(struct snd_
 		if (atomic_read(&substream->mmap_count))
 			return -EBADFD;
 
-	snd_pcm_sync_stop(substream);
+	snd_pcm_sync_stop(substream, true);
 
 	params->rmask = ~0U;
 	err = snd_pcm_hw_refine(substream, params);
@@ -809,7 +809,7 @@  static int do_hw_free(struct snd_pcm_sub
 {
 	int result = 0;
 
-	snd_pcm_sync_stop(substream);
+	snd_pcm_sync_stop(substream, true);
 	if (substream->ops->hw_free)
 		result = substream->ops->hw_free(substream);
 	if (substream->managed_buffer_alloc)
@@ -1736,7 +1736,7 @@  static void snd_pcm_post_resume(struct s
 	snd_pcm_trigger_tstamp(substream);
 	runtime->status->state = runtime->status->suspended_state;
 	snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME);
-	snd_pcm_sync_stop(substream);
+	snd_pcm_sync_stop(substream, true);
 }
 
 static const struct action_ops snd_pcm_action_resume = {
@@ -1866,7 +1866,7 @@  static int snd_pcm_do_prepare(struct snd
 			      snd_pcm_state_t state)
 {
 	int err;
-	snd_pcm_sync_stop(substream);
+	snd_pcm_sync_stop(substream, true);
 	err = substream->ops->prepare(substream);
 	if (err < 0)
 		return err;