diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-12-04 10:08:40 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-12-04 10:08:40 -0800 |
| commit | 2aa680df68062e4e0c356ec2aa7100c13654907b (patch) | |
| tree | ee3dc5125e11aac04f2e33922cfad4260e47de34 /drivers/firmware | |
| parent | 6dfafbd0299a60bfb5d5e277fdf100037c7ded07 (diff) | |
| parent | eaf526cfa4e537af86543d77f402b9ae803f606e (diff) | |
Merge tag 'sound-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"The majority of changes at this time were about ASoC with a lot of
code refactoring works. From the functionality POV, there isn't much
to see, but we have a wide range of device-specific fixes and updates.
Here are some highlights:
- Continued ASoC API cleanup work, spanned over many files
- Added a SoundWire SCDA generic class driver with regmap support
- Enhancements and fixes for Cirrus, Intel, Maxim and Qualcomm.
- Support for ASoC Allwinner A523, Mediatek MT8189, Qualcomm QCM2290,
QRB2210 and SM6115, SpacemiT K1, and TI TAS2568, TAS5802, TAS5806,
TAS5815, TAS5828 and TAS5830
- Usual HD-audio and USB-audio quirks and fixups
- Support for Onkyo SE-300PCIE, TASCAM IF-FW/DM MkII
Some gpiolib changes for shared GPIOs are included along with this PR
for covering ASoC drivers changes"
* tag 'sound-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (739 commits)
ALSA: hda/realtek: Add PCI SSIDs to HP ProBook quirks
ALSA: usb-audio: Simplify with usb_endpoint_max_periodic_payload()
ALSA: hda/realtek: fix mute/micmute LEDs don't work for more HP laptops
ALSA: rawmidi: Fix inconsistent indenting warning reported by smatch
ALSA: dice: fix buffer overflow in detect_stream_formats()
ASoC: codecs: Modify awinic amplifier dsp read and write functions
ASoC: SDCA: Fixup some more Kconfig issues
ASoC: cs35l56: Log a message if firmware is missing
ASoC: nau8325: Delete a stray tab
firmware: cs_dsp: Add test cases for client_ops == NULL
firmware: cs_dsp: Don't require client to provide a struct cs_dsp_client_ops
ASoC: fsl_micfil: Set channel range control
ASoC: fsl_micfil: Add default quality for different platforms
ASoC: intel: sof_sdw: Add codec_info for cs42l45
ASoC: sdw_utils: Add cs42l45 support functions
ASoC: intel: sof_sdw: Add ability to have auxiliary devices
ASoC: sdw_utils: Move codec_name to dai info
ASoC: sdw_utils: Add codec_conf for every DAI
ASoC: SDCA: Add terminal type into input/output widget name
ASoC: SDCA: Align mute controls to ALSA expectations
...
Diffstat (limited to 'drivers/firmware')
| -rw-r--r-- | drivers/firmware/cirrus/cs_dsp.c | 175 | ||||
| -rw-r--r-- | drivers/firmware/cirrus/test/cs_dsp_test_callbacks.c | 1 |
2 files changed, 73 insertions, 103 deletions
diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index f51047d8ea64..525ac0f0a75d 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -9,9 +9,11 @@ * Cirrus Logic International Semiconductor Ltd. */ +#include <linux/cleanup.h> #include <linux/ctype.h> #include <linux/debugfs.h> #include <linux/delay.h> +#include <linux/math.h> #include <linux/minmax.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -316,44 +318,6 @@ struct cs_dsp_alg_region_list_item { struct cs_dsp_alg_region alg_region; }; -struct cs_dsp_buf { - struct list_head list; - void *buf; -}; - -static struct cs_dsp_buf *cs_dsp_buf_alloc(const void *src, size_t len, - struct list_head *list) -{ - struct cs_dsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL); - - if (buf == NULL) - return NULL; - - buf->buf = vmalloc(len); - if (!buf->buf) { - kfree(buf); - return NULL; - } - memcpy(buf->buf, src, len); - - if (list) - list_add_tail(&buf->list, list); - - return buf; -} - -static void cs_dsp_buf_free(struct list_head *list) -{ - while (!list_empty(list)) { - struct cs_dsp_buf *buf = list_first_entry(list, - struct cs_dsp_buf, - list); - list_del(&buf->list); - vfree(buf->buf); - kfree(buf); - } -} - /** * cs_dsp_mem_region_name() - Return a name string for a memory type * @type: the memory type to match @@ -388,18 +352,14 @@ EXPORT_SYMBOL_NS_GPL(cs_dsp_mem_region_name, "FW_CS_DSP"); #ifdef CONFIG_DEBUG_FS static void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, const char *s) { - char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); - kfree(dsp->wmfw_file_name); - dsp->wmfw_file_name = tmp; + dsp->wmfw_file_name = kstrdup(s, GFP_KERNEL); } static void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp, const char *s) { - char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); - kfree(dsp->bin_file_name); - dsp->bin_file_name = tmp; + dsp->bin_file_name = kstrdup(s, GFP_KERNEL); } static void cs_dsp_debugfs_clear(struct cs_dsp *dsp) @@ -410,24 +370,33 @@ static void cs_dsp_debugfs_clear(struct cs_dsp *dsp) dsp->bin_file_name = NULL; } +static ssize_t cs_dsp_debugfs_string_read(struct cs_dsp *dsp, + char __user *user_buf, + size_t count, loff_t *ppos, + const char **pstr) +{ + const char *str __free(kfree) = NULL; + + scoped_guard(mutex, &dsp->pwr_lock) { + if (!*pstr) + return 0; + + str = kasprintf(GFP_KERNEL, "%s\n", *pstr); + if (!str) + return -ENOMEM; + + return simple_read_from_buffer(user_buf, count, ppos, str, strlen(str)); + } +} + static ssize_t cs_dsp_debugfs_wmfw_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct cs_dsp *dsp = file->private_data; - ssize_t ret; - - mutex_lock(&dsp->pwr_lock); - if (!dsp->wmfw_file_name || !dsp->booted) - ret = 0; - else - ret = simple_read_from_buffer(user_buf, count, ppos, - dsp->wmfw_file_name, - strlen(dsp->wmfw_file_name)); - - mutex_unlock(&dsp->pwr_lock); - return ret; + return cs_dsp_debugfs_string_read(dsp, user_buf, count, ppos, + &dsp->wmfw_file_name); } static ssize_t cs_dsp_debugfs_bin_read(struct file *file, @@ -435,19 +404,9 @@ static ssize_t cs_dsp_debugfs_bin_read(struct file *file, size_t count, loff_t *ppos) { struct cs_dsp *dsp = file->private_data; - ssize_t ret; - - mutex_lock(&dsp->pwr_lock); - if (!dsp->bin_file_name || !dsp->booted) - ret = 0; - else - ret = simple_read_from_buffer(user_buf, count, ppos, - dsp->bin_file_name, - strlen(dsp->bin_file_name)); - - mutex_unlock(&dsp->pwr_lock); - return ret; + return cs_dsp_debugfs_string_read(dsp, user_buf, count, ppos, + &dsp->bin_file_name); } static const struct { @@ -479,9 +438,11 @@ static int cs_dsp_debugfs_read_controls_show(struct seq_file *s, void *ignored) struct cs_dsp_coeff_ctl *ctl; unsigned int reg; + guard(mutex)(&dsp->pwr_lock); + list_for_each_entry(ctl, &dsp->ctl_list, list) { cs_dsp_coeff_base_reg(ctl, ®, 0); - seq_printf(s, "%22.*s: %#8zx %s:%08x %#8x %s %#8x %#4x %c%c%c%c %s %s\n", + seq_printf(s, "%22.*s: %#8x %s:%08x %#8x %s %#8x %#4x %c%c%c%c %s %s\n", ctl->subname_len, ctl->subname, ctl->len, cs_dsp_mem_region_name(ctl->alg_region.type), ctl->offset, reg, ctl->fw_name, ctl->alg_region.alg, ctl->type, @@ -1028,7 +989,7 @@ static void cs_dsp_signal_event_controls(struct cs_dsp *dsp, static void cs_dsp_free_ctl_blk(struct cs_dsp_coeff_ctl *ctl) { - kfree(ctl->cache); + kvfree(ctl->cache); kfree(ctl->subname); kfree(ctl); } @@ -1078,7 +1039,7 @@ static int cs_dsp_create_control(struct cs_dsp *dsp, ctl->type = type; ctl->offset = offset; ctl->len = len; - ctl->cache = kzalloc(ctl->len, GFP_KERNEL); + ctl->cache = kvzalloc(ctl->len, GFP_KERNEL); if (!ctl->cache) { ret = -ENOMEM; goto err_ctl_subname; @@ -1096,7 +1057,7 @@ static int cs_dsp_create_control(struct cs_dsp *dsp, err_list_del: list_del(&ctl->list); - kfree(ctl->cache); + kvfree(ctl->cache); err_ctl_subname: kfree(ctl->subname); err_ctl: @@ -1485,7 +1446,9 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, const struct wmfw_region *region; const struct cs_dsp_region *mem; const char *region_name; - struct cs_dsp_buf *buf; + u8 *buf __free(kfree) = NULL; + size_t buf_len = 0; + size_t region_len; unsigned int reg; int regions = 0; int ret, offset, type; @@ -1605,23 +1568,23 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, region_name); if (reg) { - buf = cs_dsp_buf_alloc(region->data, - le32_to_cpu(region->len), - &buf_list); - if (!buf) { - cs_dsp_err(dsp, "Out of memory\n"); - ret = -ENOMEM; - goto out_fw; + region_len = le32_to_cpu(region->len); + if (region_len > buf_len) { + buf_len = round_up(region_len, PAGE_SIZE); + kfree(buf); + buf = kmalloc(buf_len, GFP_KERNEL | GFP_DMA); + if (!buf) { + ret = -ENOMEM; + goto out_fw; + } } - ret = regmap_raw_write(regmap, reg, buf->buf, - le32_to_cpu(region->len)); + memcpy(buf, region->data, region_len); + ret = regmap_raw_write(regmap, reg, buf, region_len); if (ret != 0) { cs_dsp_err(dsp, - "%s.%d: Failed to write %d bytes at %d in %s: %d\n", - file, regions, - le32_to_cpu(region->len), offset, - region_name, ret); + "%s.%d: Failed to write %zu bytes at %d in %s: %d\n", + file, regions, region_len, offset, region_name, ret); goto out_fw; } } @@ -1638,8 +1601,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, ret = 0; out_fw: - cs_dsp_buf_free(&buf_list); - if (ret == -EOVERFLOW) cs_dsp_err(dsp, "%s: file content overflows file data\n", file); @@ -2171,7 +2132,9 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware struct cs_dsp_alg_region *alg_region; const char *region_name; int ret, pos, blocks, type, offset, reg, version; - struct cs_dsp_buf *buf; + u8 *buf __free(kfree) = NULL; + size_t buf_len = 0; + size_t region_len; if (!firmware) return 0; @@ -2313,20 +2276,22 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware } if (reg) { - buf = cs_dsp_buf_alloc(blk->data, - le32_to_cpu(blk->len), - &buf_list); - if (!buf) { - cs_dsp_err(dsp, "Out of memory\n"); - ret = -ENOMEM; - goto out_fw; + region_len = le32_to_cpu(blk->len); + if (region_len > buf_len) { + buf_len = round_up(region_len, PAGE_SIZE); + kfree(buf); + buf = kmalloc(buf_len, GFP_KERNEL | GFP_DMA); + if (!buf) { + ret = -ENOMEM; + goto out_fw; + } } - cs_dsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", - file, blocks, le32_to_cpu(blk->len), - reg); - ret = regmap_raw_write(regmap, reg, buf->buf, - le32_to_cpu(blk->len)); + memcpy(buf, blk->data, region_len); + + cs_dsp_dbg(dsp, "%s.%d: Writing %zu bytes at %x\n", + file, blocks, region_len, reg); + ret = regmap_raw_write(regmap, reg, buf, region_len); if (ret != 0) { cs_dsp_err(dsp, "%s.%d: Failed to write to %x in %s: %d\n", @@ -2346,8 +2311,6 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware ret = 0; out_fw: - cs_dsp_buf_free(&buf_list); - if (ret == -EOVERFLOW) cs_dsp_err(dsp, "%s: file content overflows file data\n", file); @@ -2366,6 +2329,9 @@ static int cs_dsp_create_name(struct cs_dsp *dsp) return 0; } +static const struct cs_dsp_client_ops cs_dsp_default_client_ops = { +}; + static int cs_dsp_common_init(struct cs_dsp *dsp) { int ret; @@ -2379,6 +2345,9 @@ static int cs_dsp_common_init(struct cs_dsp *dsp) mutex_init(&dsp->pwr_lock); + if (!dsp->client_ops) + dsp->client_ops = &cs_dsp_default_client_ops; + #ifdef CONFIG_DEBUG_FS /* Ensure this is invalid if client never provides a debugfs root */ dsp->debugfs_root = ERR_PTR(-ENODEV); diff --git a/drivers/firmware/cirrus/test/cs_dsp_test_callbacks.c b/drivers/firmware/cirrus/test/cs_dsp_test_callbacks.c index 8a9b66a3b7d3..e5a389808e5f 100644 --- a/drivers/firmware/cirrus/test/cs_dsp_test_callbacks.c +++ b/drivers/firmware/cirrus/test/cs_dsp_test_callbacks.c @@ -600,6 +600,7 @@ KUNIT_ARRAY_PARAM(cs_dsp_callbacks_ops, static const struct cs_dsp_callbacks_test_param cs_dsp_no_callbacks_cases[] = { { .ops = &cs_dsp_callback_test_empty_client_ops, .case_name = "empty ops" }, + { .ops = NULL, .case_name = "NULL ops" }, }; KUNIT_ARRAY_PARAM(cs_dsp_no_callbacks, |