Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor pipeline management #5262

Open
wants to merge 7 commits into
base: topic/sof-dev
Choose a base branch
from

Conversation

ranj063
Copy link
Collaborator

@ranj063 ranj063 commented Dec 4, 2024

This PR refactors the pipeline management to do the following:

  1. Make sure that BE pipeline widgets/routes are set up and freed during BE DAI ops. A BE pipeline is the one that contains the DAI widget
  2. Pipeline trigger is already split between FE and BE DAI ops except for pipeline reset. This PR also modifies pipeline set/up free to the respective DAI ops i.e BE pipeline in the BE DAI hw_free and the rest of the pipelines in the FE DAI hw_free.
  3. The widget's ipc_prepare op is intentionally left to the handled during the FE DAI hw_params because it requires propagating pipeline_params all the way from the source to the sink widget.

So the overall flow for a normal start/stop would be:

  1. Pipeline widgets are prepared during FE DAI hw_params. This includes all widgets belonging to all pipelines including the BE pipeline as well.
  2. All widgets and routes belonging to BE pipelines are set up during BE DAI prepare.
  3. All widgets and routes belonging to the remaining pipelines are set up during FE DAI prepare.
  4. All widgets and routes belonging to BE pipelines are freed and unprepared during BE DAI hw_free
  5. All widgets and routes belonging to the remaining pipelines are freed and unprepared during FE DAI hw_free

The above flow ensures that the pipelines are unprepared only during hw_free. Since the hw_params do not change because of xruns/suspend, there is no need to unprepare and re-prepare the widgets in these cases. The only critical change would be to make sure that the host DMA and the link DMA are reconfigured before restarting.

In the case of an xrun, the change would be that the BE pipeline would be freed, the link DMA will be reconfigured and the pipelines will be set up again in the prepare following the xrun stop trigger. And the remaining pipelines would be freed, host DMA reconfigured and the pipelines will be set up again in the prepare ioctl following the xrun stop trigger.

The case of a suspend/resume during audio is slightly different from the xrun case: The BE pipeline will be freed during the suspend trigger. The link DMA will be reconfigured and the BE pipeline will be set up again during the BE DAI prepare after resuming. Similarly, for the remaining pipelines, they will be freed during suspend and the host DMA will be reconfigured and pipelines set up during the prepare after resume.

@ranj063 ranj063 force-pushed the fix/pipeline_mgt branch 2 times, most recently from 50da688 to 9883c9b Compare December 4, 2024 18:52
@ranj063
Copy link
Collaborator Author

ranj063 commented Dec 4, 2024

SOFCI TEST

@ranj063 ranj063 force-pushed the fix/pipeline_mgt branch 6 times, most recently from f2569fa to 8818a53 Compare December 6, 2024 01:59
Copy link
Collaborator

@bardliao bardliao left a comment

Choose a reason for hiding this comment

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

Can we call setup in hw_params and prepare in prepare?

list = spcm->stream[dir].list;
params = &spcm->params[substream->stream];
platform_params = &spcm->platform_params[substream->stream];
ret = sof_widget_list_setup(sdev, spcm, params, platform_params, dir);
Copy link
Collaborator

Choose a reason for hiding this comment

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

As setup and prepare are split, why don't we do setup in sof_pcm_hw_params?

int stream = substream->stream;
int ret;

ret = hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, dai);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there any specific reason that we always call hw_params in .prepare?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

because sometimes we dont have a hw_free like in the case of xruns and we'll need to do everything again.

Copy link
Member

Choose a reason for hiding this comment

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

prepare() should be fast. We should call this out in comments - we need to do X,Y out of cycle because Z

drivers/soundwire/intel_ace2x.c Show resolved Hide resolved
@ranj063
Copy link
Collaborator Author

ranj063 commented Dec 6, 2024

Can we call setup in hw_params and prepare in prepare?

No. A widget needs to be prepared before it can be set up. So ipc_prepare needs to be done in hw_params before we do set up in prepare

