Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9055de1d authored by Huaibin Yang's avatar Huaibin Yang Committed by Ingrid Gallardo
Browse files

msm: mdss: debugfs: xlog: refactor xlog dump



Make overall dump facility more reliable and more useable for
debugging: write xlog info to stdout; only un-logged and un-dumped
entries will be dumped out each dump; add func line number, pid and
time stamp difference for each entry; add index for each entry dump.
Format of the log is as follows:
name:line=>[entry:timestamp:delta][pid]:params
   Where:
   name: Name of the caller function
   line: Line in the source file
   entry: Index in the circular buffer
   timestamp: time when log was taken
   delta: time difference with previous log
   pid: process id
   params: parameters used to log information
      (these are specific to each log)

Change-Id: I32853ef7e27cc8ac34775ff492d60c801df61dba
Signed-off-by: default avatarHuaibin Yang <huaibiny@codeaurora.org>
Signed-off-by: default avatarIngrid Gallardo <ingridg@codeaurora.org>
parent dbd98701
Loading
Loading
Loading
Loading
+6 −7
Original line number Diff line number Diff line
/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -41,14 +41,14 @@ enum mdss_dbg_xlog_flag {
	MDSS_XLOG_ALL = BIT(7),
};

#define MDSS_XLOG(...) mdss_xlog(__func__, MDSS_XLOG_DEFAULT, ##__VA_ARGS__, \
		DATA_LIMITER)
#define MDSS_XLOG(...) mdss_xlog(__func__, __LINE__, MDSS_XLOG_DEFAULT, \
		##__VA_ARGS__, DATA_LIMITER)

#define MDSS_XLOG_TOUT_HANDLER(...)	\
	mdss_xlog_tout_handler_default(__func__, ##__VA_ARGS__, \
		XLOG_TOUT_DATA_LIMITER)

#define MDSS_XLOG_ALL(...) mdss_xlog(__func__, MDSS_XLOG_ALL, \
#define MDSS_XLOG_ALL(...) mdss_xlog(__func__, __LINE__, MDSS_XLOG_ALL,	\
		##__VA_ARGS__, DATA_LIMITER)


@@ -103,7 +103,7 @@ int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp,
void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id);

int mdss_create_xlog_debug(struct mdss_debug_data *mdd);
void mdss_xlog(const char *name, int flag, ...);
void mdss_xlog(const char *name, int line, int flag, ...);
void mdss_dump_reg(struct mdss_debug_base *dbg, u32 reg_dump_flag);
void mdss_xlog_tout_handler_default(const char *name, ...);
#else
@@ -126,11 +126,10 @@ static inline void mdss_misr_crc_collect(struct mdss_data_type *mdata,
						int block_id) { }

static inline int create_xlog_debug(struct mdss_data_type *mdata) { return 0; }
static inline void mdss_xlog(const char *name, ...) { }
static inline void mdss_xlog_dump(void) { }
static inline void mdss_dump_reg(struct mdss_debug_base *dbg,
	u32 reg_dump_flag) { }
static inline void mdss_xlog(const char *name, int flag...) { }
static inline void mdss_xlog(const char *name, int line, int flag...) { }
static inline void mdss_dsi_debug_check_te(struct mdss_panel_data *pdata) { }
static inline void mdss_xlog_tout_handler_default(const char *name, ...) { }
#endif
+174 −74
Original line number Diff line number Diff line
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,7 @@
#include <linux/spinlock.h>
#include <linux/ktime.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>

#include "mdss.h"
#include "mdss_mdp.h"
@@ -23,18 +24,21 @@
#define MDSS_XLOG_ENTRY	256
#define MDSS_XLOG_MAX_DATA 6
#define MDSS_XLOG_BUF_MAX 512
#define MDSS_XLOG_BUF_ALIGN 32

struct tlog {
	u64 tick;
	u32 tick;
	const char *name;
	int line;
	u32 data[MDSS_XLOG_MAX_DATA];
	u32 data_cnt;
	int pid;
};

