mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
ASoC: SOF: Support for on-demand DSP boot
Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>: On system suspend / resume we always power up the DSP and boot the firmware, which is not strictly needed as right after the firmware booted up we power the DSP down again on suspend and we also power it down after resume after some inactivity. Similarly, on jack insert/removal we needlesly boot up the firmware to check the jack status, which needs no DSP/firmware communication. The on-demand DSP boot will make sure that we boot the DSP firmware up only when it is needed - for audio activity, in other cases the firmware will be not booted up, which saves time. Out of caution, add a new platform descriptor flag to enable on-demand DSP boot since this might not work without changes to platform code on certain platforms. With the on-demand dsp boot enabled we will not boot the DSP and firmware up on system or rpm resume, just enable audio subsystem since audio IPs, like HDA and SoundWire might be needed (codecs suspend/resume operation). Only boot up the DSP during the first hw_params() call when the DSP is really going to be needed. In this way we can handle the audio related use cases: normal audio use (rpm suspend/resume) system suspend/resume without active audio system suspend/resume with active audio system suspend/resume without active audio, and audio start before the rpm suspend timeout Add module option to force the on-demand DSP boot to allow it to be disabled or enabled without kernel change for testing. The on-demand boot has been tested in our CI for more than half a year and so far no issues have been seen on supported platforms since it's introduction to our development tree (sof-dev).
This commit is contained in:
@@ -159,6 +159,9 @@ struct sof_dev_desc {
|
||||
/* The platform supports DSPless mode */
|
||||
bool dspless_mode_supported;
|
||||
|
||||
/* On demand DSP booting is possible on the platform */
|
||||
bool on_demand_dsp_boot;
|
||||
|
||||
/* defaults paths for firmware, library and topology files */
|
||||
const char *default_fw_path[SOF_IPC_TYPE_COUNT];
|
||||
const char *default_lib_path[SOF_IPC_TYPE_COUNT];
|
||||
|
||||
@@ -195,6 +195,14 @@ static int sof_compr_set_params(struct snd_soc_component *component,
|
||||
if (sizeof(*pcm) + ext_data_size > sdev->ipc->max_payload_size)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Make sure that the DSP is booted up, which might not be the
|
||||
* case if the on-demand DSP boot is used
|
||||
*/
|
||||
ret = snd_sof_boot_dsp_firmware(sdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pcm = kzalloc(sizeof(*pcm) + ext_data_size, GFP_KERNEL);
|
||||
if (!pcm)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -187,14 +187,23 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
|
||||
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
|
||||
int ret, err;
|
||||
|
||||
/* ignore the ext_volatile_get call if the callbacks are not provided */
|
||||
if (!tplg_ops || !tplg_ops->control ||
|
||||
!tplg_ops->control->bytes_ext_volatile_get)
|
||||
return 0;
|
||||
|
||||
ret = pm_runtime_resume_and_get(scomp->dev);
|
||||
if (ret < 0 && ret != -EACCES) {
|
||||
dev_err_ratelimited(scomp->dev, "%s: failed to resume %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_volatile_get)
|
||||
ret = tplg_ops->control->bytes_ext_volatile_get(scontrol, binary_data, size);
|
||||
/* Make sure the DSP/firmware is booted up */
|
||||
ret = snd_sof_boot_dsp_firmware(sdev);
|
||||
if (!ret)
|
||||
ret = tplg_ops->control->bytes_ext_volatile_get(scontrol,
|
||||
binary_data,
|
||||
size);
|
||||
|
||||
err = pm_runtime_put_autosuspend(scomp->dev);
|
||||
if (err < 0)
|
||||
|
||||
@@ -680,6 +680,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
|
||||
mutex_init(&sdev->power_state_access);
|
||||
mutex_init(&sdev->ipc_client_mutex);
|
||||
mutex_init(&sdev->client_event_handler_mutex);
|
||||
mutex_init(&sdev->dsp_fw_boot_mutex);
|
||||
|
||||
/* set default timeouts if none provided */
|
||||
if (plat_data->desc->ipc_timeout == 0)
|
||||
|
||||
@@ -216,7 +216,12 @@ static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_s
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = sof_ipc_tx_message(sdev->ipc, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE);
|
||||
/* Make sure the DSP/firmware is booted up */
|
||||
ret = snd_sof_boot_dsp_firmware(sdev);
|
||||
if (!ret)
|
||||
ret = sof_ipc_tx_message(sdev->ipc, &msg, msg.size, reply,
|
||||
SOF_IPC_MSG_MAX_SIZE);
|
||||
|
||||
pm_runtime_put_autosuspend(sdev->dev);
|
||||
if (ret < 0 || reply->rhdr.error < 0) {
|
||||
ret = min(ret, reply->rhdr.error);
|
||||
|
||||
@@ -98,6 +98,17 @@ static int hda_sdw_bpt_dma_prepare(struct device *dev, struct hdac_ext_stream **
|
||||
struct hdac_ext_stream *bpt_stream;
|
||||
unsigned int format = HDA_CL_STREAM_FORMAT;
|
||||
|
||||
if (!sdev->dspless_mode_selected) {
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Make sure that the DSP is booted up, which might not be the
|
||||
* case if the on-demand DSP boot is used
|
||||
*/
|
||||
ret = snd_sof_boot_dsp_firmware(sdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* the baseline format needs to be adjusted to
|
||||
* bandwidth requirements
|
||||
|
||||
@@ -40,6 +40,7 @@ static const struct sof_dev_desc lnl_desc = {
|
||||
.ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
|
||||
.ipc_default = SOF_IPC_TYPE_4,
|
||||
.dspless_mode_supported = true,
|
||||
.on_demand_dsp_boot = true,
|
||||
.default_fw_path = {
|
||||
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/lnl",
|
||||
},
|
||||
|
||||
@@ -38,6 +38,7 @@ static const struct sof_dev_desc nvl_s_desc = {
|
||||
.ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
|
||||
.ipc_default = SOF_IPC_TYPE_4,
|
||||
.dspless_mode_supported = true,
|
||||
.on_demand_dsp_boot = true,
|
||||
.default_fw_path = {
|
||||
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/nvl-s",
|
||||
},
|
||||
|
||||
@@ -38,6 +38,7 @@ static const struct sof_dev_desc ptl_desc = {
|
||||
.ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
|
||||
.ipc_default = SOF_IPC_TYPE_4,
|
||||
.dspless_mode_supported = true,
|
||||
.on_demand_dsp_boot = true,
|
||||
.default_fw_path = {
|
||||
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/ptl",
|
||||
},
|
||||
@@ -67,6 +68,7 @@ static const struct sof_dev_desc wcl_desc = {
|
||||
.ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
|
||||
.ipc_default = SOF_IPC_TYPE_4,
|
||||
.dspless_mode_supported = true,
|
||||
.on_demand_dsp_boot = true,
|
||||
.default_fw_path = {
|
||||
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/wcl",
|
||||
},
|
||||
|
||||
@@ -171,7 +171,12 @@ static int ipc3_trace_update_filter(struct snd_sof_dev *sdev, int num_elems,
|
||||
dev_err(sdev->dev, "enabling device failed: %d\n", ret);
|
||||
goto error;
|
||||
}
|
||||
ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, msg->hdr.size);
|
||||
|
||||
/* Make sure the DSP/firmware is booted up */
|
||||
ret = snd_sof_boot_dsp_firmware(sdev);
|
||||
if (!ret)
|
||||
ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, msg->hdr.size);
|
||||
|
||||
pm_runtime_put_autosuspend(sdev->dev);
|
||||
|
||||
error:
|
||||
|
||||
@@ -175,7 +175,7 @@ static int sof_ipc4_load_library(struct snd_sof_dev *sdev, unsigned long lib_id,
|
||||
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
|
||||
struct sof_ipc4_fw_library *fw_lib;
|
||||
ssize_t payload_offset;
|
||||
int ret, i, err;
|
||||
int ret, i;
|
||||
|
||||
if (!ipc4_data->load_library) {
|
||||
dev_err(sdev->dev, "Library loading is not supported on this platform\n");
|
||||
@@ -223,24 +223,7 @@ static int sof_ipc4_load_library(struct snd_sof_dev *sdev, unsigned long lib_id,
|
||||
for (i = 0; i < fw_lib->num_modules; i++)
|
||||
fw_lib->modules[i].man4_module_entry.id |= (lib_id << SOF_IPC4_MOD_LIB_ID_SHIFT);
|
||||
|
||||
/*
|
||||
* Make sure that the DSP is booted and stays up while attempting the
|
||||
* loading the library for the first time
|
||||
*/
|
||||
ret = pm_runtime_resume_and_get(sdev->dev);
|
||||
if (ret < 0 && ret != -EACCES) {
|
||||
dev_err_ratelimited(sdev->dev, "%s: pm_runtime resume failed: %d\n",
|
||||
__func__, ret);
|
||||
goto release;
|
||||
}
|
||||
|
||||
ret = ipc4_data->load_library(sdev, fw_lib, false);
|
||||
|
||||
err = pm_runtime_put_autosuspend(sdev->dev);
|
||||
if (err < 0)
|
||||
dev_err_ratelimited(sdev->dev, "%s: pm_runtime idle failed: %d\n",
|
||||
__func__, err);
|
||||
|
||||
if (ret)
|
||||
goto release;
|
||||
|
||||
|
||||
@@ -892,6 +892,19 @@ void sof_ipc4_mic_privacy_state_change(struct snd_sof_dev *sdev, bool state)
|
||||
struct sof_ipc4_msg msg;
|
||||
u32 data = state;
|
||||
|
||||
/*
|
||||
* The mic privacy change notification's role is to notify the running
|
||||
* firmware that there is a change in mic privacy state from whatever
|
||||
* the state was before - since the firmware booted up or since the
|
||||
* previous change during runtime.
|
||||
*
|
||||
* If the firmware has not been booted up, there is no need to send
|
||||
* change notification (the firmware is not booted up).
|
||||
* The firmware checks the current state during its boot.
|
||||
*/
|
||||
if (sdev->fw_state != SOF_FW_BOOT_COMPLETE)
|
||||
return;
|
||||
|
||||
msg.primary = SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
|
||||
msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
|
||||
msg.primary |= SOF_IPC4_MOD_ID(SOF_IPC4_MOD_INIT_BASEFW_MOD_ID);
|
||||
|
||||
@@ -122,6 +122,16 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
|
||||
|
||||
spcm_dbg(spcm, substream->stream, "Entry: hw_params\n");
|
||||
|
||||
if (!sdev->dspless_mode_selected) {
|
||||
/*
|
||||
* Make sure that the DSP is booted up, which might not be the
|
||||
* case if the on-demand DSP boot is used
|
||||
*/
|
||||
ret = snd_sof_boot_dsp_firmware(sdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle repeated calls to hw_params() without free_pcm() in
|
||||
* between. At least ALSA OSS emulation depends on this.
|
||||
|
||||
@@ -8,10 +8,15 @@
|
||||
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
||||
//
|
||||
|
||||
#include <linux/module.h>
|
||||
#include "ops.h"
|
||||
#include "sof-priv.h"
|
||||
#include "sof-audio.h"
|
||||
|
||||
static int override_on_demand_boot = -1;
|
||||
module_param_named(on_demand_boot, override_on_demand_boot, int, 0444);
|
||||
MODULE_PARM_DESC(on_demand_boot, "Force on-demand DSP boot: 0 - disabled, 1 - enabled");
|
||||
|
||||
/*
|
||||
* Helper function to determine the target DSP state during
|
||||
* system suspend. This function only cares about the device
|
||||
@@ -70,12 +75,96 @@ static void sof_cache_debugfs(struct snd_sof_dev *sdev)
|
||||
}
|
||||
#endif
|
||||
|
||||
int snd_sof_boot_dsp_firmware(struct snd_sof_dev *sdev)
|
||||
{
|
||||
const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm);
|
||||
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&sdev->dsp_fw_boot_mutex);
|
||||
|
||||
if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) {
|
||||
/* Firmware already booted, just return */
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(sdev->dev, "Booting DSP firmware\n");
|
||||
|
||||
sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
|
||||
|
||||
/* load the firmware */
|
||||
ret = snd_sof_load_firmware(sdev);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "%s: failed to load DSP firmware: %d\n",
|
||||
__func__, ret);
|
||||
sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sof_set_fw_state(sdev, SOF_FW_BOOT_IN_PROGRESS);
|
||||
|
||||
/*
|
||||
* Boot the firmware. The FW boot status will be modified
|
||||
* in snd_sof_run_firmware() depending on the outcome.
|
||||
*/
|
||||
ret = snd_sof_run_firmware(sdev);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "%s: failed to boot DSP firmware: %d\n",
|
||||
__func__, ret);
|
||||
sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* resume DMA trace */
|
||||
ret = sof_fw_trace_resume(sdev);
|
||||
if (ret < 0) {
|
||||
/* non fatal */
|
||||
dev_warn(sdev->dev, "%s: failed to resume trace: %d\n",
|
||||
__func__, ret);
|
||||
}
|
||||
|
||||
/* restore pipelines */
|
||||
if (tplg_ops && tplg_ops->set_up_all_pipelines) {
|
||||
ret = tplg_ops->set_up_all_pipelines(sdev, false);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "%s: failed to restore pipeline: %d\n",
|
||||
__func__, ret);
|
||||
goto setup_fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Notify clients not managed by pm framework about core resume */
|
||||
sof_resume_clients(sdev);
|
||||
|
||||
/* notify DSP of system resume */
|
||||
if (pm_ops && pm_ops->ctx_restore) {
|
||||
ret = pm_ops->ctx_restore(sdev);
|
||||
if (ret < 0)
|
||||
dev_err(sdev->dev, "%s: ctx_restore IPC failed: %d\n",
|
||||
__func__, ret);
|
||||
}
|
||||
|
||||
setup_fail:
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* Debugfs cannot be read in runtime suspend, so cache
|
||||
* the contents upon failure. This allows to capture
|
||||
* possible DSP coredump information.
|
||||
*/
|
||||
sof_cache_debugfs(sdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_sof_boot_dsp_firmware);
|
||||
|
||||
static int sof_resume(struct device *dev, bool runtime_resume)
|
||||
{
|
||||
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
|
||||
const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm);
|
||||
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
|
||||
u32 old_state = sdev->dsp_power_state.state;
|
||||
bool on_demand_boot;
|
||||
int ret;
|
||||
|
||||
/* do nothing if dsp resume callbacks are not set */
|
||||
@@ -123,74 +212,18 @@ static int sof_resume(struct device *dev, bool runtime_resume)
|
||||
return 0;
|
||||
}
|
||||
|
||||
sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
|
||||
if (override_on_demand_boot > -1)
|
||||
on_demand_boot = override_on_demand_boot ? true : false;
|
||||
else
|
||||
on_demand_boot = sdev->pdata->desc->on_demand_dsp_boot;
|
||||
|
||||
/* load the firmware */
|
||||
ret = snd_sof_load_firmware(sdev);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev,
|
||||
"error: failed to load DSP firmware after resume %d\n",
|
||||
ret);
|
||||
sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
|
||||
return ret;
|
||||
if (on_demand_boot) {
|
||||
/* Only change the fw_state to PREPARE but skip booting */
|
||||
sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sof_set_fw_state(sdev, SOF_FW_BOOT_IN_PROGRESS);
|
||||
|
||||
/*
|
||||
* Boot the firmware. The FW boot status will be modified
|
||||
* in snd_sof_run_firmware() depending on the outcome.
|
||||
*/
|
||||
ret = snd_sof_run_firmware(sdev);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev,
|
||||
"error: failed to boot DSP firmware after resume %d\n",
|
||||
ret);
|
||||
sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* resume DMA trace */
|
||||
ret = sof_fw_trace_resume(sdev);
|
||||
if (ret < 0) {
|
||||
/* non fatal */
|
||||
dev_warn(sdev->dev,
|
||||
"warning: failed to init trace after resume %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
/* restore pipelines */
|
||||
if (tplg_ops && tplg_ops->set_up_all_pipelines) {
|
||||
ret = tplg_ops->set_up_all_pipelines(sdev, false);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "Failed to restore pipeline after resume %d\n", ret);
|
||||
goto setup_fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Notify clients not managed by pm framework about core resume */
|
||||
sof_resume_clients(sdev);
|
||||
|
||||
/* notify DSP of system resume */
|
||||
if (pm_ops && pm_ops->ctx_restore) {
|
||||
ret = pm_ops->ctx_restore(sdev);
|
||||
if (ret < 0)
|
||||
dev_err(sdev->dev, "ctx_restore IPC error during resume: %d\n", ret);
|
||||
}
|
||||
|
||||
setup_fail:
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* Debugfs cannot be read in runtime suspend, so cache
|
||||
* the contents upon failure. This allows to capture
|
||||
* possible DSP coredump information.
|
||||
*/
|
||||
sof_cache_debugfs(sdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
return snd_sof_boot_dsp_firmware(sdev);
|
||||
}
|
||||
|
||||
static int sof_suspend(struct device *dev, bool runtime_suspend)
|
||||
@@ -297,8 +330,12 @@ int snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev)
|
||||
{
|
||||
const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm);
|
||||
|
||||
/* Notify DSP of upcoming power down */
|
||||
if (sof_ops(sdev)->remove && pm_ops && pm_ops->ctx_save)
|
||||
/*
|
||||
* Notify DSP of upcoming power down only if the firmware has been
|
||||
* booted up
|
||||
*/
|
||||
if (sdev->fw_state == SOF_FW_BOOT_COMPLETE && sof_ops(sdev)->remove &&
|
||||
pm_ops && pm_ops->ctx_save)
|
||||
return pm_ops->ctx_save(sdev);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -219,9 +219,10 @@ static ssize_t sof_ipc_flood_dfs_write(struct file *file, const char __user *buf
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* flood test */
|
||||
ret = sof_debug_ipc_flood_test(cdev, flood_duration_test,
|
||||
ipc_duration_ms, ipc_count);
|
||||
ret = sof_client_boot_dsp(cdev);
|
||||
if (!ret)
|
||||
ret = sof_debug_ipc_flood_test(cdev, flood_duration_test,
|
||||
ipc_duration_ms, ipc_count);
|
||||
|
||||
err = pm_runtime_put_autosuspend(dev);
|
||||
if (err < 0)
|
||||
|
||||
@@ -63,7 +63,9 @@ static ssize_t sof_kernel_msg_inject_dfs_write(struct file *file, const char __u
|
||||
return ret;
|
||||
}
|
||||
|
||||
sof_client_ipc_rx_message(cdev, hdr, priv->kernel_buffer);
|
||||
ret = sof_client_boot_dsp(cdev);
|
||||
if (!ret)
|
||||
sof_client_ipc_rx_message(cdev, hdr, priv->kernel_buffer);
|
||||
|
||||
ret = pm_runtime_put_autosuspend(dev);
|
||||
if (ret < 0)
|
||||
|
||||
@@ -131,11 +131,15 @@ static int sof_msg_inject_send_message(struct sof_client_dev *cdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* send the message */
|
||||
ret = sof_client_ipc_tx_message(cdev, priv->tx_buffer, priv->rx_buffer,
|
||||
priv->max_msg_size);
|
||||
if (ret)
|
||||
dev_err(dev, "IPC message send failed: %d\n", ret);
|
||||
ret = sof_client_boot_dsp(cdev);
|
||||
if (!ret) {
|
||||
/* send the message */
|
||||
ret = sof_client_ipc_tx_message(cdev, priv->tx_buffer,
|
||||
priv->rx_buffer,
|
||||
priv->max_msg_size);
|
||||
if (ret)
|
||||
dev_err(dev, "IPC message send failed: %d\n", ret);
|
||||
}
|
||||
|
||||
err = pm_runtime_put_autosuspend(dev);
|
||||
if (err < 0)
|
||||
|
||||
@@ -123,6 +123,10 @@ static int sof_probes_compr_set_params(struct snd_compr_stream *cstream,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sof_client_boot_dsp(cdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ipc->init(cdev, priv->extractor_stream_tag, rtd->dma_bytes);
|
||||
if (ret < 0) {
|
||||
dev_err(dai->dev, "Failed to init probe: %d\n", ret);
|
||||
@@ -224,6 +228,10 @@ static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = sof_client_boot_dsp(cdev);
|
||||
if (ret)
|
||||
goto pm_error;
|
||||
|
||||
ret = ipc->points_info(cdev, &desc, &num_desc, type);
|
||||
if (ret < 0)
|
||||
goto pm_error;
|
||||
@@ -312,9 +320,12 @@ sof_probes_dfs_points_write(struct file *file, const char __user *from,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = ipc->points_add(cdev, desc, bytes / sizeof(*desc));
|
||||
if (!ret)
|
||||
ret = count;
|
||||
ret = sof_client_boot_dsp(cdev);
|
||||
if (!ret) {
|
||||
ret = ipc->points_add(cdev, desc, bytes / sizeof(*desc));
|
||||
if (!ret)
|
||||
ret = count;
|
||||
}
|
||||
|
||||
err = pm_runtime_put_autosuspend(dev);
|
||||
if (err < 0)
|
||||
@@ -367,9 +378,12 @@ sof_probes_dfs_points_remove_write(struct file *file, const char __user *from,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = ipc->points_remove(cdev, &array[1], array[0]);
|
||||
if (!ret)
|
||||
ret = count;
|
||||
ret = sof_client_boot_dsp(cdev);
|
||||
if (!ret) {
|
||||
ret = ipc->points_remove(cdev, &array[1], array[0]);
|
||||
if (!ret)
|
||||
ret = count;
|
||||
}
|
||||
|
||||
err = pm_runtime_put_autosuspend(dev);
|
||||
if (err < 0)
|
||||
|
||||
@@ -486,6 +486,12 @@ enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev)
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type, "SND_SOC_SOF_CLIENT");
|
||||
|
||||
int sof_client_boot_dsp(struct sof_client_dev *cdev)
|
||||
{
|
||||
return snd_sof_boot_dsp_firmware(sof_client_dev_to_sof_dev(cdev));
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(sof_client_boot_dsp, "SND_SOC_SOF_CLIENT");
|
||||
|
||||
/* module refcount management of SOF core */
|
||||
int sof_client_core_module_get(struct sof_client_dev *cdev)
|
||||
{
|
||||
|
||||
@@ -50,6 +50,9 @@ const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev
|
||||
size_t sof_client_get_ipc_max_payload_size(struct sof_client_dev *cdev);
|
||||
enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev);
|
||||
|
||||
/* DSP/firmware boot request */
|
||||
int sof_client_boot_dsp(struct sof_client_dev *cdev);
|
||||
|
||||
/* module refcount management of SOF core */
|
||||
int sof_client_core_module_get(struct sof_client_dev *cdev);
|
||||
void sof_client_core_module_put(struct sof_client_dev *cdev);
|
||||
|
||||
@@ -580,6 +580,8 @@ struct snd_sof_dev {
|
||||
wait_queue_head_t boot_wait;
|
||||
enum sof_fw_state fw_state;
|
||||
bool first_boot;
|
||||
/* mutex to protect DSP firmware boot (except initial, probe time boot */
|
||||
struct mutex dsp_fw_boot_mutex;
|
||||
|
||||
/* work queue in case the probe is implemented in two steps */
|
||||
struct work_struct probe_work;
|
||||
@@ -703,6 +705,7 @@ int snd_sof_suspend(struct device *dev);
|
||||
int snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev);
|
||||
int snd_sof_prepare(struct device *dev);
|
||||
void snd_sof_complete(struct device *dev);
|
||||
int snd_sof_boot_dsp_firmware(struct snd_sof_dev *sdev);
|
||||
|
||||
void snd_sof_new_platform_drv(struct snd_sof_dev *sdev);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user