#ifdef CONFIG_RK_LAST_LOG
#include <linux/ctype.h>
-extern char *last_log_get(unsigned *size);
-
-enum log_flags {
- LOG_NOCONS = 1, /* already flushed, do not print to console */
- LOG_NEWLINE = 2, /* text ended with a newline */
- LOG_PREFIX = 4, /* text started with a prefix */
- LOG_CONT = 8, /* text is a fragment of a continuation line */
-};
-
-struct log {
- u64 ts_nsec; /* timestamp in nanoseconds */
- u16 len; /* length of entire record */
- u16 text_len; /* length of text buffer */
- u16 dict_len; /* length of dictionary buffer */
- u8 facility; /* syslog facility */
- u8 flags:5; /* internal record flags */
- u8 level:3; /* syslog level */
-};
-
-static void dump_last_kernel_log_raw(struct fiq_debugger_state *state)
+extern char *rk_last_log_get(unsigned *size);
+static void dump_last_kernel_log(struct fiq_debugger_state *state)
{
- unsigned size, i, c, w = 0;
- char *s = last_log_get(&size);
+ unsigned size, i, c;
+ char *s = rk_last_log_get(&size);
+
for (i = 0; i < size; i++) {
if (i % 1024 == 0)
wdt_keepalive();
c = s[i];
- if (w % 80 == 79) {
- debug_putc(state, '\r');
- debug_putc(state, '\n');
- w = 0;
- }
if (c == '\n') {
- debug_putc(state, '\r');
- debug_putc(state, c);
- w = 0;
+ state->pdata->uart_putc(state->pdev, '\r');
+ state->pdata->uart_putc(state->pdev, c);
} else if (isascii(c) && isprint(c)) {
- debug_putc(state, c);
- w++;
+ state->pdata->uart_putc(state->pdev, c);
}
}
}
-
-static void dump_last_kernel_log(struct fiq_debugger_state *state)
-{
- unsigned size, i, c;
- char *s = last_log_get(&size);
- unsigned int prev = 0;
-
- for (;;) {
- size_t sz;
- struct log *l;
- bool prefix = true;
- bool newline = true;
- const char *text;
- unsigned int text_size;
-
- sz = sizeof(struct log);
- if (size < sz)
- break;
- l = (struct log *)s;
- size -= sz;
- s += sz;
-
- if (l->len == 0)
- break;
-
- sz = l->len - sz;
- text = s;
- text_size = l->text_len;
- if (size < sz)
- break;
- size -= sz;
- s += sz;
-
- if ((prev & LOG_CONT) && !(l->flags & LOG_PREFIX))
- prefix = false;
-
- if (l->flags & LOG_CONT) {
- if ((prev & LOG_CONT) && !(prev & LOG_NEWLINE))
- prefix = false;
-
- if (!(l->flags & LOG_NEWLINE))
- newline = false;
- }
-
- do {
- char *next = memchr(text, '\n', text_size);
- size_t text_len;
-
- if (next) {
- text_len = next - text;
- next++;
- text_size -= next - text;
- } else {
- text_len = text_size;
- }
-
- if (prefix) {
- char buf[32];
- size_t len = 0;
- unsigned long rem_nsec = do_div(l->ts_nsec, 1000000000);
- unsigned int prefix = (l->facility << 3) | l->level;
-
- len += snprintf(buf, sizeof(buf), "<%u>", prefix);
- len += snprintf(buf + len, sizeof(buf) - len, "[%5lu.%06lu] ", (unsigned long)l->ts_nsec, rem_nsec / 1000);
- debug_puts(state, buf);
- }
- for (i = 0; i < text_len; i++) {
- c = text[i];
- if (c == '\n') {
- debug_putc(state, '\r');
- debug_putc(state, c);
- } else if (isascii(c) && isprint(c)) {
- debug_putc(state, c);
- }
- }
- if (next || newline) {
- debug_putc(state, '\r');
- debug_putc(state, '\n');
- }
- prefix = true;
- text = next;
- } while (text);
- wdt_keepalive();
- }
-}
#endif
static char *mode_name(unsigned cpsr)
{"kmsg"},
#ifdef CONFIG_RK_LAST_LOG
{"last_kmsg"},
- {"last_kmsg_raw"},
#endif
{"version"},
{"sleep"},
" version Kernel version\n");
#ifdef CONFIG_RK_LAST_LOG
debug_printf(state, " last_kmsg Last kernel log\n");
- debug_printf(state, " last_kmsg_raw Last kernel log raw\n");
#endif
debug_printf(state, " sleep Allow sleep while in FIQ\n"
" nosleep Disable sleep while in FIQ\n"
} else if (!strcmp(cmd, "kmsg")) {
dump_kernel_log(state);
#ifdef CONFIG_RK_LAST_LOG
- } else if (!strcmp(cmd, "last_kmsg_raw")) {
- dump_last_kernel_log_raw(state);
} else if (!strcmp(cmd, "last_kmsg")) {
dump_last_kernel_log(state);
#endif
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
+#include <linux/rockchip/cpu.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 __init switch_log_buf(char *new_log_buf, unsigned size);
+#define LOG_BUF_SHIFT CONFIG_LOG_BUF_SHIFT
+#define LOG_BUF_LEN (1 << LOG_BUF_SHIFT)
+#define LOG_BUF_PAGE_ORDER (LOG_BUF_SHIFT - PAGE_SHIFT)
+static char *last_log_buf;
+static char *log_buf;
+static size_t log_pos;
+static char early_log_buf[8192];
-char *last_log_get(unsigned *size)
+char *rk_last_log_get(unsigned *size)
{
*size = LOG_BUF_LEN;
return last_log_buf;
return vmap(pages, page_count + 1, VM_MAP, pgprot_noncached(PAGE_KERNEL));
}
-static int __init last_log_init(void)
+static int __init rk_last_log_init(void)
{
- char *log_buf, *new_log_buf;
+ size_t early_log_size;
+ char *buf;
struct proc_dir_entry *entry;
- log_buf = (char *)__get_free_pages(GFP_KERNEL, LOG_BUF_PAGE_ORDER);
- if (!log_buf) {
+ if (!cpu_is_rockchip())
+ return 0;
+
+ buf = (char *)__get_free_pages(GFP_KERNEL, LOG_BUF_PAGE_ORDER);
+ if (!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));
+ log_buf = last_log_vmap(virt_to_phys(buf), 1 << LOG_BUF_PAGE_ORDER);
+ if (!log_buf) {
+ pr_err("failed to map %d pages at 0x%08x\n", 1 << LOG_BUF_PAGE_ORDER, virt_to_phys(buf));
+ return 0;
+ }
+
+ last_log_buf = (char *)vmalloc(LOG_BUF_LEN);
+ if (!last_log_buf) {
+ pr_err("failed to vmalloc(%d)\n", LOG_BUF_LEN);
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, buf, LOG_BUF_LEN);
+ early_log_size = log_pos > sizeof(early_log_buf) ? sizeof(early_log_buf) : log_pos;
+ memcpy(log_buf, early_log_buf, early_log_size);
+ memset(log_buf + early_log_size, 0, LOG_BUF_LEN - early_log_size);
- 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);
+ pr_info("0x%08x map to 0x%p and copy to 0x%p, size 0x%x early 0x%x (version 3.0)\n", virt_to_phys(buf), log_buf, last_log_buf, LOG_BUF_LEN, early_log_size);
- entry = proc_create("last_log", S_IRUSR, NULL, &last_log_fops);
+ entry = proc_create("last_kmsg", 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
+ proc_symlink("last_log", NULL, "last_kmsg");
return 0;
}
-postcore_initcall(last_log_init);
+early_initcall(rk_last_log_init);
+
+void rk_last_log_text(char *text, size_t size)
+{
+ char *buf = log_buf ? log_buf : early_log_buf;
+ size_t log_size = log_buf ? LOG_BUF_LEN : sizeof(early_log_buf);
+ size_t pos;
+
+ /* Check overflow */
+ pos = log_pos & (log_size - 1);
+ if (likely(size + pos <= log_size))
+ memcpy(&buf[pos], text, size);
+ else {
+ size_t first = log_size - pos;
+ size_t second = size - first;
+ memcpy(&buf[pos], text, first);
+ memcpy(&buf[0], text + first, second);
+ }
+
+ log_pos += size;
+}
return idx + msg->len;
}
+#ifdef CONFIG_RK_LAST_LOG
+extern void rk_last_log_text(char *text, size_t size);
+static char rk_text[1024];
+static size_t msg_print_text(const struct log *msg, enum log_flags prev,
+ bool syslog, char *buf, size_t size);
+#endif
/* insert record into the buffer, discard old ones, update heads */
static void log_store(int facility, int level,
enum log_flags flags, u64 ts_nsec,
memset(log_dict(msg) + dict_len, 0, pad_len);
msg->len = sizeof(struct log) + text_len + dict_len + pad_len;
+#ifdef CONFIG_RK_LAST_LOG
+ size = msg_print_text(msg, msg->flags, true, rk_text, sizeof(rk_text));
+ rk_last_log_text(rk_text, size);
+#endif
/* insert message */
log_next_idx += msg->len;
log_next_seq++;
}
EXPORT_SYMBOL(printk);
-#ifdef CONFIG_RK_LAST_LOG
-void __init switch_log_buf(char *new_log_buf, unsigned size)
-{
- unsigned long flags;
-
- if (!new_log_buf || log_buf_len > size)
- return;
-
- raw_spin_lock_irqsave(&logbuf_lock, flags);
- memcpy(new_log_buf, log_buf, min(log_buf_len, size));
- log_buf = new_log_buf;
- log_buf_len = size;
- raw_spin_unlock_irqrestore(&logbuf_lock, flags);
-}
-#endif /* CONFIG_RK_LAST_LOG */
#if CONFIG_RK_DEBUG_UART >= 0
void console_disable_suspend(void)
{