clear-pkgs-linux-iot-lts2018/1010-ASoC-Intel-Skylake-Gen...

220 lines
8.8 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Cezary Rojewski <cezary.rojewski@intel.com>
Date: Fri, 26 Oct 2018 15:48:27 +0200
Subject: [PATCH] ASoC: Intel: Skylake: Generic firmware recovery on IPC
timeout.
Whenever IPC routine returns an error, there are steps which driver
should take depending on error code returned. Timeout is the most basic
case and recommendation is to simply reload firmware.
Change-Id: I5d3f49f0f15a6e19d7600e6fa0c2d8c29576410a
Tracked-On: OAM-76509
Signed-off-by: PawelX Dogiel <pawelx.dogiel@intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
Reviewed-by: Lewandowski, Gustaw <gustaw.lewandowski@intel.com>
---
sound/soc/intel/skylake/skl-debug.c | 4 +-
sound/soc/intel/skylake/skl-sst-ipc.c | 55 +++++++++++++++++++--------
sound/soc/intel/skylake/skl-sst-ipc.h | 2 +
3 files changed, 44 insertions(+), 17 deletions(-)
diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c
index 28060ea2e86e..e5acb86c4ee9 100644
--- a/sound/soc/intel/skylake/skl-debug.c
+++ b/sound/soc/intel/skylake/skl-debug.c
@@ -238,11 +238,11 @@ static ssize_t mod_control_write(struct file *file,
default:
if (mbsz)
- retval = sst_ipc_tx_message_wait(&ctx->ipc, *ipc_header,
+ retval = skl_ipc_tx_message_wait(&ctx->ipc, *ipc_header,
mod_set_get->mailbx, mbsz, NULL, NULL);
else
- retval = sst_ipc_tx_message_wait(&ctx->ipc, *ipc_header,
+ retval = skl_ipc_tx_message_wait(&ctx->ipc, *ipc_header,
NULL, 0, NULL, NULL);
break;
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
index 9f2621d7a535..af84aab4689a 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -905,6 +905,31 @@ void skl_ipc_free(struct sst_generic_ipc *ipc)
sst_ipc_fini(ipc);
}
+int skl_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header,
+ void *tx_data, size_t tx_bytes, void *rx_data, size_t *rx_bytes)
+{
+ struct skl_sst *ctx = container_of(ipc, struct skl_sst, ipc);
+ int ret;
+
+ ret = sst_ipc_tx_message_wait(ipc, header, tx_data, tx_bytes,
+ rx_data, rx_bytes);
+
+ if (ret == -ETIMEDOUT) {
+ ctx->enable_miscbdcge(ipc->dev, false);
+ ctx->clock_power_gating(ipc->dev, false);
+
+ ret = ctx->dsp_ops->init_fw(ipc->dev, ctx);
+
+ ctx->enable_miscbdcge(ipc->dev, true);
+ ctx->clock_power_gating(ipc->dev, true);
+
+ dev_warn(ipc->dev, "Recover from IPC timeout: %d\n", ret);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(skl_ipc_tx_message_wait);
+
int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc,
u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode)
{
@@ -922,7 +947,7 @@ int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc,
header.extension = IPC_PPL_LP_MODE(lp_mode);
dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, NULL);
+ ret = skl_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, NULL);
if (ret < 0) {
dev_err(ipc->dev, "ipc: create pipeline fail, err: %d\n", ret);
return ret;
@@ -944,7 +969,7 @@ int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id)
header.primary |= IPC_INSTANCE_ID(instance_id);
dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, NULL);
+ ret = skl_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, NULL);
if (ret < 0) {
dev_err(ipc->dev, "ipc: delete pipeline failed, err %d\n", ret);
return ret;
@@ -968,7 +993,7 @@ int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc,
header.primary |= IPC_PPL_STATE(state);
dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, NULL);
+ ret = skl_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, NULL);
if (ret < 0) {
dev_err(ipc->dev, "ipc: set pipeline state failed, err: %d\n", ret);
return ret;
@@ -991,7 +1016,7 @@ skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id)
header.extension = IPC_DMA_ID(dma_id);
dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, NULL);
+ ret = skl_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, NULL);
if (ret < 0) {
dev_err(ipc->dev, "ipc: save pipeline failed, err: %d\n", ret);
return ret;
@@ -1013,7 +1038,7 @@ int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id)
header.primary |= IPC_INSTANCE_ID(instance_id);
dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary);
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, NULL);
+ ret = skl_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, NULL);
if (ret < 0) {
dev_err(ipc->dev, "ipc: restore pipeline failed, err: %d\n", ret);
return ret;
@@ -1038,7 +1063,7 @@ int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id,
dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
header.primary, header.extension);
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
+ ret = skl_ipc_tx_message_wait(ipc, *ipc_header,
dx, sizeof(*dx), NULL, NULL);
if (ret < 0) {
dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret);
@@ -1064,7 +1089,7 @@ int skl_ipc_delete_instance(struct sst_generic_ipc *ipc,
dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
header.primary, header.extension);
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL,
+ ret = skl_ipc_tx_message_wait(ipc, *ipc_header, NULL,
msg->param_data_size, NULL, NULL);
if (ret < 0) {
@@ -1102,7 +1127,7 @@ int skl_ipc_init_instance(struct sst_generic_ipc *ipc,
dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__,
header.primary, header.extension);
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header, param_data,
+ ret = skl_ipc_tx_message_wait(ipc, *ipc_header, param_data,
msg->param_data_size, NULL, NULL);
if (ret < 0) {
@@ -1135,7 +1160,7 @@ int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc,
dev_dbg(ipc->dev, "In %s hdr=%x ext=%x\n", __func__, header.primary,
header.extension);
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, NULL);
+ ret = skl_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, NULL);
if (ret < 0) {
dev_err(ipc->dev, "ipc: bind/unbind failed\n");
return ret;
@@ -1163,7 +1188,7 @@ int skl_ipc_load_modules(struct sst_generic_ipc *ipc,
header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS);
header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data,
+ ret = skl_ipc_tx_message_wait(ipc, *ipc_header, data,
(sizeof(u16) * module_cnt), NULL, NULL);
if (ret < 0)
dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret);
@@ -1184,7 +1209,7 @@ int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt,
header.primary |= IPC_GLB_TYPE(IPC_GLB_UNLOAD_MULTIPLE_MODS);
header.primary |= IPC_LOAD_MODULE_CNT(module_cnt);
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data,
+ ret = skl_ipc_tx_message_wait(ipc, *ipc_header, data,
(sizeof(u16) * module_cnt), NULL, NULL);
if (ret < 0)
dev_err(ipc->dev, "ipc: unload modules failed :%d\n", ret);
@@ -1224,7 +1249,7 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
header.primary, header.extension);
dev_dbg(ipc->dev, "transmitting offset: %#x, size: %#x\n",
(unsigned)data_offset, (unsigned)tx_size);
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
+ ret = skl_ipc_tx_message_wait(ipc, *ipc_header,
((char *)param) + data_offset,
tx_size, NULL, NULL);
if (ret < 0) {
@@ -1292,7 +1317,7 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
if (rx_bytes != NULL)
*rx_bytes = rx_size;
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
+ ret = skl_ipc_tx_message_wait(ipc, *ipc_header,
((char *)txparam), tx_bytes,
((char *)param) + data_offset, rx_bytes);
@@ -1357,8 +1382,8 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc,
header.primary |= IPC_MOD_ID(dma_id);
if (wait)
- ret = sst_ipc_tx_message_wait(ipc, *ipc_header,
- NULL, 0, NULL, NULL);
+ ret = skl_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0,
+ NULL, NULL);
else
ret = sst_ipc_tx_message_nowait(ipc, *ipc_header, NULL, 0);
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
index 5cdec13bbe50..d28913476d3b 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
@@ -413,6 +413,8 @@ struct skl_module_notify {
irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context);
+int skl_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header,
+ void *tx_data, size_t tx_bytes, void *rx_data, size_t *rx_bytes);
int skl_ipc_create_pipeline(struct sst_generic_ipc *sst_ipc,
u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode);
--
https://clearlinux.org