Skip to content
Closed
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
28 changes: 23 additions & 5 deletions include/sound/soc-dpcm.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,23 @@ enum snd_soc_dpcm_trigger {
SND_SOC_DPCM_TRIGGER_BESPOKE,
};

/**
* enum snd_soc_dpcm_update_mode - mode for calling soc_dpcm_runtime_update()
*
* @SND_SOC_DPCM_UPDATE_FULL: default mode, used for mux, mixer, and
* volume widgets
* @SND_SOC_DPCM_UPDATE_NEW_ONLY: a pipeline is starting. Skip checking
* for old paths.
* @SND_SOC_DPCM_UPDATE_OLD_ONLY: a pipeline is shutting down. Skip
* checking for new paths, force old path
* pruning.
*/
enum snd_soc_dpcm_update_mode {
SND_SOC_DPCM_UPDATE_FULL,
SND_SOC_DPCM_UPDATE_NEW_ONLY,
SND_SOC_DPCM_UPDATE_OLD_ONLY,
};

/*
* Dynamic PCM link
* This links together a FE and BE DAI at runtime and stores the link
Expand Down Expand Up @@ -133,7 +150,8 @@ struct snd_pcm_substream *
snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream);

/* update audio routing between PCMs and any DAI links */
int snd_soc_dpcm_runtime_update(struct snd_soc_card *card);
int snd_soc_dpcm_runtime_update(struct snd_soc_card *card,
enum snd_soc_dpcm_update_mode mode);

#ifdef CONFIG_DEBUG_FS
void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
Expand All @@ -143,11 +161,11 @@ static inline void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
}
#endif

int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
int stream, struct snd_soc_dapm_widget_list **list_);
int dpcm_path_get(struct snd_soc_pcm_runtime *fe, int stream,
struct snd_soc_dapm_widget_list **list_);
void dpcm_path_put(struct snd_soc_dapm_widget_list **list);
int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
int stream, struct snd_soc_dapm_widget_list **list, int new);
int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, int stream,
struct snd_soc_dapm_widget_list **list, bool new, bool force_prune);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was reviewed on alsa-devel, so I'll just add this as a remark but multiple booleans in function arguments is pushing limits of readability. The newly added enum reads better to convey the requested action.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kv2019i mmh, how are multiple booleans worse than multiple integers or anything else? :-) If you look inside dpcm_process_paths() you'll see that those two booleans are handled absolutely independently, they really aren't related, don't think an enum would make sense here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lyakh don't have problems with booleans, but for some reason the name "new" bothers me :), so "new" what? also plain "new" brings me recollections from c++ etc...

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juimonen oops, you're right, I keep forgetting about c++ :-) BTW, this PR is way outdated. We're back to #1501. But don't worry, the same comment applies there, so, your work wasn't in vain! But please continue there :-)

int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream);
int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream);
void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream);
Expand Down
1 change: 1 addition & 0 deletions include/sound/sof/header.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
#define SOF_IPC_PM_CLK_REQ SOF_CMD_TYPE(0x006)
#define SOF_IPC_PM_CORE_ENABLE SOF_CMD_TYPE(0x007)
#define SOF_IPC_PM_GATE SOF_CMD_TYPE(0x008)
#define SOF_IPC_PM_VFE_POWER_STATUS SOF_CMD_TYPE(0x010)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to change the ABI, but the shared file with firmware needs to be updated.
It's also unclear to me if the discontinuity is deliberate or meaningful, if yes you might want to add comments on what the bits represent.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@plbossart it is deliberate but we can discuss whether it's meaningful. I have no strong preference here. I tried to follow the pattern used in other IPC groups. Several of them jump to a new 0x10 as an indication of a new sub-group, and those jumps are never documented.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lyakh Can yo umake a FW PR for the addition. It's important to reserve the id, so it doesn't get used for something else.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lyakh we might as well start from BIT(8) to leave some space for 'regular' PM IPCs.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@plbossart as agreed with @lgirdwood in thesofproject/sof#2744 (comment) we'll drop this new IPC and re-use PM_SAVE and PM_LOAD with just adding one more field to the response structure for the latter.


/* component runtime config - multiple different types */
#define SOF_IPC_COMP_SET_VALUE SOF_CMD_TYPE(0x001)
Expand Down
2 changes: 1 addition & 1 deletion sound/soc/soc-compress.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n",
fe->dai_link->name, stream ? "capture" : "playback");
/* calculate valid and active FE <-> BE dpcms */
dpcm_process_paths(fe, stream, &list, 1);
dpcm_process_paths(fe, stream, &list, true, false);
fe->dpcm[stream].runtime = fe_substream->runtime;

fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
Expand Down
8 changes: 4 additions & 4 deletions sound/soc/soc-dapm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2291,7 +2291,7 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
card->update = NULL;
mutex_unlock(&card->dapm_mutex);
if (ret > 0)
snd_soc_dpcm_runtime_update(card);
snd_soc_dpcm_runtime_update(card, SND_SOC_DPCM_UPDATE_FULL);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
Expand Down Expand Up @@ -2356,7 +2356,7 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
card->update = NULL;
mutex_unlock(&card->dapm_mutex);
if (ret > 0)
snd_soc_dpcm_runtime_update(card);
snd_soc_dpcm_runtime_update(card, SND_SOC_DPCM_UPDATE_FULL);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
Expand Down Expand Up @@ -3396,7 +3396,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
mutex_unlock(&card->dapm_mutex);

if (ret > 0)
snd_soc_dpcm_runtime_update(card);
snd_soc_dpcm_runtime_update(card, SND_SOC_DPCM_UPDATE_FULL);

return change;
}
Expand Down Expand Up @@ -3501,7 +3501,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
mutex_unlock(&card->dapm_mutex);

if (ret > 0)
snd_soc_dpcm_runtime_update(card);
snd_soc_dpcm_runtime_update(card, SND_SOC_DPCM_UPDATE_FULL);

return change;
}
Expand Down
67 changes: 46 additions & 21 deletions sound/soc/soc-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1530,14 +1530,14 @@ static bool dpcm_be_is_active(struct snd_soc_dpcm *dpcm, int stream,
}

static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
struct snd_soc_dapm_widget_list **list_)
struct snd_soc_dapm_widget_list **list_, bool force)
{
struct snd_soc_dpcm *dpcm;
int prune = 0;

/* Destroy any old FE <--> BE connections */
for_each_dpcm_be(fe, stream, dpcm) {
if (dpcm_be_is_active(dpcm, stream, *list_))
if (!force && dpcm_be_is_active(dpcm, stream, *list_))
continue;

dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
Expand Down Expand Up @@ -1612,12 +1612,13 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
* FE substream.
*/
int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
int stream, struct snd_soc_dapm_widget_list **list, int new)
int stream, struct snd_soc_dapm_widget_list **list,
bool new, bool force_prune)
{
if (new)
return dpcm_add_paths(fe, stream, list);
else
return dpcm_prune_paths(fe, stream, list);
return dpcm_prune_paths(fe, stream, list, force_prune);
}

void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
Expand Down Expand Up @@ -2611,11 +2612,13 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
return ret;
}

static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream,
bool force)
{
struct snd_pcm_substream *substream =
snd_soc_dpcm_get_substream(fe, stream);
enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
int event = force ? SND_SOC_DAPM_STREAM_STOP : SND_SOC_DAPM_STREAM_NOP;
int err;

dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
Expand Down Expand Up @@ -2647,7 +2650,7 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);

/* run the stream event for each BE */
dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
dpcm_dapm_stream_event(fe, stream, event);

return 0;
}
Expand Down Expand Up @@ -2740,7 +2743,8 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
return ret;
}

static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, bool new,
bool force_prune)
{
struct snd_soc_dapm_widget_list *list;
int stream;
Expand Down Expand Up @@ -2786,13 +2790,13 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
}

