From: 黄涛 Date: Tue, 1 Apr 2014 02:55:45 +0000 (+0800) Subject: ARM: rockchip: add last_log support X-Git-Tag: firefly_0821_release~5686 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=cd55a91334d3b8e4f5c59c027b6be2c9cd3cf056;p=firefly-linux-kernel-4.4.55.git ARM: rockchip: add last_log support --- diff --git a/arch/arm/mach-rockchip/last_log.c b/arch/arm/mach-rockchip/last_log.c new file mode 100644 index 000000000000..23c387d9675d --- /dev/null +++ b/arch/arm/mach-rockchip/last_log.c @@ -0,0 +1,104 @@ +/* + * arch/arm/mach-rockchip/last_log.c + * + * Copyright (C) 2011-2014 ROCKCHIP, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) "last_log: " fmt +#include +#include +#include +#include +#include +#include +#include +#include + +#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 __init 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) +{ + loff_t pos = *offset; + ssize_t count; + + if (pos >= LOG_BUF_LEN) + return 0; + + count = min(len, (size_t)(LOG_BUF_LEN - pos)); + if (copy_to_user(buf, &last_log_buf[pos], count)) + return -EFAULT; + + *offset += count; + return count; +} + +static const struct file_operations last_log_fops = { + .owner = THIS_MODULE, + .read = last_log_read, +}; + +static void * __init last_log_vmap(phys_addr_t start, unsigned int page_count) +{ + struct page *pages[page_count + 1]; + 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); + } + pages[page_count] = pfn_to_page(start >> PAGE_SHIFT); + return vmap(pages, page_count + 1, VM_MAP, pgprot_noncached(PAGE_KERNEL)); +} + +static int __init last_log_init(void) +{ + char *log_buf, *new_log_buf; + struct proc_dir_entry *entry; + + log_buf = (char *)__get_free_pages(GFP_KERNEL, LOG_BUF_PAGE_ORDER); + if (!log_buf) { + 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; + } + + 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); + + memcpy(last_log_buf, new_log_buf, LOG_BUF_LEN); + memset(new_log_buf, 0, LOG_BUF_LEN); + switch_log_buf(new_log_buf, LOG_BUF_LEN); + + entry = proc_create("last_log", S_IRUSR, NULL, &last_log_fops); + if (!entry) { + pr_err("failed to create proc entry\n"); + return 0; + } + proc_set_size(entry, LOG_BUF_LEN); + +#ifndef CONFIG_ANDROID_RAM_CONSOLE + proc_symlink("last_kmsg", NULL, "last_log"); +#endif + + return 0; +} + +postcore_initcall(last_log_init);