diff --git a/msm/sde/sde_hw_util.c b/msm/sde/sde_hw_util.c index cfc537753c..f0ad45b47a 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 2411211fc0..665b6d7fbf 100644 --- a/msm/sde_dbg.c +++ b/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); diff --git a/msm/sde_dbg.h b/msm/sde_dbg.h index d39d9873f4..c4d88b9441 100644 --- a/msm/sde_dbg.h +++ b/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 diff --git a/msm/sde_dbg_evtlog.c b/msm/sde_dbg_evtlog.c index e0c176b6b3..484480b8ea 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-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(®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 */ 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(®log->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 5135364956..b8b9fb8f25 100644 --- a/msm/sde_io_util.c +++ b/msm/sde_io_util.c @@ -11,6 +11,7 @@ #include #include #include +#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);