pause SMP and fix idle clk gate when change ddr frequence
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-rockchip / last_log.c
1 /*
2  *  arch/arm/mach-rockchip/last_log.c
3  *
4  *  Copyright (C) 2011-2014 ROCKCHIP, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10
11 #define pr_fmt(fmt) "last_log: " fmt
12 #include <linux/kernel.h>
13 #include <linux/init.h>
14 #include <linux/mm.h>
15 #include <linux/module.h>
16 #include <linux/proc_fs.h>
17 #include <linux/vmalloc.h>
18 #include <asm/uaccess.h>
19 #include <asm/io.h>
20
21 #define LOG_BUF_LEN     (1 << CONFIG_LOG_BUF_SHIFT)
22 #define LOG_BUF_PAGE_ORDER      (CONFIG_LOG_BUF_SHIFT - PAGE_SHIFT)
23 static char last_log_buf[LOG_BUF_LEN];
24 extern void __init switch_log_buf(char *new_log_buf, unsigned size);
25
26 char *last_log_get(unsigned *size)
27 {
28         *size = LOG_BUF_LEN;
29         return last_log_buf;
30 }
31
32 static ssize_t last_log_read(struct file *file, char __user *buf,
33                                     size_t len, loff_t *offset)
34 {
35         loff_t pos = *offset;
36         ssize_t count;
37
38         if (pos >= LOG_BUF_LEN)
39                 return 0;
40
41         count = min(len, (size_t)(LOG_BUF_LEN - pos));
42         if (copy_to_user(buf, &last_log_buf[pos], count))
43                 return -EFAULT;
44
45         *offset += count;
46         return count;
47 }
48
49 static const struct file_operations last_log_fops = {
50         .owner = THIS_MODULE,
51         .read = last_log_read,
52 };
53
54 static void * __init last_log_vmap(phys_addr_t start, unsigned int page_count)
55 {
56         struct page *pages[page_count + 1];
57         unsigned int i;
58
59         for (i = 0; i < page_count; i++) {
60                 phys_addr_t addr = start + i * PAGE_SIZE;
61                 pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
62         }
63         pages[page_count] = pfn_to_page(start >> PAGE_SHIFT);
64         return vmap(pages, page_count + 1, VM_MAP, pgprot_noncached(PAGE_KERNEL));
65 }
66
67 static int __init last_log_init(void)
68 {
69         char *log_buf, *new_log_buf;
70         struct proc_dir_entry *entry;
71
72         log_buf = (char *)__get_free_pages(GFP_KERNEL, LOG_BUF_PAGE_ORDER);
73         if (!log_buf) {
74                 pr_err("failed to __get_free_pages(%d)\n", LOG_BUF_PAGE_ORDER);
75                 return 0;
76         }
77
78         new_log_buf = last_log_vmap(virt_to_phys(log_buf), 1 << LOG_BUF_PAGE_ORDER);
79         if (!new_log_buf) {
80                 pr_err("failed to map %d pages at 0x%08x\n", 1 << LOG_BUF_PAGE_ORDER, virt_to_phys(log_buf));
81                 return 0;
82         }
83
84         pr_info("0x%08x map to 0x%p and copy to 0x%p (version 2.2)\n", virt_to_phys(log_buf), new_log_buf, last_log_buf);
85
86         memcpy(last_log_buf, new_log_buf, LOG_BUF_LEN);
87         memset(new_log_buf, 0, LOG_BUF_LEN);
88         switch_log_buf(new_log_buf, LOG_BUF_LEN);
89
90         entry = proc_create("last_log", S_IRUSR, NULL, &last_log_fops);
91         if (!entry) {
92                 pr_err("failed to create proc entry\n");
93                 return 0;
94         }
95         proc_set_size(entry, LOG_BUF_LEN);
96
97 #ifndef CONFIG_ANDROID_RAM_CONSOLE
98         proc_symlink("last_kmsg", NULL, "last_log");
99 #endif
100
101         return 0;
102 }
103
104 postcore_initcall(last_log_init);