struct mdss_dbg_xlog {
	struct tlog logs[MDSS_XLOG_ENTRY];
	int first;
	int last;
	u32 first;
	u32 last;
	spinlock_t xlock;
	struct dentry *xlog;
	u32 xlog_enable;
@@ -42,55 +46,13 @@ struct mdss_dbg_xlog {
	u32 enable_reg_dump;
} mdss_dbg_xlog;

static int mdss_xlog_dump_open(struct inode *inode, struct file *file)
{
	/* non-seekable */
	file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
	file->private_data = inode->i_private;
	return 0;
}

static ssize_t mdss_xlog_dump_read(struct file *file, char __user *buff,
		size_t count, loff_t *ppos)
{
	MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1", "edp", "hdmi", "panic");
	return 0;
}

static const struct file_operations mdss_xlog_fops = {
	.open = mdss_xlog_dump_open,
	.read = mdss_xlog_dump_read,
};

int mdss_create_xlog_debug(struct mdss_debug_data *mdd)
{
	spin_lock_init(&mdss_dbg_xlog.xlock);

	mdss_dbg_xlog.xlog = debugfs_create_dir("xlog", mdd->root);
	if (IS_ERR_OR_NULL(mdss_dbg_xlog.xlog)) {
		pr_err("debugfs_create_dir fail, error %ld\n",
		       PTR_ERR(mdss_dbg_xlog.xlog));
		mdss_dbg_xlog.xlog = NULL;
		return -ENODEV;
	}
	debugfs_create_file("dump", 0644, mdss_dbg_xlog.xlog, NULL,
						&mdss_xlog_fops);
	debugfs_create_u32("enable", 0644, mdss_dbg_xlog.xlog,
			    &mdss_dbg_xlog.xlog_enable);
	debugfs_create_bool("panic", 0644, mdss_dbg_xlog.xlog,
			    &mdss_dbg_xlog.panic_on_err);
	debugfs_create_u32("reg_dump", 0644, mdss_dbg_xlog.xlog,
			    &mdss_dbg_xlog.enable_reg_dump);
	return 0;
}

static inline bool mdss_xlog_is_enabled(u32 flag)
{
	return (flag & mdss_dbg_xlog.xlog_enable) ||
		(flag == MDSS_XLOG_ALL && mdss_dbg_xlog.xlog_enable);
}

void mdss_xlog(const char *name, int flag, ...)
void mdss_xlog(const char *name, int line, int flag, ...)
{
	unsigned long flags;
	int i, val = 0;
@@ -105,10 +67,12 @@ void mdss_xlog(const char *name, int flag, ...)

	time = ktime_get();

	log = &mdss_dbg_xlog.logs[mdss_dbg_xlog.first];
	log = &mdss_dbg_xlog.logs[mdss_dbg_xlog.last % MDSS_XLOG_ENTRY];
	log->tick = local_clock();
	log->name = name;
	log->line = line;
	log->data_cnt = 0;
	log->pid = current->pid;

	va_start(args, flag);
	for (i = 0; i < MDSS_XLOG_MAX_DATA; i++) {
@@ -120,43 +84,97 @@ void mdss_xlog(const char *name, int flag, ...)
		log->data[i] = val;
	}
	va_end(args);

	log->data_cnt = i;

	mdss_dbg_xlog.last = mdss_dbg_xlog.first;
	mdss_dbg_xlog.first++;
	mdss_dbg_xlog.first %= MDSS_XLOG_ENTRY;
	mdss_dbg_xlog.last++;

	spin_unlock_irqrestore(&mdss_dbg_xlog.xlock, flags);
}

static void mdss_xlog_dump(void)
/* always dump the last entries which are not dumped yet */
static bool __mdss_xlog_dump_calc_range(void)
{
	int i, n, d_cnt, off;
	static u32 next;
	bool need_dump = true;
	unsigned long flags;
	unsigned long rem_nsec;
	struct tlog *log;
	char xlog_buf[MDSS_XLOG_BUF_MAX];
	struct mdss_dbg_xlog *xlog = &mdss_dbg_xlog;

	spin_lock_irqsave(&mdss_dbg_xlog.xlock, flags);
	i = mdss_dbg_xlog.first;
	for (n = 0; n < MDSS_XLOG_ENTRY; n++) {
		log = &mdss_dbg_xlog.logs[i];
		rem_nsec = do_div(log->tick, 1000000000);
		off = snprintf(xlog_buf, MDSS_XLOG_BUF_MAX,
				"%-32s => [%5llu.%06lu]: ", log->name,
					log->tick, rem_nsec / 1000);
		for (d_cnt = 0; d_cnt < log->data_cnt;) {
			off += snprintf((xlog_buf + off),
					(MDSS_XLOG_BUF_MAX - off),
					"%x ", log->data[d_cnt]);
			d_cnt++;
		}
		pr_err("%s\n", xlog_buf);

		i = (i + 1) % MDSS_XLOG_ENTRY;

	xlog->first = next;

	if (xlog->last == xlog->first) {
		need_dump = false;
		goto dump_exit;
	}

	if (xlog->last < xlog->first) {
		xlog->first %= MDSS_XLOG_ENTRY;
		if (xlog->last < xlog->first)
			xlog->last += MDSS_XLOG_ENTRY;
	}

	if ((xlog->last - xlog->first) > MDSS_XLOG_ENTRY) {
		pr_warn("xlog buffer overflow before dump: %d\n",
			xlog->last - xlog->first);
		xlog->first = xlog->last - MDSS_XLOG_ENTRY;
	}
	need_dump = true;
	next = xlog->first + 1;

dump_exit:
	spin_unlock_irqrestore(&mdss_dbg_xlog.xlock, flags);

	return need_dump;
}

static ssize_t mdss_xlog_dump_entry(char *xlog_buf, ssize_t xlog_buf_size)
{
	int i;
	ssize_t off = 0;
	struct tlog *log, *prev_log;
	unsigned long flags;

	spin_lock_irqsave(&mdss_dbg_xlog.xlock, flags);

	log = &mdss_dbg_xlog.logs[mdss_dbg_xlog.first %
		MDSS_XLOG_ENTRY];

	prev_log = &mdss_dbg_xlog.logs[(mdss_dbg_xlog.first - 1) %
		MDSS_XLOG_ENTRY];

	off = snprintf((xlog_buf + off), (xlog_buf_size - off), "%s:%-4d",
		log->name, log->line);

	if (off < MDSS_XLOG_BUF_ALIGN) {
		memset((xlog_buf + off), 0x20, (MDSS_XLOG_BUF_ALIGN - off));
		off = MDSS_XLOG_BUF_ALIGN;
	}

	off += snprintf((xlog_buf + off), (xlog_buf_size - off),
		"=>[%-8d:%-11u:%9u][%-4d]:", mdss_dbg_xlog.first,
		log->tick / 1000, (log->tick - prev_log->tick) / 1000,
		log->pid);

	for (i = 0; i < log->data_cnt; i++)
		off += snprintf((xlog_buf + off), (xlog_buf_size - off),
			"%x ", log->data[i]);

	off += snprintf((xlog_buf + off), (xlog_buf_size - off), "\n");

	spin_unlock_irqrestore(&mdss_dbg_xlog.xlock, flags);

	return off;
}

static void mdss_xlog_dump_all(void)
{
	char xlog_buf[MDSS_XLOG_BUF_MAX];

	while (__mdss_xlog_dump_calc_range()) {
		mdss_xlog_dump_entry(xlog_buf, MDSS_XLOG_BUF_MAX);
		pr_info("%s", xlog_buf);
	}
}

static void mdss_dump_reg_by_blk(const char *blk_name)
@@ -176,6 +194,22 @@ static void mdss_dump_reg_by_blk(const char *blk_name)
	}
}

