soc: qcom: pdr: Add PDR notification timeout handler

This is a debug feature where a kernel panic is triggered when
pdr notification to the APPS client is taking too long. This scenario
can happen if the one of notifier gets stuck and due to which subsystem
did not get ack back from APPS in time and trigger timeout panic.
So, trigger a kernel panic in APPS if PDR notifications is taking
too long.

Change-Id: Ic58c421723a71ba87ba0306617eafc2ed39b6ee2
Signed-off-by: Mukesh Ojha <quic_mojha@quicinc.com>
Signed-off-by: Gokul krishna Krishnakumar <quic_gokukris@quicinc.com>
[quic_gurus@quicinc.com: Dropped kalama_GKI.config change]
Signed-off-by: Guru Das Srinagesh <quic_gurus@quicinc.com>
This commit is contained in:
Mukesh Ojha 2021-09-21 18:39:15 +05:30 committed by Guru Das Srinagesh
parent e4dd10a51a
commit 33ad78c141
2 changed files with 46 additions and 0 deletions

View File

@ -134,6 +134,24 @@ config QCOM_PDR_HELPERS
crash/recover without disrupting the other PDs running on
the same Q6 ADSP.
config QCOM_PANIC_ON_PDR_NOTIF_TIMEOUT
bool "Trigger kernel panic when PDR notification timeout expires"
help
This is a debug feature where a kernel panic is triggered when
pdr notification to the APPS client is taking too long. This scneario
can happen if the one of notifier gets stuck and due to which subsystem
did not get ack back from APPS in time and trigger timeout panic.
So, trigger a kernel panic in APPS if PDR notifications is taking
too long.
config PDR_INDICATION_NOTIF_TIMEOUT
int "Pdr notifications timeout in ms"
default 3000
help
The amount of time, in milliseconds, that should elapse between
the start and end of notifications, before a warning
is emitted.
config QCOM_QMI_HELPERS
tristate
depends on NET

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/kernel.h>
@ -10,6 +11,9 @@
#include <linux/workqueue.h>
#include "pdr_internal.h"
#include "../../remoteproc/qcom_common.h"
#define PDR_IND_NOTIF_TIMEOUT CONFIG_PDR_INDICATION_NOTIF_TIMEOUT
struct pdr_service {
char service_name[SERVREG_NAME_LENGTH + 1];
@ -67,8 +71,12 @@ struct pdr_list_node {
u16 transaction_id;
struct pdr_service *pds;
struct list_head node;
struct timer_list timer;
};
static const char * const ind_notif_timeout_msg =
"PDR: Indication notifier %s, state: 0x%x, trans-id: %d\n taking too long";
static int pdr_locator_new_server(struct qmi_handle *qmi,
struct qmi_service *svc)
{
@ -270,19 +278,38 @@ static int pdr_send_indack_msg(struct pdr_handle *pdr, struct pdr_service *pds,
return ret;
}
static void ind_notif_timeout_handler(struct timer_list *t)
{
struct pdr_list_node *ind = from_timer(ind, t, timer);
struct pdr_service *pds = ind->pds;
if (IS_ENABLED(CONFIG_QCOM_PANIC_ON_PDR_NOTIF_TIMEOUT) &&
system_state != SYSTEM_RESTART &&
system_state != SYSTEM_POWER_OFF &&
system_state != SYSTEM_HALT &&
!qcom_device_shutdown_in_progress)
panic(ind_notif_timeout_msg, pds->service_path, pds->state, ind->transaction_id);
else
WARN(1, ind_notif_timeout_msg, pds->service_path, pds->state, ind->transaction_id);
}
static void pdr_indack_work(struct work_struct *work)
{
struct pdr_handle *pdr = container_of(work, struct pdr_handle,
indack_work);
struct pdr_list_node *ind, *tmp;
struct pdr_service *pds;
unsigned long timeout;
list_for_each_entry_safe(ind, tmp, &pdr->indack_list, node) {
pds = ind->pds;
mutex_lock(&pdr->status_lock);
pds->state = ind->curr_state;
timeout = jiffies + msecs_to_jiffies(PDR_IND_NOTIF_TIMEOUT);
mod_timer(&ind->timer, timeout);
pdr->status(pds->state, pds->service_path, pdr->priv);
del_timer_sync(&ind->timer);
mutex_unlock(&pdr->status_lock);
/* Ack the indication after clients release the PD resources */
@ -338,6 +365,7 @@ static void pdr_indication_cb(struct qmi_handle *qmi,
ind->curr_state = ind_msg->curr_state;
ind->pds = pds;
timer_setup(&ind->timer, ind_notif_timeout_handler, 0);
mutex_lock(&pdr->list_lock);
list_add_tail(&ind->node, &pdr->indack_list);
mutex_unlock(&pdr->list_lock);