-
Notifications
You must be signed in to change notification settings - Fork 132
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
base: topic/sof-dev
Are you sure you want to change the base?
Conversation
50da688
to
9883c9b
Compare
SOFCI TEST |
f2569fa
to
8818a53
Compare
There was a problem hiding this 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); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
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 |
0a0cbf9
to
dae9464
Compare
SOFCI TEST |
0b23916
to
c3a3b54
Compare
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]>
c3a3b54
to
43f86ee
Compare
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]>
43f86ee
to
32588f6
Compare
SOFCI TEST |
int ret; | ||
|
||
/* set up the widget if it belongs to the same pipeline as the DAI widget */ | ||
if (swidget->spipe != spipe || !swidget->prepared) |
There was a problem hiding this comment.
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().
SOFCI TEST |
@ranj063, this sequence still fails (HDA machine): terminal 2: terminal 1:
|
There was a problem hiding this 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); |
There was a problem hiding this comment.
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
@ujfalusi can you review whilst the HDA issue is being resolved. Thanks ! |
@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. |
@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)
{ |
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. |
There was a problem hiding this 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; |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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?
This PR refactors the pipeline management to do the following:
So the overall flow for a normal start/stop would be:
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.