From: Cezary Rojewski Date: Mon, 9 Mar 2026 09:16:01 +0000 (+0100) Subject: ASoC: Intel: catpt: Synchronize stream access X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b0b49c77bddac75db79f7c2c6ec0b07d61864f2f;p=thirdparty%2Flinux.git ASoC: Intel: catpt: Synchronize stream access Streams may have individual controls assigned to them e.g.: volume control in case of offload streams. If such a stream is running and simultaneously its controls are being manipulated, both processes are touching the exact same descriptors - access to these must be synchronized. Replace spinlock with mutex as IPCs are non-atomic operations and add proper locking for all ->stream_list users. Signed-off-by: Cezary Rojewski Link: https://patch.msgid.link/20260309091605.896307-2-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- diff --git a/sound/soc/intel/catpt/core.h b/sound/soc/intel/catpt/core.h index df8a5fd95e13e..7e479ef89ad0b 100644 --- a/sound/soc/intel/catpt/core.h +++ b/sound/soc/intel/catpt/core.h @@ -96,7 +96,7 @@ struct catpt_dev { struct catpt_module_type modules[CATPT_MODULE_COUNT]; struct catpt_ssp_device_format devfmt[CATPT_SSP_COUNT]; struct list_head stream_list; - spinlock_t list_lock; + struct mutex stream_mutex; struct mutex clk_mutex; struct catpt_dx_context dx_ctx; diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c index 0638aecba40de..b5f4361d4465f 100644 --- a/sound/soc/intel/catpt/device.c +++ b/sound/soc/intel/catpt/device.c @@ -226,7 +226,7 @@ static void catpt_dev_init(struct catpt_dev *cdev, struct device *dev, cdev->spec = spec; init_completion(&cdev->fw_ready); INIT_LIST_HEAD(&cdev->stream_list); - spin_lock_init(&cdev->list_lock); + mutex_init(&cdev->stream_mutex); mutex_init(&cdev->clk_mutex); /* diff --git a/sound/soc/intel/catpt/ipc.c b/sound/soc/intel/catpt/ipc.c index 5a01a9afb26ee..2e3b7a5cbb9b2 100644 --- a/sound/soc/intel/catpt/ipc.c +++ b/sound/soc/intel/catpt/ipc.c @@ -5,6 +5,7 @@ // Author: Cezary Rojewski // +#include #include #include "core.h" #include "messages.h" @@ -151,6 +152,8 @@ catpt_dsp_notify_stream(struct catpt_dev *cdev, union catpt_notify_msg msg) struct catpt_notify_position pos; struct catpt_notify_glitch glitch; + guard(mutex)(&cdev->stream_mutex); + stream = catpt_stream_find(cdev, msg.stream_hw_id); if (!stream) { dev_warn(cdev->dev, "notify %d for non-existent stream %d\n", diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c index dc7afe587e6f2..432cb1f0ab4e2 100644 --- a/sound/soc/intel/catpt/loader.c +++ b/sound/soc/intel/catpt/loader.c @@ -90,6 +90,7 @@ int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) { struct catpt_stream_runtime *stream; + /* Lockless as no streams can be added or removed during D3 -> D0 transition. */ list_for_each_entry(stream, &cdev->stream_list, node) { u32 off, size; int ret; @@ -180,6 +181,7 @@ catpt_restore_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) { struct catpt_stream_runtime *stream; + /* Lockless as no streams can be added or removed during D3 -> D0 transition. */ list_for_each_entry(stream, &cdev->stream_list, node) { u32 off, size; int ret; diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index 2c5ea4e0ff3d7..fbe4821755bda 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -5,6 +5,7 @@ // Author: Cezary Rojewski // +#include #include #include #include @@ -97,12 +98,12 @@ catpt_get_stream_template(struct snd_pcm_substream *substream) return catpt_topology[type]; } +/* Caller responsible for holding ->stream_mutex. */ struct catpt_stream_runtime * catpt_stream_find(struct catpt_dev *cdev, u8 stream_hw_id) { struct catpt_stream_runtime *pos, *result = NULL; - spin_lock(&cdev->list_lock); list_for_each_entry(pos, &cdev->stream_list, node) { if (pos->info.stream_hw_id == stream_hw_id) { result = pos; @@ -110,7 +111,6 @@ catpt_stream_find(struct catpt_dev *cdev, u8 stream_hw_id) } } - spin_unlock(&cdev->list_lock); return result; } @@ -286,10 +286,6 @@ static int catpt_dai_startup(struct snd_pcm_substream *substream, INIT_LIST_HEAD(&stream->node); snd_soc_dai_set_dma_data(dai, substream, stream); - spin_lock(&cdev->list_lock); - list_add_tail(&stream->node, &cdev->stream_list); - spin_unlock(&cdev->list_lock); - return 0; err_request: @@ -307,10 +303,6 @@ static void catpt_dai_shutdown(struct snd_pcm_substream *substream, stream = snd_soc_dai_get_dma_data(dai, substream); - spin_lock(&cdev->list_lock); - list_del(&stream->node); - spin_unlock(&cdev->list_lock); - release_resource(stream->persistent); kfree(stream->persistent); catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask); @@ -410,12 +402,15 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream, if (ret) return CATPT_IPC_RET(ret); + guard(mutex)(&cdev->stream_mutex); + ret = catpt_dai_apply_usettings(dai, stream); if (ret) { catpt_ipc_free_stream(cdev, stream->info.stream_hw_id); return ret; } + list_add_tail(&stream->node, &cdev->stream_list); stream->allocated = true; return 0; } @@ -430,6 +425,10 @@ static int catpt_dai_hw_free(struct snd_pcm_substream *substream, if (!stream->allocated) return 0; + mutex_lock(&cdev->stream_mutex); + list_del(&stream->node); + mutex_unlock(&cdev->stream_mutex); + catpt_ipc_reset_stream(cdev, stream->info.stream_hw_id); catpt_ipc_free_stream(cdev, stream->info.stream_hw_id); @@ -910,6 +909,8 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol, int ret; int i; + guard(mutex)(&cdev->stream_mutex); + stream = catpt_stream_find(cdev, pin_id); if (!stream) { for (i = 0; i < CATPT_CHANNELS_MAX; i++) @@ -941,6 +942,8 @@ static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol, long *ctlvol = (long *)kcontrol->private_value; int ret, i; + guard(mutex)(&cdev->stream_mutex); + stream = catpt_stream_find(cdev, pin_id); if (!stream) { for (i = 0; i < CATPT_CHANNELS_MAX; i++) @@ -1017,6 +1020,8 @@ static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol, bool mute; int ret; + guard(mutex)(&cdev->stream_mutex); + mute = (bool)ucontrol->value.integer.value[0]; stream = catpt_stream_find(cdev, CATPT_PIN_ID_REFERENCE); if (!stream) {