aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2025-06-02 16:51:02 +0100
committerMark Brown <broonie@kernel.org>2025-06-02 16:51:02 +0100
commitb3f3ca04ec3f0587b92fcffa4d581e73b335701a (patch)
treea6ced6de2bc004e493df9907e4cd9f9d6536f891 /sound
parentASoC: ti: omap-hdmi: Re-add dai_link->platform to fix card init (diff)
parentASoC: Intel: avs: Include missing string.h (diff)
downloadlinux-rng-b3f3ca04ec3f0587b92fcffa4d581e73b335701a.tar.xz
linux-rng-b3f3ca04ec3f0587b92fcffa4d581e73b335701a.zip
ASoC: Intel: avs: Set of functional fixes
Merge series from Cezary Rojewski <cezary.rojewski@intel.com>: Medium range of fixes all avs-driver related. The most important fixes lead the way: 1. For ASoC-hda codec driver, existing RPM manipulation in hda_codec_probe_complete()'s error path is superfluous and leads to RPM usage count underflow if the probe exists early e.g.: build-controls operation fails. 2. Resolve deadlock when DSP-recovery is a consequence of SET_D0IX IPC. The procedure handling IPC timeouts and EXCEPTION_CAUGHT notification shall cancel any D0IX work before proceeding with DSP recovery. If SET_D0IX called from delayed_work is the failing IPC the procedure will deadlock. 3. LINK format (PPLCxFMT) calculation is incorrect. HDAudio transfer types utilize SDxFMT for front-end (HOST) and PPLCxFMT for back-end (LINK) side when setting up the stream. BE's substream->runtime duplicates FE runtime so switch to using BE's hw_params to address incorrect format values on the LINK side when FE and BE formats differ. Below three patches address problems found by Coverity static analyzer: ASoC: Intel: avs: Fix possible null-ptr-deref when initing hw ASoC: Intel: avs: Verify kcalloc() status when setting constraints ASoC: Intel: avs: Verify content returned by parse_int_array() While unlikely in runtime, it's good to keep code resilient. The last few patches are readability/cohesiveness improvements.
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/hda.c4
-rw-r--r--sound/soc/intel/avs/core.c20
-rw-r--r--sound/soc/intel/avs/debugfs.c6
-rw-r--r--sound/soc/intel/avs/ipc.c4
-rw-r--r--sound/soc/intel/avs/loader.c1
-rw-r--r--sound/soc/intel/avs/path.c2
-rw-r--r--sound/soc/intel/avs/pcm.c13
7 files changed, 29 insertions, 21 deletions
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
index ddc00927313c..dc7794c9ac44 100644
--- a/sound/soc/codecs/hda.c
+++ b/sound/soc/codecs/hda.c
@@ -152,7 +152,7 @@ int hda_codec_probe_complete(struct hda_codec *codec)
ret = snd_hda_codec_build_controls(codec);
if (ret < 0) {
dev_err(&hdev->dev, "unable to create controls %d\n", ret);
- goto out;
+ return ret;
}
/* Bus suspended codecs as it does not manage their pm */
@@ -160,7 +160,7 @@ int hda_codec_probe_complete(struct hda_codec *codec)
/* rpm was forbidden in snd_hda_codec_device_new() */
snd_hda_codec_set_power_save(codec, 2000);
snd_hda_codec_register(codec);
-out:
+
/* Complement pm_runtime_get_sync(bus) in probe */
pm_runtime_mark_last_busy(bus->dev);
pm_runtime_put_autosuspend(bus->dev);
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index 485842838025..ec1b3f55cb5c 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -945,14 +945,14 @@ MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
MODULE_AUTHOR("Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>");
MODULE_DESCRIPTION("Intel cAVS sound driver");
MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("intel/skl/dsp_basefw.bin");
-MODULE_FIRMWARE("intel/apl/dsp_basefw.bin");
-MODULE_FIRMWARE("intel/cnl/dsp_basefw.bin");
-MODULE_FIRMWARE("intel/icl/dsp_basefw.bin");
-MODULE_FIRMWARE("intel/jsl/dsp_basefw.bin");
-MODULE_FIRMWARE("intel/lkf/dsp_basefw.bin");
-MODULE_FIRMWARE("intel/tgl/dsp_basefw.bin");
-MODULE_FIRMWARE("intel/ehl/dsp_basefw.bin");
-MODULE_FIRMWARE("intel/adl/dsp_basefw.bin");
-MODULE_FIRMWARE("intel/adl_n/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/skl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/apl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/cnl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/icl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/jsl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/lkf/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/tgl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/ehl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/adl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/avs/adl_n/dsp_basefw.bin");
MODULE_FIRMWARE("intel/fcl/dsp_basefw.bin");
diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c
index 8c4edda97f75..0e826ca20619 100644
--- a/sound/soc/intel/avs/debugfs.c
+++ b/sound/soc/intel/avs/debugfs.c
@@ -373,7 +373,10 @@ static ssize_t trace_control_write(struct file *file, const char __user *from, s
return ret;
num_elems = *array;
- resource_mask = array[1];
+ if (!num_elems) {
+ ret = -EINVAL;
+ goto free_array;
+ }
/*
* Disable if just resource mask is provided - no log priority flags.
@@ -381,6 +384,7 @@ static ssize_t trace_control_write(struct file *file, const char __user *from, s
* Enable input format: mask, prio1, .., prioN
* Where 'N' equals number of bits set in the 'mask'.
*/
+ resource_mask = array[1];
if (num_elems == 1) {
ret = disable_logs(adev, resource_mask);
} else {
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index 08ed9d96738a..0314f9d4ea5f 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -169,7 +169,9 @@ static void avs_dsp_exception_caught(struct avs_dev *adev, union avs_notify_msg
dev_crit(adev->dev, "communication severed, rebooting dsp..\n");
- cancel_delayed_work_sync(&ipc->d0ix_work);
+ /* Avoid deadlock as the exception may be the response to SET_D0IX. */
+ if (current_work() != &ipc->d0ix_work.work)
+ cancel_delayed_work_sync(&ipc->d0ix_work);
ipc->in_d0ix = false;
/* Re-enabled on recovery completion. */
pm_runtime_disable(adev->dev);
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index 138e4e9de5e3..353e343b1d28 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -9,6 +9,7 @@
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <sound/hdaudio.h>
#include <sound/hdaudio_ext.h>
#include "avs.h"
diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c
index ed8f0ea0e10d..e8e6b1c7fc90 100644
--- a/sound/soc/intel/avs/path.c
+++ b/sound/soc/intel/avs/path.c
@@ -134,6 +134,8 @@ int avs_path_set_constraint(struct avs_dev *adev, struct avs_tplg_path_template
rlist = kcalloc(i, sizeof(*rlist), GFP_KERNEL);
clist = kcalloc(i, sizeof(*clist), GFP_KERNEL);
slist = kcalloc(i, sizeof(*slist), GFP_KERNEL);
+ if (!rlist || !clist || !slist)
+ return -ENOMEM;
i = 0;
list_for_each_entry(path_template, &template->path_list, node) {
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 405cfc1ab0cb..ccf90428126d 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -83,10 +83,8 @@ void avs_period_elapsed(struct snd_pcm_substream *substream)
static int hw_rule_param_size(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule);
static int avs_hw_constraints_init(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_hw_constraint_list *r, *c, *s;
- struct avs_tplg_path_template *template;
struct avs_dma_data *data;
int ret;
@@ -99,8 +97,7 @@ static int avs_hw_constraints_init(struct snd_pcm_substream *substream, struct s
c = &(data->channels_list);
s = &(data->sample_bits_list);
- template = avs_dai_find_path_template(dai, !rtd->dai_link->no_pcm, substream->stream);
- ret = avs_path_set_constraint(data->adev, template, r, c, s);
+ ret = avs_path_set_constraint(data->adev, data->template, r, c, s);
if (ret <= 0)
return ret;
@@ -450,9 +447,10 @@ static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct sn
static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);
const struct snd_soc_pcm_stream *stream_info;
struct hdac_ext_stream *link_stream;
+ const struct snd_pcm_hw_params *p;
struct avs_dma_data *data;
unsigned int format_val;
unsigned int bits;
@@ -460,14 +458,15 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn
data = snd_soc_dai_get_dma_data(dai, substream);
link_stream = data->link_stream;
+ p = &be->dpcm[substream->stream].hw_params;
if (link_stream->link_prepared)
return 0;
stream_info = snd_soc_dai_get_pcm_stream(dai, substream->stream);
- bits = snd_hdac_stream_format_bits(runtime->format, runtime->subformat,
+ bits = snd_hdac_stream_format_bits(params_format(p), params_subformat(p),
stream_info->sig_bits);
- format_val = snd_hdac_stream_format(runtime->channels, bits, runtime->rate);
+ format_val = snd_hdac_stream_format(params_channels(p), bits, params_rate(p));
snd_hdac_ext_stream_decouple(&data->adev->base.core, link_stream, true);
snd_hdac_ext_stream_reset(link_stream);