mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-11 13:27:06 +09:00
[x86] ASoC: SOF sound driver: back port fixes to prevent crash
Prevents kernel crash on firmware reload Closes: #940726 Signed-off-by: Héctor Orón Martínez <zumbi@debian.org> Tested-by: Mark Pearson <mpearson@lenovo.com>
This commit is contained in:
5
debian/changelog
vendored
5
debian/changelog
vendored
@@ -8,6 +8,11 @@ linux (5.2.17-2) UNRELEASED; urgency=medium
|
||||
* KEYS: Re-enable SECONDARY_TRUSTED_KEYRING, dropped in 5.2.6-1 by
|
||||
mis-merge (Closes: #935945)
|
||||
|
||||
[ Héctor Orón Martínez ]
|
||||
* [x86] ASoC: SOF sound driver: back port fixes to prevent kernel crash on
|
||||
firmware reload (Closes: #940726)
|
||||
- Based on patchset by Mark Pearson.
|
||||
|
||||
-- Romain Perier <romain.perier@gmail.com> Mon, 30 Sep 2019 16:09:14 +0200
|
||||
|
||||
linux (5.2.17-1) unstable; urgency=medium
|
||||
|
||||
65
debian/config/amd64/config
vendored
65
debian/config/amd64/config
vendored
@@ -247,3 +247,68 @@ CONFIG_ZONE_DEVICE=y
|
||||
##
|
||||
CONFIG_LSM_MMAP_MIN_ADDR=65536
|
||||
|
||||
##
|
||||
## file: sound/soc/sof/Kconfig
|
||||
##
|
||||
|
||||
CONFIG_SND_SOC_SOF_TOPLEVEL=y
|
||||
CONFIG_SND_SOC_SOF_PCI=m
|
||||
CONFIG_SND_SOC_SOF_ACPI=m
|
||||
|
||||
##
|
||||
## file: sound/soc/sof/intel/Kconfig
|
||||
##
|
||||
CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL=y
|
||||
CONFIG_SND_SOC_SOF_BAYTRAIL_SUPPORT=y
|
||||
CONFIG_SND_SOC_SOF_BROADWELL_SUPPORT=y
|
||||
CONFIG_SND_SOC_SOF_MERRIFIELD_SUPPORT=y
|
||||
CONFIG_SND_SOC_SOF_APOLLOLAKE_SUPPORT=y
|
||||
CONFIG_SND_SOC_SOF_GEMINILAKE_SUPPORT=y
|
||||
CONFIG_SND_SOC_SOF_CANNONLAKE_SUPPORT=y
|
||||
CONFIG_SND_SOC_SOF_COFFEELAKE_SUPPORT=y
|
||||
CONFIG_SND_SOC_SOF_ICELAKE_SUPPORT=y
|
||||
CONFIG_SND_SOC_SOF_HDA_LINK=y
|
||||
CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC=y
|
||||
|
||||
##
|
||||
## file: sound/soc/intel/Kconfig
|
||||
##
|
||||
CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC=y
|
||||
|
||||
##
|
||||
## file: sound/soc/intel/boards/Kconfig
|
||||
##
|
||||
CONFIG_SND_SOC_INTEL_HASWELL_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_BROADWELL_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_CHT_BSW_NAU8824_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_BXT_RT298_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH=m
|
||||
CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH=m
|
||||
|
||||
##
|
||||
## file: sound/pci/hda/Kconfig
|
||||
##
|
||||
CONFIG_SND_HDA_INTEL=m
|
||||
CONFIG_SND_HDA_INPUT_BEEP=y
|
||||
CONFIG_SND_HDA_CODEC_REALTEK=m
|
||||
CONFIG_SND_HDA_CODEC_ANALOG=m
|
||||
CONFIG_SND_HDA_CODEC_SIGMATEL=m
|
||||
CONFIG_SND_HDA_CODEC_VIA=m
|
||||
CONFIG_SND_HDA_CODEC_HDMI=m
|
||||
CONFIG_SND_HDA_CODEC_CIRRUS=m
|
||||
CONFIG_SND_HDA_CODEC_CONEXANT=m
|
||||
CONFIG_SND_HDA_CODEC_CA0110=m
|
||||
CONFIG_SND_HDA_CODEC_CA0132=m
|
||||
CONFIG_SND_HDA_CODEC_CMEDIA=m
|
||||
CONFIG_SND_HDA_CODEC_SI3054=m
|
||||
CONFIG_SND_HDA_GENERIC=m
|
||||
|
||||
25
debian/patches/bugfix/x86/ASoC-SOF-Intel-hda-add-new-macro-hstream_to_sof_hda_.patch
vendored
Normal file
25
debian/patches/bugfix/x86/ASoC-SOF-Intel-hda-add-new-macro-hstream_to_sof_hda_.patch
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
commit f5dbba9fee801f4678a50d92c785f7f24d4ee2c6
|
||||
Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
|
||||
Date: Wed Jun 12 12:23:34 2019 -0500
|
||||
|
||||
ASoC: SOF: Intel: hda: add new macro hstream_to_sof_hda_stream()
|
||||
|
||||
Add a new macro to get sof_intel_hda_stream from hdac_ext_stream.
|
||||
|
||||
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
|
||||
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
|
||||
index 502b0a3c2e3c..376b1ca51e2b 100644
|
||||
--- a/sound/soc/sof/intel/hda.h
|
||||
+++ b/sound/soc/sof/intel/hda.h
|
||||
@@ -415,6 +415,9 @@ struct sof_intel_hda_stream {
|
||||
int hw_params_upon_resume; /* set up hw_params upon resume */
|
||||
};
|
||||
|
||||
+#define hstream_to_sof_hda_stream(hstream) \
|
||||
+ container_of(hstream, struct sof_intel_hda_stream, hda_stream)
|
||||
+
|
||||
#define bus_to_sof_hda(bus) \
|
||||
container_of(bus, struct sof_intel_hda_dev, hbus.core)
|
||||
|
||||
168
debian/patches/bugfix/x86/ASoC-SOF-Intel-hda-release-link-DMA-for-paused-strea.patch
vendored
Normal file
168
debian/patches/bugfix/x86/ASoC-SOF-Intel-hda-release-link-DMA-for-paused-strea.patch
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
commit 7077a07a72d38a78040873bbc13a77d1e45f8aa0
|
||||
Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
|
||||
Date: Wed Jun 12 12:23:38 2019 -0500
|
||||
|
||||
ASoC: SOF: Intel: hda: release link DMA for paused streams during suspend
|
||||
|
||||
Paused streams do not get suspended when the system enters S3.
|
||||
So, clear and release link DMA channel for such streams in the
|
||||
hda_dsp_set_hw_params_upon_resume() callback. Also, invalidate
|
||||
the link DMA channel in the DAI config before restoring the
|
||||
dai config upon resume. Also, modify the signature for the
|
||||
set_hw_params_upon_resume() op to return an int.
|
||||
|
||||
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
|
||||
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
|
||||
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
|
||||
index 5b73115a0b78..c6eea3079ab7 100644
|
||||
--- a/sound/soc/sof/intel/hda-dsp.c
|
||||
+++ b/sound/soc/sof/intel/hda-dsp.c
|
||||
@@ -454,18 +454,45 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
|
||||
+int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct hdac_bus *bus = sof_to_bus(sdev);
|
||||
struct sof_intel_hda_stream *hda_stream;
|
||||
struct hdac_ext_stream *stream;
|
||||
struct hdac_stream *s;
|
||||
|
||||
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
|
||||
+ struct snd_soc_pcm_runtime *rtd;
|
||||
+ struct hdac_ext_link *link;
|
||||
+ const char *name;
|
||||
+ int stream_tag;
|
||||
+#endif
|
||||
+
|
||||
/* set internal flag for BE */
|
||||
list_for_each_entry(s, &bus->stream_list, list) {
|
||||
stream = stream_to_hdac_ext_stream(s);
|
||||
hda_stream = container_of(stream, struct sof_intel_hda_stream,
|
||||
hda_stream);
|
||||
hda_stream->hw_params_upon_resume = 1;
|
||||
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
|
||||
+ /*
|
||||
+ * clear and release stream. This should already be taken care
|
||||
+ * for running streams when the SUSPEND trigger is called.
|
||||
+ * But paused streams do not get suspended, so this needs to be
|
||||
+ * done explicitly during suspend.
|
||||
+ */
|
||||
+ if (stream->link_substream) {
|
||||
+ rtd = snd_pcm_substream_chip(stream->link_substream);
|
||||
+ name = rtd->codec_dai->component->name;
|
||||
+ link = snd_hdac_ext_bus_get_link(bus, name);
|
||||
+ if (!link)
|
||||
+ return -EINVAL;
|
||||
+ stream_tag = hdac_stream(stream)->stream_tag;
|
||||
+ snd_hdac_ext_link_clear_stream_id(link, stream_tag);
|
||||
+ snd_hdac_ext_stream_release(stream,
|
||||
+ HDAC_EXT_STREAM_TYPE_LINK);
|
||||
+ }
|
||||
+#endif
|
||||
}
|
||||
+ return 0;
|
||||
}
|
||||
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
|
||||
index 2862b4b3b07c..327621ef5cf3 100644
|
||||
--- a/sound/soc/sof/intel/hda.h
|
||||
+++ b/sound/soc/sof/intel/hda.h
|
||||
@@ -451,7 +451,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state);
|
||||
int hda_dsp_resume(struct snd_sof_dev *sdev);
|
||||
int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state);
|
||||
int hda_dsp_runtime_resume(struct snd_sof_dev *sdev);
|
||||
-void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
|
||||
+int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
|
||||
void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags);
|
||||
void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
|
||||
void hda_ipc_dump(struct snd_sof_dev *sdev);
|
||||
diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h
|
||||
index 80fc3b374c2b..a23297353750 100644
|
||||
--- a/sound/soc/sof/ops.h
|
||||
+++ b/sound/soc/sof/ops.h
|
||||
@@ -134,10 +134,11 @@ static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static inline void snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev)
|
||||
+static inline int snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev)
|
||||
{
|
||||
if (sof_ops(sdev)->set_hw_params_upon_resume)
|
||||
- sof_ops(sdev)->set_hw_params_upon_resume(sdev);
|
||||
+ return sof_ops(sdev)->set_hw_params_upon_resume(sdev);
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq)
|
||||
diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c
|
||||
index b7843f02ef67..8eeb3a1029f2 100644
|
||||
--- a/sound/soc/sof/pm.c
|
||||
+++ b/sound/soc/sof/pm.c
|
||||
@@ -153,6 +153,15 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev)
|
||||
continue;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * The link DMA channel would be invalidated for running
|
||||
+ * streams but not for streams that were in the PAUSED
|
||||
+ * state during suspend. So invalidate it here before setting
|
||||
+ * the dai config in the DSP.
|
||||
+ */
|
||||
+ if (config->type == SOF_DAI_INTEL_HDA)
|
||||
+ config->hda.link_dma_ch = DMA_CHAN_INVALID;
|
||||
+
|
||||
ret = sof_ipc_tx_message(sdev->ipc,
|
||||
config->hdr.cmd, config,
|
||||
config->hdr.size,
|
||||
@@ -204,7 +213,7 @@ static int sof_send_pm_ipc(struct snd_sof_dev *sdev, int cmd)
|
||||
sizeof(pm_ctx), &reply, sizeof(reply));
|
||||
}
|
||||
|
||||
-static void sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
|
||||
+static int sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
struct snd_sof_pcm *spcm;
|
||||
@@ -229,7 +238,7 @@ static void sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
|
||||
}
|
||||
|
||||
/* set internal flag for BE */
|
||||
- snd_sof_dsp_hw_params_upon_resume(sdev);
|
||||
+ return snd_sof_dsp_hw_params_upon_resume(sdev);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
|
||||
@@ -333,8 +342,15 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
|
||||
snd_sof_release_trace(sdev);
|
||||
|
||||
/* set restore_stream for all streams during system suspend */
|
||||
- if (!runtime_suspend)
|
||||
- sof_set_hw_params_upon_resume(sdev);
|
||||
+ if (!runtime_suspend) {
|
||||
+ ret = sof_set_hw_params_upon_resume(sdev);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(sdev->dev,
|
||||
+ "error: setting hw_params flag during suspend %d\n",
|
||||
+ ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
|
||||
/* cache debugfs contents during runtime suspend */
|
||||
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
|
||||
index b80d93e5df2f..cf1b047f8cb6 100644
|
||||
--- a/sound/soc/sof/sof-priv.h
|
||||
+++ b/sound/soc/sof/sof-priv.h
|
||||
@@ -172,7 +172,7 @@ struct snd_sof_dsp_ops {
|
||||
int (*runtime_suspend)(struct snd_sof_dev *sof_dev,
|
||||
int state); /* optional */
|
||||
int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */
|
||||
- void (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */
|
||||
+ int (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */
|
||||
|
||||
/* DSP clocking */
|
||||
int (*set_clk)(struct snd_sof_dev *sof_dev, u32 freq); /* optional */
|
||||
47
debian/patches/bugfix/x86/ASoC-SOF-Intel-hda-save-handle-to-sdev-in-sof_intel_.patch
vendored
Normal file
47
debian/patches/bugfix/x86/ASoC-SOF-Intel-hda-save-handle-to-sdev-in-sof_intel_.patch
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
commit 7623ae793c28cc0928c5d1292542dbb92fc2e9e2
|
||||
Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
|
||||
Date: Wed Jun 12 12:23:33 2019 -0500
|
||||
|
||||
ASoC: SOF: Intel: hda: save handle to sdev in sof_intel_hda_stream
|
||||
|
||||
Add a snd_sof_dev member to sof_intel_hda_stream. This will be
|
||||
used to access the snd_sof_dev during link hw_params callback.
|
||||
|
||||
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
|
||||
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
|
||||
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
|
||||
index c92006f89499..1cd94e7631a8 100644
|
||||
--- a/sound/soc/sof/intel/hda-stream.c
|
||||
+++ b/sound/soc/sof/intel/hda-stream.c
|
||||
@@ -564,6 +564,8 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
|
||||
if (!hda_stream)
|
||||
return -ENOMEM;
|
||||
|
||||
+ hda_stream->sdev = sdev;
|
||||
+
|
||||
stream = &hda_stream->hda_stream;
|
||||
|
||||
stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
|
||||
@@ -617,6 +619,8 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
|
||||
if (!hda_stream)
|
||||
return -ENOMEM;
|
||||
|
||||
+ hda_stream->sdev = sdev;
|
||||
+
|
||||
stream = &hda_stream->hda_stream;
|
||||
|
||||
/* we always have DSP support */
|
||||
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
|
||||
index 6c7dee2627d0..502b0a3c2e3c 100644
|
||||
--- a/sound/soc/sof/intel/hda.h
|
||||
+++ b/sound/soc/sof/intel/hda.h
|
||||
@@ -409,6 +409,7 @@ static inline struct hda_bus *sof_to_hbus(struct snd_sof_dev *s)
|
||||
}
|
||||
|
||||
struct sof_intel_hda_stream {
|
||||
+ struct snd_sof_dev *sdev;
|
||||
struct hdac_ext_stream hda_stream;
|
||||
struct sof_intel_stream stream;
|
||||
int hw_params_upon_resume; /* set up hw_params upon resume */
|
||||
516
debian/patches/bugfix/x86/ASoC-SOF-assign-link-DMA-channel-at-run-time.patch
vendored
Normal file
516
debian/patches/bugfix/x86/ASoC-SOF-assign-link-DMA-channel-at-run-time.patch
vendored
Normal file
@@ -0,0 +1,516 @@
|
||||
commit bdf4ad3fd01f5dc53c5d6d3b17afc98cd76d8988
|
||||
Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
|
||||
Date: Wed Jun 12 12:23:36 2019 -0500
|
||||
|
||||
ASoC: SOF: Intel: hda: assign link DMA channel at run-time
|
||||
|
||||
The recommended HDA HW programming sequence for setting
|
||||
the DMA format requires that the link DMA and host DMA
|
||||
channels be coupled before setting the format. This
|
||||
change means that host DMA or link DMA channels be
|
||||
reserved even if only one is used.
|
||||
|
||||
Statically assigned link DMA channels would mean that
|
||||
all the corresponding host DMA channels will need to be
|
||||
reserved, leaving only a few channels available at run-time.
|
||||
So, the suggestion here is to switch to dynamically assigning
|
||||
both host DMA channels and link DMA channels are run-time.
|
||||
|
||||
The host DMA channel is assigned when the pcm
|
||||
is opened as before. While choosing the link DMA channel,
|
||||
if the host DMA channel corresponding to the link DMA channel
|
||||
is already taken, the proposed method checks to make
|
||||
sure that the BE is connected to the FE that has been assigned
|
||||
this host DMA channel. Once the link DMA channel is assigned,
|
||||
an IPC is sent to the DSP to set the link DMA channel.
|
||||
|
||||
The link DMA channel is freed during hw_free() and also in the
|
||||
SUSPEND trigger callback. It will be re-assigned when hw_params
|
||||
are set upon resume.
|
||||
|
||||
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
|
||||
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
|
||||
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
|
||||
index e1decf25aeac..c270fd7a0878 100644
|
||||
--- a/sound/soc/sof/intel/hda-dai.c
|
||||
+++ b/sound/soc/sof/intel/hda-dai.c
|
||||
@@ -30,62 +30,84 @@ struct hda_pipe_params {
|
||||
};
|
||||
|
||||
/*
|
||||
- * Unlike GP dma, there is a set of stream registers in hda controller
|
||||
- * to control the link dma channels. Each register controls one link
|
||||
- * dma channel and the relation is fixed. To make sure FW uses correct
|
||||
- * link dma channels, host allocates stream registers and sends the
|
||||
- * corresponding link dma channels to FW to allocate link dma channel
|
||||
- *
|
||||
- * FIXME: this API is abused in the sense that tx_num and rx_num are
|
||||
- * passed as arguments, not returned. We need to find a better way to
|
||||
- * retrieve the stream tag allocated for the link DMA
|
||||
+ * This function checks if the host dma channel corresponding
|
||||
+ * to the link DMA stream_tag argument is assigned to one
|
||||
+ * of the FEs connected to the BE DAI.
|
||||
*/
|
||||
-static int hda_link_dma_get_channels(struct snd_soc_dai *dai,
|
||||
- unsigned int *tx_num,
|
||||
- unsigned int *tx_slot,
|
||||
- unsigned int *rx_num,
|
||||
- unsigned int *rx_slot)
|
||||
+static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
|
||||
+ int dir, int stream_tag)
|
||||
{
|
||||
- struct hdac_bus *bus;
|
||||
- struct hdac_ext_stream *stream;
|
||||
- struct snd_pcm_substream substream;
|
||||
- struct snd_sof_dev *sdev =
|
||||
- snd_soc_component_get_drvdata(dai->component);
|
||||
-
|
||||
- bus = sof_to_bus(sdev);
|
||||
-
|
||||
- memset(&substream, 0, sizeof(substream));
|
||||
- if (*tx_num == 1) {
|
||||
- substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
|
||||
- stream = snd_hdac_ext_stream_assign(bus, &substream,
|
||||
- HDAC_EXT_STREAM_TYPE_LINK);
|
||||
- if (!stream) {
|
||||
- dev_err(bus->dev, "error: failed to find a free hda ext stream for playback");
|
||||
- return -EBUSY;
|
||||
- }
|
||||
+ struct snd_pcm_substream *fe_substream;
|
||||
+ struct hdac_stream *fe_hstream;
|
||||
+ struct snd_soc_dpcm *dpcm;
|
||||
+
|
||||
+ for_each_dpcm_fe(rtd, dir, dpcm) {
|
||||
+ fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir);
|
||||
+ fe_hstream = fe_substream->runtime->private_data;
|
||||
+ if (fe_hstream->stream_tag == stream_tag)
|
||||
+ return true;
|
||||
+ }
|
||||
|
||||
- snd_soc_dai_set_dma_data(dai, &substream, stream);
|
||||
- *tx_slot = hdac_stream(stream)->stream_tag - 1;
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+static struct hdac_ext_stream *
|
||||
+ hda_link_stream_assign(struct hdac_bus *bus,
|
||||
+ struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct sof_intel_hda_stream *hda_stream;
|
||||
+ struct hdac_ext_stream *res = NULL;
|
||||
+ struct hdac_stream *stream = NULL;
|
||||
|
||||
- dev_dbg(bus->dev, "link dma channel %d for playback", *tx_slot);
|
||||
+ int stream_dir = substream->stream;
|
||||
+
|
||||
+ if (!bus->ppcap) {
|
||||
+ dev_err(bus->dev, "stream type not supported\n");
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
- if (*rx_num == 1) {
|
||||
- substream.stream = SNDRV_PCM_STREAM_CAPTURE;
|
||||
- stream = snd_hdac_ext_stream_assign(bus, &substream,
|
||||
- HDAC_EXT_STREAM_TYPE_LINK);
|
||||
- if (!stream) {
|
||||
- dev_err(bus->dev, "error: failed to find a free hda ext stream for capture");
|
||||
- return -EBUSY;
|
||||
+ list_for_each_entry(stream, &bus->stream_list, list) {
|
||||
+ struct hdac_ext_stream *hstream =
|
||||
+ stream_to_hdac_ext_stream(stream);
|
||||
+ if (stream->direction != substream->stream)
|
||||
+ continue;
|
||||
+
|
||||
+ hda_stream = hstream_to_sof_hda_stream(hstream);
|
||||
+
|
||||
+ /* check if available */
|
||||
+ if (!hstream->link_locked) {
|
||||
+ if (stream->opened) {
|
||||
+ /*
|
||||
+ * check if the stream tag matches the stream
|
||||
+ * tag of one of the connected FEs
|
||||
+ */
|
||||
+ if (hda_check_fes(rtd, stream_dir,
|
||||
+ stream->stream_tag)) {
|
||||
+ res = hstream;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ res = hstream;
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
+ }
|
||||
|
||||
- snd_soc_dai_set_dma_data(dai, &substream, stream);
|
||||
- *rx_slot = hdac_stream(stream)->stream_tag - 1;
|
||||
-
|
||||
- dev_dbg(bus->dev, "link dma channel %d for capture", *rx_slot);
|
||||
+ if (res) {
|
||||
+ /*
|
||||
+ * Decouple host and link DMA. The decoupled flag
|
||||
+ * is updated in snd_hdac_ext_stream_decouple().
|
||||
+ */
|
||||
+ if (!res->decoupled)
|
||||
+ snd_hdac_ext_stream_decouple(bus, res, true);
|
||||
+ spin_lock_irq(&bus->reg_lock);
|
||||
+ res->link_locked = 1;
|
||||
+ res->link_substream = substream;
|
||||
+ spin_unlock_irq(&bus->reg_lock);
|
||||
}
|
||||
|
||||
- return 0;
|
||||
+ return res;
|
||||
}
|
||||
|
||||
static int hda_link_dma_params(struct hdac_ext_stream *stream,
|
||||
@@ -122,6 +144,51 @@ static int hda_link_dma_params(struct hdac_ext_stream *stream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/* Send DAI_CONFIG IPC to the DAI that matches the dai_name and direction */
|
||||
+static int hda_link_config_ipc(struct sof_intel_hda_stream *hda_stream,
|
||||
+ const char *dai_name, int channel, int dir)
|
||||
+{
|
||||
+ struct sof_ipc_dai_config *config;
|
||||
+ struct snd_sof_dai *sof_dai;
|
||||
+ struct sof_ipc_reply reply;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ list_for_each_entry(sof_dai, &hda_stream->sdev->dai_list, list) {
|
||||
+ if (!sof_dai->cpu_dai_name)
|
||||
+ continue;
|
||||
+
|
||||
+ if (!strcmp(dai_name, sof_dai->cpu_dai_name) &&
|
||||
+ dir == sof_dai->comp_dai.direction) {
|
||||
+ config = sof_dai->dai_config;
|
||||
+
|
||||
+ if (!config) {
|
||||
+ dev_err(hda_stream->sdev->dev,
|
||||
+ "error: no config for DAI %s\n",
|
||||
+ sof_dai->name);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* update config with stream tag */
|
||||
+ config->hda.link_dma_ch = channel;
|
||||
+
|
||||
+ /* send IPC */
|
||||
+ ret = sof_ipc_tx_message(hda_stream->sdev->ipc,
|
||||
+ config->hdr.cmd,
|
||||
+ config,
|
||||
+ config->hdr.size,
|
||||
+ &reply, sizeof(reply));
|
||||
+
|
||||
+ if (ret < 0)
|
||||
+ dev_err(hda_stream->sdev->dev,
|
||||
+ "error: failed to set dai config for %s\n",
|
||||
+ sof_dai->name);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
static int hda_link_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
@@ -135,20 +202,31 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream,
|
||||
struct hda_pipe_params p_params = {0};
|
||||
struct hdac_ext_link *link;
|
||||
int stream_tag;
|
||||
+ int ret;
|
||||
|
||||
- link_dev = snd_soc_dai_get_dma_data(dai, substream);
|
||||
+ link_dev = hda_link_stream_assign(bus, substream);
|
||||
+ if (!link_dev)
|
||||
+ return -EBUSY;
|
||||
+
|
||||
+ stream_tag = hdac_stream(link_dev)->stream_tag;
|
||||
+
|
||||
+ hda_stream = hstream_to_sof_hda_stream(link_dev);
|
||||
+
|
||||
+ /* update the DSP with the new tag */
|
||||
+ ret = hda_link_config_ipc(hda_stream, dai->name, stream_tag - 1,
|
||||
+ substream->stream);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
|
||||
|
||||
- hda_stream = container_of(link_dev, struct sof_intel_hda_stream,
|
||||
- hda_stream);
|
||||
hda_stream->hw_params_upon_resume = 0;
|
||||
|
||||
link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
|
||||
if (!link)
|
||||
return -EINVAL;
|
||||
|
||||
- stream_tag = hdac_stream(link_dev)->stream_tag;
|
||||
-
|
||||
- /* set the stream tag in the codec dai dma params */
|
||||
+ /* set the stream tag in the codec dai dma params */
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0);
|
||||
else
|
||||
@@ -181,8 +259,7 @@ static int hda_link_pcm_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
int stream = substream->stream;
|
||||
|
||||
- hda_stream = container_of(link_dev, struct sof_intel_hda_stream,
|
||||
- hda_stream);
|
||||
+ hda_stream = hstream_to_sof_hda_stream(link_dev);
|
||||
|
||||
/* setup hw_params again only if resuming from system suspend */
|
||||
if (!hda_stream->hw_params_upon_resume)
|
||||
@@ -199,8 +276,24 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct hdac_ext_stream *link_dev =
|
||||
snd_soc_dai_get_dma_data(dai, substream);
|
||||
+ struct sof_intel_hda_stream *hda_stream;
|
||||
+ struct snd_soc_pcm_runtime *rtd;
|
||||
+ struct hdac_ext_link *link;
|
||||
+ struct hdac_stream *hstream;
|
||||
+ struct hdac_bus *bus;
|
||||
+ int stream_tag;
|
||||
int ret;
|
||||
|
||||
+ hstream = substream->runtime->private_data;
|
||||
+ bus = hstream->bus;
|
||||
+ rtd = snd_pcm_substream_chip(substream);
|
||||
+
|
||||
+ link = snd_hdac_ext_bus_get_link(bus, rtd->codec_dai->component->name);
|
||||
+ if (!link)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ hda_stream = hstream_to_sof_hda_stream(link_dev);
|
||||
+
|
||||
dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
@@ -217,8 +310,22 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
snd_hdac_ext_link_stream_start(link_dev);
|
||||
break;
|
||||
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
+ /*
|
||||
+ * clear and release link DMA channel. It will be assigned when
|
||||
+ * hw_params is set up again after resume.
|
||||
+ */
|
||||
+ ret = hda_link_config_ipc(hda_stream, dai->name,
|
||||
+ DMA_CHAN_INVALID, substream->stream);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ stream_tag = hdac_stream(link_dev)->stream_tag;
|
||||
+ snd_hdac_ext_link_clear_stream_id(link, stream_tag);
|
||||
+ snd_hdac_ext_stream_release(link_dev,
|
||||
+ HDAC_EXT_STREAM_TYPE_LINK);
|
||||
+
|
||||
+ /* fallthrough */
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
snd_hdac_ext_link_stream_clear(link_dev);
|
||||
break;
|
||||
@@ -228,62 +335,38 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
-/*
|
||||
- * FIXME: This API is also abused since it's used for two purposes.
|
||||
- * when the substream argument is NULL this function is used for cleanups
|
||||
- * that aren't necessarily required, and called explicitly by handling
|
||||
- * ASoC core structures, which is not recommended.
|
||||
- * This part will be reworked in follow-up patches.
|
||||
- */
|
||||
static int hda_link_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
- const char *name;
|
||||
unsigned int stream_tag;
|
||||
+ struct sof_intel_hda_stream *hda_stream;
|
||||
struct hdac_bus *bus;
|
||||
struct hdac_ext_link *link;
|
||||
struct hdac_stream *hstream;
|
||||
- struct hdac_ext_stream *stream;
|
||||
struct snd_soc_pcm_runtime *rtd;
|
||||
struct hdac_ext_stream *link_dev;
|
||||
- struct snd_pcm_substream pcm_substream;
|
||||
-
|
||||
- memset(&pcm_substream, 0, sizeof(pcm_substream));
|
||||
- if (substream) {
|
||||
- hstream = substream->runtime->private_data;
|
||||
- bus = hstream->bus;
|
||||
- rtd = snd_pcm_substream_chip(substream);
|
||||
- link_dev = snd_soc_dai_get_dma_data(dai, substream);
|
||||
- snd_hdac_ext_stream_decouple(bus, link_dev, false);
|
||||
- name = rtd->codec_dai->component->name;
|
||||
- link = snd_hdac_ext_bus_get_link(bus, name);
|
||||
- if (!link)
|
||||
- return -EINVAL;
|
||||
-
|
||||
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
- stream_tag = hdac_stream(link_dev)->stream_tag;
|
||||
- snd_hdac_ext_link_clear_stream_id(link, stream_tag);
|
||||
- }
|
||||
+ int ret;
|
||||
|
||||
- link_dev->link_prepared = 0;
|
||||
- } else {
|
||||
- /* release all hda streams when dai link is unloaded */
|
||||
- pcm_substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
|
||||
- stream = snd_soc_dai_get_dma_data(dai, &pcm_substream);
|
||||
- if (stream) {
|
||||
- snd_soc_dai_set_dma_data(dai, &pcm_substream, NULL);
|
||||
- snd_hdac_ext_stream_release(stream,
|
||||
- HDAC_EXT_STREAM_TYPE_LINK);
|
||||
- }
|
||||
+ hstream = substream->runtime->private_data;
|
||||
+ bus = hstream->bus;
|
||||
+ rtd = snd_pcm_substream_chip(substream);
|
||||
+ link_dev = snd_soc_dai_get_dma_data(dai, substream);
|
||||
+ hda_stream = hstream_to_sof_hda_stream(link_dev);
|
||||
|
||||
- pcm_substream.stream = SNDRV_PCM_STREAM_CAPTURE;
|
||||
- stream = snd_soc_dai_get_dma_data(dai, &pcm_substream);
|
||||
- if (stream) {
|
||||
- snd_soc_dai_set_dma_data(dai, &pcm_substream, NULL);
|
||||
- snd_hdac_ext_stream_release(stream,
|
||||
- HDAC_EXT_STREAM_TYPE_LINK);
|
||||
- }
|
||||
- }
|
||||
+ /* free the link DMA channel in the FW */
|
||||
+ ret = hda_link_config_ipc(hda_stream, dai->name, DMA_CHAN_INVALID,
|
||||
+ substream->stream);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ link = snd_hdac_ext_bus_get_link(bus, rtd->codec_dai->component->name);
|
||||
+ if (!link)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ stream_tag = hdac_stream(link_dev)->stream_tag;
|
||||
+ snd_hdac_ext_link_clear_stream_id(link, stream_tag);
|
||||
+ snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK);
|
||||
+ link_dev->link_prepared = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -293,7 +376,6 @@ static const struct snd_soc_dai_ops hda_link_dai_ops = {
|
||||
.hw_free = hda_link_hw_free,
|
||||
.trigger = hda_link_pcm_trigger,
|
||||
.prepare = hda_link_pcm_prepare,
|
||||
- .get_channel_map = hda_link_dma_get_channels,
|
||||
};
|
||||
#endif
|
||||
|
||||
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
|
||||
index 8c3ac149bbb9..b80d93e5df2f 100644
|
||||
--- a/sound/soc/sof/sof-priv.h
|
||||
+++ b/sound/soc/sof/sof-priv.h
|
||||
@@ -56,6 +56,8 @@
|
||||
#define SOF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_FLOAT)
|
||||
|
||||
+#define DMA_CHAN_INVALID 0xFFFFFFFF
|
||||
+
|
||||
struct snd_sof_dev;
|
||||
struct snd_sof_ipc_msg;
|
||||
struct snd_sof_ipc;
|
||||
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
|
||||
index 178256e338b1..432ae343f960 100644
|
||||
--- a/sound/soc/sof/topology.c
|
||||
+++ b/sound/soc/sof/topology.c
|
||||
@@ -2571,9 +2571,7 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
|
||||
*/
|
||||
static int sof_link_hda_process(struct snd_sof_dev *sdev,
|
||||
struct snd_soc_dai_link *link,
|
||||
- struct sof_ipc_dai_config *config,
|
||||
- int tx_slot,
|
||||
- int rx_slot)
|
||||
+ struct sof_ipc_dai_config *config)
|
||||
{
|
||||
struct sof_ipc_reply reply;
|
||||
u32 size = sizeof(*config);
|
||||
@@ -2586,22 +2584,11 @@ static int sof_link_hda_process(struct snd_sof_dev *sdev,
|
||||
continue;
|
||||
|
||||
if (strcmp(link->name, sof_dai->name) == 0) {
|
||||
- if (sof_dai->comp_dai.direction ==
|
||||
- SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
- if (!link->dpcm_playback)
|
||||
- return -EINVAL;
|
||||
-
|
||||
- config->hda.link_dma_ch = tx_slot;
|
||||
- } else {
|
||||
- if (!link->dpcm_capture)
|
||||
- return -EINVAL;
|
||||
-
|
||||
- config->hda.link_dma_ch = rx_slot;
|
||||
- }
|
||||
-
|
||||
config->dai_index = sof_dai->comp_dai.dai_index;
|
||||
found = 1;
|
||||
|
||||
+ config->hda.link_dma_ch = DMA_CHAN_INVALID;
|
||||
+
|
||||
/* save config in dai component */
|
||||
sof_dai->dai_config = kmemdup(config, size, GFP_KERNEL);
|
||||
if (!sof_dai->dai_config)
|
||||
@@ -2648,10 +2635,6 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index,
|
||||
struct snd_soc_tplg_private *private = &cfg->priv;
|
||||
struct snd_soc_dai *dai;
|
||||
u32 size = sizeof(*config);
|
||||
- u32 tx_num = 0;
|
||||
- u32 tx_slot = 0;
|
||||
- u32 rx_num = 0;
|
||||
- u32 rx_slot = 0;
|
||||
int ret;
|
||||
|
||||
/* init IPC */
|
||||
@@ -2677,22 +2660,7 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- if (link->dpcm_playback)
|
||||
- tx_num = 1;
|
||||
-
|
||||
- if (link->dpcm_capture)
|
||||
- rx_num = 1;
|
||||
-
|
||||
- ret = snd_soc_dai_get_channel_map(dai, &tx_num, &tx_slot,
|
||||
- &rx_num, &rx_slot);
|
||||
- if (ret < 0) {
|
||||
- dev_err(sdev->dev, "error: failed to get dma channel for HDA%d\n",
|
||||
- config->dai_index);
|
||||
-
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- ret = sof_link_hda_process(sdev, link, config, tx_slot, rx_slot);
|
||||
+ ret = sof_link_hda_process(sdev, link, config);
|
||||
if (ret < 0)
|
||||
dev_err(sdev->dev, "error: failed to process hda dai link %s",
|
||||
link->name);
|
||||
@@ -2819,17 +2787,6 @@ static int sof_link_hda_unload(struct snd_sof_dev *sdev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * FIXME: this call to hw_free is mainly to release the link DMA ID.
|
||||
- * This is abusing the API and handling SOC internals is not
|
||||
- * recommended. This part will be reworked.
|
||||
- */
|
||||
- if (dai->driver->ops->hw_free)
|
||||
- ret = dai->driver->ops->hw_free(NULL, dai);
|
||||
- if (ret < 0)
|
||||
- dev_err(sdev->dev, "error: failed to free hda resource for %s\n",
|
||||
- link->name);
|
||||
-
|
||||
return ret;
|
||||
}
|
||||
|
||||
516
debian/patches/bugfix/x86/ASoC-SOF-dont-wake-dsp-up-in-kcontrol-IO.patch
vendored
Normal file
516
debian/patches/bugfix/x86/ASoC-SOF-dont-wake-dsp-up-in-kcontrol-IO.patch
vendored
Normal file
@@ -0,0 +1,516 @@
|
||||
commit 0c888baba8e041c92c5c1882f25b8df5c29bff9f
|
||||
Author: Bard Liao <yung-chuan.liao@linux.intel.com>
|
||||
Date: Wed Jun 12 12:01:48 2019 -0500
|
||||
|
||||
ASoC: SOF: dont wake dsp up in kcontrol IO
|
||||
|
||||
Always get kcontrol value from cache, set kcontrol value to DSP
|
||||
when DSP is active. Kcontrol values will be restored when DSP boot up.
|
||||
We will set the default value of kcontrol in sof_complete to make sure
|
||||
the value is align with firmware.
|
||||
|
||||
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
|
||||
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
|
||||
diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c
|
||||
index 84e2cbfbbcbb..a4983f90ff5b 100644
|
||||
--- a/sound/soc/sof/control.c
|
||||
+++ b/sound/soc/sof/control.c
|
||||
@@ -39,26 +39,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
|
||||
struct soc_mixer_control *sm =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct snd_sof_control *scontrol = sm->dobj.private;
|
||||
- struct snd_sof_dev *sdev = scontrol->sdev;
|
||||
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
|
||||
unsigned int i, channels = scontrol->num_channels;
|
||||
- int err, ret;
|
||||
-
|
||||
- ret = pm_runtime_get_sync(sdev->dev);
|
||||
- if (ret < 0) {
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: volume get failed to resume %d\n",
|
||||
- ret);
|
||||
- pm_runtime_put_noidle(sdev->dev);
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- /* get all the mixer data from DSP */
|
||||
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
- SOF_IPC_COMP_GET_VALUE,
|
||||
- SOF_CTRL_TYPE_VALUE_CHAN_GET,
|
||||
- SOF_CTRL_CMD_VOLUME,
|
||||
- false);
|
||||
|
||||
/* read back each channel */
|
||||
for (i = 0; i < channels; i++)
|
||||
@@ -66,12 +48,6 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
|
||||
ipc_to_mixer(cdata->chanv[i].value,
|
||||
scontrol->volume_table, sm->max + 1);
|
||||
|
||||
- pm_runtime_mark_last_busy(sdev->dev);
|
||||
- err = pm_runtime_put_autosuspend(sdev->dev);
|
||||
- if (err < 0)
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: volume get failed to idle %d\n",
|
||||
- err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -84,16 +60,6 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_sof_dev *sdev = scontrol->sdev;
|
||||
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
|
||||
unsigned int i, channels = scontrol->num_channels;
|
||||
- int ret, err;
|
||||
-
|
||||
- ret = pm_runtime_get_sync(sdev->dev);
|
||||
- if (ret < 0) {
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: volume put failed to resume %d\n",
|
||||
- ret);
|
||||
- pm_runtime_put_noidle(sdev->dev);
|
||||
- return ret;
|
||||
- }
|
||||
|
||||
/* update each channel */
|
||||
for (i = 0; i < channels; i++) {
|
||||
@@ -104,18 +70,13 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
|
||||
}
|
||||
|
||||
/* notify DSP of mixer updates */
|
||||
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
- SOF_IPC_COMP_SET_VALUE,
|
||||
- SOF_CTRL_TYPE_VALUE_CHAN_GET,
|
||||
- SOF_CTRL_CMD_VOLUME,
|
||||
- true);
|
||||
-
|
||||
- pm_runtime_mark_last_busy(sdev->dev);
|
||||
- err = pm_runtime_put_autosuspend(sdev->dev);
|
||||
- if (err < 0)
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: volume put failed to idle %d\n",
|
||||
- err);
|
||||
+ if (pm_runtime_active(sdev->dev))
|
||||
+ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
+ SOF_IPC_COMP_SET_VALUE,
|
||||
+ SOF_CTRL_TYPE_VALUE_CHAN_GET,
|
||||
+ SOF_CTRL_CMD_VOLUME,
|
||||
+ true);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -125,37 +86,13 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
|
||||
struct soc_mixer_control *sm =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct snd_sof_control *scontrol = sm->dobj.private;
|
||||
- struct snd_sof_dev *sdev = scontrol->sdev;
|
||||
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
|
||||
unsigned int i, channels = scontrol->num_channels;
|
||||
- int err, ret;
|
||||
-
|
||||
- ret = pm_runtime_get_sync(sdev->dev);
|
||||
- if (ret < 0) {
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: switch get failed to resume %d\n",
|
||||
- ret);
|
||||
- pm_runtime_put_noidle(sdev->dev);
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- /* get all the mixer data from DSP */
|
||||
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
- SOF_IPC_COMP_GET_VALUE,
|
||||
- SOF_CTRL_TYPE_VALUE_CHAN_GET,
|
||||
- SOF_CTRL_CMD_SWITCH,
|
||||
- false);
|
||||
|
||||
/* read back each channel */
|
||||
for (i = 0; i < channels; i++)
|
||||
ucontrol->value.integer.value[i] = cdata->chanv[i].value;
|
||||
|
||||
- pm_runtime_mark_last_busy(sdev->dev);
|
||||
- err = pm_runtime_put_autosuspend(sdev->dev);
|
||||
- if (err < 0)
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: switch get failed to idle %d\n",
|
||||
- err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -168,16 +105,6 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_sof_dev *sdev = scontrol->sdev;
|
||||
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
|
||||
unsigned int i, channels = scontrol->num_channels;
|
||||
- int ret, err;
|
||||
-
|
||||
- ret = pm_runtime_get_sync(sdev->dev);
|
||||
- if (ret < 0) {
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: switch put failed to resume %d\n",
|
||||
- ret);
|
||||
- pm_runtime_put_noidle(sdev->dev);
|
||||
- return ret;
|
||||
- }
|
||||
|
||||
/* update each channel */
|
||||
for (i = 0; i < channels; i++) {
|
||||
@@ -186,18 +113,13 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
|
||||
}
|
||||
|
||||
/* notify DSP of mixer updates */
|
||||
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
- SOF_IPC_COMP_SET_VALUE,
|
||||
- SOF_CTRL_TYPE_VALUE_CHAN_GET,
|
||||
- SOF_CTRL_CMD_SWITCH,
|
||||
- true);
|
||||
-
|
||||
- pm_runtime_mark_last_busy(sdev->dev);
|
||||
- err = pm_runtime_put_autosuspend(sdev->dev);
|
||||
- if (err < 0)
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: switch put failed to idle %d\n",
|
||||
- err);
|
||||
+ if (pm_runtime_active(sdev->dev))
|
||||
+ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
+ SOF_IPC_COMP_SET_VALUE,
|
||||
+ SOF_CTRL_TYPE_VALUE_CHAN_GET,
|
||||
+ SOF_CTRL_CMD_SWITCH,
|
||||
+ true);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -207,37 +129,13 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
|
||||
struct soc_enum *se =
|
||||
(struct soc_enum *)kcontrol->private_value;
|
||||
struct snd_sof_control *scontrol = se->dobj.private;
|
||||
- struct snd_sof_dev *sdev = scontrol->sdev;
|
||||
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
|
||||
unsigned int i, channels = scontrol->num_channels;
|
||||
- int err, ret;
|
||||
-
|
||||
- ret = pm_runtime_get_sync(sdev->dev);
|
||||
- if (ret < 0) {
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: enum get failed to resume %d\n",
|
||||
- ret);
|
||||
- pm_runtime_put_noidle(sdev->dev);
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- /* get all the enum data from DSP */
|
||||
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
- SOF_IPC_COMP_GET_VALUE,
|
||||
- SOF_CTRL_TYPE_VALUE_CHAN_GET,
|
||||
- SOF_CTRL_CMD_ENUM,
|
||||
- false);
|
||||
|
||||
/* read back each channel */
|
||||
for (i = 0; i < channels; i++)
|
||||
ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
|
||||
|
||||
- pm_runtime_mark_last_busy(sdev->dev);
|
||||
- err = pm_runtime_put_autosuspend(sdev->dev);
|
||||
- if (err < 0)
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: enum get failed to idle %d\n",
|
||||
- err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -250,16 +148,6 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_sof_dev *sdev = scontrol->sdev;
|
||||
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
|
||||
unsigned int i, channels = scontrol->num_channels;
|
||||
- int ret, err;
|
||||
-
|
||||
- ret = pm_runtime_get_sync(sdev->dev);
|
||||
- if (ret < 0) {
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: enum put failed to resume %d\n",
|
||||
- ret);
|
||||
- pm_runtime_put_noidle(sdev->dev);
|
||||
- return ret;
|
||||
- }
|
||||
|
||||
/* update each channel */
|
||||
for (i = 0; i < channels; i++) {
|
||||
@@ -268,18 +156,13 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
|
||||
}
|
||||
|
||||
/* notify DSP of enum updates */
|
||||
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
- SOF_IPC_COMP_SET_VALUE,
|
||||
- SOF_CTRL_TYPE_VALUE_CHAN_GET,
|
||||
- SOF_CTRL_CMD_ENUM,
|
||||
- true);
|
||||
-
|
||||
- pm_runtime_mark_last_busy(sdev->dev);
|
||||
- err = pm_runtime_put_autosuspend(sdev->dev);
|
||||
- if (err < 0)
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: enum put failed to idle %d\n",
|
||||
- err);
|
||||
+ if (pm_runtime_active(sdev->dev))
|
||||
+ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
+ SOF_IPC_COMP_SET_VALUE,
|
||||
+ SOF_CTRL_TYPE_VALUE_CHAN_GET,
|
||||
+ SOF_CTRL_CMD_ENUM,
|
||||
+ true);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -293,7 +176,7 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
|
||||
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
|
||||
struct sof_abi_hdr *data = cdata->data;
|
||||
size_t size;
|
||||
- int ret, err;
|
||||
+ int ret = 0;
|
||||
|
||||
if (be->max > sizeof(ucontrol->value.bytes.data)) {
|
||||
dev_err_ratelimited(sdev->dev,
|
||||
@@ -302,22 +185,6 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- ret = pm_runtime_get_sync(sdev->dev);
|
||||
- if (ret < 0) {
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: bytes get failed to resume %d\n",
|
||||
- ret);
|
||||
- pm_runtime_put_noidle(sdev->dev);
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- /* get all the binary data from DSP */
|
||||
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
- SOF_IPC_COMP_GET_DATA,
|
||||
- SOF_CTRL_TYPE_DATA_GET,
|
||||
- scontrol->cmd,
|
||||
- false);
|
||||
-
|
||||
size = data->size + sizeof(*data);
|
||||
if (size > be->max) {
|
||||
dev_err_ratelimited(sdev->dev,
|
||||
@@ -331,12 +198,6 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
|
||||
memcpy(ucontrol->value.bytes.data, data, size);
|
||||
|
||||
out:
|
||||
- pm_runtime_mark_last_busy(sdev->dev);
|
||||
- err = pm_runtime_put_autosuspend(sdev->dev);
|
||||
- if (err < 0)
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: bytes get failed to idle %d\n",
|
||||
- err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -350,7 +211,6 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
|
||||
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
|
||||
struct sof_abi_hdr *data = cdata->data;
|
||||
size_t size = data->size + sizeof(*data);
|
||||
- int ret, err;
|
||||
|
||||
if (be->max > sizeof(ucontrol->value.bytes.data)) {
|
||||
dev_err_ratelimited(sdev->dev,
|
||||
@@ -366,32 +226,18 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- ret = pm_runtime_get_sync(sdev->dev);
|
||||
- if (ret < 0) {
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: bytes put failed to resume %d\n",
|
||||
- ret);
|
||||
- pm_runtime_put_noidle(sdev->dev);
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
/* copy from kcontrol */
|
||||
memcpy(data, ucontrol->value.bytes.data, size);
|
||||
|
||||
/* notify DSP of byte control updates */
|
||||
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
- SOF_IPC_COMP_SET_DATA,
|
||||
- SOF_CTRL_TYPE_DATA_SET,
|
||||
- scontrol->cmd,
|
||||
- true);
|
||||
-
|
||||
- pm_runtime_mark_last_busy(sdev->dev);
|
||||
- err = pm_runtime_put_autosuspend(sdev->dev);
|
||||
- if (err < 0)
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: bytes put failed to idle %d\n",
|
||||
- err);
|
||||
- return ret;
|
||||
+ if (pm_runtime_active(sdev->dev))
|
||||
+ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
+ SOF_IPC_COMP_SET_DATA,
|
||||
+ SOF_CTRL_TYPE_DATA_SET,
|
||||
+ scontrol->cmd,
|
||||
+ true);
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
|
||||
@@ -406,8 +252,6 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_tlv header;
|
||||
const struct snd_ctl_tlv __user *tlvd =
|
||||
(const struct snd_ctl_tlv __user *)binary_data;
|
||||
- int ret;
|
||||
- int err;
|
||||
|
||||
/*
|
||||
* The beginning of bytes data contains a header from where
|
||||
@@ -453,30 +297,15 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- ret = pm_runtime_get_sync(sdev->dev);
|
||||
- if (ret < 0) {
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: bytes_ext put failed to resume %d\n",
|
||||
- ret);
|
||||
- pm_runtime_put_noidle(sdev->dev);
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
/* notify DSP of byte control updates */
|
||||
- snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
- SOF_IPC_COMP_SET_DATA,
|
||||
- SOF_CTRL_TYPE_DATA_SET,
|
||||
- scontrol->cmd,
|
||||
- true);
|
||||
-
|
||||
- pm_runtime_mark_last_busy(sdev->dev);
|
||||
- err = pm_runtime_put_autosuspend(sdev->dev);
|
||||
- if (err < 0)
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: bytes_ext put failed to idle %d\n",
|
||||
- err);
|
||||
+ if (pm_runtime_active(sdev->dev))
|
||||
+ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
+ SOF_IPC_COMP_SET_DATA,
|
||||
+ SOF_CTRL_TYPE_DATA_SET,
|
||||
+ scontrol->cmd,
|
||||
+ true);
|
||||
|
||||
- return ret;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
|
||||
@@ -492,17 +321,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_tlv __user *tlvd =
|
||||
(struct snd_ctl_tlv __user *)binary_data;
|
||||
int data_size;
|
||||
- int err;
|
||||
- int ret;
|
||||
-
|
||||
- ret = pm_runtime_get_sync(sdev->dev);
|
||||
- if (ret < 0) {
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: bytes_ext get failed to resume %d\n",
|
||||
- ret);
|
||||
- pm_runtime_put_noidle(sdev->dev);
|
||||
- return ret;
|
||||
- }
|
||||
+ int ret = 0;
|
||||
|
||||
/*
|
||||
* Decrement the limit by ext bytes header size to
|
||||
@@ -514,13 +333,6 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
|
||||
cdata->data->magic = SOF_ABI_MAGIC;
|
||||
cdata->data->abi = SOF_ABI_VERSION;
|
||||
|
||||
- /* get all the component data from DSP */
|
||||
- ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
- SOF_IPC_COMP_GET_DATA,
|
||||
- SOF_CTRL_TYPE_DATA_GET,
|
||||
- scontrol->cmd,
|
||||
- false);
|
||||
-
|
||||
/* Prevent read of other kernel data or possibly corrupt response */
|
||||
data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
|
||||
|
||||
@@ -543,11 +355,5 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
|
||||
ret = -EFAULT;
|
||||
|
||||
out:
|
||||
- pm_runtime_mark_last_busy(sdev->dev);
|
||||
- err = pm_runtime_put_autosuspend(sdev->dev);
|
||||
- if (err < 0)
|
||||
- dev_err_ratelimited(sdev->dev,
|
||||
- "error: bytes_ext get failed to idle %d\n",
|
||||
- err);
|
||||
return ret;
|
||||
}
|
||||
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
|
||||
index 8e00f829bfdb..aaf459af89d0 100644
|
||||
--- a/sound/soc/sof/topology.c
|
||||
+++ b/sound/soc/sof/topology.c
|
||||
@@ -3016,6 +3016,49 @@ static int sof_route_load(struct snd_soc_component *scomp, int index,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+/* Function to set the initial value of SOF kcontrols.
|
||||
+ * The value will be stored in scontrol->control_data
|
||||
+ */
|
||||
+static int snd_sof_cache_kcontrol_val(struct snd_sof_dev *sdev)
|
||||
+{
|
||||
+ struct snd_sof_control *scontrol = NULL;
|
||||
+ int ipc_cmd, ctrl_type;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
|
||||
+
|
||||
+ /* notify DSP of kcontrol values */
|
||||
+ switch (scontrol->cmd) {
|
||||
+ case SOF_CTRL_CMD_VOLUME:
|
||||
+ case SOF_CTRL_CMD_ENUM:
|
||||
+ case SOF_CTRL_CMD_SWITCH:
|
||||
+ ipc_cmd = SOF_IPC_COMP_GET_VALUE;
|
||||
+ ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_GET;
|
||||
+ break;
|
||||
+ case SOF_CTRL_CMD_BINARY:
|
||||
+ ipc_cmd = SOF_IPC_COMP_GET_DATA;
|
||||
+ ctrl_type = SOF_CTRL_TYPE_DATA_GET;
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_err(sdev->dev,
|
||||
+ "error: Invalid scontrol->cmd: %d\n",
|
||||
+ scontrol->cmd);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
|
||||
+ ipc_cmd, ctrl_type,
|
||||
+ scontrol->cmd,
|
||||
+ false);
|
||||
+ if (ret < 0) {
|
||||
+ dev_warn(sdev->dev,
|
||||
+ "error: kcontrol value get for widget: %d\n",
|
||||
+ scontrol->comp_id);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
int snd_sof_complete_pipeline(struct snd_sof_dev *sdev,
|
||||
struct snd_sof_widget *swidget)
|
||||
{
|
||||
@@ -3059,6 +3102,11 @@ static void sof_complete(struct snd_soc_component *scomp)
|
||||
break;
|
||||
}
|
||||
}
|
||||
+ /*
|
||||
+ * cache initial values of SOF kcontrols by reading DSP value over
|
||||
+ * IPC. It may be overwritten by alsa-mixer after booting up
|
||||
+ */
|
||||
+ snd_sof_cache_kcontrol_val(sdev);
|
||||
}
|
||||
|
||||
/* manifest - optional to inform component of manifest */
|
||||
50
debian/patches/bugfix/x86/ASoC-SOF-ignore-unrecoverable-CTX_SAVE-IPC-errors-at.patch
vendored
Normal file
50
debian/patches/bugfix/x86/ASoC-SOF-ignore-unrecoverable-CTX_SAVE-IPC-errors-at.patch
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
commit e2eba551d2f4226400a6bb7871fef439ad1318dd
|
||||
Author: Kai Vehmanen <kai.vehmanen@linux.intel.com>
|
||||
Date: Wed Jun 12 11:57:04 2019 -0500
|
||||
|
||||
ASoC: SOF: ignore unrecoverable CTX_SAVE IPC errors at suspend
|
||||
|
||||
As part of the suspend flow, a context save IPC message is
|
||||
sent to the firmware before powering down the DSP. If errors
|
||||
are met, the suspend flow is aborted with current code.
|
||||
|
||||
Change the behaviour such that if firmware returns -EBUSY or
|
||||
-EAGAIN, return the error codes to PM core as before. The device
|
||||
is left in active state in this case.
|
||||
|
||||
If other errors are reported, print a warning but do not block the
|
||||
suspend flow. As per interface specification, no valid error can be
|
||||
returned in this scenario. If the hardware has hit a fatal error and
|
||||
is not able to respond successfully, best recovery method is to
|
||||
proceed with suspend and power off the DSP.
|
||||
|
||||
Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
|
||||
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
|
||||
diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c
|
||||
index 8ef1d51025d8..b7843f02ef67 100644
|
||||
--- a/sound/soc/sof/pm.c
|
||||
+++ b/sound/soc/sof/pm.c
|
||||
@@ -343,11 +343,20 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
|
||||
#endif
|
||||
/* notify DSP of upcoming power down */
|
||||
ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
|
||||
- if (ret < 0) {
|
||||
+ if (ret == -EBUSY || ret == -EAGAIN) {
|
||||
+ /*
|
||||
+ * runtime PM has logic to handle -EBUSY/-EAGAIN so
|
||||
+ * pass these errors up
|
||||
+ */
|
||||
dev_err(sdev->dev,
|
||||
"error: ctx_save ipc error during suspend %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
+ } else if (ret < 0) {
|
||||
+ /* FW in unexpected state, continue to power down */
|
||||
+ dev_warn(sdev->dev,
|
||||
+ "ctx_save ipc error %d, proceeding with suspend\n",
|
||||
+ ret);
|
||||
}
|
||||
|
||||
/* power down all DSP cores */
|
||||
51
debian/patches/bugfix/x86/ASoC-SOF-topology-add-cpu_dai_name-for-DAIs.patch
vendored
Normal file
51
debian/patches/bugfix/x86/ASoC-SOF-topology-add-cpu_dai_name-for-DAIs.patch
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
commit 1b7e1956860d7566325502651c6bf14f115cd91d
|
||||
Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
|
||||
Date: Wed Jun 12 12:23:35 2019 -0500
|
||||
|
||||
ASoC: SOF: topology: add cpu_dai_name for DAIs
|
||||
|
||||
Add the cpu_dai_name member to snd_sof_dai and save the
|
||||
cpu_dai_name while setting the DAI config.
|
||||
|
||||
The internal SOF representation will have to change at a later point
|
||||
as well when we have multiple CPU dais.
|
||||
|
||||
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
|
||||
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
|
||||
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
|
||||
index 8760a4694d8f..8c3ac149bbb9 100644
|
||||
--- a/sound/soc/sof/sof-priv.h
|
||||
+++ b/sound/soc/sof/sof-priv.h
|
||||
@@ -337,6 +337,7 @@ struct snd_sof_route {
|
||||
struct snd_sof_dai {
|
||||
struct snd_sof_dev *sdev;
|
||||
const char *name;
|
||||
+ const char *cpu_dai_name;
|
||||
|
||||
struct sof_ipc_comp_dai comp_dai;
|
||||
struct sof_ipc_dai_config *dai_config;
|
||||
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
|
||||
index aaf459af89d0..178256e338b1 100644
|
||||
--- a/sound/soc/sof/topology.c
|
||||
+++ b/sound/soc/sof/topology.c
|
||||
@@ -2360,6 +2360,9 @@ static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size,
|
||||
if (!dai->dai_config)
|
||||
return -ENOMEM;
|
||||
|
||||
+ /* set cpu_dai_name */
|
||||
+ dai->cpu_dai_name = link->cpu_dai_name;
|
||||
+
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
@@ -2624,6 +2627,8 @@ static int sof_link_hda_process(struct snd_sof_dev *sdev,
|
||||
if (!sof_dai->dai_config)
|
||||
return -ENOMEM;
|
||||
|
||||
+ sof_dai->cpu_dai_name = link->cpu_dai_name;
|
||||
+
|
||||
/* send message to DSP */
|
||||
ret = sof_ipc_tx_message(sdev->ipc,
|
||||
config->hdr.cmd, config, size,
|
||||
7
debian/patches/series
vendored
7
debian/patches/series
vendored
@@ -88,6 +88,13 @@ bugfix/all/fs-add-module_softdep-declarations-for-hard-coded-cr.patch
|
||||
bugfix/all/partially-revert-usb-kconfig-using-select-for-usb_co.patch
|
||||
debian/revert-objtool-fix-config_stack_validation-y-warning.patch
|
||||
bugfix/all/partially-revert-net-socket-implement-64-bit-timestamps.patch
|
||||
bugfix/x86/ASoC-SOF-ignore-unrecoverable-CTX_SAVE-IPC-errors-at.patch
|
||||
bugfix/x86/ASoC-SOF-topology-add-cpu_dai_name-for-DAIs.patch
|
||||
bugfix/x86/ASoC-SOF-assign-link-DMA-channel-at-run-time.patch
|
||||
bugfix/x86/ASoC-SOF-Intel-hda-release-link-DMA-for-paused-strea.patch
|
||||
bugfix/x86/ASoC-SOF-dont-wake-dsp-up-in-kcontrol-IO.patch
|
||||
bugfix/x86/ASoC-SOF-Intel-hda-add-new-macro-hstream_to_sof_hda_.patch
|
||||
bugfix/x86/ASoC-SOF-Intel-hda-save-handle-to-sdev-in-sof_intel_.patch
|
||||
|
||||
# Miscellaneous features
|
||||
|
||||
|
||||
Reference in New Issue
Block a user