static void mdss_dump_reg_all(void)
{
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	struct mdss_debug_data *mdd = mdata->debug_inf.debug_data;
	struct mdss_debug_base *blk_base, *tmp;

	if (!mdd)
		return;

	list_for_each_entry_safe(blk_base, tmp, &mdd->base_list, head) {
		if (blk_base->name)
			mdss_dump_reg(blk_base,
				mdss_dbg_xlog.enable_reg_dump);
	}
}

void mdss_xlog_tout_handler_default(const char *name, ...)
{
	int i, dead = 0;
@@ -198,8 +232,74 @@ void mdss_xlog_tout_handler_default(const char *name, ...)
	}
	va_end(args);

	mdss_xlog_dump();
	mdss_xlog_dump_all();

	if (dead && mdss_dbg_xlog.panic_on_err)
		panic(name);
}
static int mdss_xlog_dump_open(struct inode *inode, struct file *file)
{
	/* non-seekable */
	file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
	file->private_data = inode->i_private;
	return 0;
}

static ssize_t mdss_xlog_dump_read(struct file *file, char __user *buff,
		size_t count, loff_t *ppos)
{
	ssize_t len = 0;
	char xlog_buf[MDSS_XLOG_BUF_MAX];

	if (__mdss_xlog_dump_calc_range()) {
		len = mdss_xlog_dump_entry(xlog_buf, MDSS_XLOG_BUF_MAX);
		if (copy_to_user(buff, xlog_buf, len))
			return -EFAULT;
		*ppos += len;
	}

	return len;
}

static ssize_t mdss_xlog_dump_write(struct file *file,
	const char __user *user_buf, size_t count, loff_t *ppos)
{
	mdss_dump_reg_all();

	mdss_xlog_dump_all();

	if (mdss_dbg_xlog.panic_on_err)
		panic("mdss");

	return count;
}


static const struct file_operations mdss_xlog_fops = {
	.open = mdss_xlog_dump_open,
	.read = mdss_xlog_dump_read,
	.write = mdss_xlog_dump_write,
};

int mdss_create_xlog_debug(struct mdss_debug_data *mdd)
{
	spin_lock_init(&mdss_dbg_xlog.xlock);

	mdss_dbg_xlog.xlog = debugfs_create_dir("xlog", mdd->root);
	if (IS_ERR_OR_NULL(mdss_dbg_xlog.xlog)) {
		pr_err("debugfs_create_dir fail, error %ld\n",
		       PTR_ERR(mdss_dbg_xlog.xlog));
		mdss_dbg_xlog.xlog = NULL;
		return -ENODEV;
	}
	debugfs_create_file("dump", 0644, mdss_dbg_xlog.xlog, NULL,
						&mdss_xlog_fops);
	debugfs_create_u32("enable", 0644, mdss_dbg_xlog.xlog,
			    &mdss_dbg_xlog.xlog_enable);
	debugfs_create_bool("panic", 0644, mdss_dbg_xlog.xlog,
			    &mdss_dbg_xlog.panic_on_err);
	debugfs_create_u32("reg_dump", 0644, mdss_dbg_xlog.xlog,
			    &mdss_dbg_xlog.enable_reg_dump);
	return 0;
}