disp: msm: sde: save register write logs in dump
Changes are made to add register write logs to memory dump. This can be extracted from crash dumps and used for analysis. Change-Id: If46aaa4ae68f83c79d4b51cbe5dfd22340aa991d Signed-off-by: Yashwanth <yvulapu@codeaurora.org>
This commit is contained in:
@@ -77,6 +77,8 @@ void sde_reg_write(struct sde_hw_blk_reg_map *c,
|
|||||||
SDE_DEBUG_DRIVER("[%s:0x%X] <= 0x%X\n",
|
SDE_DEBUG_DRIVER("[%s:0x%X] <= 0x%X\n",
|
||||||
name, c->blk_off + reg_off, val);
|
name, c->blk_off + reg_off, val);
|
||||||
writel_relaxed(val, c->base_off + c->blk_off + reg_off);
|
writel_relaxed(val, c->base_off + c->blk_off + reg_off);
|
||||||
|
SDE_REG_LOG(c->log_mask ? ilog2(c->log_mask)+1 : 0,
|
||||||
|
val, c->blk_off + reg_off);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sde_reg_read(struct sde_hw_blk_reg_map *c, u32 reg_off)
|
int sde_reg_read(struct sde_hw_blk_reg_map *c, u32 reg_off)
|
||||||
|
@@ -234,6 +234,7 @@ struct sde_dbg_regbuf {
|
|||||||
/**
|
/**
|
||||||
* struct sde_dbg_base - global sde debug base structure
|
* struct sde_dbg_base - global sde debug base structure
|
||||||
* @evtlog: event log instance
|
* @evtlog: event log instance
|
||||||
|
* @reglog: reg log instance
|
||||||
* @reg_base_list: list of register dumping regions
|
* @reg_base_list: list of register dumping regions
|
||||||
* @dev: device pointer
|
* @dev: device pointer
|
||||||
* @mutex: mutex to serialize access to serialze dumps, debugfs access
|
* @mutex: mutex to serialize access to serialze dumps, debugfs access
|
||||||
@@ -253,12 +254,14 @@ struct sde_dbg_regbuf {
|
|||||||
* @dump_secure: dump entries excluding few as it is in secure-session
|
* @dump_secure: dump entries excluding few as it is in secure-session
|
||||||
* @regbuf: buffer data to track the register dumping in hw recovery
|
* @regbuf: buffer data to track the register dumping in hw recovery
|
||||||
* @cur_evt_index: index used for tracking event logs dump in hw recovery
|
* @cur_evt_index: index used for tracking event logs dump in hw recovery
|
||||||
|
* @cur_reglog_index: index used for tracking register logs dump in hw recovery
|
||||||
* @dbgbus_dump_idx: index used for tracking dbg-bus dump in hw recovery
|
* @dbgbus_dump_idx: index used for tracking dbg-bus dump in hw recovery
|
||||||
* @vbif_dbgbus_dump_idx: index for tracking vbif dumps in hw recovery
|
* @vbif_dbgbus_dump_idx: index for tracking vbif dumps in hw recovery
|
||||||
* @hw_ownership: indicates if the VM owns the HW resources
|
* @hw_ownership: indicates if the VM owns the HW resources
|
||||||
*/
|
*/
|
||||||
static struct sde_dbg_base {
|
static struct sde_dbg_base {
|
||||||
struct sde_dbg_evtlog *evtlog;
|
struct sde_dbg_evtlog *evtlog;
|
||||||
|
struct sde_dbg_reglog *reglog;
|
||||||
struct list_head reg_base_list;
|
struct list_head reg_base_list;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
@@ -283,6 +286,7 @@ static struct sde_dbg_base {
|
|||||||
|
|
||||||
struct sde_dbg_regbuf regbuf;
|
struct sde_dbg_regbuf regbuf;
|
||||||
u32 cur_evt_index;
|
u32 cur_evt_index;
|
||||||
|
u32 cur_reglog_index;
|
||||||
enum sde_dbg_dump_context dump_mode;
|
enum sde_dbg_dump_context dump_mode;
|
||||||
bool hw_ownership;
|
bool hw_ownership;
|
||||||
} sde_dbg_base;
|
} sde_dbg_base;
|
||||||
@@ -293,6 +297,9 @@ static DEFINE_MUTEX(sde_dbg_dsi_mutex);
|
|||||||
/* sde_dbg_base_evtlog - global pointer to main sde event log for macro use */
|
/* sde_dbg_base_evtlog - global pointer to main sde event log for macro use */
|
||||||
struct sde_dbg_evtlog *sde_dbg_base_evtlog;
|
struct sde_dbg_evtlog *sde_dbg_base_evtlog;
|
||||||
|
|
||||||
|
/* sde_dbg_base_reglog - global pointer to main sde reg log for macro use */
|
||||||
|
struct sde_dbg_reglog *sde_dbg_base_reglog;
|
||||||
|
|
||||||
static void _sde_debug_bus_xbar_dump(u32 wr_addr, u32 block_id, u32 test_id, u32 val)
|
static void _sde_debug_bus_xbar_dump(u32 wr_addr, u32 block_id, u32 test_id, u32 val)
|
||||||
{
|
{
|
||||||
SDE_DBG_LOG_DEBUGBUS("xbar", wr_addr, block_id, test_id, val);
|
SDE_DBG_LOG_DEBUGBUS("xbar", wr_addr, block_id, test_id, val);
|
||||||
@@ -2206,6 +2213,12 @@ int sde_dbg_init(struct device *dev)
|
|||||||
|
|
||||||
sde_dbg_base_evtlog = sde_dbg_base.evtlog;
|
sde_dbg_base_evtlog = sde_dbg_base.evtlog;
|
||||||
|
|
||||||
|
sde_dbg_base.reglog = sde_reglog_init();
|
||||||
|
if (IS_ERR_OR_NULL(sde_dbg_base.reglog))
|
||||||
|
return PTR_ERR(sde_dbg_base.reglog);
|
||||||
|
|
||||||
|
sde_dbg_base_reglog = sde_dbg_base.reglog;
|
||||||
|
|
||||||
INIT_WORK(&sde_dbg_base.dump_work, _sde_dump_work);
|
INIT_WORK(&sde_dbg_base.dump_work, _sde_dump_work);
|
||||||
sde_dbg_base.work_panic = false;
|
sde_dbg_base.work_panic = false;
|
||||||
sde_dbg_base.panic_on_err = DEFAULT_PANIC;
|
sde_dbg_base.panic_on_err = DEFAULT_PANIC;
|
||||||
@@ -2265,6 +2278,8 @@ void sde_dbg_destroy(void)
|
|||||||
sde_dbg_base_evtlog = NULL;
|
sde_dbg_base_evtlog = NULL;
|
||||||
sde_evtlog_destroy(sde_dbg_base.evtlog);
|
sde_evtlog_destroy(sde_dbg_base.evtlog);
|
||||||
sde_dbg_base.evtlog = NULL;
|
sde_dbg_base.evtlog = NULL;
|
||||||
|
sde_reglog_destroy(sde_dbg_base.reglog);
|
||||||
|
sde_dbg_base.reglog = NULL;
|
||||||
sde_dbg_reg_base_destroy();
|
sde_dbg_reg_base_destroy();
|
||||||
sde_dbg_dsi_ctrl_destroy();
|
sde_dbg_dsi_ctrl_destroy();
|
||||||
mutex_destroy(&sde_dbg_base.mutex);
|
mutex_destroy(&sde_dbg_base.mutex);
|
||||||
|
@@ -72,6 +72,34 @@ enum sde_dbg_dump_context {
|
|||||||
SDE_DBG_DUMP_CLK_ENABLED_CTX,
|
SDE_DBG_DUMP_CLK_ENABLED_CTX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define blocks for register write logging.
|
||||||
|
*/
|
||||||
|
#define SDE_REG_LOG_DEFAULT 0
|
||||||
|
#define SDE_REG_LOG_NONE 1
|
||||||
|
#define SDE_REG_LOG_CDM 2
|
||||||
|
#define SDE_REG_LOG_DSPP 3
|
||||||
|
#define SDE_REG_LOG_INTF 4
|
||||||
|
#define SDE_REG_LOG_LM 5
|
||||||
|
#define SDE_REG_LOG_CTL 6
|
||||||
|
#define SDE_REG_LOG_PINGPONG 7
|
||||||
|
#define SDE_REG_LOG_SSPP 8
|
||||||
|
#define SDE_REG_LOG_WB 9
|
||||||
|
#define SDE_REG_LOG_TOP 10
|
||||||
|
#define SDE_REG_LOG_VBIF 11
|
||||||
|
#define SDE_REG_LOG_DSC 12
|
||||||
|
#define SDE_REG_LOG_ROT 13
|
||||||
|
#define SDE_REG_LOG_DS 14
|
||||||
|
#define SDE_REG_LOG_REGDMA 15
|
||||||
|
#define SDE_REG_LOG_UIDLE 16
|
||||||
|
#define SDE_REG_LOG_SID 16
|
||||||
|
#define SDE_REG_LOG_QDSS 17
|
||||||
|
/*
|
||||||
|
* 0-32 are reserved for sde_reg_write due to log masks
|
||||||
|
* Additional blocks are assigned from 33 to avoid conflict
|
||||||
|
*/
|
||||||
|
#define SDE_REG_LOG_RSCC 33
|
||||||
|
|
||||||
#define SDE_EVTLOG_DEFAULT_ENABLE (SDE_EVTLOG_CRITICAL | SDE_EVTLOG_IRQ | \
|
#define SDE_EVTLOG_DEFAULT_ENABLE (SDE_EVTLOG_CRITICAL | SDE_EVTLOG_IRQ | \
|
||||||
SDE_EVTLOG_EXTERNAL)
|
SDE_EVTLOG_EXTERNAL)
|
||||||
|
|
||||||
@@ -126,6 +154,44 @@ struct sde_dbg_evtlog {
|
|||||||
|
|
||||||
extern struct sde_dbg_evtlog *sde_dbg_base_evtlog;
|
extern struct sde_dbg_evtlog *sde_dbg_base_evtlog;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reglog keeps this number of entries in memory for debug purpose. This
|
||||||
|
* number must be greater than number of possible writes in at least one
|
||||||
|
* single commit.
|
||||||
|
*/
|
||||||
|
#define SDE_REGLOG_ENTRY 1024
|
||||||
|
|
||||||
|
struct sde_dbg_reglog_log {
|
||||||
|
s64 time;
|
||||||
|
u32 pid;
|
||||||
|
u32 addr;
|
||||||
|
u32 val;
|
||||||
|
u8 blk_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @last_dump: Index of last entry to be output during reglog dumps
|
||||||
|
* @filter_list: Linked list of currently active filter strings
|
||||||
|
*/
|
||||||
|
struct sde_dbg_reglog {
|
||||||
|
struct sde_dbg_reglog_log logs[SDE_REGLOG_ENTRY];
|
||||||
|
u32 first;
|
||||||
|
u32 last;
|
||||||
|
u32 last_dump;
|
||||||
|
u32 curr;
|
||||||
|
u32 next;
|
||||||
|
u32 enable;
|
||||||
|
u32 enable_mask;
|
||||||
|
spinlock_t spin_lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct sde_dbg_reglog *sde_dbg_base_reglog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SDE_REG_LOG - Write register write to the register log
|
||||||
|
*/
|
||||||
|
#define SDE_REG_LOG(blk_id, val, addr) sde_reglog_log(blk_id, val, addr)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SDE_EVT32 - Write a list of 32bit values to the event log, default area
|
* SDE_EVT32 - Write a list of 32bit values to the event log, default area
|
||||||
* ... - variable arguments
|
* ... - variable arguments
|
||||||
@@ -207,6 +273,12 @@ extern struct sde_dbg_evtlog *sde_dbg_base_evtlog;
|
|||||||
*/
|
*/
|
||||||
struct sde_dbg_evtlog *sde_evtlog_init(void);
|
struct sde_dbg_evtlog *sde_evtlog_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sde_reglog_init - allocate a new reg log object
|
||||||
|
* Returns: reglog or -ERROR
|
||||||
|
*/
|
||||||
|
struct sde_dbg_reglog *sde_reglog_init(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sde_evtlog_destroy - destroy previously allocated event log
|
* sde_evtlog_destroy - destroy previously allocated event log
|
||||||
* @evtlog: pointer to evtlog
|
* @evtlog: pointer to evtlog
|
||||||
@@ -214,6 +286,13 @@ struct sde_dbg_evtlog *sde_evtlog_init(void);
|
|||||||
*/
|
*/
|
||||||
void sde_evtlog_destroy(struct sde_dbg_evtlog *evtlog);
|
void sde_evtlog_destroy(struct sde_dbg_evtlog *evtlog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sde_reglog_destroy - destroy previously allocated reg log
|
||||||
|
* @reglog: pointer to reglog
|
||||||
|
* Returns: none
|
||||||
|
*/
|
||||||
|
void sde_reglog_destroy(struct sde_dbg_reglog *reglog);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sde_evtlog_log - log an entry into the event log.
|
* sde_evtlog_log - log an entry into the event log.
|
||||||
* log collection may be enabled/disabled entirely via debugfs
|
* log collection may be enabled/disabled entirely via debugfs
|
||||||
@@ -227,6 +306,15 @@ void sde_evtlog_destroy(struct sde_dbg_evtlog *evtlog);
|
|||||||
void sde_evtlog_log(struct sde_dbg_evtlog *evtlog, const char *name, int line,
|
void sde_evtlog_log(struct sde_dbg_evtlog *evtlog, const char *name, int line,
|
||||||
int flag, ...);
|
int flag, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sde_reglog_log - log an entry into the reg log.
|
||||||
|
* log collection may be enabled/disabled entirely via debugfs
|
||||||
|
* log area collection may be filtered by user provided flags via debugfs.
|
||||||
|
* @reglog: pointer to evtlog
|
||||||
|
* Returns: none
|
||||||
|
*/
|
||||||
|
void sde_reglog_log(u8 blk_id, u32 val, u32 addr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sde_evtlog_dump_all - print all entries in event log to kernel log
|
* sde_evtlog_dump_all - print all entries in event log to kernel log
|
||||||
* @evtlog: pointer to evtlog
|
* @evtlog: pointer to evtlog
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define pr_fmt(fmt) "sde_dbg:[%s] " fmt, __func__
|
#define pr_fmt(fmt) "sde_dbg:[%s] " fmt, __func__
|
||||||
@@ -101,6 +101,31 @@ exit:
|
|||||||
spin_unlock_irqrestore(&evtlog->spin_lock, flags);
|
spin_unlock_irqrestore(&evtlog->spin_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sde_reglog_log(u8 blk_id, u32 val, u32 addr)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
struct sde_dbg_reglog_log *log;
|
||||||
|
struct sde_dbg_reglog *reglog = sde_dbg_base_reglog;
|
||||||
|
|
||||||
|
if (!reglog)
|
||||||
|
return;
|
||||||
|
|
||||||
|
spin_lock_irqsave(®log->spin_lock, flags);
|
||||||
|
|
||||||
|
log = ®log->logs[reglog->curr];
|
||||||
|
|
||||||
|
log->blk_id = blk_id;
|
||||||
|
log->val = val;
|
||||||
|
log->addr = addr;
|
||||||
|
log->time = local_clock();
|
||||||
|
log->pid = current->pid;
|
||||||
|
|
||||||
|
reglog->curr = (reglog->curr + 1) % SDE_REGLOG_ENTRY;
|
||||||
|
reglog->last++;
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(®log->spin_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
/* always dump the last entries which are not dumped yet */
|
/* always dump the last entries which are not dumped yet */
|
||||||
static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog,
|
static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog,
|
||||||
bool update_last_entry, bool full_dump)
|
bool update_last_entry, bool full_dump)
|
||||||
@@ -211,6 +236,19 @@ struct sde_dbg_evtlog *sde_evtlog_init(void)
|
|||||||
return evtlog;
|
return evtlog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sde_dbg_reglog *sde_reglog_init(void)
|
||||||
|
{
|
||||||
|
struct sde_dbg_reglog *reglog;
|
||||||
|
|
||||||
|
reglog = kzalloc(sizeof(*reglog), GFP_KERNEL);
|
||||||
|
if (!reglog)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
spin_lock_init(®log->spin_lock);
|
||||||
|
|
||||||
|
return reglog;
|
||||||
|
}
|
||||||
|
|
||||||
int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog, int index,
|
int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog, int index,
|
||||||
char *buf, size_t bufsz)
|
char *buf, size_t bufsz)
|
||||||
{
|
{
|
||||||
@@ -312,3 +350,11 @@ void sde_evtlog_destroy(struct sde_dbg_evtlog *evtlog)
|
|||||||
}
|
}
|
||||||
kfree(evtlog);
|
kfree(evtlog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sde_reglog_destroy(struct sde_dbg_reglog *reglog)
|
||||||
|
{
|
||||||
|
if (!reglog)
|
||||||
|
return;
|
||||||
|
|
||||||
|
kfree(reglog);
|
||||||
|
}
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/sde_io_util.h>
|
#include <linux/sde_io_util.h>
|
||||||
#include <linux/sde_vm_event.h>
|
#include <linux/sde_vm_event.h>
|
||||||
|
#include "sde_dbg.h"
|
||||||
|
|
||||||
#define MAX_I2C_CMDS 16
|
#define MAX_I2C_CMDS 16
|
||||||
void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug)
|
void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug)
|
||||||
@@ -36,6 +37,7 @@ void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug)
|
|||||||
(u32)(unsigned long)(io->base + offset),
|
(u32)(unsigned long)(io->base + offset),
|
||||||
value, in_val);
|
value, in_val);
|
||||||
}
|
}
|
||||||
|
SDE_REG_LOG(SDE_REG_LOG_RSCC, value, offset);
|
||||||
} /* dss_reg_w */
|
} /* dss_reg_w */
|
||||||
EXPORT_SYMBOL(dss_reg_w);
|
EXPORT_SYMBOL(dss_reg_w);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user