Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile
[pandora-kernel.git] / kernel / printk.c
index da8ca81..3518539 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/smp.h>
 #include <linux/security.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/syscalls.h>
 #include <linux/kexec.h>
 #include <linux/kdb.h>
@@ -167,46 +168,74 @@ void log_buf_kexec_setup(void)
 }
 #endif
 
+/* requested log_buf_len from kernel cmdline */
+static unsigned long __initdata new_log_buf_len;
+
+/* save requested log_buf_len since it's too early to process it */
 static int __init log_buf_len_setup(char *str)
 {
        unsigned size = memparse(str, &str);
-       unsigned long flags;
 
        if (size)
                size = roundup_pow_of_two(size);
-       if (size > log_buf_len) {
-               unsigned start, dest_idx, offset;
-               char *new_log_buf;
+       if (size > log_buf_len)
+               new_log_buf_len = size;
 
-               new_log_buf = alloc_bootmem(size);
-               if (!new_log_buf) {
-                       printk(KERN_WARNING "log_buf_len: allocation failed\n");
-                       goto out;
-               }
+       return 0;
+}
+early_param("log_buf_len", log_buf_len_setup);
 
-               spin_lock_irqsave(&logbuf_lock, flags);
-               log_buf_len = size;
-               log_buf = new_log_buf;
-
-               offset = start = min(con_start, log_start);
-               dest_idx = 0;
-               while (start != log_end) {
-                       log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)];
-                       start++;
-                       dest_idx++;
-               }
-               log_start -= offset;
-               con_start -= offset;
-               log_end -= offset;
-               spin_unlock_irqrestore(&logbuf_lock, flags);
+void __init setup_log_buf(int early)
+{
+       unsigned long flags;
+       unsigned start, dest_idx, offset;
+       char *new_log_buf;
+       int free;
+
+       if (!new_log_buf_len)
+               return;
+
+       if (early) {
+               unsigned long mem;
 
-               printk(KERN_NOTICE "log_buf_len: %d\n", log_buf_len);
+               mem = memblock_alloc(new_log_buf_len, PAGE_SIZE);
+               if (mem == MEMBLOCK_ERROR)
+                       return;
+               new_log_buf = __va(mem);
+       } else {
+               new_log_buf = alloc_bootmem_nopanic(new_log_buf_len);
        }
-out:
-       return 1;
-}
 
-__setup("log_buf_len=", log_buf_len_setup);
+       if (unlikely(!new_log_buf)) {
+               pr_err("log_buf_len: %ld bytes not available\n",
+                       new_log_buf_len);
+               return;
+       }
+
+       spin_lock_irqsave(&logbuf_lock, flags);
+       log_buf_len = new_log_buf_len;
+       log_buf = new_log_buf;
+       new_log_buf_len = 0;
+       free = __LOG_BUF_LEN - log_end;
+
+       offset = start = min(con_start, log_start);
+       dest_idx = 0;
+       while (start != log_end) {
+               unsigned log_idx_mask = start & (__LOG_BUF_LEN - 1);
+
+               log_buf[dest_idx] = __log_buf[log_idx_mask];
+               start++;
+               dest_idx++;
+       }
+       log_start -= offset;
+       con_start -= offset;
+       log_end -= offset;
+       spin_unlock_irqrestore(&logbuf_lock, flags);
+
+       pr_info("log_buf_len: %d\n", log_buf_len);
+       pr_info("early log buf free: %d(%d%%)\n",
+               free, (free * 100) / __LOG_BUF_LEN);
+}
 
 #ifdef CONFIG_BOOT_PRINTK_DELAY