Loading drivers/video/msm/mdss/mdss_debug.h +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 Loading Loading @@ -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) Loading Loading @@ -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 Loading @@ -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 Loading drivers/video/msm/mdss/mdss_debug_xlog.c +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 Loading @@ -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" Loading @@ -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; Loading @@ -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; Loading @@ -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++) { Loading @@ -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) Loading @@ -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; Loading @@ -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; } Loading
drivers/video/msm/mdss/mdss_debug.h +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 Loading Loading @@ -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) Loading Loading @@ -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 Loading @@ -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 Loading
drivers/video/msm/mdss/mdss_debug_xlog.c +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 Loading @@ -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" Loading @@ -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; Loading @@ -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; Loading @@ -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++) { Loading @@ -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) Loading @@ -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; Loading @@ -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; }