瀏覽代碼

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 <[email protected]>
Yashwanth 4 年之前
父節點
當前提交
43d147f299
共有 5 個文件被更改,包括 154 次插入1 次删除
  1. 2 0
      msm/sde/sde_hw_util.c
  2. 15 0
      msm/sde_dbg.c
  3. 88 0
      msm/sde_dbg.h
  4. 47 1
      msm/sde_dbg_evtlog.c
  5. 2 0
      msm/sde_io_util.c

+ 2 - 0
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)

+ 15 - 0
msm/sde_dbg.c

@@ -234,6 +234,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
@@ -253,12 +254,14 @@ struct sde_dbg_regbuf {
  * @dump_secure: dump entries excluding few as it is in secure-session
  * @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
  * @hw_ownership: indicates if the VM owns the HW resources
  */
 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;
@@ -283,6 +286,7 @@ static struct sde_dbg_base {
 
 	struct sde_dbg_regbuf regbuf;
 	u32 cur_evt_index;
+	u32 cur_reglog_index;
 	enum sde_dbg_dump_context dump_mode;
 	bool hw_ownership;
 } 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 */
 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)
 {
 	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.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;
@@ -2265,6 +2278,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();
 	sde_dbg_dsi_ctrl_destroy();
 	mutex_destroy(&sde_dbg_base.mutex);

+ 88 - 0
msm/sde_dbg.h

@@ -72,6 +72,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)
 
@@ -126,6 +154,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
@@ -207,6 +273,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
@@ -214,6 +286,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
@@ -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,
 		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

+ 47 - 1
msm/sde_dbg_evtlog.c

@@ -1,6 +1,6 @@
 // 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__
@@ -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);
+}

+ 2 - 0
msm/sde_io_util.c

@@ -11,6 +11,7 @@
 #include <linux/delay.h>
 #include <linux/sde_io_util.h>
 #include <linux/sde_vm_event.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)
@@ -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),
 			value, in_val);
 	}
+	SDE_REG_LOG(SDE_REG_LOG_RSCC, value, offset);
 } /* dss_reg_w */
 EXPORT_SYMBOL(dss_reg_w);