rk: last_log: version 2.0, map log buf as noncached, add last_log_get API
author黄涛 <huangtao@rock-chips.com>
Mon, 17 Dec 2012 03:49:56 +0000 (11:49 +0800)
committer黄涛 <huangtao@rock-chips.com>
Mon, 17 Dec 2012 06:42:38 +0000 (14:42 +0800)
arch/arm/plat-rk/last_log.c

index 6e6ead70372b129537534d44a82ac3bc28e44ea2..61a1d83bb2f79c9ca04e192d7c88d764ca875ea6 100644 (file)
@@ -8,17 +8,27 @@
  * published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) "last_log: " fmt
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
 #define LOG_BUF_LEN    (1 << CONFIG_LOG_BUF_SHIFT)
+#define LOG_BUF_PAGE_ORDER     (CONFIG_LOG_BUF_SHIFT - PAGE_SHIFT)
 static char last_log_buf[LOG_BUF_LEN];
 extern void switch_log_buf(char *new_log_buf, unsigned size);
 
+char *last_log_get(unsigned *size)
+{
+       *size = LOG_BUF_LEN;
+       return last_log_buf;
+}
+
 static ssize_t last_log_read(struct file *file, char __user *buf,
                                    size_t len, loff_t *offset)
 {
@@ -41,24 +51,43 @@ static const struct file_operations last_log_file_ops = {
        .read = last_log_read,
 };
 
+static void * __init last_log_vmap(phys_addr_t start, unsigned int page_count)
+{
+       struct page *pages[page_count];
+       unsigned int i;
+
+       for (i = 0; i < page_count; i++) {
+               phys_addr_t addr = start + i * PAGE_SIZE;
+               pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
+       }
+       return vmap(pages, page_count, VM_MAP, pgprot_noncached(PAGE_KERNEL));
+}
+
 static int __init last_log_init(void)
 {
-       char *log_buf;
+       char *log_buf, *new_log_buf;
        struct proc_dir_entry *entry;
 
-       log_buf = (char *)__get_free_pages(GFP_KERNEL, CONFIG_LOG_BUF_SHIFT - PAGE_SHIFT);
+       log_buf = (char *)__get_free_pages(GFP_KERNEL, LOG_BUF_PAGE_ORDER);
        if (!log_buf) {
-               printk(KERN_ERR "last_log: failed to __get_free_pages(%d)\n", CONFIG_LOG_BUF_SHIFT - PAGE_SHIFT);
+               pr_err("failed to __get_free_pages(%d)\n", LOG_BUF_PAGE_ORDER);
+               return 0;
+       }
+
+       new_log_buf = last_log_vmap(virt_to_phys(log_buf), 1 << LOG_BUF_PAGE_ORDER);
+       if (!new_log_buf) {
+               pr_err("failed to map %d pages at 0x%08x\n", 1 << LOG_BUF_PAGE_ORDER, virt_to_phys(log_buf));
                return 0;
        }
-       printk("last_log: 0x%p 0x%p\n", log_buf, last_log_buf);
+
+       pr_info("0x%p map to 0x%p and copy to 0x%p (version 2.0)\n", log_buf, new_log_buf, last_log_buf);
 
        memcpy(last_log_buf, log_buf, LOG_BUF_LEN);
-       switch_log_buf(log_buf, LOG_BUF_LEN);
+       switch_log_buf(new_log_buf, LOG_BUF_LEN);
 
        entry = create_proc_entry("last_log", S_IFREG | S_IRUGO, NULL);
        if (!entry) {
-               printk(KERN_ERR "last_log: failed to create proc entry\n");
+               pr_err("failed to create proc entry\n");
                return 0;
        }