clear-pkgs-linux-iot-lts2018/0402-ASoC-Intel-Skylake-Imp...

256 lines
9.1 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "R, Dharageswari" <dharageswari.r@intel.com>
Date: Thu, 28 Dec 2017 08:31:45 +0530
Subject: [PATCH] ASoC: Intel: Skylake: Implement recovery for cAVS platforms
This patch implements the Audio dsp crash recovery for cAVS platforms
for single and multiple streams. As a part of recovery, the firmware
needs to be re-downloaded which requires the DMA channel 0. The patch
does the necessary changes to reuse the DMA channel 0 for firmware
download
Change-Id: Icb09bca1525759d45a7739b42aa4404556087922
Signed-off-by: R, Dharageswari <dharageswari.r@intel.com>
Signed-off-by: Pradeep Tewani <pradeep.d.tewani@intel.com>
Reviewed-on:
Reviewed-by: Prusty, Subhransu S <subhransu.s.prusty@intel.com>
Tested-by: Madiwalar, MadiwalappaX <madiwalappax.madiwalar@intel.com>
---
sound/soc/intel/common/sst-dsp-priv.h | 1 +
sound/soc/intel/skylake/bxt-sst.c | 3 ++
sound/soc/intel/skylake/cnl-sst.c | 7 ++++
sound/soc/intel/skylake/skl-messages.c | 54 ++++++++++++++++++++++++--
sound/soc/intel/skylake/skl-pcm.c | 2 +
sound/soc/intel/skylake/skl-sst-dsp.h | 2 +
sound/soc/intel/skylake/skl-topology.c | 1 +
sound/soc/intel/skylake/skl-topology.h | 2 +
sound/soc/intel/skylake/skl.c | 3 ++
9 files changed, 71 insertions(+), 4 deletions(-)
diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h
index 196bb7d7ebf0..b9935fdd0910 100644
--- a/sound/soc/intel/common/sst-dsp-priv.h
+++ b/sound/soc/intel/common/sst-dsp-priv.h
@@ -355,6 +355,7 @@ struct sst_dsp {
/* To allocate CL dma buffers */
struct skl_dsp_loader_ops dsp_ops;
struct skl_dsp_fw_ops fw_ops;
+ bool is_recovery;
struct skl_cl_dev cl_dev;
u32 intr_status;
const struct firmware *fw;
diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c
index dd5453daa562..2eb57d75f1b1 100644
--- a/sound/soc/intel/skylake/bxt-sst.c
+++ b/sound/soc/intel/skylake/bxt-sst.c
@@ -680,6 +680,9 @@ int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx)
int ret;
struct sst_dsp *sst = ctx->dsp;
+ if (sst->is_recovery)
+ skl_dsp_disable_core(sst, SKL_DSP_CORE0_MASK);
+
ret = sst->fw_ops.load_fw(sst);
if (ret < 0) {
dev_err(dev, "Load base fw failed: %x\n", ret);
diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c
index bfc4da85c043..59448c1ba37c 100644
--- a/sound/soc/intel/skylake/cnl-sst.c
+++ b/sound/soc/intel/skylake/cnl-sst.c
@@ -796,6 +796,13 @@ int cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx)
struct sst_dsp *sst = ctx->dsp;
int ret;
+ if (sst->is_recovery) {
+ cnl_dsp_disable_core(sst, SKL_DSP_CORE0_MASK);
+ ret = cnl_load_base_firmware(sst);
+ if (ret < 0)
+ return ret;
+ }
+
skl_dsp_init_core_state(sst);
if (ctx->lib_count > 1) {
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index 5fb1093cdfa2..bc8d3afcf7d1 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -293,7 +293,8 @@ static const struct skl_dsp_ops dsp_ops[] = {
.loader_ops = bxt_get_loader_ops,
.init = bxt_sst_dsp_init,
.init_fw = bxt_sst_init_fw,
- .cleanup = bxt_sst_dsp_cleanup
+ .cleanup = bxt_sst_dsp_cleanup,
+ .do_recovery = skl_do_recovery
},
{
.id = 0x3198,
@@ -301,7 +302,8 @@ static const struct skl_dsp_ops dsp_ops[] = {
.loader_ops = bxt_get_loader_ops,
.init = bxt_sst_dsp_init,
.init_fw = bxt_sst_init_fw,
- .cleanup = bxt_sst_dsp_cleanup
+ .cleanup = bxt_sst_dsp_cleanup,
+ .do_recovery = skl_do_recovery
},
{
.id = 0x9dc8,
@@ -309,7 +311,8 @@ static const struct skl_dsp_ops dsp_ops[] = {
.loader_ops = bxt_get_loader_ops,
.init = cnl_sst_dsp_init,
.init_fw = cnl_sst_init_fw,
- .cleanup = cnl_sst_dsp_cleanup
+ .cleanup = cnl_sst_dsp_cleanup,
+ .do_recovery = skl_do_recovery
},
{
.id = 0x34c8,
@@ -317,7 +320,8 @@ static const struct skl_dsp_ops dsp_ops[] = {
.loader_ops = bxt_get_loader_ops,
.init = cnl_sst_dsp_init,
.init_fw = cnl_sst_init_fw,
- .cleanup = cnl_sst_dsp_cleanup
+ .cleanup = cnl_sst_dsp_cleanup,
+ .do_recovery = skl_do_recovery
},
};
@@ -364,6 +368,48 @@ static int cnl_sdw_bra_pipe_trigger(struct skl_sst *ctx, bool enable,
return ret;
}
+void skl_do_recovery(struct skl *skl)
+{
+ struct snd_soc_component *soc_component = skl->component;
+ const struct skl_dsp_ops *ops;
+ struct snd_soc_card *card;
+ struct hdac_stream *azx_dev;
+ struct hdac_ext_bus *ebus = &skl->ebus;
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct snd_pcm_substream *substream = NULL;
+ struct hdac_ext_stream *stream;
+
+ skl->skl_sst->dsp->is_recovery = true;
+ skl_dsp_reset_core_state(skl->skl_sst->dsp);
+ card = soc_component->card;
+ snd_soc_suspend(card->dev);
+ skl_cleanup_resources(skl);
+ skl_reset_instance_id(skl->skl_sst);
+
+ /* Free up DMA channel 0 for firmware re-download */
+ list_for_each_entry(azx_dev, &bus->stream_list, list) {
+ if (azx_dev->stream_tag == 1 &&
+ azx_dev->direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (azx_dev->opened) {
+ substream = azx_dev->substream;
+ stream = stream_to_hdac_ext_stream(azx_dev);
+ snd_hdac_ext_stream_release(stream,
+ skl_get_host_stream_type(ebus));
+ }
+ break;
+ }
+ }
+ ops = skl_get_dsp_ops(skl->pci->device);
+ if (ops->init_fw(soc_component->dev, skl->skl_sst) < 0)
+ dev_err(skl->skl_sst->dev, "Recovery failed\n");
+ if (substream != NULL) {
+ stream = snd_hdac_ext_stream_assign(ebus, substream,
+ skl_get_host_stream_type(ebus));
+ }
+ snd_soc_resume(card->dev);
+ skl->skl_sst->dsp->is_recovery = false;
+}
+
void skl_trigger_recovery(struct work_struct *work)
{
struct skl_monitor *monitor_dsp = container_of(work,
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index a2315144d7e3..15fbded46dcb 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -189,6 +189,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
params->host_dma_id + 1);
if (!hstream)
return -EINVAL;
+ hstream->substream = params->substream;
stream = stream_to_hdac_ext_stream(hstream);
snd_hdac_ext_stream_decouple(bus, stream, true);
@@ -377,6 +378,7 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
p_params.host_dma_id = dma_id;
p_params.stream = substream->stream;
p_params.format = params_format(params);
+ p_params.substream = substream;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
p_params.host_bps = dai->driver->playback.sig_bits;
else
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
index ef9bf4a4a1b7..dc793d503115 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
@@ -22,6 +22,7 @@
#include <sound/memalloc.h>
#include <uapi/sound/snd_sst_tokens.h>
#include "skl-sst-cldma.h"
+#include "skl.h"
struct sst_dsp;
struct skl_sst;
@@ -270,6 +271,7 @@ struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
struct sst_dsp_device *sst_dev, int irq);
int skl_dsp_acquire_irq(struct sst_dsp *sst);
bool is_skl_dsp_running(struct sst_dsp *ctx);
+void skl_do_recovery(struct skl *skl);
unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx);
void skl_dsp_init_core_state(struct sst_dsp *ctx);
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index e7c86d4b2439..1606aee09306 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -2517,6 +2517,7 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
pipe->p_params->s_freq = params->s_freq;
pipe->p_params->stream = params->stream;
pipe->p_params->format = params->format;
+ pipe->p_params->substream = params->substream;
} else {
memcpy(pipe->p_params, params, sizeof(*params));
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index 97b9614f57af..e86b84e9868d 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -317,6 +317,7 @@ struct skl_pipe_params {
int stream;
unsigned int host_bps;
unsigned int link_bps;
+ struct snd_pcm_substream *substream;
};
struct skl_pipe_fmt {
@@ -616,6 +617,7 @@ int skl_pcm_host_dma_prepare(struct device *dev,
struct skl_pipe_params *params);
int skl_pcm_link_dma_prepare(struct device *dev,
struct skl_pipe_params *params);
+enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *ebus);
int skl_dai_load(struct snd_soc_component *cmp, int index,
struct snd_soc_dai_driver *dai_drv,
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 40cd27fad180..44718e849bd0 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -389,6 +389,9 @@ static int skl_suspend(struct device *dev)
struct skl *skl = bus_to_skl(bus);
int ret = 0;
+ if (skl->skl_sst->dsp->is_recovery)
+ return -EBUSY;
+
/*
* Do not suspend if streams which are marked ignore suspend are
* running, we need to save the state for these and continue
--
https://clearlinux.org