Lloyd Atkinson | 5d40d31 | 2016-09-06 08:34:13 -0400 | [diff] [blame] | 1 | /* Copyright (c) 2016, The Linux Foundation. All rights reserved. |
| 2 | * |
| 3 | * This program is free software; you can redistribute it and/or modify |
| 4 | * it under the terms of the GNU General Public License version 2 and |
| 5 | * only version 2 as published by the Free Software Foundation. |
| 6 | * |
| 7 | * This program is distributed in the hope that it will be useful, |
| 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 10 | * GNU General Public License for more details. |
| 11 | */ |
| 12 | |
| 13 | #define pr_fmt(fmt) "sde_evtlog:[%s] " fmt, __func__ |
| 14 | |
| 15 | #include <linux/delay.h> |
| 16 | #include <linux/spinlock.h> |
| 17 | #include <linux/ktime.h> |
| 18 | #include <linux/debugfs.h> |
| 19 | #include <linux/uaccess.h> |
| 20 | #include <linux/dma-buf.h> |
| 21 | |
| 22 | #include "sde_dbg.h" |
| 23 | #include "sde_trace.h" |
| 24 | |
| 25 | #ifdef CONFIG_DRM_SDE_EVTLOG_DEBUG |
Lloyd Atkinson | a54513f | 2016-10-03 22:31:43 -0400 | [diff] [blame] | 26 | #define SDE_EVTLOG_DEFAULT_ENABLE 1 |
Lloyd Atkinson | 5d40d31 | 2016-09-06 08:34:13 -0400 | [diff] [blame] | 27 | #else |
Lloyd Atkinson | a54513f | 2016-10-03 22:31:43 -0400 | [diff] [blame] | 28 | #define SDE_EVTLOG_DEFAULT_ENABLE 0 |
Lloyd Atkinson | 5d40d31 | 2016-09-06 08:34:13 -0400 | [diff] [blame] | 29 | #endif |
| 30 | |
Lloyd Atkinson | a54513f | 2016-10-03 22:31:43 -0400 | [diff] [blame] | 31 | #define SDE_DBG_DEFAULT_PANIC 1 |
Lloyd Atkinson | 5d40d31 | 2016-09-06 08:34:13 -0400 | [diff] [blame] | 32 | |
| 33 | /* |
| 34 | * evtlog will print this number of entries when it is called through |
| 35 | * sysfs node or panic. This prevents kernel log from evtlog message |
| 36 | * flood. |
| 37 | */ |
| 38 | #define SDE_EVTLOG_PRINT_ENTRY 256 |
| 39 | |
| 40 | /* |
| 41 | * evtlog keeps this number of entries in memory for debug purpose. This |
| 42 | * number must be greater than print entry to prevent out of bound evtlog |
| 43 | * entry array access. |
| 44 | */ |
| 45 | #define SDE_EVTLOG_ENTRY (SDE_EVTLOG_PRINT_ENTRY * 4) |
| 46 | #define SDE_EVTLOG_MAX_DATA 15 |
| 47 | #define SDE_EVTLOG_BUF_MAX 512 |
| 48 | #define SDE_EVTLOG_BUF_ALIGN 32 |
| 49 | |
| 50 | DEFINE_SPINLOCK(sde_evtloglock); |
| 51 | |
| 52 | struct tlog { |
| 53 | u32 counter; |
| 54 | s64 time; |
| 55 | const char *name; |
| 56 | int line; |
| 57 | u32 data[SDE_EVTLOG_MAX_DATA]; |
| 58 | u32 data_cnt; |
| 59 | int pid; |
| 60 | }; |
| 61 | |
| 62 | static struct sde_dbg_evtlog { |
| 63 | struct tlog logs[SDE_EVTLOG_ENTRY]; |
| 64 | u32 first; |
| 65 | u32 last; |
| 66 | u32 curr; |
| 67 | struct dentry *evtlog; |
| 68 | u32 evtlog_enable; |
| 69 | u32 panic_on_err; |
Lloyd Atkinson | a54513f | 2016-10-03 22:31:43 -0400 | [diff] [blame] | 70 | struct work_struct evtlog_dump_work; |
| 71 | bool work_panic; |
Lloyd Atkinson | 5d40d31 | 2016-09-06 08:34:13 -0400 | [diff] [blame] | 72 | } sde_dbg_evtlog; |
| 73 | |
| 74 | static inline bool sde_evtlog_is_enabled(u32 flag) |
| 75 | { |
| 76 | return (flag & sde_dbg_evtlog.evtlog_enable) || |
| 77 | (flag == SDE_EVTLOG_ALL && sde_dbg_evtlog.evtlog_enable); |
| 78 | } |
| 79 | |
| 80 | void sde_evtlog(const char *name, int line, int flag, ...) |
| 81 | { |
| 82 | unsigned long flags; |
| 83 | int i, val = 0; |
| 84 | va_list args; |
| 85 | struct tlog *log; |
| 86 | |
| 87 | if (!sde_evtlog_is_enabled(flag)) |
| 88 | return; |
| 89 | |
| 90 | spin_lock_irqsave(&sde_evtloglock, flags); |
| 91 | log = &sde_dbg_evtlog.logs[sde_dbg_evtlog.curr]; |
| 92 | log->time = ktime_to_us(ktime_get()); |
| 93 | log->name = name; |
| 94 | log->line = line; |
| 95 | log->data_cnt = 0; |
| 96 | log->pid = current->pid; |
| 97 | |
| 98 | va_start(args, flag); |
| 99 | for (i = 0; i < SDE_EVTLOG_MAX_DATA; i++) { |
| 100 | |
| 101 | val = va_arg(args, int); |
| 102 | if (val == SDE_EVTLOG_DATA_LIMITER) |
| 103 | break; |
| 104 | |
| 105 | log->data[i] = val; |
| 106 | } |
| 107 | va_end(args); |
| 108 | log->data_cnt = i; |
| 109 | sde_dbg_evtlog.curr = (sde_dbg_evtlog.curr + 1) % SDE_EVTLOG_ENTRY; |
| 110 | sde_dbg_evtlog.last++; |
| 111 | |
| 112 | trace_sde_evtlog(name, line, i > 0 ? log->data[0] : 0, |
| 113 | i > 1 ? log->data[1] : 0); |
| 114 | |
| 115 | spin_unlock_irqrestore(&sde_evtloglock, flags); |
| 116 | } |
| 117 | |
| 118 | /* always dump the last entries which are not dumped yet */ |
Lloyd Atkinson | a54513f | 2016-10-03 22:31:43 -0400 | [diff] [blame] | 119 | static bool _sde_evtlog_dump_calc_range(void) |
Lloyd Atkinson | 5d40d31 | 2016-09-06 08:34:13 -0400 | [diff] [blame] | 120 | { |
| 121 | static u32 next; |
| 122 | bool need_dump = true; |
| 123 | unsigned long flags; |
| 124 | struct sde_dbg_evtlog *evtlog = &sde_dbg_evtlog; |
| 125 | |
| 126 | spin_lock_irqsave(&sde_evtloglock, flags); |
| 127 | |
| 128 | evtlog->first = next; |
| 129 | |
| 130 | if (evtlog->last == evtlog->first) { |
| 131 | need_dump = false; |
| 132 | goto dump_exit; |
| 133 | } |
| 134 | |
| 135 | if (evtlog->last < evtlog->first) { |
| 136 | evtlog->first %= SDE_EVTLOG_ENTRY; |
| 137 | if (evtlog->last < evtlog->first) |
| 138 | evtlog->last += SDE_EVTLOG_ENTRY; |
| 139 | } |
| 140 | |
| 141 | if ((evtlog->last - evtlog->first) > SDE_EVTLOG_PRINT_ENTRY) { |
| 142 | pr_warn("evtlog buffer overflow before dump: %d\n", |
| 143 | evtlog->last - evtlog->first); |
| 144 | evtlog->first = evtlog->last - SDE_EVTLOG_PRINT_ENTRY; |
| 145 | } |
| 146 | next = evtlog->first + 1; |
| 147 | |
| 148 | dump_exit: |
| 149 | spin_unlock_irqrestore(&sde_evtloglock, flags); |
| 150 | |
| 151 | return need_dump; |
| 152 | } |
| 153 | |
| 154 | static ssize_t sde_evtlog_dump_entry(char *evtlog_buf, ssize_t evtlog_buf_size) |
| 155 | { |
| 156 | int i; |
| 157 | ssize_t off = 0; |
| 158 | struct tlog *log, *prev_log; |
| 159 | unsigned long flags; |
| 160 | |
| 161 | spin_lock_irqsave(&sde_evtloglock, flags); |
| 162 | |
| 163 | log = &sde_dbg_evtlog.logs[sde_dbg_evtlog.first % |
| 164 | SDE_EVTLOG_ENTRY]; |
| 165 | |
| 166 | prev_log = &sde_dbg_evtlog.logs[(sde_dbg_evtlog.first - 1) % |
| 167 | SDE_EVTLOG_ENTRY]; |
| 168 | |
| 169 | off = snprintf((evtlog_buf + off), (evtlog_buf_size - off), "%s:%-4d", |
| 170 | log->name, log->line); |
| 171 | |
| 172 | if (off < SDE_EVTLOG_BUF_ALIGN) { |
| 173 | memset((evtlog_buf + off), 0x20, (SDE_EVTLOG_BUF_ALIGN - off)); |
| 174 | off = SDE_EVTLOG_BUF_ALIGN; |
| 175 | } |
| 176 | |
| 177 | off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), |
| 178 | "=>[%-8d:%-11llu:%9llu][%-4d]:", sde_dbg_evtlog.first, |
| 179 | log->time, (log->time - prev_log->time), log->pid); |
| 180 | |
| 181 | for (i = 0; i < log->data_cnt; i++) |
| 182 | off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), |
| 183 | "%x ", log->data[i]); |
| 184 | |
| 185 | off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), "\n"); |
| 186 | |
| 187 | spin_unlock_irqrestore(&sde_evtloglock, flags); |
| 188 | |
| 189 | return off; |
| 190 | } |
| 191 | |
Lloyd Atkinson | a54513f | 2016-10-03 22:31:43 -0400 | [diff] [blame] | 192 | static void _sde_evtlog_dump_all(void) |
Lloyd Atkinson | 5d40d31 | 2016-09-06 08:34:13 -0400 | [diff] [blame] | 193 | { |
| 194 | char evtlog_buf[SDE_EVTLOG_BUF_MAX]; |
| 195 | |
Lloyd Atkinson | a54513f | 2016-10-03 22:31:43 -0400 | [diff] [blame] | 196 | while (_sde_evtlog_dump_calc_range()) { |
Lloyd Atkinson | 5d40d31 | 2016-09-06 08:34:13 -0400 | [diff] [blame] | 197 | sde_evtlog_dump_entry(evtlog_buf, SDE_EVTLOG_BUF_MAX); |
| 198 | pr_info("%s", evtlog_buf); |
| 199 | } |
| 200 | } |
| 201 | |
Lloyd Atkinson | a54513f | 2016-10-03 22:31:43 -0400 | [diff] [blame] | 202 | static void _sde_dump_array(bool dead, const char *name) |
| 203 | { |
| 204 | _sde_evtlog_dump_all(); |
| 205 | |
| 206 | if (dead && sde_dbg_evtlog.panic_on_err) |
| 207 | panic(name); |
| 208 | } |
| 209 | |
| 210 | static void _sde_dump_work(struct work_struct *work) |
| 211 | { |
| 212 | _sde_dump_array(sde_dbg_evtlog.work_panic, "evtlog_workitem"); |
| 213 | } |
| 214 | |
| 215 | void sde_dbg_dump(bool queue, const char *name, ...) |
| 216 | { |
| 217 | int i; |
| 218 | bool dead = false; |
| 219 | va_list args; |
| 220 | char *blk_name = NULL; |
| 221 | |
| 222 | if (!sde_evtlog_is_enabled(SDE_EVTLOG_DEFAULT)) |
| 223 | return; |
| 224 | |
| 225 | if (queue && work_pending(&sde_dbg_evtlog.evtlog_dump_work)) |
| 226 | return; |
| 227 | |
| 228 | va_start(args, name); |
| 229 | for (i = 0; i < SDE_EVTLOG_MAX_DATA; i++) { |
| 230 | blk_name = va_arg(args, char*); |
| 231 | if (IS_ERR_OR_NULL(blk_name)) |
| 232 | break; |
| 233 | |
| 234 | if (!strcmp(blk_name, "panic")) |
| 235 | dead = true; |
| 236 | } |
| 237 | va_end(args); |
| 238 | |
| 239 | if (queue) { |
| 240 | /* schedule work to dump later */ |
| 241 | sde_dbg_evtlog.work_panic = dead; |
| 242 | schedule_work(&sde_dbg_evtlog.evtlog_dump_work); |
| 243 | } else { |
| 244 | _sde_dump_array(dead, name); |
| 245 | } |
| 246 | } |
| 247 | |
Lloyd Atkinson | 5d40d31 | 2016-09-06 08:34:13 -0400 | [diff] [blame] | 248 | static int sde_evtlog_dump_open(struct inode *inode, struct file *file) |
| 249 | { |
| 250 | /* non-seekable */ |
| 251 | file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); |
| 252 | file->private_data = inode->i_private; |
| 253 | return 0; |
| 254 | } |
| 255 | |
| 256 | static ssize_t sde_evtlog_dump_read(struct file *file, char __user *buff, |
| 257 | size_t count, loff_t *ppos) |
| 258 | { |
| 259 | ssize_t len = 0; |
| 260 | char evtlog_buf[SDE_EVTLOG_BUF_MAX]; |
| 261 | |
Lloyd Atkinson | a54513f | 2016-10-03 22:31:43 -0400 | [diff] [blame] | 262 | if (_sde_evtlog_dump_calc_range()) { |
Lloyd Atkinson | 5d40d31 | 2016-09-06 08:34:13 -0400 | [diff] [blame] | 263 | len = sde_evtlog_dump_entry(evtlog_buf, SDE_EVTLOG_BUF_MAX); |
| 264 | if (copy_to_user(buff, evtlog_buf, len)) |
| 265 | return -EFAULT; |
| 266 | *ppos += len; |
| 267 | } |
| 268 | |
| 269 | return len; |
| 270 | } |
| 271 | |
| 272 | static ssize_t sde_evtlog_dump_write(struct file *file, |
| 273 | const char __user *user_buf, size_t count, loff_t *ppos) |
| 274 | { |
Lloyd Atkinson | a54513f | 2016-10-03 22:31:43 -0400 | [diff] [blame] | 275 | _sde_evtlog_dump_all(); |
Lloyd Atkinson | 5d40d31 | 2016-09-06 08:34:13 -0400 | [diff] [blame] | 276 | |
| 277 | if (sde_dbg_evtlog.panic_on_err) |
| 278 | panic("sde"); |
| 279 | |
| 280 | return count; |
| 281 | } |
| 282 | |
| 283 | static const struct file_operations sde_evtlog_fops = { |
| 284 | .open = sde_evtlog_dump_open, |
| 285 | .read = sde_evtlog_dump_read, |
| 286 | .write = sde_evtlog_dump_write, |
| 287 | }; |
| 288 | |
| 289 | int sde_evtlog_init(struct dentry *debugfs_root) |
| 290 | { |
| 291 | int i; |
| 292 | |
| 293 | sde_dbg_evtlog.evtlog = debugfs_create_dir("evt_dbg", debugfs_root); |
| 294 | if (IS_ERR_OR_NULL(sde_dbg_evtlog.evtlog)) { |
| 295 | pr_err("debugfs_create_dir fail, error %ld\n", |
| 296 | PTR_ERR(sde_dbg_evtlog.evtlog)); |
| 297 | sde_dbg_evtlog.evtlog = NULL; |
| 298 | return -ENODEV; |
| 299 | } |
| 300 | |
Lloyd Atkinson | a54513f | 2016-10-03 22:31:43 -0400 | [diff] [blame] | 301 | INIT_WORK(&sde_dbg_evtlog.evtlog_dump_work, _sde_dump_work); |
| 302 | sde_dbg_evtlog.work_panic = false; |
| 303 | |
Lloyd Atkinson | 5d40d31 | 2016-09-06 08:34:13 -0400 | [diff] [blame] | 304 | for (i = 0; i < SDE_EVTLOG_ENTRY; i++) |
| 305 | sde_dbg_evtlog.logs[i].counter = i; |
| 306 | |
| 307 | debugfs_create_file("dump", 0644, sde_dbg_evtlog.evtlog, NULL, |
| 308 | &sde_evtlog_fops); |
| 309 | debugfs_create_u32("enable", 0644, sde_dbg_evtlog.evtlog, |
| 310 | &sde_dbg_evtlog.evtlog_enable); |
| 311 | debugfs_create_u32("panic", 0644, sde_dbg_evtlog.evtlog, |
| 312 | &sde_dbg_evtlog.panic_on_err); |
| 313 | |
Lloyd Atkinson | a54513f | 2016-10-03 22:31:43 -0400 | [diff] [blame] | 314 | sde_dbg_evtlog.evtlog_enable = SDE_EVTLOG_DEFAULT_ENABLE; |
| 315 | sde_dbg_evtlog.panic_on_err = SDE_DBG_DEFAULT_PANIC; |
Lloyd Atkinson | 5d40d31 | 2016-09-06 08:34:13 -0400 | [diff] [blame] | 316 | |
| 317 | pr_info("evtlog_status: enable:%d, panic:%d\n", |
| 318 | sde_dbg_evtlog.evtlog_enable, sde_dbg_evtlog.panic_on_err); |
| 319 | |
| 320 | return 0; |
| 321 | } |
| 322 | |
| 323 | void sde_evtlog_destroy(void) |
| 324 | { |
| 325 | debugfs_remove(sde_dbg_evtlog.evtlog); |
| 326 | } |