ipc: apr: Support ADSP restart recovery when stuck
Add interface to register callback with adsp loader client. When adsp is stuck and does not respond for apr_send_pkt, resulting in continuous EAGAIN error, trigger this callback to enable adsp subsystem restart. Change-Id: Ib59cfdfba3313581d6612b872a2b7f1e19f8a76d Signed-off-by: Soumya Managoli <smanag@codeaurora.org>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2010-2017, 2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2010-2017, 2019, 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#ifndef __APR_H_
|
||||
#define __APR_H_
|
||||
@@ -12,6 +12,7 @@ enum apr_subsys_state {
|
||||
APR_SUBSYS_DOWN,
|
||||
APR_SUBSYS_UP,
|
||||
APR_SUBSYS_LOADED,
|
||||
APR_SUBSYS_UNKNOWN,
|
||||
};
|
||||
|
||||
struct apr_q6 {
|
||||
@@ -19,6 +20,13 @@ struct apr_q6 {
|
||||
atomic_t q6_state;
|
||||
atomic_t modem_state;
|
||||
struct mutex lock;
|
||||
/*
|
||||
* ToDo - Multiple client support to be added.
|
||||
* And checking for state UNKNOWN currently.
|
||||
*/
|
||||
void (*state_notify_cb)(enum apr_subsys_state state,
|
||||
void *client_handle);
|
||||
void *client_handle;
|
||||
};
|
||||
|
||||
struct apr_hdr {
|
||||
@@ -186,4 +194,5 @@ const char *apr_get_lpass_subsys_name(void);
|
||||
uint16_t apr_get_reset_domain(uint16_t proc);
|
||||
int apr_start_rx_rt(void *handle);
|
||||
int apr_end_rx_rt(void *handle);
|
||||
void apr_register_adsp_state_cb(void *adsp_cb, void *client_handle);
|
||||
#endif
|
||||
|
38
ipc/apr.c
38
ipc/apr.c
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2010-2014, 2016-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2010-2014, 2016-2020 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@@ -32,9 +32,14 @@
|
||||
|
||||
#define APR_PKT_IPC_LOG_PAGE_CNT 2
|
||||
|
||||
static int apr_pkt_cnt_adsp_restart = 20;
|
||||
module_param(apr_pkt_cnt_adsp_restart, int, 0664);
|
||||
MODULE_PARM_DESC(apr_pkt_cnt_adsp_restart, "set apr pktcount for adsp restart feature");
|
||||
|
||||
static struct apr_q6 q6;
|
||||
static struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
|
||||
static void *apr_pkt_ctx;
|
||||
static int apr_send_pkt_count;
|
||||
static wait_queue_head_t modem_wait;
|
||||
static bool is_modem_up;
|
||||
static char *subsys_name = NULL;
|
||||
@@ -61,6 +66,8 @@ struct apr_private {
|
||||
|
||||
static struct apr_private *apr_priv;
|
||||
static bool apr_cf_debug;
|
||||
static struct work_struct apr_cb_work;
|
||||
static void state_notify_cb(struct work_struct *work);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static struct dentry *debugfs_apr_debug;
|
||||
@@ -313,6 +320,7 @@ static void apr_adsp_up(void)
|
||||
schedule_work(&apr_priv->add_chld_dev_work);
|
||||
spin_unlock(&apr_priv->apr_lock);
|
||||
snd_event_notify(apr_priv->dev, SND_EVENT_UP);
|
||||
cancel_work_sync(&apr_cb_work);
|
||||
}
|
||||
|
||||
int apr_load_adsp_image(void)
|
||||
@@ -415,7 +423,7 @@ int apr_send_pkt(void *handle, uint32_t *buf)
|
||||
w_len = rc;
|
||||
if (w_len != hdr->pkt_size) {
|
||||
pr_err("%s: Unable to write whole APR pkt successfully: %d\n",
|
||||
__func__, rc);
|
||||
__func__, rc);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
} else {
|
||||
@@ -426,6 +434,17 @@ int apr_send_pkt(void *handle, uint32_t *buf)
|
||||
__func__);
|
||||
rc = -ENETRESET;
|
||||
}
|
||||
if (rc == -EAGAIN || rc == -ETIMEDOUT) {
|
||||
apr_send_pkt_count++;
|
||||
pr_err("%s:: send pkt timedout apr_send_pkt_count %d\n",
|
||||
__func__, apr_send_pkt_count);
|
||||
}
|
||||
}
|
||||
if (apr_send_pkt_count == apr_pkt_cnt_adsp_restart) {
|
||||
pr_debug("%s:: schedule work for adsp loader restart cb\n",
|
||||
__func__);
|
||||
schedule_work(&apr_cb_work);
|
||||
apr_send_pkt_count = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&svc->w_lock, flags);
|
||||
|
||||
@@ -800,6 +819,19 @@ static void apr_reset_deregister(struct work_struct *work)
|
||||
kfree(apr_reset);
|
||||
}
|
||||
|
||||
static void state_notify_cb(struct work_struct *work)
|
||||
{
|
||||
if (q6.state_notify_cb)
|
||||
q6.state_notify_cb(APR_SUBSYS_UNKNOWN, q6.client_handle);
|
||||
}
|
||||
|
||||
void apr_register_adsp_state_cb(void *adsp_cb, void *client_handle)
|
||||
{
|
||||
q6.state_notify_cb = adsp_cb;
|
||||
q6.client_handle = client_handle;
|
||||
}
|
||||
EXPORT_SYMBOL(apr_register_adsp_state_cb);
|
||||
|
||||
/**
|
||||
* apr_start_rx_rt - Clients call to vote for thread
|
||||
* priority upgrade whenever needed.
|
||||
@@ -1212,7 +1244,7 @@ static int apr_probe(struct platform_device *pdev)
|
||||
__func__, ret);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
INIT_WORK(&apr_cb_work, state_notify_cb);
|
||||
return apr_debug_init();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user