]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/printk.c
r8169: convert bitfield to plain enum mask
[linux-2.6-omap-h63xx.git] / kernel / printk.c
index 5c7c325b29cc9ddc5e3f6cee6cfa73074ebacdbe..52493474f0abafdfd7939ab57f3f2d6ad2006695 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/tty_driver.h>
 #include <linux/console.h>
 #include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/nmi.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/interrupt.h>                   /* For in_interrupt() */
@@ -162,6 +164,113 @@ out:
 
 __setup("log_buf_len=", log_buf_len_setup);
 
+#ifdef CONFIG_BOOT_PRINTK_DELAY
+
+static unsigned int boot_delay; /* msecs delay after each printk during bootup */
+static unsigned long long printk_delay_msec; /* per msec, based on boot_delay */
+
+static int __init boot_delay_setup(char *str)
+{
+       unsigned long lpj;
+       unsigned long long loops_per_msec;
+
+       lpj = preset_lpj ? preset_lpj : 1000000;        /* some guess */
+       loops_per_msec = (unsigned long long)lpj / 1000 * HZ;
+
+       get_option(&str, &boot_delay);
+       if (boot_delay > 10 * 1000)
+               boot_delay = 0;
+
+       printk_delay_msec = loops_per_msec;
+       printk(KERN_DEBUG "boot_delay: %u, preset_lpj: %ld, lpj: %lu, "
+               "HZ: %d, printk_delay_msec: %llu\n",
+               boot_delay, preset_lpj, lpj, HZ, printk_delay_msec);
+       return 1;
+}
+__setup("boot_delay=", boot_delay_setup);
+
+static void boot_delay_msec(void)
+{
+       unsigned long long k;
+       unsigned long timeout;
+
+       if (boot_delay == 0 || system_state != SYSTEM_BOOTING)
+               return;
+
+       k = (unsigned long long)printk_delay_msec * boot_delay;
+
+       timeout = jiffies + msecs_to_jiffies(boot_delay);
+       while (k) {
+               k--;
+               cpu_relax();
+               /*
+                * use (volatile) jiffies to prevent
+                * compiler reduction; loop termination via jiffies
+                * is secondary and may or may not happen.
+                */
+               if (time_after(jiffies, timeout))
+                       break;
+               touch_nmi_watchdog();
+       }
+}
+#else
+static inline void boot_delay_msec(void)
+{
+}
+#endif
+
+/*
+ * Return the number of unread characters in the log buffer.
+ */
+int log_buf_get_len(void)
+{
+       return logged_chars;
+}
+
+/*
+ * Copy a range of characters from the log buffer.
+ */
+int log_buf_copy(char *dest, int idx, int len)
+{
+       int ret, max;
+       bool took_lock = false;
+
+       if (!oops_in_progress) {
+               spin_lock_irq(&logbuf_lock);
+               took_lock = true;
+       }
+
+       max = log_buf_get_len();
+       if (idx < 0 || idx >= max) {
+               ret = -1;
+       } else {
+               if (len > max)
+                       len = max;
+               ret = len;
+               idx += (log_end - max);
+               while (len-- > 0)
+                       dest[len] = LOG_BUF(idx + len);
+       }
+
+       if (took_lock)
+               spin_unlock_irq(&logbuf_lock);
+
+       return ret;
+}
+
+/*
+ * Extract a single character from the log buffer.
+ */
+int log_buf_read(int idx)
+{
+       char ret;
+
+       if (log_buf_copy(&ret, idx, 1) == 1)
+               return ret;
+       else
+               return -1;
+}
+
 /*
  * Commands to do_syslog:
  *
@@ -527,6 +636,8 @@ asmlinkage int vprintk(const char *fmt, va_list args)
        static char printk_buf[1024];
        static int log_level_unknown = 1;
 
+       boot_delay_msec();
+
        preempt_disable();
        if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id())
                /* If a crash is occurring during printk() on this CPU,
@@ -1085,10 +1196,12 @@ EXPORT_SYMBOL(unregister_console);
 
 static int __init disable_boot_consoles(void)
 {
-       if (console_drivers->flags & CON_BOOT) {
-               printk(KERN_INFO "turn off boot console %s%d\n",
-                       console_drivers->name, console_drivers->index);
-               return unregister_console(console_drivers);
+       if (console_drivers != NULL) {
+               if (console_drivers->flags & CON_BOOT) {
+                       printk(KERN_INFO "turn off boot console %s%d\n",
+                               console_drivers->name, console_drivers->index);
+                       return unregister_console(console_drivers);
+               }
        }
        return 0;
 }