@ranj063 ranj063 force-pushed the fix/pipeline_mgt branch 2 times, most recently from 0a0cbf9 to dae9464 Compare December 6, 2024 17:31
@ranj063
Copy link
Collaborator Author

ranj063 commented Dec 7, 2024

SOFCI TEST

@ranj063 ranj063 force-pushed the fix/pipeline_mgt branch 2 times, most recently from 0b23916 to c3a3b54 Compare December 7, 2024 19:56
Add a new host_config op in struct sof_ipc_tplg_ops and define it for
IPC4. This will be used to configure the host widget during prepare
after a suspend/resume or after an xrun.

Signed-off-by: Ranjani Sridharan <[email protected]>
In preparation for refacting pipeline management, split the widget
prepare and set up between the hw_params and prepare ioctls. This is
required to ensure that the BE pipeline widgets can be set up during the
BE DAI prepare and the remaining widgets will be set up during the FE
DAI prepare. The widget's ipc_prepare op for all widgets in both the
BE and FE pipelines are handled during the FE DAI hw_params to make sure
that the pipeline params can be propagated all the way from the source
widget to the sink widget.

Signed-off-by: Ranjani Sridharan <[email protected]>
Define 3 new ops in struct hda_dai_widget_dma_ops for setting
up/freeing/unpreparing the BE pipeline and set them for IPC4 version
of the ops. These ops will be used when the pipeline management is
refactored to set up/free widgets, routes and pipelines during BE DAI
prepare or hw_free.

Signed-off-by: Ranjani Sridharan <[email protected]>
This will be used in the BE DAI ops in the following patches.

Signed-off-by: Ranjani Sridharan <[email protected]>
Add and define the prepare op for Intel ACE2.x platforms. For the
moment, the prepare_stream op is exactly the same as the prepare_stream
op.  But it will be modified in the following patch when the pipeline
management is refactored.

Signed-off-by: Ranjani Sridharan <[email protected]>
Invoke the set_up_be_pipeline and free_be_pipeline ops in the BE DAI
prepare and hw_free to ensure that all the widgets and routes belonging
to the BE pipeline are handled in the BE DAI ops. Add a new field in
struct snd_sof_pipeline to identify BE pipelines i.e. those that contain
the DAI widget. Modify the FE ops to make sure that the widgets/routes
belonging to these pipelines are skipped during setup/free/unprepare.

Signed-off-by: Ranjani Sridharan <[email protected]>
Now that all widgets/routes/pipelines are setup, triggered and freed in
the BE DAI ops, we can reuse the be_pipeline flag in struct
snd_sof_pipeline to skip triggering the BE pipelines in the PCM trigger.
So remove the skip_during_fe_trigger flag from struct sof_ipc4_pipeline.

Signed-off-by: Ranjani Sridharan <[email protected]>
@ranj063
Copy link
Collaborator Author

ranj063 commented Dec 8, 2024

SOFCI TEST

@ranj063 ranj063 marked this pull request as ready for review December 8, 2024 02:00
int ret;

/* set up the widget if it belongs to the same pipeline as the DAI widget */
if (swidget->spipe != spipe || !swidget->prepared)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need to go through the widgets in the path like hda_dai_unprepare_widgets_in_pipeline() does in the !swidget->prepared case? And same question for hda_dai_free_widgets_in_pipeline().

@bardliao
Copy link
Collaborator

bardliao commented Dec 9, 2024

SOFCI TEST

@ujfalusi
Copy link
Collaborator

ujfalusi commented Dec 9, 2024

@ranj063, this sequence still fails (HDA machine):
terminal 1:
aplay -Dhw:0,0
CTRL+z

terminal 2:
aplay -Dhw:0,3

terminal 1:
fg

