Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/sound/sof.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
8 changes: 8 additions & 0 deletions sound/soc/sof/compress.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
13 changes: 11 additions & 2 deletions sound/soc/sof/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

pm_runtime_mark_last_busy(scomp->dev);
err = pm_runtime_put_autosuspend(scomp->dev);
Expand Down
1 change: 1 addition & 0 deletions sound/soc/sof/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,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)
Expand Down
7 changes: 6 additions & 1 deletion sound/soc/sof/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_mark_last_busy(sdev->dev);
pm_runtime_put_autosuspend(sdev->dev);
if (ret < 0 || reply->rhdr.error < 0) {
Expand Down
11 changes: 11 additions & 0 deletions sound/soc/sof/intel/hda-sdw-bpt.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,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
Expand Down
1 change: 1 addition & 0 deletions sound/soc/sof/intel/pci-lnl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
},
Expand Down
2 changes: 2 additions & 0 deletions sound/soc/sof/intel/pci-ptl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
},
Expand Down Expand Up @@ -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",
},
Expand Down
7 changes: 6 additions & 1 deletion sound/soc/sof/ipc3-dtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_mark_last_busy(sdev->dev);
pm_runtime_put_autosuspend(sdev->dev);

Expand Down
20 changes: 1 addition & 19 deletions sound/soc/sof/ipc4-loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,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");
Expand Down Expand Up @@ -232,25 +232,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);

pm_runtime_mark_last_busy(sdev->dev);
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;

Expand Down
10 changes: 10 additions & 0 deletions sound/soc/sof/pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,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.
Expand Down
138 changes: 82 additions & 56 deletions sound/soc/sof/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,67 +70,28 @@ static void sof_cache_debugfs(struct snd_sof_dev *sdev)
}
#endif

static int sof_resume(struct device *dev, bool runtime_resume)
int snd_sof_boot_dsp_firmware(struct snd_sof_dev *sdev)
{
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;
int ret;

/* do nothing if dsp resume callbacks are not set */
if (!runtime_resume && !sof_ops(sdev)->resume)
return 0;

if (runtime_resume && !sof_ops(sdev)->runtime_resume)
return 0;
guard(mutex)(&sdev->dsp_fw_boot_mutex);

/* DSP was never successfully started, nothing to resume */
if (sdev->first_boot)
if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) {
/* Firmware already booted, just return */
return 0;

/*
* if the runtime_resume flag is set, call the runtime_resume routine
* or else call the system resume routine
*/
if (runtime_resume)
ret = snd_sof_dsp_runtime_resume(sdev);
else
ret = snd_sof_dsp_resume(sdev);
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to power up DSP after resume\n");
return ret;
}

if (sdev->dspless_mode_selected) {
sof_set_fw_state(sdev, SOF_DSPLESS_MODE);
return 0;
}

/*
* Nothing further to be done for platforms that support the low power
* D0 substate. Resume trace and return when resuming from
* low-power D0 substate
*/
if (!runtime_resume && sof_ops(sdev)->set_power_state &&
old_state == SOF_DSP_PM_D0) {
ret = sof_fw_trace_resume(sdev);
if (ret < 0)
/* non fatal */
dev_warn(sdev->dev,
"failed to enable trace after resume %d\n", ret);
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, NULL);
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to load DSP firmware after resume %d\n",
ret);
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;
}
Expand All @@ -143,9 +104,8 @@ static int sof_resume(struct device *dev, bool runtime_resume)
*/
ret = snd_sof_run_firmware(sdev);
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to boot DSP firmware after resume %d\n",
ret);
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;
}
Expand All @@ -154,16 +114,16 @@ static int sof_resume(struct device *dev, bool runtime_resume)
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);
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, "Failed to restore pipeline after resume %d\n", ret);
dev_err(sdev->dev, "%s: failed to restore pipeline: %d\n",
__func__, ret);
goto setup_fail;
}
}
Expand All @@ -175,7 +135,8 @@ static int sof_resume(struct device *dev, bool runtime_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);
dev_err(sdev->dev, "%s: ctx_restore IPC failed: %d\n",
__func__, ret);
}

setup_fail:
Expand All @@ -192,6 +153,67 @@ static int sof_resume(struct device *dev, bool runtime_resume)

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);
u32 old_state = sdev->dsp_power_state.state;
int ret;

/* do nothing if dsp resume callbacks are not set */
if (!runtime_resume && !sof_ops(sdev)->resume)
return 0;

if (runtime_resume && !sof_ops(sdev)->runtime_resume)
return 0;

/* DSP was never successfully started, nothing to resume */
if (sdev->first_boot)
return 0;

/*
* if the runtime_resume flag is set, call the runtime_resume routine
* or else call the system resume routine
*/
if (runtime_resume)
ret = snd_sof_dsp_runtime_resume(sdev);
else
ret = snd_sof_dsp_resume(sdev);
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to power up DSP after resume\n");
return ret;
}

if (sdev->dspless_mode_selected) {
sof_set_fw_state(sdev, SOF_DSPLESS_MODE);
return 0;
}

/*
* Nothing further to be done for platforms that support the low power
* D0 substate. Resume trace and return when resuming from
* low-power D0 substate
*/
if (!runtime_resume && sof_ops(sdev)->set_power_state &&
old_state == SOF_DSP_PM_D0) {
ret = sof_fw_trace_resume(sdev);
if (ret < 0)
/* non fatal */
dev_warn(sdev->dev,
"failed to enable trace after resume %d\n", ret);
return 0;
}

if (sdev->pdata->desc->on_demand_dsp_boot) {
/* Only change the fw_state to PREPARE but skip booting */
sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
return 0;
}

return snd_sof_boot_dsp_firmware(sdev);
}

static int sof_suspend(struct device *dev, bool runtime_suspend)
{
Expand Down Expand Up @@ -297,8 +319,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;
Expand Down
7 changes: 4 additions & 3 deletions sound/soc/sof/sof-client-ipc-flood-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

pm_runtime_mark_last_busy(dev);
err = pm_runtime_put_autosuspend(dev);
Expand Down
Loading
Loading