mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-11 15:11:48 -04:00
mhi: core: provide an API to retrieve device failure reason
When device asserts, the subsystem failure reason from device can be read via an external API using the name of the MHI controller. Change-Id: Ic0bcba77e0a7e4c4a7570df3eda21e1f38b80277 Signed-off-by: Bhaumik Bhatt <bbhatt@codeaurora.org>
This commit is contained in:
parent
886b3174c7
commit
067a14395f
5 changed files with 67 additions and 3 deletions
|
|
@ -75,6 +75,19 @@ static const char * const mhi_pm_state_str[] = {
|
|||
|
||||
struct mhi_bus mhi_bus;
|
||||
|
||||
struct mhi_controller *find_mhi_controller_by_name(const char *name)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl, *tmp_cntrl;
|
||||
|
||||
list_for_each_entry_safe(mhi_cntrl, tmp_cntrl, &mhi_bus.controller_list,
|
||||
node) {
|
||||
if (mhi_cntrl->name && (!strcmp(name, mhi_cntrl->name)))
|
||||
return mhi_cntrl;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *to_mhi_pm_state_str(enum MHI_PM_STATE state)
|
||||
{
|
||||
int index = find_last_bit((unsigned long *)&state, 32);
|
||||
|
|
@ -667,6 +680,9 @@ int mhi_init_sfr(struct mhi_controller *mhi_cntrl)
|
|||
if (!sfr_info)
|
||||
return ret;
|
||||
|
||||
/* do a clean-up if we reach here post SSR */
|
||||
memset(sfr_info->str, 0, sfr_info->len);
|
||||
|
||||
sfr_info->buf_addr = mhi_alloc_coherent(mhi_cntrl, sfr_info->len,
|
||||
&sfr_info->dma_addr, GFP_KERNEL);
|
||||
if (!sfr_info->buf_addr) {
|
||||
|
|
@ -1348,6 +1364,8 @@ static int of_parse_dt(struct mhi_controller *mhi_cntrl,
|
|||
if (!ret)
|
||||
mhi_cntrl->bhie = mhi_cntrl->regs + bhie_offset;
|
||||
|
||||
of_property_read_string(of_node, "mhi,name", &mhi_cntrl->name);
|
||||
|
||||
return 0;
|
||||
|
||||
error_ev_cfg:
|
||||
|
|
@ -1495,6 +1513,12 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl)
|
|||
goto error_add_dev;
|
||||
}
|
||||
|
||||
sfr_info->str = kzalloc(mhi_cntrl->sfr_len, GFP_KERNEL);
|
||||
if (!sfr_info->str) {
|
||||
ret = -ENOMEM;
|
||||
goto error_alloc_sfr;
|
||||
}
|
||||
|
||||
sfr_info->len = mhi_cntrl->sfr_len;
|
||||
mhi_cntrl->mhi_sfr = sfr_info;
|
||||
}
|
||||
|
|
@ -1509,6 +1533,9 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl)
|
|||
|
||||
return 0;
|
||||
|
||||
error_alloc_sfr:
|
||||
kfree(sfr_info);
|
||||
|
||||
error_add_dev:
|
||||
mhi_dealloc_device(mhi_cntrl, mhi_dev);
|
||||
|
||||
|
|
@ -1527,12 +1554,17 @@ EXPORT_SYMBOL(of_register_mhi_controller);
|
|||
void mhi_unregister_mhi_controller(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
struct mhi_device *mhi_dev = mhi_cntrl->mhi_dev;
|
||||
struct mhi_sfr_info *sfr_info = mhi_cntrl->mhi_sfr;
|
||||
|
||||
kfree(mhi_cntrl->mhi_cmd);
|
||||
kfree(mhi_cntrl->mhi_event);
|
||||
vfree(mhi_cntrl->mhi_chan);
|
||||
kfree(mhi_cntrl->mhi_tsync);
|
||||
kfree(mhi_cntrl->mhi_sfr);
|
||||
|
||||
if (sfr_info) {
|
||||
kfree(sfr_info->str);
|
||||
kfree(sfr_info);
|
||||
}
|
||||
|
||||
device_del(&mhi_dev->dev);
|
||||
put_device(&mhi_dev->dev);
|
||||
|
|
|
|||
|
|
@ -734,6 +734,7 @@ struct mhi_sfr_info {
|
|||
void *buf_addr;
|
||||
dma_addr_t dma_addr;
|
||||
size_t len;
|
||||
char *str;
|
||||
enum MHI_EV_CCS ccs;
|
||||
struct completion completion;
|
||||
};
|
||||
|
|
@ -747,6 +748,8 @@ struct mhi_bus {
|
|||
#define MHI_TIMEOUT_MS (1000)
|
||||
extern struct mhi_bus mhi_bus;
|
||||
|
||||
struct mhi_controller *find_mhi_controller_by_name(const char *name);
|
||||
|
||||
/* debug fs related functions */
|
||||
int mhi_debugfs_mhi_chan_show(struct seq_file *m, void *d);
|
||||
int mhi_debugfs_mhi_event_show(struct seq_file *m, void *d);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
#include <linux/mhi.h>
|
||||
#include "mhi_internal.h"
|
||||
|
||||
static char *mhi_generic_sfr = "unknown reason";
|
||||
|
||||
static void __mhi_unprepare_channel(struct mhi_controller *mhi_cntrl,
|
||||
struct mhi_chan *mhi_chan);
|
||||
|
||||
|
|
@ -2691,3 +2693,20 @@ void mhi_debug_reg_dump(struct mhi_controller *mhi_cntrl)
|
|||
}
|
||||
}
|
||||
EXPORT_SYMBOL(mhi_debug_reg_dump);
|
||||
|
||||
char *mhi_get_restart_reason(const char *name)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl;
|
||||
struct mhi_sfr_info *sfr_info;
|
||||
|
||||
mhi_cntrl = find_mhi_controller_by_name(name);
|
||||
if (!mhi_cntrl)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
sfr_info = mhi_cntrl->mhi_sfr;
|
||||
if (!sfr_info)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return strlen(sfr_info->str) ? sfr_info->str : mhi_generic_sfr;
|
||||
}
|
||||
EXPORT_SYMBOL(mhi_get_restart_reason);
|
||||
|
|
|
|||
|
|
@ -1008,8 +1008,11 @@ void mhi_control_error(struct mhi_controller *mhi_cntrl)
|
|||
TO_MHI_STATE_STR(mhi_cntrl->dev_state));
|
||||
|
||||
/* copy subsystem failure reason string if supported */
|
||||
if (sfr_info && sfr_info->buf_addr)
|
||||
pr_err("mhi: sfr: %s\n", sfr_info->buf_addr);
|
||||
if (sfr_info && sfr_info->buf_addr) {
|
||||
memcpy(sfr_info->str, sfr_info->buf_addr, sfr_info->len);
|
||||
pr_err("mhi: %s sfr: %s\n", mhi_cntrl->name,
|
||||
sfr_info->buf_addr);
|
||||
}
|
||||
|
||||
/* link is not down if device is in RDDM */
|
||||
transition_state = (mhi_cntrl->ee == MHI_EE_RDDM) ?
|
||||
|
|
|
|||
|
|
@ -404,6 +404,7 @@ struct mhi_controller {
|
|||
enum MHI_DEBUG_LEVEL log_lvl;
|
||||
|
||||
/* controller specific data */
|
||||
const char *name;
|
||||
bool power_down;
|
||||
void *priv_data;
|
||||
void *log_buf;
|
||||
|
|
@ -849,6 +850,12 @@ void mhi_control_error(struct mhi_controller *mhi_cntrl);
|
|||
*/
|
||||
void mhi_debug_reg_dump(struct mhi_controller *mhi_cntrl);
|
||||
|
||||
/**
|
||||
* mhi_get_restart_reason - retrieve the subsystem failure reason
|
||||
* @name: controller name
|
||||
*/
|
||||
char *mhi_get_restart_reason(const char *name);
|
||||
|
||||
#ifndef CONFIG_ARCH_QCOM
|
||||
|
||||
#ifdef CONFIG_MHI_DEBUG
|
||||
|
|
|
|||
Loading…
Reference in a new issue