[11038.698037] snd_soc_core:dpcm_be_dai_trigger:  Analog Playback and Capture: ASoC: trigger BE Analog Playback and Capture cmd 1
[11038.698057] snd_sof_intel_hda_common:hda_dai_trigger: sof-audio-pci-intel-tgl 0000:00:1f.3: cmd=1 dai Analog CPU DAI direction 0
[11038.698071] snd_sof:sof_ipc4_set_pipeline_state: sof-audio-pci-intel-tgl 0000:00:1f.3: ipc4 set pipeline instance 0 state 3
[11038.698078] snd_sof:sof_ipc4_log_header: sof-audio-pci-intel-tgl 0000:00:1f.3: ipc tx      : 0x13000003|0x0: GLB_SET_PIPELINE_STATE
[11038.698434] snd_sof:sof_ipc4_log_header: sof-audio-pci-intel-tgl 0000:00:1f.3: ipc tx reply: 0x33000000|0x0: GLB_SET_PIPELINE_STATE
[11038.698455] snd_sof:sof_ipc4_log_header: sof-audio-pci-intel-tgl 0000:00:1f.3: ipc tx done : 0x13000003|0x0: GLB_SET_PIPELINE_STATE
[11038.698460] snd_sof:sof_ipc4_set_pipeline_state: sof-audio-pci-intel-tgl 0000:00:1f.3: ipc4 set pipeline instance 0 state 4
[11038.698464] snd_sof:sof_ipc4_log_header: sof-audio-pci-intel-tgl 0000:00:1f.3: ipc tx      : 0x13000004|0x0: GLB_SET_PIPELINE_STATE
[11038.703027] snd_sof:sof_ipc4_log_header: sof-audio-pci-intel-tgl 0000:00:1f.3: ipc tx reply: 0x33000007|0x0: GLB_SET_PIPELINE_STATE
[11038.703031] sof-audio-pci-intel-tgl 0000:00:1f.3: FW reported error: 7 - Unsupported operation requested
[11038.703058] sof-audio-pci-intel-tgl 0000:00:1f.3: ipc error for msg 0x13000004|0x0
[11038.703062] sof-audio-pci-intel-tgl 0000:00:1f.3: ASoC: error at soc_dai_trigger on Analog CPU DAI: -22
[11038.703067]  HDA Analog: ASoC: trigger FE cmd: 1 failed: -22

Copy link
Member

@lgirdwood lgirdwood left a comment

Choose a reason for hiding this comment

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

@ranj063 we you able to see any IP programming delta with debug in the hw_read(), hw_write() ?

int stream = substream->stream;
int ret;

ret = hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, dai);
Copy link
Member

Choose a reason for hiding this comment

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

prepare() should be fast. We should call this out in comments - we need to do X,Y out of cycle because Z

@lgirdwood
Copy link
Member

@ujfalusi can you review whilst the HDA issue is being resolved. Thanks !

@ranj063
Copy link
Collaborator Author

ranj063 commented Dec 16, 2024

@ranj063 we you able to see any IP programming delta with debug in the hw_read(), hw_write() ?

@lgirdwood no there would no IP programming delta at all. The only thing that would change is the timing of the pipeline setup/free and its a clean split now with the BE pipeline handled in the BE DAI ops.

@ujfalusi
Copy link
Collaborator

ujfalusi commented Dec 18, 2024

@ranj063, with a quick test this appears to work fine (no regression), but needs to be rebased because of the spcm print PR and also this:

diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 915a1109b2e3..c7625b73d713 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -745,7 +745,7 @@ int sdw_hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_pcm_hw_p
 
 	return ret;
 }
