]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ASoC: Intel: catpt: Synchronize stream access
authorCezary Rojewski <cezary.rojewski@intel.com>
Mon, 9 Mar 2026 09:16:01 +0000 (10:16 +0100)
committerMark Brown <broonie@kernel.org>
Wed, 11 Mar 2026 13:34:09 +0000 (13:34 +0000)
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 <cezary.rojewski@intel.com>
Link: https://patch.msgid.link/20260309091605.896307-2-cezary.rojewski@intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/intel/catpt/core.h
sound/soc/intel/catpt/device.c
sound/soc/intel/catpt/ipc.c
sound/soc/intel/catpt/loader.c
sound/soc/intel/catpt/pcm.c

index df8a5fd95e13ed3db3d997e788263d5c15b5bf4a..7e479ef89ad0b787f84159bea11a4dbadbb30f30 100644 (file)
@@ -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;
index 0638aecba40de42f09fb658f9ed6d57f9f530ffc..b5f4361d4465ff80134a4de4b48cac113a340d44 100644 (file)
@@ -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);
 
        /*
index 5a01a9afb26ee42807566d7b67de2cf7ad3aa5c7..2e3b7a5cbb9b252bf648f0d17700945ea29c540c 100644 (file)
@@ -5,6 +5,7 @@
 // Author: Cezary Rojewski <cezary.rojewski@intel.com>
 //
 
+#include <linux/cleanup.h>
 #include <linux/irqreturn.h>
 #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",
index dc7afe587e6f2636ff1554edd78dfa9d9720f73d..432cb1f0ab4e234265a1d8ee08c6f1dedae3f2b8 100644 (file)
@@ -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;
index 2c5ea4e0ff3d79dca19cba825e862281a8397c23..fbe4821755bda3aa277caca2598261e9841e5b8f 100644 (file)
@@ -5,6 +5,7 @@
 // Author: Cezary Rojewski <cezary.rojewski@intel.com>
 //
 
+#include <linux/cleanup.h>
 #include <linux/pm_runtime.h>
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
@@ -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) {