From 12aec928b63aba063105dad9f6d61a2ea5950571 Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Fri, 13 Sep 2019 19:11:17 +0530 Subject: [PATCH] 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 --- include/ipc/apr.h | 11 ++++++++++- ipc/apr.c | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/include/ipc/apr.h b/include/ipc/apr.h index 7aecee265530..40fc92c7d8d3 100644 --- a/include/ipc/apr.h +++ b/include/ipc/apr.h @@ -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 diff --git a/ipc/apr.c b/ipc/apr.c index 6adb8ef42fac..a8419d4460b7 100644 --- a/ipc/apr.c +++ b/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 @@ -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(); }