/* update any playback/capture paths */
count = dpcm_process_paths(fe, stream, &list, new);
count = dpcm_process_paths(fe, stream, &list, new, force_prune);
if (count) {
dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
if (new)
ret = dpcm_run_update_startup(fe, stream);
else
ret = dpcm_run_update_shutdown(fe, stream);
ret = dpcm_run_update_shutdown(fe, stream, force_prune);
if (ret < 0)
dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
Expand All @@ -2810,25 +2814,46 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
* any DAI links.
*/
int snd_soc_dpcm_runtime_update(struct snd_soc_card *card)
int snd_soc_dpcm_runtime_update(struct snd_soc_card *card,
enum snd_soc_dpcm_update_mode mode)
{
struct snd_soc_pcm_runtime *fe;
int ret = 0;

mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);

/* shutdown all old paths first */
for_each_card_rtds(card, fe) {
ret = soc_dpcm_fe_runtime_update(fe, 0);
if (ret)
goto out;
}
if (mode != SND_SOC_DPCM_UPDATE_NEW_ONLY)
/*
* This is entered if mode == FULL or OLD_ONLY. In both cases we
* have to call soc_dpcm_fe_runtime_update() but only in the
* OLD_ONLY case we have to set the "force" (last) parameter to
* "true."
*/
for_each_card_rtds(card, fe) {
/*
* check "old" paths (new = false), only force for
* shutting down.
*/
ret = soc_dpcm_fe_runtime_update(fe, false,
mode == SND_SOC_DPCM_UPDATE_OLD_ONLY);
if (ret)
goto out;
}

/* bring new paths up */
for_each_card_rtds(card, fe) {
ret = soc_dpcm_fe_runtime_update(fe, 1);
if (ret)
goto out;
}
if (mode != SND_SOC_DPCM_UPDATE_OLD_ONLY)
/*
* This is entered if mode == FULL or NEW_ONLY. In both cases we
* have to call soc_dpcm_fe_runtime_update() with the "force"
* (last) parameter set to "false"
*/
for_each_card_rtds(card, fe) {
/* check "new" paths (new = true), no forcing */
ret = soc_dpcm_fe_runtime_update(fe, true, false);
if (ret)
goto out;
}

out:
mutex_unlock(&card->mutex);
Expand Down Expand Up @@ -2884,7 +2909,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
}

/* calculate valid and active FE <-> BE dpcms */
dpcm_process_paths(fe, stream, &list, 1);
dpcm_process_paths(fe, stream, &list, true, false);

ret = dpcm_fe_dai_startup(fe_substream);
if (ret < 0)
Expand Down
87 changes: 51 additions & 36 deletions sound/soc/sof/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//

#include <linux/atomic.h>
#include <linux/firmware.h>
#include <linux/module.h>
#include <sound/soc.h>
Expand Down Expand Up @@ -135,6 +136,53 @@ EXPORT_SYMBOL(snd_sof_get_status);
* (System Suspend/Runtime Suspend)
*/

static int sof_load_and_run_firmware(struct snd_sof_dev *sdev)
{
/* load the firmware */
int ret = snd_sof_load_firmware(sdev);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to load DSP firmware %d\n",
ret);
return ret;
}

sdev->fw_state = 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 %d\n",
ret);
goto fw_run_err;
}

if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE) ||
(sof_core_debug & SOF_DBG_ENABLE_TRACE)) {
sdev->dtrace_is_supported = true;

/* init DMA trace */
ret = snd_sof_init_trace(sdev);
if (ret < 0) {
/* non fatal */
dev_warn(sdev->dev,
"warning: failed to initialize trace %d\n",
ret);
}
} else {
dev_dbg(sdev->dev, "SOF firmware trace disabled\n");
}

return 0;

fw_run_err:
snd_sof_fw_unload(sdev);

return ret;
}

static int sof_probe_continue(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *plat_data = sdev->pdata;
Expand Down Expand Up @@ -180,42 +228,9 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
goto ipc_err;
}

/* load the firmware */
ret = snd_sof_load_firmware(sdev);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to load DSP firmware %d\n",
ret);
ret = sof_load_and_run_firmware(sdev);
if (ret < 0)
goto fw_load_err;
}

sdev->fw_state = 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 %d\n",
ret);
goto fw_run_err;
}

if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE) ||
(sof_core_debug & SOF_DBG_ENABLE_TRACE)) {
sdev->dtrace_is_supported = true;

/* init DMA trace */
ret = snd_sof_init_trace(sdev);
if (ret < 0) {
/* non fatal */
dev_warn(sdev->dev,
"warning: failed to initialize trace %d\n",
ret);
}
} else {
dev_dbg(sdev->dev, "SOF firmware trace disabled\n");
}

/* hereafter all FW boot flows are for PM reasons */
sdev->first_boot = false;
Expand Down Expand Up @@ -249,7 +264,6 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)

fw_trace_err:
snd_sof_free_trace(sdev);
fw_run_err:
snd_sof_fw_unload(sdev);
fw_load_err:
snd_sof_ipc_free(sdev);
Expand Down Expand Up @@ -298,6 +312,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID;
#endif
atomic_set(&sdev->dsp_reset_count, 0);
dev_set_drvdata(dev, sdev);

/* check all mandatory ops */
Expand Down
Loading