In the BE hw_params configuration, the existing code checks if any of the
existing FEs are prepared, running, paused or suspended - and skips the
configuration in those cases. This allows multiple calls of hw_params
which the ALSA state machine supports.
This check is not handled for the prepare stage, which can lead to the
same BE being prepared multiple times. This patch adds a check similar to
that of the hw_params, with the main difference being that the suspended
state is allowed: the ALSA state machine allows a transition from
suspended to prepared with hw_params skipped.
This problem was detected on Intel IPC4/SoundWire devices, where the BE
dailink .prepare stage is used to configure the SoundWire stream with a
bank switch. Multiple .prepare calls lead to conflicts with the .trigger
operation with IPC4 configurations. This problem was not detected earlier
on Intel devices, HDaudio BE dailinks detect that the link is already
prepared and skip the configuration, and for IPC3 devices there is no BE
trigger.
Link: https://github.com/thesofproject/sof/issues/7596
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com
Link: https://lore.kernel.org/r/20230517185731.487124-1-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org
substream->runtime will be attached when substream was opened
at snd_pcm_attach_substream(). When it uses DPCM,
FE substream->runtime is attached, but BE substream->runtime is not.
Thus, we are copying FE substream->runtime to BE.
But, we are copyig FE substream->runtime to FE dpcm->runtime first (A),
and copy it to BE dpcm->runtime (B), and copy it to
BE substream->runtime (C).
static int dpcm_fe_dai_open(...) {
...
(A) fe->dpcm[stream].runtime = fe_substream->runtime;
...
}
static int dpcm_be_connect(...) {
...
(B) be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
...
}
int dpcm_be_dai_startup(...) {
...
(C) be_substream->runtime = be->dpcm[stream].runtime;
...
}
It is too roundabout and troublesome.
OTOH, it is directly copying fe_substream->runtime at dpcm_be_reparent()
without using be->dpcm[stream].runtime.
static void dpcm_be_reparent(...)
{
...
for_each_dpcm_fe(be, stream, dpcm) {
...
=> be_substream->runtime = fe_substream->runtime;
break;
}
}
This patch removes indirect copying.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87v8je64dh.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Export the widget_in_list() function to be used by other modules.
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Link: https://lore.kernel.org/r/20230127120031.10709-3-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Current soc-pcm.c is coping fe hw_param to dpcm->hw_param (A),
fixup it (B), and copy it to be (C).
int dpcm_be_dai_hw_params(...)
{
...
for_each_dpcm_be(fe, stream, dpcm) {
...
/* copy params for each dpcm */
(A) memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params, ...) ;
/* perform any hw_params fixups */
(B) ret = snd_soc_link_be_hw_params_fixup(be, &dpcm->hw_params);
...
/* copy the fixed-up hw params for BE dai */
(C) memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params, ...);
...
}
...
}
But here, (1) it is coping hw_params without caring stream (Playback/Capture),
(2) we can get same value from be. We don't need to have dpcm->hw_params.
This patch removes it.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Reviewed-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Link: https://lore.kernel.org/r/87v8ogsl6h.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Commit 3aa1e96a2b ("ASoC: soc-pcm: fix BE handling of PAUSE_RELEASE")
did not modify the existing logic and kept the same logic for the following
transition
play FE1 -> BE state is START
pause FE1 -> BE state is PAUSED
play FE2 -> BE state is START
stop FE2 -> BE state is STOP <<< !!
release FE1 -> BE state is START
stop FE1 -> BE state is STOP
At the time it was identified by reviewers that a better solution
might consist in
play FE1 -> BE state is START
pause FE1 -> BE state is PAUSED
play FE2 -> BE state is START
stop FE2 -> BE state is PAUSE <<< !!
release FE1 -> BE state is START
stop FE1 -> BE state is STOP
This patch suggest a transition to PAUSE when all the 'active' streams
are paused. This would allow for a more consistent resource management
for platforms where PAUSE and STOP are handled differently.
To track the special case of an FE going from PAUSE_PUSH to STOP, we
add a state variable for each FE context. This 'fe_pause' boolean is
set on PAUSE_PUSH and cleared on either PAUSE_RELEASE and STOP
triggers.
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Rander Wang <rander.wang@intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20220406190056.233481-2-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
On start/pause_release/resume, when more than one FE is connected to
the same BE, it's possible that the trigger is sent more than
once. This is not desirable, we only want to trigger a BE once, which
is straightforward to implement with a refcount.
For stop/pause/suspend, the problem is more complicated: the check
implemented in snd_soc_dpcm_can_be_free_stop() may fail due to a
conceptual deadlock when we trigger the BE before the FE. In this
case, the FE states have not yet changed, so there are corner cases
where the TRIGGER_STOP is never sent - the dual case of start where
multiple triggers might be sent.
This patch suggests an unconditional trigger in all cases, without
checking the FE states, using a refcount protected by the BE PCM
stream lock.
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Link: https://lore.kernel.org/r/20211207173745.15850-6-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Export a couple of DAPM functions that can be used by
ASoC drivers to determine connected widgets when a PCM
is started.
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Link: https://lore.kernel.org/r/20210927120517.20505-6-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
soc-pcm has very similar but different DPCM BE DAI stop operation at
1) dpcm_be_dai_startup() error case rollback
2) dpcm_be_dai_startup_unwind()
3) dpcm_be_dai_shutdown()
The differences are
1) for rollback
2) Doesn't check by snd_soc_dpcm_be_can_update() (Is this bug ?)
3) Do soc_pcm_hw_free() if it was not !OPENed and !HW_FREEed,
and call soc_pcm_close().
We can share same code by
1) hw_free is not needed. Needs last dpcm as rollback.
2) hw_free is not needed.
3) hw_free is needed.
This patch adds new dpcm_be_dai_stop() and share these 3.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87a6rduoam.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This makes DPCM runtime update functions available for external
calling. As an example, virtualised ASoC component drivers may need
to call these when managing shared DAPM routes that are used by more
than one driver (i.e. when host driver and guest drivers have a DAPM
path from guest PCM to host DAI where some parts are owned by host
driver and others by guest driver).
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Link: https://lore.kernel.org/r/20200312095214.15126-3-guennadi.liakhovetski@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
dpcm_path_put() (A) is calling kfree(*list).
The freed list is created by dapm_widget_list_create() (B) which is called
from snd_soc_dapm_dai_get_connected_widgets() (C) which is called from
dpcm_path_get() (D).
(B) dapm_widget_list_create(**list, ...)
{
...
=> *list = kzalloc();
...
}
(C) snd_soc_dapm_dai_get_connected_widgets(..., **list, ...)
{
...
dapm_widget_list_create(list, ...);
...
}
(D) dpcm_path_get(..., **list)
{
...
snd_soc_dapm_dai_get_connected_widgets(..., list, ...);
...
}
(A) dpcm_path_put(**list)
{
=> kfree(*list);
}
This kind of unbalance code is very difficult to read/understand.
To avoid this issue, this patch adds each missing paired function
dapm_widget_list_free() for dapm_widget_list_create() (B), and
snd_soc_dapm_dai_free_widgets() for snd_soc_dapm_dai_get_connected_widgets() (C).
This patch uses these, and moves dpcm_path_put() next to dpcm_path_get().
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87a75fjc9q.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
No one is using snd_soc_dpcm_be_get/set_state().
If it exists only by assumption that "it may be necessary someday",
let's remove it now. Otherwise code maintenance will be difficult.
We can revive it when we really needed it.
Let's remove it, so far.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/87a75hbou7.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
No one is using soc_dpcm_be_digital_mute().
If it exists only by assumption that "it may be necessary someday",
let's remove it now. Otherwise code maintenance will be difficult.
We can revive it when we really needed it.
Let's remove it, so far.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/87blpxbouc.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
for_each_dpcm_xx() macro is using "dpcm" as parameter (1),
but, it is also struct member (2).
#define for_each_dpcm_fe(be, stream, dpcm) \
list_for_each_entry(dpcm, &(be)->dpcm[stream]...)
^^^^(1) ^^^^(2)
Thus, it will be compile error if user not used "dpcm" as parameter
for_each_dpcm_fe(be, stream, dp)
^^
This patch fixup it.
Reported-by: Pavel Machek <pavel@denx.de>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87tv7x7idx.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
soc_dpcm_debugfs_add() is implemented at soc-pcm.c under CONFIG_DEBUG_FS.
Thus, soc-core.c which is only user of it need to use CONFIG_DEBUG_FS, too.
This patch defines soc_dpcm_debugfs_add() for non CONFIG_DEBUG_FS case.
Then, we can remove #ifdef CONFIG_DEBUG_FS from soc-core.c
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/875zn9ahnv.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
To be more readable code, this patch adds
new for_each_dpcm_be() macro, and replace existing code to it.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
To be more readable code, this patch adds
new for_each_dpcm_fe() macro, and replace existing code to it.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Failing to register the debugfs entries is not fatal and will not affect
normal operation of the sound card. Don't abort the card registration if
soc_dpcm_debugfs_add() fails.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@kernel.org>
DPCM can update the FE/BE connection states totally asynchronously
from the FE's PCM state. Most of FE/BE state changes are protected by
mutex, so that they won't race, but there are still some actions that
are uncovered. For example, suppose to switch a BE while a FE's
stream is running. This would call soc_dpcm_runtime_update(), which
sets FE's runtime_update flag, then sets up and starts BEs, and clears
FE's runtime_update flag again.
When a device emits XRUN during this operation, the PCM core triggers
snd_pcm_stop(XRUN). Since the trigger action is an atomic ops, this
isn't blocked by the mutex, thus it kicks off DPCM's trigger action.
It eventually updates and clears FE's runtime_update flag while
soc_dpcm_runtime_update() is running concurrently, and it results in
confusion.
Usually, for avoiding such a race, we take a lock. There is a PCM
stream lock for that purpose. However, as already mentioned, the
trigger action is atomic, and we can't take the lock for the whole
soc_dpcm_runtime_update() or other operations that include the lengthy
jobs like hw_params or prepare.
This patch provides an alternative solution. This adds a way to defer
the conflicting trigger callback to be executed at the end of FE/BE
state changes. For doing it, two things are introduced:
- Each runtime_update state change of FEs is protected via PCM stream
lock.
- The FE's trigger callback checks the runtime_update flag. If it's
not set, the trigger action is executed there. If set, mark the
pending trigger action and returns immediately.
- At the exit of runtime_update state change, it checks whether the
pending trigger is present. If yes, it executes the trigger action
at this point.
Reported-and-tested-by: Qiao Zhou <zhouqiao@marvell.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Acked-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Cc: stable@vger.kernel.org
The ASoC compressed code needs to call the internal DPCM APIs in order to
dynamically route compressed data to different DAIs.
Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
soc_dpcm_runtime_update() operates on a ASoC card as a whole. Currently it takes
a snd_soc_dapm_widget as its only parameter though. The widget is then used to
look up the card and is otherwise unused. This patch changes the function to
take a pointer to the card directly. This makes it possible to to call
soc_dpcm_runtime_update() for updates which are not related to one specific
widget.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@linaro.org>
Some on SoC DSP HW is very tightly coupled with DMA and DAI drivers. It's
necessary to allow some flexability wrt to PCM operations here so that we
can define a bespoke DPCM trigger() PCM operation for such HW.
A bespoke DPCM trigger() allows exact ordering and timing of component
triggering by allowing a component driver to manage the final enable
and disable configurations without adding extra complexity to other
component drivers. e.g. The McPDM DAI and ABE are tightly coupled on
OMAP4 so we have a bespoke trigger to manage the trigger to improve
performance and reduce complexity when triggering new McPDM BEs.
Signed-off-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This patch allows DPCM to dynamically alter the FE to BE PCM links
at runtime based on mixer setting updates. DAPM is looked up after
every mixer update and we perform a DPCM runtime update if the
mixer has a change of value.
This patchs adds/changes the following :-
o Adds DPCM runtime update core.
o Changes soc_dapm_mixer_update_power() and soc_dapm_mux_update_power()
to return if a change has occured rather than 0. No other users check
atm.
Signed-off-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Add debugFS files for DPCM link management information.
Signed-off-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
The Dynamic PCM core allows digital audio data to be dynamically
routed between different ALSA PCMs and DAI links on SoC CPUs with
on chip DSP devices. e.g. audio data could be played on pcm:0,0 and
routed to any (or all) SoC DAI links.
Dynamic PCM introduces the concept of Front End (FE) PCMs and Back
End (BE) PCMs. The FE PCMs are normal ALSA PCM devices except that
they can dynamically route digital audio data to any supported BE
PCM. A BE PCM has no ALSA device, but represents a DAI link and it's
substream and audio HW parameters.
e.g. pcm:0,0 routing digital data to 2 external codecs.
FE pcm:0,0 ----> BE (McBSP.0) ----> CODEC 0
+--> BE (McPDM.0) ----> CODEC 1
e.g. pcm:0,0 and pcm:0,1 routing digital data to 1 external codec.
FE pcm:0,0 ---
+--> BE (McBSP.0) ----> CODEC
FE pcm:0,1 ---
The digital audio routing is controlled by the usual ALSA method
of mixer kcontrols. Dynamic PCM uses a DAPM graph to work out the
routing based upon the mixer settings and configures the BE PCMs
based on routing and the FE HW params.
DPCM is designed so that most ASoC component drivers will need no
modification at all. It's intended that existing CODEC, DAI and
platform drivers can be used in DPCM based audio devices without
any changes. However, there will be some cases where minor changes
are required (e.g. for very tightly coupled HW) and there are
helpers to support this too.
Somethimes the HW params of a FE and BE do not match or are
incompatible, so in these cases the machine driver can reconfigure
any hw_params and make any DSP perform sample rate / format conversion.
This patch adds the core DPCM code and contains :-
o The FE and BE PCM operations.
o FE and BE DAI link support.
o FE and BE PCM creation.
o BE support API.
o BE and FE link management.
Signed-off-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>