Loading sound/soc/sof/Kconfig +8 −0 Original line number Diff line number Diff line Loading @@ -194,6 +194,14 @@ config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST Say Y if you want to enable IPC flood test. If unsure, select "N". config SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR bool "SOF enable IPC message injector" help This option enables the IPC message injector which can be used to send crafted IPC messages to the DSP to test its robustness. Say Y if you want to enable the IPC message injector. If unsure, select "N". config SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT bool "SOF retain DSP context on any FW exceptions" help Loading sound/soc/sof/debug.c +107 −0 Original line number Diff line number Diff line Loading @@ -336,6 +336,104 @@ static int sof_debug_ipc_flood_test(struct snd_sof_dev *sdev, } #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) static ssize_t msg_inject_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct snd_sof_dfsentry *dfse = file->private_data; struct sof_ipc_reply *rhdr = dfse->msg_inject_rx; if (!rhdr->hdr.size || !count || *ppos) return 0; if (count > rhdr->hdr.size) count = rhdr->hdr.size; if (copy_to_user(buffer, dfse->msg_inject_rx, count)) return -EFAULT; *ppos += count; return count; } static ssize_t msg_inject_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct snd_sof_dfsentry *dfse = file->private_data; struct snd_sof_dev *sdev = dfse->sdev; struct sof_ipc_cmd_hdr *hdr = dfse->msg_inject_tx; size_t size; int ret, err; if (*ppos) return 0; size = simple_write_to_buffer(dfse->msg_inject_tx, SOF_IPC_MSG_MAX_SIZE, ppos, buffer, count); if (size != count) return size > 0 ? -EFAULT : size; ret = pm_runtime_get_sync(sdev->dev); if (ret < 0 && ret != -EACCES) { dev_err_ratelimited(sdev->dev, "%s: DSP resume failed: %d\n", __func__, ret); pm_runtime_put_noidle(sdev->dev); goto out; } /* send the message */ memset(dfse->msg_inject_rx, 0, SOF_IPC_MSG_MAX_SIZE); ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, dfse->msg_inject_tx, count, dfse->msg_inject_rx, SOF_IPC_MSG_MAX_SIZE); pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) dev_err_ratelimited(sdev->dev, "%s: DSP idle failed: %d\n", __func__, err); /* return size if test is successful */ if (ret >= 0) ret = size; out: return ret; } static const struct file_operations msg_inject_fops = { .open = simple_open, .read = msg_inject_read, .write = msg_inject_write, .llseek = default_llseek, }; static int snd_sof_debugfs_msg_inject_item(struct snd_sof_dev *sdev, const char *name, mode_t mode, const struct file_operations *fops) { struct snd_sof_dfsentry *dfse; dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); if (!dfse) return -ENOMEM; /* pre allocate the tx and rx buffers */ dfse->msg_inject_tx = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); dfse->msg_inject_rx = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); if (!dfse->msg_inject_tx || !dfse->msg_inject_rx) return -ENOMEM; dfse->type = SOF_DFSENTRY_TYPE_BUF; dfse->sdev = sdev; debugfs_create_file(name, mode, sdev->debugfs_root, dfse, fops); /* add to dfsentry list */ list_add(&dfse->list, &sdev->dfsentry_list); return 0; } #endif static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { Loading Loading @@ -812,6 +910,15 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) return err; #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) err = snd_sof_debugfs_msg_inject_item(sdev, "ipc_msg_inject", 0644, &msg_inject_fops); /* errors are only due to memory allocation, not debugfs */ if (err < 0) return err; #endif return 0; } EXPORT_SYMBOL_GPL(snd_sof_dbg_init); Loading sound/soc/sof/imx/imx8.c +1 −36 Original line number Diff line number Diff line Loading @@ -59,40 +59,6 @@ struct imx8_priv { }; static void imx8_get_reply(struct snd_sof_dev *sdev) { struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; int ret = 0; if (!msg) { dev_warn(sdev->dev, "unexpected ipc interrupt\n"); return; } /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); if (reply.error < 0) { memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; } else { /* reply has correct size? */ if (reply.hdr.size != msg->reply_size) { dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", msg->reply_size, reply.hdr.size); ret = -EINVAL; } /* read the message */ if (msg->reply_size > 0) sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, msg->reply_size); } msg->reply_error = ret; } static int imx8_get_mailbox_offset(struct snd_sof_dev *sdev) { return MBOX_OFFSET; Loading @@ -109,8 +75,7 @@ static void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc) unsigned long flags; spin_lock_irqsave(&priv->sdev->ipc_lock, flags); imx8_get_reply(priv->sdev); snd_sof_ipc_reply(priv->sdev, 0); snd_sof_ipc_process_reply(priv->sdev, 0); spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); } Loading sound/soc/sof/imx/imx8m.c +1 −36 Original line number Diff line number Diff line Loading @@ -32,40 +32,6 @@ struct imx8m_priv { struct platform_device *ipc_dev; }; static void imx8m_get_reply(struct snd_sof_dev *sdev) { struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; int ret = 0; if (!msg) { dev_warn(sdev->dev, "unexpected ipc interrupt\n"); return; } /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); if (reply.error < 0) { memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; } else { /* reply has correct size? */ if (reply.hdr.size != msg->reply_size) { dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", msg->reply_size, reply.hdr.size); ret = -EINVAL; } /* read the message */ if (msg->reply_size > 0) sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, msg->reply_size); } msg->reply_error = ret; } static int imx8m_get_mailbox_offset(struct snd_sof_dev *sdev) { return MBOX_OFFSET; Loading @@ -82,8 +48,7 @@ static void imx8m_dsp_handle_reply(struct imx_dsp_ipc *ipc) unsigned long flags; spin_lock_irqsave(&priv->sdev->ipc_lock, flags); imx8m_get_reply(priv->sdev); snd_sof_ipc_reply(priv->sdev, 0); snd_sof_ipc_process_reply(priv->sdev, 0); spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); } Loading sound/soc/sof/intel/atom.c +1 −42 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ static void atom_host_done(struct snd_sof_dev *sdev); static void atom_dsp_done(struct snd_sof_dev *sdev); static void atom_get_reply(struct snd_sof_dev *sdev); /* * Debug Loading Loading @@ -154,8 +153,7 @@ irqreturn_t atom_irq_thread(int irq, void *context) * because the done bit can't be set in cmd_done function * which is triggered by msg */ atom_get_reply(sdev); snd_sof_ipc_reply(sdev, ipcx); snd_sof_ipc_process_reply(sdev, ipcx); atom_dsp_done(sdev); Loading Loading @@ -195,45 +193,6 @@ int atom_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) } EXPORT_SYMBOL_NS(atom_send_msg, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); static void atom_get_reply(struct snd_sof_dev *sdev) { struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; int ret = 0; /* * Sometimes, there is unexpected reply ipc arriving. The reply * ipc belongs to none of the ipcs sent from driver. * In this case, the driver must ignore the ipc. */ if (!msg) { dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); return; } /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); if (reply.error < 0) { memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; } else { /* reply correct size ? */ if (reply.hdr.size != msg->reply_size) { dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", msg->reply_size, reply.hdr.size); ret = -EINVAL; } /* read the message */ if (msg->reply_size > 0) sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, msg->reply_size); } msg->reply_error = ret; } int atom_get_mailbox_offset(struct snd_sof_dev *sdev) { return MBOX_OFFSET; Loading Loading
sound/soc/sof/Kconfig +8 −0 Original line number Diff line number Diff line Loading @@ -194,6 +194,14 @@ config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST Say Y if you want to enable IPC flood test. If unsure, select "N". config SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR bool "SOF enable IPC message injector" help This option enables the IPC message injector which can be used to send crafted IPC messages to the DSP to test its robustness. Say Y if you want to enable the IPC message injector. If unsure, select "N". config SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT bool "SOF retain DSP context on any FW exceptions" help Loading
sound/soc/sof/debug.c +107 −0 Original line number Diff line number Diff line Loading @@ -336,6 +336,104 @@ static int sof_debug_ipc_flood_test(struct snd_sof_dev *sdev, } #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) static ssize_t msg_inject_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct snd_sof_dfsentry *dfse = file->private_data; struct sof_ipc_reply *rhdr = dfse->msg_inject_rx; if (!rhdr->hdr.size || !count || *ppos) return 0; if (count > rhdr->hdr.size) count = rhdr->hdr.size; if (copy_to_user(buffer, dfse->msg_inject_rx, count)) return -EFAULT; *ppos += count; return count; } static ssize_t msg_inject_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct snd_sof_dfsentry *dfse = file->private_data; struct snd_sof_dev *sdev = dfse->sdev; struct sof_ipc_cmd_hdr *hdr = dfse->msg_inject_tx; size_t size; int ret, err; if (*ppos) return 0; size = simple_write_to_buffer(dfse->msg_inject_tx, SOF_IPC_MSG_MAX_SIZE, ppos, buffer, count); if (size != count) return size > 0 ? -EFAULT : size; ret = pm_runtime_get_sync(sdev->dev); if (ret < 0 && ret != -EACCES) { dev_err_ratelimited(sdev->dev, "%s: DSP resume failed: %d\n", __func__, ret); pm_runtime_put_noidle(sdev->dev); goto out; } /* send the message */ memset(dfse->msg_inject_rx, 0, SOF_IPC_MSG_MAX_SIZE); ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, dfse->msg_inject_tx, count, dfse->msg_inject_rx, SOF_IPC_MSG_MAX_SIZE); pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) dev_err_ratelimited(sdev->dev, "%s: DSP idle failed: %d\n", __func__, err); /* return size if test is successful */ if (ret >= 0) ret = size; out: return ret; } static const struct file_operations msg_inject_fops = { .open = simple_open, .read = msg_inject_read, .write = msg_inject_write, .llseek = default_llseek, }; static int snd_sof_debugfs_msg_inject_item(struct snd_sof_dev *sdev, const char *name, mode_t mode, const struct file_operations *fops) { struct snd_sof_dfsentry *dfse; dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); if (!dfse) return -ENOMEM; /* pre allocate the tx and rx buffers */ dfse->msg_inject_tx = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); dfse->msg_inject_rx = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); if (!dfse->msg_inject_tx || !dfse->msg_inject_rx) return -ENOMEM; dfse->type = SOF_DFSENTRY_TYPE_BUF; dfse->sdev = sdev; debugfs_create_file(name, mode, sdev->debugfs_root, dfse, fops); /* add to dfsentry list */ list_add(&dfse->list, &sdev->dfsentry_list); return 0; } #endif static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { Loading Loading @@ -812,6 +910,15 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) return err; #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR) err = snd_sof_debugfs_msg_inject_item(sdev, "ipc_msg_inject", 0644, &msg_inject_fops); /* errors are only due to memory allocation, not debugfs */ if (err < 0) return err; #endif return 0; } EXPORT_SYMBOL_GPL(snd_sof_dbg_init); Loading
sound/soc/sof/imx/imx8.c +1 −36 Original line number Diff line number Diff line Loading @@ -59,40 +59,6 @@ struct imx8_priv { }; static void imx8_get_reply(struct snd_sof_dev *sdev) { struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; int ret = 0; if (!msg) { dev_warn(sdev->dev, "unexpected ipc interrupt\n"); return; } /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); if (reply.error < 0) { memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; } else { /* reply has correct size? */ if (reply.hdr.size != msg->reply_size) { dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", msg->reply_size, reply.hdr.size); ret = -EINVAL; } /* read the message */ if (msg->reply_size > 0) sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, msg->reply_size); } msg->reply_error = ret; } static int imx8_get_mailbox_offset(struct snd_sof_dev *sdev) { return MBOX_OFFSET; Loading @@ -109,8 +75,7 @@ static void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc) unsigned long flags; spin_lock_irqsave(&priv->sdev->ipc_lock, flags); imx8_get_reply(priv->sdev); snd_sof_ipc_reply(priv->sdev, 0); snd_sof_ipc_process_reply(priv->sdev, 0); spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); } Loading
sound/soc/sof/imx/imx8m.c +1 −36 Original line number Diff line number Diff line Loading @@ -32,40 +32,6 @@ struct imx8m_priv { struct platform_device *ipc_dev; }; static void imx8m_get_reply(struct snd_sof_dev *sdev) { struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; int ret = 0; if (!msg) { dev_warn(sdev->dev, "unexpected ipc interrupt\n"); return; } /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); if (reply.error < 0) { memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; } else { /* reply has correct size? */ if (reply.hdr.size != msg->reply_size) { dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", msg->reply_size, reply.hdr.size); ret = -EINVAL; } /* read the message */ if (msg->reply_size > 0) sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, msg->reply_size); } msg->reply_error = ret; } static int imx8m_get_mailbox_offset(struct snd_sof_dev *sdev) { return MBOX_OFFSET; Loading @@ -82,8 +48,7 @@ static void imx8m_dsp_handle_reply(struct imx_dsp_ipc *ipc) unsigned long flags; spin_lock_irqsave(&priv->sdev->ipc_lock, flags); imx8m_get_reply(priv->sdev); snd_sof_ipc_reply(priv->sdev, 0); snd_sof_ipc_process_reply(priv->sdev, 0); spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); } Loading
sound/soc/sof/intel/atom.c +1 −42 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ static void atom_host_done(struct snd_sof_dev *sdev); static void atom_dsp_done(struct snd_sof_dev *sdev); static void atom_get_reply(struct snd_sof_dev *sdev); /* * Debug Loading Loading @@ -154,8 +153,7 @@ irqreturn_t atom_irq_thread(int irq, void *context) * because the done bit can't be set in cmd_done function * which is triggered by msg */ atom_get_reply(sdev); snd_sof_ipc_reply(sdev, ipcx); snd_sof_ipc_process_reply(sdev, ipcx); atom_dsp_done(sdev); Loading Loading @@ -195,45 +193,6 @@ int atom_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) } EXPORT_SYMBOL_NS(atom_send_msg, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); static void atom_get_reply(struct snd_sof_dev *sdev) { struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; int ret = 0; /* * Sometimes, there is unexpected reply ipc arriving. The reply * ipc belongs to none of the ipcs sent from driver. * In this case, the driver must ignore the ipc. */ if (!msg) { dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); return; } /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); if (reply.error < 0) { memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; } else { /* reply correct size ? */ if (reply.hdr.size != msg->reply_size) { dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", msg->reply_size, reply.hdr.size); ret = -EINVAL; } /* read the message */ if (msg->reply_size > 0) sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, msg->reply_size); } msg->reply_error = ret; } int atom_get_mailbox_offset(struct snd_sof_dev *sdev) { return MBOX_OFFSET; Loading