summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndhavarapu Karthik <kartkart@codeaurora.org>2020-11-19 13:05:58 +0530
committerAndhavarapu Karthik <kartkart@codeaurora.org>2020-12-07 20:59:27 +0530
commit9c5880443c8878371bc5345842c6a6fc02667f6a (patch)
treef63ba7239e62738609fd1801fb5d9ab9c03ba68a
parent213d04499e661bed3b36a5294271706088a4964f (diff)
downloaddisplay-drivers-9c5880443c8878371bc5345842c6a6fc02667f6a.tar.gz
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: I02038f62ecee86a9c82a913c6ed24bdd18465686 Signed-off-by: Andhavarapu Karthik <kartkart@codeaurora.org>
-rw-r--r--msm/sde/sde_hw_util.c2
-rw-r--r--msm/sde_dbg.c15
-rw-r--r--msm/sde_dbg.h92
-rw-r--r--msm/sde_dbg_evtlog.c48
-rw-r--r--msm/sde_io_util.c2
5 files changed, 158 insertions, 1 deletions
diff --git a/msm/sde/sde_hw_util.c b/msm/sde/sde_hw_util.c
index ff4b5dfd..17bc2e76 100644
--- a/msm/sde/sde_hw_util.c
+++ b/msm/sde/sde_hw_util.c
@@ -77,6 +77,8 @@ void sde_reg_write(struct sde_hw_blk_reg_map *c,
SDE_DEBUG_DRIVER("[%s:0x%X] <= 0x%X\n",
name, c->blk_off + reg_off, val);
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)
diff --git a/msm/sde_dbg.c b/msm/sde_dbg.c
index 6178e1bf..5c21f488 100644
--- a/msm/sde_dbg.c
+++ b/msm/sde_dbg.c
@@ -197,6 +197,7 @@ struct sde_dbg_regbuf {
/**
* struct sde_dbg_base - global sde debug base structure
* @evtlog: event log instance
+ * @reglog: reg log instance
* @reg_base_list: list of register dumping regions
* @dev: device pointer
* @mutex: mutex to serialize access to serialze dumps, debugfs access
@@ -212,11 +213,13 @@ struct sde_dbg_regbuf {
* @dsi_dbg_bus: dump dsi debug bus register
* @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_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
* @vbif_dbgbus_dump_idx: index for tracking vbif dumps in hw recovery
*/
static struct sde_dbg_base {
struct sde_dbg_evtlog *evtlog;
+ struct sde_dbg_reglog *reglog;
struct list_head reg_base_list;
struct device *dev;
struct mutex mutex;
@@ -238,6 +241,7 @@ static struct sde_dbg_base {
struct sde_dbg_regbuf regbuf;
u32 cur_evt_index;
+ u32 cur_reglog_index;
u32 dbgbus_dump_idx;
u32 vbif_dbgbus_dump_idx;
enum sde_dbg_dump_context dump_mode;
@@ -246,6 +250,9 @@ static struct sde_dbg_base {
/* sde_dbg_base_evtlog - global pointer to main sde event log for macro use */
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(void __iomem *mem_base,
struct sde_debug_bus_entry *entry, u32 val)
{
@@ -4665,6 +4672,12 @@ int sde_dbg_init(struct device *dev)
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);
sde_dbg_base.work_panic = false;
sde_dbg_base.panic_on_err = DEFAULT_PANIC;
@@ -4709,6 +4722,8 @@ void sde_dbg_destroy(void)
sde_dbg_base_evtlog = NULL;
sde_evtlog_destroy(sde_dbg_base.evtlog);
sde_dbg_base.evtlog = NULL;
+ sde_reglog_destroy(sde_dbg_base.reglog);
+ sde_dbg_base.reglog = NULL;
sde_dbg_reg_base_destroy();
mutex_destroy(&sde_dbg_base.mutex);
}
diff --git a/msm/sde_dbg.h b/msm/sde_dbg.h
index e336f323..a9618578 100644
--- a/msm/sde_dbg.h
+++ b/msm/sde_dbg.h
@@ -49,6 +49,34 @@ enum sde_dbg_dump_context {
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 | \
SDE_EVTLOG_EXTERNAL)
@@ -103,6 +131,44 @@ struct sde_dbg_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
* ... - variable arguments
@@ -184,6 +250,12 @@ extern struct sde_dbg_evtlog *sde_dbg_base_evtlog;
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
* @evtlog: pointer to evtlog
* Returns: none
@@ -191,6 +263,13 @@ struct sde_dbg_evtlog *sde_evtlog_init(void);
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.
* log collection may be enabled/disabled entirely via debugfs
* log area collection may be filtered by user provided flags via debugfs.
@@ -204,6 +283,15 @@ void sde_evtlog_log(struct sde_dbg_evtlog *evtlog, const char *name, int line,
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
* @evtlog: pointer to evtlog
* Returns: none
@@ -386,6 +474,10 @@ static inline void sde_evtlog_log(struct sde_dbg_evtlog *evtlog,
{
}
+static inline void sde_reglog_log(u8 blk_id, u32 val, u32 addr)
+{
+}
+
static inline void sde_evtlog_dump_all(struct sde_dbg_evtlog *evtlog)
{
}
diff --git a/msm/sde_dbg_evtlog.c b/msm/sde_dbg_evtlog.c
index 71ec3283..ddb4c996 100644
--- a/msm/sde_dbg_evtlog.c
+++ b/msm/sde_dbg_evtlog.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "sde_dbg:[%s] " fmt, __func__
@@ -101,6 +101,31 @@ exit:
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(&reglog->spin_lock, flags);
+
+ log = &reglog->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(&reglog->spin_lock, flags);
+}
+
/* always dump the last entries which are not dumped yet */
static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog,
bool update_last_entry, bool full_dump)
@@ -211,6 +236,19 @@ struct sde_dbg_evtlog *sde_evtlog_init(void)
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(&reglog->spin_lock);
+
+ return reglog;
+}
+
int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog, int index,
char *buf, size_t bufsz)
{
@@ -312,3 +350,11 @@ void sde_evtlog_destroy(struct sde_dbg_evtlog *evtlog)
}
kfree(evtlog);
}
+
+void sde_reglog_destroy(struct sde_dbg_reglog *reglog)
+{
+ if (!reglog)
+ return;
+
+ kfree(reglog);
+}
diff --git a/msm/sde_io_util.c b/msm/sde_io_util.c
index 09649c59..1bb030b5 100644
--- a/msm/sde_io_util.c
+++ b/msm/sde_io_util.c
@@ -9,6 +9,7 @@
#include <linux/regulator/consumer.h>
#include <linux/delay.h>
#include <linux/sde_io_util.h>
+#include "sde_dbg.h"
#define MAX_I2C_CMDS 16
void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug)
@@ -34,6 +35,7 @@ void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug)
(u32)(unsigned long)(io->base + offset),
value, in_val);
}
+ SDE_REG_LOG(SDE_REG_LOG_RSCC, value, offset);
} /* dss_reg_w */
EXPORT_SYMBOL(dss_reg_w);