From 18ebffe4d043bf5f3a9b669d8d91f855bde8f6b7 Mon Sep 17 00:00:00 2001 From: Iulian Olaru Date: Thu, 17 Sep 2020 13:56:26 +0300 Subject: [PATCH 1/8] ASoC: SOF: imx: Add debug support for imx platforms This patch adds debug support for imx platforms. This is important in order to gather information about the state of the DSP in case of an oops and the reason for the oops. This is done by checking if a message with a panic code has been placed in the debug box, in the imx8_dsp_handle_request function from sof/imx. If positive, the function imx8_dump, added in common, will be called. The first step is to gather information about the registers, filename, line number and stack by calling the imx8_get_registers, added in common. Then the information will be printed to the console by calling the get_status function. Signed-off-by: Iulian Olaru Reviewed-by: Guennadi Liakhovetski Reviewed-by: Daniel Baluta Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20200917105633.2579047-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/imx/Kconfig | 8 ++++ sound/soc/sof/imx/Makefile | 3 ++ sound/soc/sof/imx/imx-common.c | 72 ++++++++++++++++++++++++++++++++++ sound/soc/sof/imx/imx-common.h | 16 ++++++++ sound/soc/sof/imx/imx8.c | 23 ++++++++++- sound/soc/sof/imx/imx8m.c | 17 +++++++- 6 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 sound/soc/sof/imx/imx-common.c create mode 100644 sound/soc/sof/imx/imx-common.h diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig index 23bfd79d09c3..48f998a19ddb 100644 --- a/sound/soc/sof/imx/Kconfig +++ b/sound/soc/sof/imx/Kconfig @@ -19,6 +19,12 @@ config SND_SOC_SOF_IMX_OF This option is not user-selectable but automagically handled by 'select' statements at a higher level +config SND_SOC_SOF_IMX_COMMON + tristate + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level. + config SND_SOC_SOF_IMX8_SUPPORT bool "SOF support for i.MX8" depends on IMX_SCU=y || IMX_SCU=SND_SOC_SOF_IMX_OF @@ -30,6 +36,7 @@ config SND_SOC_SOF_IMX8_SUPPORT config SND_SOC_SOF_IMX8 tristate + select SND_SOC_SOF_IMX_COMMON select SND_SOC_SOF_XTENSA help This option is not user-selectable but automagically handled by @@ -45,6 +52,7 @@ config SND_SOC_SOF_IMX8M_SUPPORT config SND_SOC_SOF_IMX8M tristate + select SND_SOC_SOF_IMX_COMMON select SND_SOC_SOF_XTENSA help This option is not user-selectable but automagically handled by diff --git a/sound/soc/sof/imx/Makefile b/sound/soc/sof/imx/Makefile index 2b933b02bbac..dba93c3466ec 100644 --- a/sound/soc/sof/imx/Makefile +++ b/sound/soc/sof/imx/Makefile @@ -2,5 +2,8 @@ snd-sof-imx8-objs := imx8.o snd-sof-imx8m-objs := imx8m.o +snd-sof-imx-common-objs := imx-common.o + obj-$(CONFIG_SND_SOC_SOF_IMX8) += snd-sof-imx8.o obj-$(CONFIG_SND_SOC_SOF_IMX8M) += snd-sof-imx8m.o +obj-$(CONFIG_SND_SOC_SOF_IMX_COMMON) += imx-common.o diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c new file mode 100644 index 000000000000..63d8a5d7bc44 --- /dev/null +++ b/sound/soc/sof/imx/imx-common.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright 2020 NXP +// +// Common helpers for the audio DSP on i.MX8 + +#include +#include "../ops.h" + +#include "imx-common.h" + +/** + * imx8_get_registers() - This function is called in case of DSP oops + * in order to gather information about the registers, filename and + * linenumber and stack. + * @sdev: SOF device + * @xoops: Stores information about registers. + * @panic_info: Stores information about filename and line number. + * @stack: Stores the stack dump. + * @stack_words: Size of the stack dump. + */ +void imx8_get_registers(struct snd_sof_dev *sdev, + struct sof_ipc_dsp_oops_xtensa *xoops, + struct sof_ipc_panic_info *panic_info, + u32 *stack, size_t stack_words) +{ + u32 offset = sdev->dsp_oops_offset; + + /* first read registers */ + sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops)); + + /* then get panic info */ + if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) { + dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n", + xoops->arch_hdr.totalsize); + return; + } + offset += xoops->arch_hdr.totalsize; + sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info)); + + /* then get the stack */ + offset += sizeof(*panic_info); + sof_mailbox_read(sdev, offset, stack, stack_words * sizeof(u32)); +} + +/** + * imx8_dump() - This function is called when a panic message is + * received from the firmware. + */ +void imx8_dump(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_dsp_oops_xtensa xoops; + struct sof_ipc_panic_info panic_info; + u32 stack[IMX8_STACK_DUMP_SIZE]; + u32 status; + + /* Get information about the panic status from the debug box area. + * Compute the trace point based on the status. + */ + sof_mailbox_read(sdev, sdev->debug_box.offset + 0x4, &status, 4); + + /* Get information about the registers, the filename and line + * number and the stack. + */ + imx8_get_registers(sdev, &xoops, &panic_info, stack, + IMX8_STACK_DUMP_SIZE); + + /* Print the information to the console */ + snd_sof_get_status(sdev, status, status, &xoops, &panic_info, stack, + IMX8_STACK_DUMP_SIZE); +} +EXPORT_SYMBOL(imx8_dump); diff --git a/sound/soc/sof/imx/imx-common.h b/sound/soc/sof/imx/imx-common.h new file mode 100644 index 000000000000..1cc7d6704182 --- /dev/null +++ b/sound/soc/sof/imx/imx-common.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ + +#ifndef __IMX_COMMON_H__ +#define __IMX_COMMON_H__ + +#define EXCEPT_MAX_HDR_SIZE 0x400 +#define IMX8_STACK_DUMP_SIZE 32 + +void imx8_get_registers(struct snd_sof_dev *sdev, + struct sof_ipc_dsp_oops_xtensa *xoops, + struct sof_ipc_panic_info *panic_info, + u32 *stack, size_t stack_words); + +void imx8_dump(struct snd_sof_dev *sdev, u32 flags); + +#endif diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 3b9ffc760cb5..4e7dccadd7d0 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -21,6 +21,7 @@ #include #include #include "../ops.h" +#include "imx-common.h" /* DSP memories */ #define IRAM_OFFSET 0x10000 @@ -115,8 +116,16 @@ static void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc) static void imx8_dsp_handle_request(struct imx_dsp_ipc *ipc) { struct imx8_priv *priv = imx_dsp_get_data(ipc); + u32 p; /* panic code */ - snd_sof_ipc_msgs_rx(priv->sdev); + /* Read the message from the debug box. */ + sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p)); + + /* Check to see if the message is a panic code (0x0dead***) */ + if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) + snd_sof_dsp_panic(priv->sdev, p); + else + snd_sof_ipc_msgs_rx(priv->sdev); } static struct imx_dsp_ops dsp_ops = { @@ -409,6 +418,9 @@ struct snd_sof_dsp_ops sof_imx8_ops = { .block_read = sof_block_read, .block_write = sof_block_write, + /* Module IO */ + .read64 = sof_io_read64, + /* ipc */ .send_msg = imx8_send_msg, .fw_ready = sof_fw_ready, @@ -424,6 +436,9 @@ struct snd_sof_dsp_ops sof_imx8_ops = { /* firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, + /* Debug information */ + .dbg_dump = imx8_dump, + /* Firmware ops */ .arch_ops = &sof_xtensa_arch_ops, @@ -452,6 +467,9 @@ struct snd_sof_dsp_ops sof_imx8x_ops = { .block_read = sof_block_read, .block_write = sof_block_write, + /* Module IO */ + .read64 = sof_io_read64, + /* ipc */ .send_msg = imx8_send_msg, .fw_ready = sof_fw_ready, @@ -467,6 +485,9 @@ struct snd_sof_dsp_ops sof_imx8x_ops = { /* firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, + /* Debug information */ + .dbg_dump = imx8_dump, + /* Firmware ops */ .arch_ops = &sof_xtensa_arch_ops, diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index ca23ac99a63d..cb822d953767 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -17,6 +17,7 @@ #include #include "../ops.h" +#include "imx-common.h" #define MBOX_OFFSET 0x800000 #define MBOX_SIZE 0x1000 @@ -88,8 +89,16 @@ static void imx8m_dsp_handle_reply(struct imx_dsp_ipc *ipc) static void imx8m_dsp_handle_request(struct imx_dsp_ipc *ipc) { struct imx8m_priv *priv = imx_dsp_get_data(ipc); + u32 p; /* Panic code */ - snd_sof_ipc_msgs_rx(priv->sdev); + /* Read the message from the debug box. */ + sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p)); + + /* Check to see if the message is a panic code (0x0dead***) */ + if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) + snd_sof_dsp_panic(priv->sdev, p); + else + snd_sof_ipc_msgs_rx(priv->sdev); } static struct imx_dsp_ops imx8m_dsp_ops = { @@ -262,6 +271,9 @@ struct snd_sof_dsp_ops sof_imx8m_ops = { .block_read = sof_block_read, .block_write = sof_block_write, + /* Module IO */ + .read64 = sof_io_read64, + /* ipc */ .send_msg = imx8m_send_msg, .fw_ready = sof_fw_ready, @@ -277,6 +289,9 @@ struct snd_sof_dsp_ops sof_imx8m_ops = { /* firmware loading */ .load_firmware = snd_sof_load_firmware_memcpy, + /* Debug information */ + .dbg_dump = imx8_dump, + /* Firmware ops */ .arch_ops = &sof_xtensa_arch_ops, From 6eab771472af50e11a484d56ba444e2ec82e9126 Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Thu, 17 Sep 2020 13:56:27 +0300 Subject: [PATCH 2/8] ASoC: SOF: Add `src_hash` to `sof_ipc_fw_version` structure This field will be used to compare ldc file with loaded fw version, to assert validity of trace logs. Value used in sof-logger. Signed-off-by: Karol Trzcinski Reviewed-by: Guennadi Liakhovetski Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20200917105633.2579047-3-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/info.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/sound/sof/info.h b/include/sound/sof/info.h index 313e3e70c630..0b7101aef596 100644 --- a/include/sound/sof/info.h +++ b/include/sound/sof/info.h @@ -46,9 +46,11 @@ struct sof_ipc_fw_version { uint8_t time[10]; uint8_t tag[6]; uint32_t abi_version; + /* used to check FW and ldc file compatibility, reproducible value */ + uint32_t src_hash; /* reserved for future use */ - uint32_t reserved[4]; + uint32_t reserved[3]; } __packed; /* FW ready Message - sent by firmware when boot has completed */ From 7db6db9d1a4a7864cd2557e983e06f3adf788c6a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Sep 2020 13:56:28 +0300 Subject: [PATCH 3/8] ASoC: SOF: debug: update test for pm_runtime_get_sync() We need to avoid reporting an error for -EACCESS when pm_runtime is not enabled. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20200917105633.2579047-4-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 8e15f105d1d5..9419a99bab53 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -405,7 +405,7 @@ static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer, } ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { + if (ret < 0 && ret != -EACCES) { dev_err_ratelimited(sdev->dev, "error: debugfs write failed to resume %d\n", ret); From 99ceec5ca0cb29e3b1d556d108ddc54654377792 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Sep 2020 13:56:29 +0300 Subject: [PATCH 4/8] ASoC: SOF: control: update test for pm_runtime_get_sync() We need to avoid reporting an error for -EACCESS when pm_runtime is not enabled. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20200917105633.2579047-5-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index d5e2966cafac..5419c93badd2 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -367,7 +367,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ int err; ret = pm_runtime_get_sync(scomp->dev); - if (ret < 0) { + if (ret < 0 && ret != -EACCES) { dev_err_ratelimited(scomp->dev, "error: bytes_ext get failed to resume %d\n", ret); pm_runtime_put_noidle(scomp->dev); return ret; From b9f8e1387cf0c9911b26c9d1fca84605d923de66 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 17 Sep 2020 13:56:30 +0300 Subject: [PATCH 5/8] ASoC: SOF: (cosmetic) remove redundant "ret" variable uses In some cases no "ret" variable is even needed, those functions always return 0 anyway, in other cases "ret" initialisation is redundant. Signed-off-by: Guennadi Liakhovetski Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20200917105633.2579047-6-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/control.c | 22 +++++++--------------- sound/soc/sof/topology.c | 24 +++++++++++------------- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 5419c93badd2..63ead9ebc4c6 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -221,7 +221,6 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_abi_hdr *data = cdata->data; size_t size; - int ret = 0; if (be->max > sizeof(ucontrol->value.bytes.data)) { dev_err_ratelimited(scomp->dev, @@ -235,15 +234,13 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, dev_err_ratelimited(scomp->dev, "error: DSP sent %zu bytes max is %d\n", size, be->max); - ret = -EINVAL; - goto out; + return -EINVAL; } /* copy back to kcontrol */ memcpy(ucontrol->value.bytes.data, data, size); -out: - return ret; + return 0; } int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, @@ -424,7 +421,6 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data; int data_size; - int ret = 0; /* * Decrement the limit by ext bytes header size to @@ -443,20 +439,16 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, if (data_size > be->max) { dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %d.\n", data_size, be->max); - ret = -EINVAL; - goto out; + return -EINVAL; } header.numid = scontrol->cmd; header.length = data_size; - if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) { - ret = -EFAULT; - goto out; - } + if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) + return -EFAULT; if (copy_to_user(tlvd->tlv, cdata->data, data_size)) - ret = -EFAULT; + return -EFAULT; -out: - return ret; + return 0; } diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index d5efac3af5c2..fa85a22b5880 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -63,7 +63,7 @@ static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir) struct sof_ipc_pcm_params pcm; struct snd_pcm_hw_params *params; struct snd_sof_pcm *spcm; - int ret = 0; + int ret; memset(&pcm, 0, sizeof(pcm)); @@ -121,7 +121,7 @@ static int ipc_trigger(struct snd_sof_widget *swidget, int cmd) struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc_stream stream; struct sof_ipc_reply reply; - int ret = 0; + int ret; /* set IPC stream params */ stream.hdr.size = sizeof(stream); @@ -1033,7 +1033,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, struct sof_ipc_ctrl_data *cdata; int tlv[TLV_ITEMS]; unsigned int i; - int ret = 0; + int ret; /* validate topology data */ if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) { @@ -1098,7 +1098,7 @@ skip: dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d\n", scontrol->comp_id, scontrol->num_channels); - return ret; + return 0; out_free_table: if (le32_to_cpu(mc->max) > 1) @@ -1151,7 +1151,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, container_of(hdr, struct snd_soc_tplg_bytes_control, hdr); struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; int max_size = sbe->max; - int ret = 0; + int ret; /* init the get/put bytes data */ scontrol->size = sizeof(struct sof_ipc_ctrl_data) + @@ -1204,7 +1204,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, } } - return ret; + return 0; out_free: kfree(scontrol->control_data); @@ -1223,7 +1223,7 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_dobj *dobj; struct snd_sof_control *scontrol; - int ret = -EINVAL; + int ret; dev_dbg(scomp->dev, "tplg: load control type %d name : %s\n", hdr->type, hdr->name); @@ -1276,7 +1276,7 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, dobj->private = scontrol; list_add(&scontrol->list, &sdev->kcontrol_list); - return ret; + return 0; } static int sof_control_unload(struct snd_soc_component *scomp, @@ -2659,7 +2659,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_private *private = &pcm->priv; struct snd_sof_pcm *spcm; int stream; - int ret = 0; + int ret; /* nothing to do for BEs atm */ if (!pcm) @@ -3350,7 +3350,6 @@ static int sof_link_hda_unload(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link) { struct snd_soc_dai *dai; - int ret = 0; dai = snd_soc_find_dai(link->cpus); if (!dai) { @@ -3359,7 +3358,7 @@ static int sof_link_hda_unload(struct snd_sof_dev *sdev, return -EINVAL; } - return ret; + return 0; } static int sof_link_unload(struct snd_soc_component *scomp, @@ -3492,7 +3491,6 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, sink_swidget->id != snd_soc_dapm_buffer) { dev_dbg(scomp->dev, "warning: neither Linked source component %s nor sink component %s is of buffer type, ignoring link\n", route->source, route->sink); - ret = 0; goto err; } else { ret = sof_ipc_tx_message(sdev->ipc, @@ -3526,7 +3524,7 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, /* add route to route list */ list_add(&sroute->list, &sdev->route_list); - return ret; + return 0; } err: From db69bcf915a37d7b8e54acf5f67d09d8159eb616 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 17 Sep 2020 13:56:31 +0300 Subject: [PATCH 6/8] ASoC: SOF: remove several superfluous type-casts No need to type-cast assignments between void and other pointers in C. Signed-off-by: Guennadi Liakhovetski Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20200917105633.2579047-7-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-audio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index cd506a4bfc4b..afe7e503bf66 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -485,13 +485,13 @@ EXPORT_SYMBOL(sof_machine_check); int sof_machine_register(struct snd_sof_dev *sdev, void *pdata) { - struct snd_sof_pdata *plat_data = (struct snd_sof_pdata *)pdata; + struct snd_sof_pdata *plat_data = pdata; const char *drv_name; const void *mach; int size; drv_name = plat_data->machine->drv_name; - mach = (const void *)plat_data->machine; + mach = plat_data->machine; size = sizeof(*plat_data->machine); /* register machine driver, pass machine info as pdata */ @@ -510,7 +510,7 @@ EXPORT_SYMBOL(sof_machine_register); void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata) { - struct snd_sof_pdata *plat_data = (struct snd_sof_pdata *)pdata; + struct snd_sof_pdata *plat_data = pdata; if (!IS_ERR_OR_NULL(plat_data->pdev_mach)) platform_device_unregister(plat_data->pdev_mach); From 0e4ea878708be903566ad93d4972ad3dd4c1c30e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 17 Sep 2020 13:56:32 +0300 Subject: [PATCH 7/8] ASoC: SOF: fix range checks On multiple locations checks are performed of untrusted values after adding a constant to them. This is wrong, because the addition might overflow and the result can then pass the check, although the original value is invalid. Fix multiple such issues by checking the actual value and not a sum of it and a constant. Signed-off-by: Guennadi Liakhovetski Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20200917105633.2579047-8-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/control.c | 38 ++++++++++++++++++++++---------------- sound/soc/sof/topology.c | 22 ++++++++++++++-------- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 63ead9ebc4c6..58f8c998e6af 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -229,14 +229,16 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, return -EINVAL; } - size = data->size + sizeof(*data); - if (size > be->max) { + /* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */ + if (data->size > be->max - sizeof(*data)) { dev_err_ratelimited(scomp->dev, - "error: DSP sent %zu bytes max is %d\n", - size, be->max); + "error: %u bytes of control data is invalid, max is %zu\n", + data->size, be->max - sizeof(*data)); return -EINVAL; } + size = data->size + sizeof(*data); + /* copy back to kcontrol */ memcpy(ucontrol->value.bytes.data, data, size); @@ -252,7 +254,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_abi_hdr *data = cdata->data; - size_t size = data->size + sizeof(*data); + size_t size; if (be->max > sizeof(ucontrol->value.bytes.data)) { dev_err_ratelimited(scomp->dev, @@ -261,13 +263,16 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - if (size > be->max) { + /* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */ + if (data->size > be->max - sizeof(*data)) { dev_err_ratelimited(scomp->dev, - "error: size too big %zu bytes max is %d\n", - size, be->max); + "error: data size too big %u bytes max is %zu\n", + data->size, be->max - sizeof(*data)); return -EINVAL; } + size = data->size + sizeof(*data); + /* copy from kcontrol */ memcpy(data, ucontrol->value.bytes.data, size); @@ -334,7 +339,8 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - if (cdata->data->size + sizeof(const struct sof_abi_hdr) > be->max) { + /* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */ + if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) { dev_err_ratelimited(scomp->dev, "error: Mismatch in ABI data size (truncated?).\n"); return -EINVAL; } @@ -420,7 +426,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, struct snd_ctl_tlv header; struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data; - int data_size; + size_t data_size; /* * Decrement the limit by ext bytes header size to @@ -432,16 +438,16 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, cdata->data->magic = SOF_ABI_MAGIC; cdata->data->abi = SOF_ABI_VERSION; - /* Prevent read of other kernel data or possibly corrupt response */ - data_size = cdata->data->size + sizeof(const struct sof_abi_hdr); - /* check data size doesn't exceed max coming from topology */ - if (data_size > be->max) { - dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %d.\n", - data_size, be->max); + if (cdata->data->size > be->max - sizeof(const struct sof_abi_hdr)) { + dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %zu.\n", + cdata->data->size, + be->max - sizeof(const struct sof_abi_hdr)); return -EINVAL; } + data_size = cdata->data->size + sizeof(const struct sof_abi_hdr); + header.numid = scontrol->cmd; header.length = data_size; if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index fa85a22b5880..eaa1122d5a68 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1150,20 +1150,26 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, struct snd_soc_tplg_bytes_control *control = container_of(hdr, struct snd_soc_tplg_bytes_control, hdr); struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; - int max_size = sbe->max; + size_t max_size = sbe->max; + size_t priv_size = le32_to_cpu(control->priv.size); int ret; - /* init the get/put bytes data */ - scontrol->size = sizeof(struct sof_ipc_ctrl_data) + - le32_to_cpu(control->priv.size); - - if (scontrol->size > max_size) { - dev_err(scomp->dev, "err: bytes data size %d exceeds max %d.\n", - scontrol->size, max_size); + if (max_size < sizeof(struct sof_ipc_ctrl_data) || + max_size < sizeof(struct sof_abi_hdr)) { ret = -EINVAL; goto out; } + /* init the get/put bytes data */ + if (priv_size > max_size - sizeof(struct sof_ipc_ctrl_data)) { + dev_err(scomp->dev, "err: bytes data size %zu exceeds max %zu.\n", + priv_size, max_size - sizeof(struct sof_ipc_ctrl_data)); + ret = -EINVAL; + goto out; + } + + scontrol->size = sizeof(struct sof_ipc_ctrl_data) + priv_size; + scontrol->control_data = kzalloc(max_size, GFP_KERNEL); cdata = scontrol->control_data; if (!scontrol->control_data) { From 776100a4ce6da8f7fa451509e46852d69c2162a8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Sep 2020 13:56:33 +0300 Subject: [PATCH 8/8] ASoC: SOF: Intel: hda: reduce verbosity of boot error logs Previous commits reduced the verbosity of errors during boot iterations, but there are still a couple remaining which generate false positives. Errors should only be logged when after last attempt to download firmware failed. Duplicating logs and assigning them different levels based on the iteration number isn't really elegant, use macro as suggested by Guennadi. Suggested-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20200917105633.2579047-9-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-loader.c | 16 +++++++++------- sound/soc/sof/intel/hda.c | 12 +++++++++--- sound/soc/sof/intel/hda.h | 2 ++ sound/soc/sof/sof-priv.h | 8 ++++++++ 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index dfbfc89ffe70..2707a16c6a4d 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -82,7 +82,7 @@ error: * status on core 1, so power up core 1 also momentarily, keep it in * reset/stall and then turn it off */ -static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, int iteration) +static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; @@ -93,7 +93,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, int iteration) /* step 1: power up corex */ ret = hda_dsp_core_power_up(sdev, chip->host_managed_cores_mask); if (ret < 0) { - if (iteration == HDA_FW_BOOT_ATTEMPTS) + if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n"); goto err; } @@ -116,7 +116,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, int iteration) /* step 3: unset core 0 reset state & unstall/run core 0 */ ret = hda_dsp_core_run(sdev, BIT(0)); if (ret < 0) { - if (iteration == HDA_FW_BOOT_ATTEMPTS) + if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) dev_err(sdev->dev, "error: dsp core start failed %d\n", ret); ret = -EIO; @@ -132,7 +132,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, int iteration) HDA_DSP_INIT_TIMEOUT_US); if (ret < 0) { - if (iteration == HDA_FW_BOOT_ATTEMPTS) + if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) dev_err(sdev->dev, "error: %s: timeout for HIPCIE done\n", __func__); @@ -148,7 +148,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, int iteration) /* step 5: power down corex */ ret = hda_dsp_core_power_down(sdev, chip->host_managed_cores_mask & ~(BIT(0))); if (ret < 0) { - if (iteration == HDA_FW_BOOT_ATTEMPTS) + if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) dev_err(sdev->dev, "error: dsp core x power down failed\n"); goto err; @@ -168,7 +168,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, int iteration) if (!ret) return 0; - if (iteration == HDA_FW_BOOT_ATTEMPTS) + if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) dev_err(sdev->dev, "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", __func__); @@ -328,6 +328,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct snd_sof_pdata *plat_data = sdev->pdata; const struct sof_dev_desc *desc = plat_data->desc; const struct sof_intel_dsp_desc *chip_info; @@ -364,7 +365,8 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "Attempting iteration %d of Core En/ROM load...\n", i); - ret = cl_dsp_init(sdev, stream->hstream.stream_tag, i + 1); + hda->boot_iteration = i + 1; + ret = cl_dsp_init(sdev, stream->hstream.stream_tag); /* don't retry anymore if successful */ if (!ret) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 882527119c70..bb4128a72a42 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -418,6 +418,7 @@ void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags) /* dump the first 8 dwords representing the extended ROM status */ static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; char msg[128]; int len = 0; u32 value; @@ -428,11 +429,14 @@ static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev) len += snprintf(msg + len, sizeof(msg) - len, " 0x%x", value); } - dev_err(sdev->dev, "error: extended rom status:%s", msg); + sof_dev_dbg_or_err(sdev->dev, hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS, + "extended rom status: %s", msg); + } void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct sof_ipc_dsp_oops_xtensa xoops; struct sof_ipc_panic_info panic_info; u32 stack[HDA_DSP_STACK_DUMP_SIZE]; @@ -452,8 +456,10 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, HDA_DSP_STACK_DUMP_SIZE); } else { - dev_err(sdev->dev, "error: status = 0x%8.8x panic = 0x%8.8x\n", - status, panic); + sof_dev_dbg_or_err(sdev->dev, hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS, + "status = 0x%8.8x panic = 0x%8.8x\n", + status, panic); + hda_dsp_dump_ext_rom_status(sdev); hda_dsp_get_status(sdev); } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index f0f8f95c082b..badb308aed81 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -274,6 +274,7 @@ #define BXT_D0I3_DELAY 5000 #define FW_CL_STREAM_NUMBER 0x1 +#define HDA_FW_BOOT_ATTEMPTS 3 /* ADSPCS - Audio DSP Control & Status */ @@ -416,6 +417,7 @@ enum sof_hda_D0_substate { /* represents DSP HDA controller frontend - i.e. host facing control */ struct sof_intel_hda_dev { + int boot_iteration; struct hda_bus hbus; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 1c51d99f0459..0aed2a7ab858 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -578,4 +578,12 @@ int intel_pcm_close(struct snd_sof_dev *sdev, int sof_machine_check(struct snd_sof_dev *sdev); +#define sof_dev_dbg_or_err(dev, is_err, fmt, ...) \ + do { \ + if (is_err) \ + dev_err(dev, "error: " fmt, __VA_ARGS__); \ + else \ + dev_dbg(dev, fmt, __VA_ARGS__); \ + } while (0) + #endif