import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / atf_log / atf_logger.c
1 #define DEBUG
2 #include <linux/module.h>
3 #include <linux/file.h>
4 #include <linux/fs.h>
5 #include <linux/cdev.h>
6 #include <linux/miscdevice.h>
7 #include <linux/kernel.h> //min()
8 #include <linux/uaccess.h> //copy_to_user()
9 #include <linux/sched.h> //TASK_INTERRUPTIBLE/signal_pending/schedule
10 #include <linux/poll.h>
11 #include <linux/io.h> //ioremap()
12 #include <linux/of_fdt.h>
13 #include <linux/seq_file.h>
14 #include <asm/setup.h>
15 #include <linux/interrupt.h>
16 #include <linux/proc_fs.h>
17 #include <asm/atomic.h>
18
19 #define ATF_LOG_CTRL_BUF_SIZE 256
20 #define ATF_CRASH_MAGIC_NO 0xdead1abf
21 //#define atf_log_lock() atomic_inc(&(atf_buf_vir_ctl->info.atf_buf_lock))
22 //#define atf_log_unlock() atomic_dec(&(atf_buf_vir_ctl->info.atf_buf_lock))
23
24 #define atf_log_lock() ((void)0)
25 #define atf_log_unlock() ((void)0)
26 static int has_dumped;
27 static unsigned char *atf_log_buffer;
28 static unsigned char *atf_crash_log_buf;
29 static wait_queue_head_t atf_log_wq;
30
31 #ifdef __aarch64__
32 static void *_memcpy(void *dest, const void *src, size_t count)
33 {
34 char *tmp = dest;
35 const char *s = src;
36
37 while (count--)
38 *tmp++ = *s++;
39 return dest;
40 }
41
42 #define memcpy _memcpy
43 #endif
44
45 typedef union atf_log_ctl {
46 struct {
47 unsigned int atf_buf_addr;
48 unsigned int atf_buf_size;
49 unsigned int atf_write_pos;
50 unsigned int atf_read_pos;
51 //atf_spinlock_t atf_buf_lock;
52 unsigned int atf_buf_lock;
53 unsigned int atf_buf_unread_size;
54 unsigned int atf_irq_count;
55 unsigned int atf_reader_alive;
56 unsigned long long atf_write_seq;
57 unsigned long long atf_read_seq;
58 unsigned int atf_aee_dbg_buf_addr;
59 unsigned int atf_aee_dbg_buf_size;
60 unsigned int atf_crash_log_addr;
61 unsigned int atf_crash_log_size;
62 unsigned int atf_crash_flag;
63 } info;
64 unsigned char data[ATF_LOG_CTRL_BUF_SIZE];
65 } atf_log_ctl_t;
66
67
68 struct ipanic_atf_log_rec {
69 size_t total_size;
70 size_t has_read;
71 unsigned long start_idx;
72 };
73
74 atf_log_ctl_t *atf_buf_vir_ctl;
75 unsigned long atf_buf_phy_ctl;
76 unsigned int atf_buf_len;
77 unsigned char *atf_log_vir_addr;
78 unsigned int atf_log_len;
79 unsigned int write_index;
80 unsigned int read_index;
81
82 static void show_data(unsigned long addr, int nbytes, const char *name);
83 static unsigned int pos_to_index(unsigned int pos)
84 {
85 return pos - (atf_buf_phy_ctl + ATF_LOG_CTRL_BUF_SIZE);
86 }
87
88 static unsigned int index_to_pos(unsigned int index)
89 {
90 return (atf_buf_phy_ctl + ATF_LOG_CTRL_BUF_SIZE) + index;
91 }
92 #if 0
93 static size_t atf_log_dump_nolock(unsigned char *buffer, unsigned int start, size_t size)
94 {
95 unsigned int len;
96 unsigned int least;
97 size_t skip = 0;
98 unsigned char *p = atf_log_vir_addr + start;
99 write_index = pos_to_index(atf_buf_vir_ctl->info.atf_write_pos);
100 least = (write_index + atf_buf_len - start) % atf_buf_len;
101 if (size > least)
102 size = least;
103 len = min(size, atf_log_len - start);
104 if (size == len) {
105 memcpy(buffer, atf_log_vir_addr + start, size);
106 } else {
107 size_t right = atf_log_len - start;
108 while (skip < right) {
109 if (*p != 0)
110 break;
111 p++;
112 skip++;
113 }
114 //pr_notice("skip:%d, right:%d, %p\n", skip, right, p);
115 memcpy(buffer, p, right - skip);
116 memcpy(buffer, atf_log_vir_addr, size - right);
117 return size - skip;
118 }
119 return size;
120 }
121 #endif
122
123 static size_t atf_log_dump_nolock(unsigned char *buffer, struct ipanic_atf_log_rec *rec, size_t size)
124 {
125 unsigned int len;
126 unsigned int least;
127 write_index = pos_to_index(atf_buf_vir_ctl->info.atf_write_pos);
128 //find the first letter to read
129 while ((write_index + atf_log_len - rec->start_idx) % atf_log_len > 0) {
130 if (*(atf_log_vir_addr + rec->start_idx) != 0)
131 break;
132 rec->start_idx++;
133 if (rec->start_idx == atf_log_len)
134 rec->start_idx = 0;
135 }
136 least = (write_index + atf_buf_len - rec->start_idx) % atf_buf_len;
137 if (size > least)
138 size = least;
139 len = min(size, atf_log_len - rec->start_idx);
140 if (size == len) {
141 memcpy(buffer, atf_log_vir_addr + rec->start_idx, size);
142 } else {
143 size_t right = atf_log_len - rec->start_idx;
144 memcpy(buffer, atf_log_vir_addr + rec->start_idx, right);
145 memcpy(buffer, atf_log_vir_addr, size - right);
146 }
147 rec->start_idx += size;
148 rec->start_idx %= atf_log_len;
149 return size;
150 }
151 //static size_t atf_log_dump(unsigned char *buffer, unsigned int start, size_t size)
152 static size_t atf_log_dump(unsigned char *buffer, struct ipanic_atf_log_rec *rec, size_t size)
153 {
154 size_t ret;
155 atf_log_lock();
156 //ret = atf_log_dump_nolock(buffer, start, size);
157 ret = atf_log_dump_nolock(buffer, rec, size);
158 atf_log_unlock();
159 //show_data(atf_log_vir_addr, 24*1024, "atf_buf");
160 return ret;
161 }
162
163 size_t ipanic_atflog_buffer(void *data, unsigned char *buffer, size_t sz_buffer)
164 {
165 if (atf_buf_len == 0)
166 return 0;
167 static bool last_read = false;
168 size_t count;
169 struct ipanic_atf_log_rec *rec = (struct ipanic_atf_log_rec *)data;
170 //pr_notice("ipanic_atf_log: need %d, rec:%d, %d, %lu\n", sz_buffer, rec->total_size, rec->has_read, rec->start_idx);
171 if (rec->total_size == rec->has_read || last_read) {
172 last_read = false;
173 return 0;
174 }
175 if (rec->has_read == 0) {
176 if (atf_buf_vir_ctl->info.atf_write_seq < atf_log_len && atf_buf_vir_ctl->info.atf_write_seq < sz_buffer)
177 rec->start_idx = 0;
178 else {
179 //atf_log_lock();
180 write_index = pos_to_index(atf_buf_vir_ctl->info.atf_write_pos);
181 //atf_log_unlock();
182 rec->start_idx = (write_index + atf_log_len - rec->total_size) % atf_log_len;
183 }
184 }
185 //count = atf_log_dump_nolock(buffer, (rec->start_idx + rec->has_read) % atf_log_len, sz_buffer);
186 //count = atf_log_dump_nolock(buffer, rec, sz_buffer);
187 count = atf_log_dump(buffer, rec, sz_buffer);
188 //pr_notice("ipanic_atf_log: dump %d\n", count);
189 rec->has_read += count;
190 if (count != sz_buffer)
191 last_read = true;
192 return count;
193 }
194
195 static ssize_t atf_log_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t ppos)
196 {
197 wake_up_interruptible(&atf_log_wq);
198 return 1;
199 }
200
201 static ssize_t do_read_log_to_usr(char __user *buf, size_t count)
202 {
203 size_t len;
204 size_t least;
205 write_index = pos_to_index(atf_buf_vir_ctl->info.atf_write_pos);
206 read_index = pos_to_index(atf_buf_vir_ctl->info.atf_read_pos);
207 least = (write_index + atf_buf_len - read_index) % atf_buf_len;
208 if (count > least)
209 count = least;
210 len = min(count, atf_log_len - read_index);
211 if (count == len) {
212 if (copy_to_user(buf, atf_log_vir_addr + read_index, count))
213 return -EFAULT;
214 } else {
215 size_t right = atf_log_len - read_index;
216 if (copy_to_user(buf, atf_log_vir_addr + read_index, right))
217 return -EFAULT;
218 if (copy_to_user(buf, atf_log_vir_addr, count - right))
219 return -EFAULT;
220 }
221 read_index = (read_index + count) % atf_log_len;
222 return count;
223 }
224
225 static int atf_log_fix_reader()
226 {
227 if (atf_buf_vir_ctl->info.atf_write_seq < atf_log_len) {
228 atf_buf_vir_ctl->info.atf_read_seq = 0;
229 atf_buf_vir_ctl->info.atf_read_pos = index_to_pos(0);
230 } else {
231 atf_buf_vir_ctl->info.atf_read_seq = atf_buf_vir_ctl->info.atf_write_seq;
232 atf_buf_vir_ctl->info.atf_read_pos = atf_buf_vir_ctl->info.atf_write_pos;
233 }
234 return 0;
235 }
236
237 static int atf_log_open(struct inode *inode, struct file *file)
238 {
239 int ret;
240 ret = nonseekable_open(inode, file);
241 if (unlikely(ret))
242 return ret;
243 file->private_data = NULL;
244 atf_log_lock();
245 if (!atf_buf_vir_ctl->info.atf_reader_alive) {
246 atf_log_fix_reader();
247 }
248 atf_buf_vir_ctl->info.atf_reader_alive++;
249 atf_log_unlock();
250 return 0;
251 }
252
253 static int atf_log_release(struct inode *ignored, struct file *file)
254 {
255 atf_buf_vir_ctl->info.atf_reader_alive--;
256 return 0;
257 }
258
259 static ssize_t atf_log_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
260 {
261 ssize_t ret;
262 unsigned int write_pos;
263 unsigned int read_pos;
264 DEFINE_WAIT(wait);
265
266 start:
267 while (1) {
268 atf_log_lock();
269 write_pos = atf_buf_vir_ctl->info.atf_write_pos;
270 read_pos = atf_buf_vir_ctl->info.atf_read_pos;
271 //pr_notice("atf_log_read: wait in wq\n");
272 prepare_to_wait(&atf_log_wq, &wait, TASK_INTERRUPTIBLE);
273 ret = (write_pos == read_pos);
274 atf_log_unlock();
275 if (!ret)
276 break;
277 if (file->f_flags & O_NONBLOCK) {
278 ret = -EAGAIN;
279 break;
280 }
281 if (signal_pending(current)) {
282 ret = -EINTR;
283 break;
284 }
285 schedule();
286 }
287 finish_wait(&atf_log_wq, &wait);
288 //pr_notice("atf_log_read: finish wait\n");
289 if (ret)
290 return ret;
291 atf_log_lock();
292 if (unlikely(write_pos == read_pos)) {
293 atf_log_unlock();
294 goto start;
295 }
296 ret = do_read_log_to_usr(buf, count);
297 atf_buf_vir_ctl->info.atf_read_pos = index_to_pos(read_index);
298 atf_buf_vir_ctl->info.atf_read_seq += ret;
299 atf_log_unlock();
300 //pr_notice("atf_log_read: return %d, idx: %lu, readpos: %p, writepos: %p\n", ret, read_index, atf_buf_vir_ctl->info.atf_read_pos, atf_buf_vir_ctl->info.atf_write_pos);
301 return ret;
302 }
303
304 static unsigned int atf_log_poll(struct file *file, poll_table *wait)
305 {
306 unsigned int ret = POLLOUT | POLLWRNORM;
307 if (!(file->f_mode & FMODE_READ))
308 return ret;
309 poll_wait(file, &atf_log_wq, wait);
310 atf_log_lock();
311 if (atf_buf_vir_ctl->info.atf_write_pos != atf_buf_vir_ctl->info.atf_read_pos)
312 ret |= POLLIN | POLLRDNORM;
313 atf_log_unlock();
314 return ret;
315 }
316
317 long atf_log_ioctl(struct file *flip, unsigned int cmd, unsigned long arg)
318 {
319 }
320
321 static struct file_operations atf_log_fops = {
322 .owner = THIS_MODULE,
323 .unlocked_ioctl = atf_log_ioctl,
324 .poll = atf_log_poll,
325 .read = atf_log_read,
326 .open = atf_log_open,
327 .release = atf_log_release,
328 .write = atf_log_write,
329 };
330
331 static struct miscdevice atf_log_dev = {
332 .minor = MISC_DYNAMIC_MINOR,
333 .name = "atf_log",
334 .fops = &atf_log_fops,
335 .mode = 0644,
336 };
337
338 static int dt_scan_memory(unsigned long node, const char *uname, int depth, void *data)
339 {
340 char *type = of_get_flat_dt_prop(node, "device_type", NULL);
341 __be32 *reg, *endp;
342 unsigned long l;
343
344 /* We are scanning "memory" nodes only */
345 if (type == NULL) {
346 /*
347 * The longtrail doesn't have a device_type on the
348 * /memory node, so look for the node called /memory@0.
349 */
350 if (depth != 1 || strcmp(uname, "memory@0") != 0)
351 return 0;
352 } else if (strcmp(type, "memory") != 0)
353 return 0;
354
355 reg = of_get_flat_dt_prop(node, "reg", &l);
356 if (reg == NULL)
357 return 0;
358
359 endp = reg + (l / sizeof(__be32));
360
361 while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
362 u64 base, size;
363
364 base = dt_mem_next_cell(dt_root_addr_cells, &reg);
365 size = dt_mem_next_cell(dt_root_size_cells, &reg);
366
367 if (size == 0)
368 continue;
369 //pr_notice(
370 // "[PHY layout]DRAM size (dt) : 0x%llx - 0x%llx (0x%llx)\n",
371 // (unsigned long long)base,
372 // (unsigned long long)base + (unsigned long long)size - 1,
373 // (unsigned long long)size);
374 }
375 *(unsigned long *)data = node;
376 return node;
377 }
378
379 unsigned long long atf_get_from_dt(unsigned long *phy_addr, unsigned int *len) {
380 unsigned long node = 0;
381 mem_desc_t *mem_desc;
382 if (of_scan_flat_dt(dt_scan_memory, &node)) {
383 mem_desc = (mem_desc_t *)of_get_flat_dt_prop(node, "tee_reserved_mem", NULL);
384 if (mem_desc && mem_desc->size) {
385 pr_notice("ATF reserved memory: 0x%08llx - 0x%08llx (0x%llx)\n", mem_desc->start, mem_desc->start+mem_desc->size - 1, mem_desc->size); }
386 }
387 *phy_addr = mem_desc->start;
388 *len = mem_desc->size;
389 return 0;
390 }
391
392 void show_atf_log_ctl() {
393 pr_notice("atf_buf_addr(%p) = 0x%x\n", &(atf_buf_vir_ctl->info.atf_buf_addr), atf_buf_vir_ctl->info.atf_buf_addr);
394 pr_notice("atf_buf_size(%p) = 0x%x\n", &(atf_buf_vir_ctl->info.atf_buf_size), atf_buf_vir_ctl->info.atf_buf_size);
395 pr_notice("atf_write_pos(%p) = %u\n", &(atf_buf_vir_ctl->info.atf_write_pos), atf_buf_vir_ctl->info.atf_write_pos);
396 pr_notice("atf_read_pos(%p) = %u\n", &(atf_buf_vir_ctl->info.atf_read_pos), atf_buf_vir_ctl->info.atf_read_pos);
397 pr_notice("atf_buf_lock(%p) = %u\n", &(atf_buf_vir_ctl->info.atf_buf_lock), atf_buf_vir_ctl->info.atf_buf_lock);
398 pr_notice("atf_buf_unread_size(%p) = %u\n", &(atf_buf_vir_ctl->info.atf_buf_unread_size), atf_buf_vir_ctl->info.atf_buf_unread_size);
399 pr_notice("atf_irq_count(%p) = %u\n", &(atf_buf_vir_ctl->info.atf_irq_count), atf_buf_vir_ctl->info.atf_irq_count);
400 pr_notice("atf_reader_alive(%p) = %u\n", &(atf_buf_vir_ctl->info.atf_reader_alive), atf_buf_vir_ctl->info.atf_reader_alive);
401 pr_notice("atf_write_seq(%p) = %llu\n", &(atf_buf_vir_ctl->info.atf_write_seq), atf_buf_vir_ctl->info.atf_write_seq);
402 pr_notice("atf_read_seq(%p) = %llu\n", &(atf_buf_vir_ctl->info.atf_read_seq), atf_buf_vir_ctl->info.atf_read_seq);
403 }
404
405 static void show_data(unsigned long addr, int nbytes, const char *name)
406 {
407 int i, j;
408 int nlines;
409 u32 *p;
410
411 /*
412 * don't attempt to dump non-kernel addresses or
413 * values that are probably just small negative numbers
414 */
415 if (addr < PAGE_OFFSET || addr > -256UL)
416 return;
417
418 printk("\n%s: %#lx:\n", name, addr);
419
420 /*
421 * round address down to a 32 bit boundary
422 * and always dump a multiple of 32 bytes
423 */
424 p = (u32 *)(addr & ~(sizeof(u32) - 1));
425 nbytes += (addr & (sizeof(u32) - 1));
426 nlines = (nbytes + 31) / 32;
427
428
429 for (i = 0; i < nlines; i++) {
430 /*
431 * just display low 16 bits of address to keep
432 * each line of the dump < 80 characters
433 */
434 printk("%04lx ", (unsigned long)p & 0xffff);
435 for (j = 0; j < 8; j++) {
436 u32 data;
437 if (probe_kernel_address(p, data)) {
438 printk(" ********");
439 } else {
440 printk(" %08x", data);
441 }
442 ++p;
443 }
444 printk("\n");
445 }
446 }
447
448 static irqreturn_t ATF_log_irq_handler(int irq, void *dev_id)
449 {
450 if (!atf_buf_vir_ctl->info.atf_reader_alive) {
451 pr_err("No alive reader, but still recieve irq\n");
452 } else {
453 pr_info("ATF_log_irq triggered!\n");
454 }
455 wake_up_interruptible(&atf_log_wq);
456 return IRQ_HANDLED;
457 }
458
459 static const struct file_operations proc_atf_log_file_operations = {
460 .owner = THIS_MODULE,
461 .open = atf_log_open,
462 .read = atf_log_read,
463 .unlocked_ioctl = atf_log_ioctl,
464 .release = atf_log_release,
465 .poll = atf_log_poll,
466 };
467
468 static int atf_crash_show(struct seq_file *m, void *v)
469 {
470 seq_write(m, atf_crash_log_buf, atf_buf_vir_ctl->info.atf_crash_log_size);
471 return 0;
472 }
473
474 static int atf_crash_file_open(struct inode *inode, struct file *file)
475 {
476 return single_open(file, atf_crash_show, inode->i_private);
477 }
478
479 static const struct file_operations proc_atf_crash_file_operations = {
480 .owner = THIS_MODULE,
481 .open = atf_crash_file_open,
482 .read = seq_read,
483 .llseek = seq_lseek,
484 .release = seq_release,
485 };
486
487 static struct proc_dir_entry *atf_log_proc_dir;
488 static struct proc_dir_entry *atf_log_proc_file;
489 static struct proc_dir_entry *atf_crash_proc_file;
490
491 static int __init atf_log_init(void)
492 {
493 //register module driver
494 int err;
495 err = misc_register(&atf_log_dev);
496 if (unlikely(err)) {
497 pr_err("atf_log: failed to register device");
498 return -1;
499 } else {
500 pr_notice("atf_log: inited");
501 }
502 //get atf reserved memory(atf_buf_phy_ctl) from device
503 atf_get_from_dt(&atf_buf_phy_ctl, &atf_buf_len); //TODO
504 if (atf_buf_len == 0) {
505 pr_err("No atf_log_buffer!\n");
506 return -1;
507 }
508 // map control header
509 atf_buf_vir_ctl = ioremap_wc(atf_buf_phy_ctl, ATF_LOG_CTRL_BUF_SIZE);
510 atf_log_len = atf_buf_vir_ctl->info.atf_buf_size;
511 // map log buffer
512 atf_log_vir_addr = ioremap_wc(atf_buf_phy_ctl + ATF_LOG_CTRL_BUF_SIZE, atf_log_len);
513 pr_notice("atf_buf_phy_ctl: 0x%lu\n", atf_buf_phy_ctl);
514 pr_notice("atf_buf_len: %u\n", atf_buf_len);
515 pr_notice("atf_buf_vir_ctl: %p\n", atf_buf_vir_ctl);
516 pr_notice("atf_log_vir_addr: %p\n", atf_log_vir_addr);
517 pr_notice("atf_log_len: %u\n", atf_log_len);
518 //show_atf_log_ctl();
519 //show_data(atf_buf_vir_ctl, 512, "atf_buf");
520 atf_buf_vir_ctl->info.atf_reader_alive = 0;
521 atf_buf_vir_ctl->info.atf_read_seq = 0;
522 //initial wait queue
523 init_waitqueue_head(&atf_log_wq);
524 if (request_irq(281, (irq_handler_t)ATF_log_irq_handler, IRQF_TRIGGER_NONE, "ATF_irq",NULL) != 0) {
525 pr_crit("Fail to request ATF_log_irq interrupt!\n");
526 return -1;
527 }
528 // create /proc/atf_log
529 atf_log_proc_dir = proc_mkdir("atf_log", NULL);
530 if (atf_log_proc_dir == NULL) {
531 pr_err("atf_log proc_mkdir failed\n");
532 return -ENOMEM;
533 }
534 // create /proc/atf_log/atf_log
535 atf_log_proc_file = proc_create("atf_log", 0444, atf_log_proc_dir, &proc_atf_log_file_operations);
536 if (atf_log_proc_file == NULL) {
537 pr_err("atf_log proc_create failed at atf_log\n");
538 return -ENOMEM;
539 }
540
541 if (atf_buf_vir_ctl->info.atf_crash_flag == ATF_CRASH_MAGIC_NO) {
542 atf_crash_proc_file = proc_create("atf_crash", 0444, atf_log_proc_dir, &proc_atf_crash_file_operations);
543 if (atf_crash_proc_file == NULL) {
544 pr_err("atf_log proc_create failed at atf_crash\n");
545 return -ENOMEM;
546 }
547 atf_buf_vir_ctl->info.atf_crash_flag = 0;
548 atf_crash_log_buf = ioremap_wc(atf_buf_vir_ctl->info.atf_crash_log_addr, atf_buf_vir_ctl->info.atf_crash_log_size);
549 }
550
551 return 0;
552 }
553
554 static void __exit atf_log_exit(void)
555 {
556 //deregister module driver
557 int err;
558 err = misc_deregister(&atf_log_dev);
559 if (unlikely(err)) {
560 pr_err("atf_log: failed to unregister device");
561 }
562 pr_notice("atf_log: exited");
563 }
564
565 module_init(atf_log_init);
566 module_exit(atf_log_exit);
567
568 MODULE_DESCRIPTION("MEDIATEK Module ATF Logging Driver");
569 MODULE_AUTHOR("Ji Zhang<ji.zhang@mediatek.com>");
570