-
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
?
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.
we dont do setup in hw_params @bardliao. See my earlier comment. Its widget_prepare in hw_params and widget setup in prepare
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 |
43f86ee
to
32588f6
Compare
SOFCI TEST |
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?
@@ -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.
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 a bit of confusion wrt naming between the pcm ioctl and widgets. But what we do is widget_prepare during hw_params and widget_setup during prepare because prepare succeeds hw_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.
Right, but we will sof_widget_list_prepare() in sof_pcm_setup_connected_widgets()
iow, we prepare from setup
and
sof_widget_list_setup() in sof_pcm_prepare()
iow we setup from prepare
I know it is all fine if you know the background on what these are, but for an untrained eye this is confusing.
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.
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]>
This will be used in the BE DAI ops in the following patches. 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]>
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]>
f48cd1e
to
f417fc7
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.
@ranj063, finally I think I managed to get the idea and I really like it!
However I think there could be a better and probably more intuitive way to achieve this.
I would add the hda_ipc4_set_up_be_pipeline()/hda_ipc4_free_be_pipeline()/hda_dai_unprepare_widgets_in_pipeline() and their helpers to generic SOF code (to sof-audio.c perhaps)
as snd_sof_set_up_be_pipeline()/snd_sof_free_be_pipeline()/snd_sof_unprepare_widgets_in_pipeline() and export them.
In Intel/HDA code instead of callbacks I would have a flag to not that these platforms will manage the BE pipeline themselves (IPC4)
If this flag is set then you would set the swidget->spipe->be_managed_pipeline which will cause core to skip the BE pipe and in hda code you would either use this swidget->spipe-be_managed_pipeline flag or the one which is local to intel code and call the appropriate generic helper to do the pipeline handling.
I do think that this would make it more intuitive at the end while keeping the core idea intact.
@@ -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.
Right, but we will sof_widget_list_prepare() in sof_pcm_setup_connected_widgets()
iow, we prepare from setup
and
sof_widget_list_setup() in sof_pcm_prepare()
iow we setup from prepare
I know it is all fine if you know the background on what these are, but for an untrained eye this is confusing.
@@ -286,6 +286,27 @@ static int intel_params_stream(struct sdw_intel *sdw, | |||
return -EIO; | |||
} | |||
|
|||
static int intel_prepare_stream(struct sdw_intel *sdw, |
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.
Commit message:
For the moment, the prepare_stream op is exactly the same as the prepare_stream op.
I think one of them should be different, in this form it sound obvious that A is exactly the same as A.
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.
also, this applies to ACE2+ platforms, I guess.
|
||
if (ops->free_be_pipeline) { | ||
ret = ops->free_be_pipeline(w, | ||
hdac_stream(hext_stream)->direction); |
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.
hdac_stream(hext_stream)
== s
, no?
|
||
/* if this is a prepare without a hw_free or a suspend, free the BE pipeline */ | ||
if (swidget->spipe->complete && ops->free_be_pipeline) { | ||
ret = ops->free_be_pipeline(w, substream->stream); |
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 have substream->stream saved as local variable.
if (ops && ops->set_up_be_pipeline) | ||
return ops->set_up_be_pipeline(w, substream->stream); | ||
|
||
return ret; |
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 can return 0 from here to be more explicit (ret must be 0 if you reached this point)
|
||
return non_hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai); | ||
return ret; |
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.
Here also, just return 0
if (ops->set_up_be_pipeline) | ||
return ops->set_up_be_pipeline(w, stream); | ||
|
||
return ret; |
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.
return 0;
int ret; | ||
|
||
/* set the be_pipeline flag true for the pipeline */ | ||
swidget->spipe->be_pipeline = true; |
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.
This will be done each time a stream starts?
dev_err(sdev->dev, "failed to set up routes in the BE pipeline with DAI: %s\n", | ||
w->name); | ||
|
||
swidget->spipe->complete = 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.
even if it fails?
{ | ||
struct snd_sof_widget *swidget = w->dobj.private; | ||
|
||
if (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.
I would rather use be_managed_pipeline
. This flag is not set for example for IPC3 BE pipelines which does not make them non BE pipelines.
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.