220 lines
8.8 KiB
Diff
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 30507fa..eecd90b 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 9f2621d..af84aab 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 5cdec13..d289134 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
|
|
|