-EXPORT_SYMBOL_NS(sdw_hda_dai_prepare, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(sdw_hda_dai_prepare, "SND_SOC_SOF_INTEL_HDA_COMMON");
 
 static int hda_dai_suspend(struct hdac_bus *bus)
 {

@ujfalusi
Copy link
Collaborator

Suspend while pause still have problems, but it is the same without the PR.

@lgirdwood
Copy link
Member

Suspend while pause still have problems, but it is the same without the PR.

We should not be pausing anymore when topology is being used to indicate pause support or not.

@ujfalusi
Copy link
Collaborator

Suspend while pause still have problems, but it is the same without the PR.

We should not be pausing anymore when topology is being used to indicate pause support or not.

True, but if the topology indicates that then we should handle it.

@lgirdwood
Copy link
Member

Suspend while pause still have problems, but it is the same without the PR.

We should not be pausing anymore when topology is being used to indicate pause support or not.

True, but if the topology indicates that then we should handle it.

There should be no pipelines/topologies supporting pause today.

Copy link
Collaborator

@ujfalusi ujfalusi left a comment

Choose a reason for hiding this comment

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

@ranj063, I get the overall idea now.
What I'm a bit puzzled is that all vendors will need to implement the BE pipe management (which is mostly generic pipe/widget mangling code) on their own.

I'm not sure if we can do better? Some how have the BE code also up in the core and call in to platform if needed?

struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
u32 host_dma_id = platform_params->stream_tag - 1;
Copy link
Collaborator

Choose a reason for hiding this comment

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

host_dma_id can be moved under the ChainDMA case?

u32 host_dma_id = platform_params->stream_tag - 1;

if (pipeline->use_chain_dma) {
pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id);
Copy link
Collaborator

Choose a reason for hiding this comment

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

it would be better to clear the HOST_ID bits before or-ing

{
struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need NULL check here?

This is going to be skipped in DSPless mode, right?

@@ -230,6 +231,8 @@ struct sof_ipc_tplg_ops {
int (*widget_free)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
int (*dai_config)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
unsigned int flags, struct snd_sof_dai_config_data *data);
void (*host_config)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
struct snd_sof_platform_stream_params *platform_params);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are we confident that the host_config can never fail, not even in the future?

@@ -106,9 +106,9 @@ sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_run

spcm->stream[dir].list = list;

ret = sof_widget_list_setup(sdev, spcm, params, platform_params, dir);
ret = sof_widget_list_prepare(sdev, spcm, params, platform_params, dir);
Copy link
Collaborator

Choose a reason for hiding this comment

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

it is really confusing that in setup we prepare and later in prepare we setup

I'm not sure which has precedence... Do we need to prepare things to be able to setup or we need to setup to be able to prepare them.

@@ -446,6 +688,9 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
.codec_dai_set_stream = hda_codec_dai_set_stream,
.calc_stream_format = hda_calc_stream_format,
.get_hlink = hda_get_hlink,
.set_up_be_pipeline = hda_ipc4_set_up_be_pipeline,
.free_be_pipeline = hda_ipc4_free_be_pipeline,
.unprepare_be_pipeline = hda_dai_unprepare_widgets_in_pipeline,
Copy link
Collaborator

Choose a reason for hiding this comment

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

So, if the BE is not serviced by HD-DMA (but with dwdma or something else) and not IPC4 I assume then we don't need to do this black magic?

return 0;
}

static int hda_ipc4_set_up_be_pipeline(struct snd_soc_dapm_widget *w, int dir)
Copy link
Collaborator

Choose a reason for hiding this comment

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

there is not much IPC4 specific code in these and what they call are not IPC4 specific anymore.
I'm not sure if I follow it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@ujfalusi there's isnt anything IPC4 specific here but I dont want to modify anything for IPC3 anymore. So we just let IPC3 work as before without moving the pipeline management to the BE DAI ops.

@@ -291,6 +291,7 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc
sroute->setup = true;
return 0;
}
EXPORT_SYMBOL(sof_route_setup);
Copy link
Collaborator

Choose a reason for hiding this comment

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

You should have done this earlier, the previous patch uses the function.

* if it belongs to a BE pipeline.
*/
if (!swidget || !swidget->prepared || swidget->use_count > 0 ||
swidget->spipe->be_pipeline)
Copy link
Collaborator

Choose a reason for hiding this comment

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

In some places use use sof_is_be_pipeline_widget() in some swidget->spipe->be_pipeline


if (pipeline->skip_during_fe_trigger)
if (spipe->be_pipeline)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess sof_is_be_pipeline_widget(pipe_widget) would be too much indirection to take, right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants