Merge tag 'v3.10.78' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / kernel / printk.c
index abbdd9e2ac82c423a3dc6c778632c37887241b41..617bc0d08e2b77ae53b7b6ea28700f3298b9b891 100644 (file)
@@ -16,6 +16,7 @@
  *     01Mar01 Andrew Morton
  */
 
+
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/tty.h>
@@ -32,7 +33,9 @@
 #include <linux/security.h>
 #include <linux/bootmem.h>
 #include <linux/memblock.h>
+#include <linux/aio.h>
 #include <linux/syscalls.h>
+#include <linux/suspend.h>
 #include <linux/kexec.h>
 #include <linux/kdb.h>
 #include <linux/ratelimit.h>
 #include <linux/rculist.h>
 #include <linux/poll.h>
 #include <linux/irq_work.h>
+#include <linux/utsname.h>
+#include <linux/mt_sched_mon.h>
+#include <linux/aee.h>
 
 #include <asm/uaccess.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/printk.h>
 
-/*
- * Architectures can override it:
- */
-void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
-{
-}
+/* Some options {*/
+#define LOG_TOO_MUCH_WARNING
+#ifdef LOG_TOO_MUCH_WARNING
+static int log_in_resume;
+#endif
+/* Some options }*/
+#ifdef CONFIG_EARLY_PRINTK_DIRECT
+extern void printascii(char *);
+#endif
 
+bool printk_disable_uart = 0;
+static DEFINE_PER_CPU(char, printk_state);
 /* printk's without a loglevel use this.. */
 #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
 
 /* We show everything that is MORE important than this.. */
 #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
-#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */
+#define DEFAULT_CONSOLE_LOGLEVEL 6 /* anything MORE serious than KERN_INFO */
 
 int console_printk[4] = {
        DEFAULT_CONSOLE_LOGLEVEL,       /* console_loglevel */
@@ -69,6 +80,7 @@ int console_printk[4] = {
        MINIMUM_CONSOLE_LOGLEVEL,       /* minimum_console_loglevel */
        DEFAULT_CONSOLE_LOGLEVEL,       /* default_console_loglevel */
 };
+EXPORT_SYMBOL_GPL(console_printk);
 
 /*
  * Low level drivers may need that to know if they can schedule in
@@ -112,7 +124,7 @@ static struct console *exclusive_console;
  */
 struct console_cmdline
 {
-       char    name[8];                        /* Name of the driver       */
+       char    name[16];                       /* Name of the driver       */
        int     index;                          /* Minor dev. to use        */
        char    *options;                       /* Options for the driver   */
 #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
@@ -230,12 +242,12 @@ static enum log_flags syslog_prev;
 static size_t syslog_partial;
 
 /* index and sequence number of the first record stored in the buffer */
-static u64 log_first_seq;
-static u32 log_first_idx;
+/*static*/ u64 log_first_seq;
+/*static*/ u32 log_first_idx;
 
 /* index and sequence number of the next record to store in the buffer */
-static u64 log_next_seq;
-static u32 log_next_idx;
+/*static*/ u64 log_next_seq;
+/*static*/ u32 log_next_idx;
 
 /* the next printk record to write to the console */
 static u64 console_seq;
@@ -260,6 +272,31 @@ static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
 static char *log_buf = __log_buf;
 static u32 log_buf_len = __LOG_BUF_LEN;
 
+#ifdef CONFIG_MT_PRINTK_UART_CONSOLE
+
+extern int mt_need_uart_console;
+inline void mt_disable_uart()
+{
+    if (mt_need_uart_console == 0) {
+        printk("<< printk console disable >>\n");
+        printk_disable_uart = 1;
+    } else {
+        printk("<< printk console can't be disabled >>\n");
+    }
+}
+inline void mt_enable_uart()
+{
+    if (mt_need_uart_console == 1) {
+        if (printk_disable_uart == 0)
+            return;
+        printk_disable_uart = 0;
+        printk("<< printk console enable >>\n");
+    } else {
+        printk("<< printk console can't be enabled >>\n");
+    }
+}
+
+#endif
 /* cpu currently holding logbuf_lock */
 static volatile unsigned int logbuf_cpu = UINT_MAX;
 
@@ -315,9 +352,24 @@ static void log_store(int facility, int level,
 {
        struct log *msg;
        u32 size, pad_len;
-
+    int this_cpu = smp_processor_id();
+    char state = __raw_get_cpu_var(printk_state);
+    if (state == 0) {
+       __raw_get_cpu_var(printk_state) = ' ';
+       state = ' ';
+    }
+    /*printk prefix {*/
+    char tbuf[50];
+    unsigned tlen;
+    if (console_suspended == 0) {
+       tlen = snprintf(tbuf, sizeof(tbuf), "%c(%x)[%d:%s]",
+               state, this_cpu, current->pid, current->comm); 
+    } else {
+        tlen = snprintf(tbuf, sizeof(tbuf), "%c%x)", state, this_cpu);
+    }
+    /*printk prefix }*/
        /* number of '\0' padding bytes to next message */
-       size = sizeof(struct log) + text_len + dict_len;
+       size = sizeof(struct log) + text_len +tlen + dict_len;
        pad_len = (-size) & (LOG_ALIGN - 1);
        size += pad_len;
 
@@ -349,7 +401,10 @@ static void log_store(int facility, int level,
 
        /* fill message */
        msg = (struct log *)(log_buf + log_next_idx);
-       memcpy(log_text(msg), text, text_len);
+       //memcpy(log_text(msg), text, text_len);
+    memcpy(log_text(msg), tbuf, tlen);
+       memcpy(log_text(msg) + tlen, text, text_len);
+    text_len += tlen;
        msg->text_len = text_len;
        memcpy(log_dict(msg), dict, dict_len);
        msg->dict_len = dict_len;
@@ -368,6 +423,53 @@ static void log_store(int facility, int level,
        log_next_seq++;
 }
 
+#ifdef CONFIG_SECURITY_DMESG_RESTRICT
+int dmesg_restrict = 1;
+#else
+int dmesg_restrict;
+#endif
+
+static int syslog_action_restricted(int type)
+{
+       if (dmesg_restrict)
+               return 1;
+       /*
+        * Unless restricted, we allow "read all" and "get buffer size"
+        * for everybody.
+        */
+       return type != SYSLOG_ACTION_READ_ALL &&
+              type != SYSLOG_ACTION_SIZE_BUFFER;
+}
+
+static int check_syslog_permissions(int type, bool from_file)
+{
+       /*
+        * If this is from /proc/kmsg and we've already opened it, then we've
+        * already done the capabilities checks at open time.
+        */
+       if (from_file && type != SYSLOG_ACTION_OPEN)
+               return 0;
+
+       if (syslog_action_restricted(type)) {
+               if (capable(CAP_SYSLOG))
+                       return 0;
+               /*
+                * For historical reasons, accept CAP_SYS_ADMIN too, with
+                * a warning.
+                */
+               if (capable(CAP_SYS_ADMIN)) {
+                       pr_warn_once("%s (%d): Attempt to access syslog with "
+                                    "CAP_SYS_ADMIN but no CAP_SYSLOG "
+                                    "(deprecated).\n",
+                                current->comm, task_pid_nr(current));
+                       return 0;
+               }
+               return -EPERM;
+       }
+       return security_syslog(type);
+}
+
+
 /* /dev/kmsg - userspace message inject/listen interface */
 struct devkmsg_user {
        u64 seq;
@@ -608,7 +710,8 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
                /* return error when data has vanished underneath us */
                if (user->seq < log_first_seq)
                        ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;
-               ret = POLLIN|POLLRDNORM;
+               else
+                       ret = POLLIN|POLLRDNORM;
        }
        raw_spin_unlock_irq(&logbuf_lock);
 
@@ -624,7 +727,8 @@ static int devkmsg_open(struct inode *inode, struct file *file)
        if ((file->f_flags & O_ACCMODE) == O_WRONLY)
                return 0;
 
-       err = security_syslog(SYSLOG_ACTION_READ_ALL);
+       err = check_syslog_permissions(SYSLOG_ACTION_READ_ALL,
+                                      SYSLOG_FROM_READER);
        if (err)
                return err;
 
@@ -817,51 +921,13 @@ static inline void boot_delay_msec(int level)
 }
 #endif
 
-#ifdef CONFIG_SECURITY_DMESG_RESTRICT
-int dmesg_restrict = 1;
-#else
-int dmesg_restrict;
-#endif
-
-static int syslog_action_restricted(int type)
-{
-       if (dmesg_restrict)
-               return 1;
-       /* Unless restricted, we allow "read all" and "get buffer size" for everybody */
-       return type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER;
-}
-
-static int check_syslog_permissions(int type, bool from_file)
-{
-       /*
-        * If this is from /proc/kmsg and we've already opened it, then we've
-        * already done the capabilities checks at open time.
-        */
-       if (from_file && type != SYSLOG_ACTION_OPEN)
-               return 0;
-
-       if (syslog_action_restricted(type)) {
-               if (capable(CAP_SYSLOG))
-                       return 0;
-               /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */
-               if (capable(CAP_SYS_ADMIN)) {
-                       printk_once(KERN_WARNING "%s (%d): "
-                                "Attempt to access syslog with CAP_SYS_ADMIN "
-                                "but no CAP_SYSLOG (deprecated).\n",
-                                current->comm, task_pid_nr(current));
-                       return 0;
-               }
-               return -EPERM;
-       }
-       return 0;
-}
-
 #if defined(CONFIG_PRINTK_TIME)
 static bool printk_time = 1;
 #else
 static bool printk_time;
 #endif
 module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
+module_param_named(disable_uart, printk_disable_uart, bool, S_IRUGO | S_IWUSR);
 
 static size_t print_time(u64 ts, char *buf)
 {
@@ -873,9 +939,9 @@ static size_t print_time(u64 ts, char *buf)
        rem_nsec = do_div(ts, 1000000000);
 
        if (!buf)
-               return snprintf(NULL, 0, "[%5lu.000000] ", (unsigned long)ts);
+               return snprintf(NULL, 0, "[%5lu.000000]", (unsigned long)ts);
 
-       return sprintf(buf, "[%5lu.%06lu] ",
+       return sprintf(buf, "[%5lu.%06lu]",
                       (unsigned long)ts, rem_nsec / 1000);
 }
 
@@ -1253,7 +1319,7 @@ out:
 
 SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
 {
-       return do_syslog(type, buf, len, SYSLOG_FROM_CALL);
+       return do_syslog(type, buf, len, SYSLOG_FROM_READER);
 }
 
 /*
@@ -1265,7 +1331,7 @@ static void call_console_drivers(int level, const char *text, size_t len)
 {
        struct console *con;
 
-       trace_console(text, 0, len, len);
+       trace_console(text, len);
 
        if (level >= console_loglevel && !ignore_loglevel)
                return;
@@ -1273,6 +1339,8 @@ static void call_console_drivers(int level, const char *text, size_t len)
                return;
 
        for_each_console(con) {
+        if (printk_disable_uart && (con->flags & CON_CONSDEV))
+            continue;
                if (exclusive_console && con != exclusive_console)
                        continue;
                if (!(con->flags & CON_ENABLED))
@@ -1364,9 +1432,9 @@ static int console_trylock_for_printk(unsigned int cpu)
                }
        }
        logbuf_cpu = UINT_MAX;
+       raw_spin_unlock(&logbuf_lock);
        if (wake)
                up(&console_sem);
-       raw_spin_unlock(&logbuf_lock);
        return retval;
 }
 
@@ -1500,7 +1568,11 @@ asmlinkage int vprintk_emit(int facility, int level,
        unsigned long flags;
        int this_cpu;
        int printed_len = 0;
-
+    int in_irq_disable, in_non_preempt;
+    in_irq_disable = irqs_disabled();
+    in_non_preempt = in_atomic();
+       vscnprintf(text, sizeof(textbuf), fmt, args);
+       memset(text, 0x0, sizeof(textbuf));
        boot_delay_msec(level);
        printk_delay();
 
@@ -1573,12 +1645,27 @@ asmlinkage int vprintk_emit(int facility, int level,
                }
        }
 
+#ifdef CONFIG_EARLY_PRINTK_DIRECT
+       printascii(text);
+#endif
+
        if (level == -1)
                level = default_message_loglevel;
 
        if (dict)
                lflags |= LOG_PREFIX|LOG_NEWLINE;
-
+        
+#ifdef CONFIG_PRINTK_PROCESS_INFO
+    if (in_irq_disable)
+        __raw_get_cpu_var(printk_state) = '-';
+#ifdef CONFIG_MT_PRINTK_UART_CONSOLE
+    else if (printk_disable_uart == 0)
+        __raw_get_cpu_var(printk_state) = '.';
+#endif
+    else
+        __raw_get_cpu_var(printk_state) = ' ';
+#endif
+       
        if (!(lflags & LOG_NEWLINE)) {
                /*
                 * Flush the conflicting buffer. An earlier newline was missing,
@@ -1723,6 +1810,29 @@ static size_t cont_print_text(char *text, size_t size) { return 0; }
 
 #endif /* CONFIG_PRINTK */
 
+#ifdef CONFIG_EARLY_PRINTK
+struct console *early_console;
+
+void early_vprintk(const char *fmt, va_list ap)
+{
+       if (early_console) {
+               char buf[512];
+               int n = vscnprintf(buf, sizeof(buf), fmt, ap);
+
+               early_console->write(early_console, buf, n);
+       }
+}
+
+asmlinkage void early_printk(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       early_vprintk(fmt, ap);
+       va_end(ap);
+}
+#endif
+
 static int __add_preferred_console(char *name, int idx, char *options,
                                   char *brl_options)
 {
@@ -1871,16 +1981,28 @@ void suspend_console(void)
        console_lock();
        console_suspended = 1;
        up(&console_sem);
+       mutex_release(&console_lock_dep_map, 1, _RET_IP_);
 }
+EXPORT_SYMBOL_GPL(suspend_console);
 
 void resume_console(void)
 {
        if (!console_suspend_enabled)
                return;
        down(&console_sem);
+       mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_);
        console_suspended = 0;
-       console_unlock();
+#ifdef LOG_TOO_MUCH_WARNING
+//    __raw_get_cpu_var(MT_trace_in_resume_console) = 1;
+//    log_in_resume = 1;
+    console_unlock();
+//    log_in_resume = 0;
+//    __raw_get_cpu_var(MT_trace_in_resume_console) = 0;
+#else
+    console_unlock();
+#endif
 }
+EXPORT_SYMBOL_GPL(resume_console);
 
 /**
  * console_cpu_notify - print deferred console messages after CPU hotplug
@@ -1999,6 +2121,10 @@ out:
  *
  * console_unlock(); may be called from any context.
  */
+#ifdef LOG_TOO_MUCH_WARNING
+static int console_log_max = 400000;
+static int already_skip_log;
+#endif
 void console_unlock(void)
 {
        static char text[LOG_LINE_MAX + PREFIX_MAX];
@@ -2006,6 +2132,12 @@ void console_unlock(void)
        unsigned long flags;
        bool wake_klogd = false;
        bool retry;
+#ifdef LOG_TOO_MUCH_WARNING
+    unsigned long total_log_size = 0;
+    unsigned long long t1 = 0, t2 = 0;
+    char aee_str[512];
+    int org_loglevel = console_loglevel;
+#endif
 
        if (console_suspended) {
                up(&console_sem);
@@ -2023,6 +2155,12 @@ again:
                int level;
 
                raw_spin_lock_irqsave(&logbuf_lock, flags);
+#ifdef LOG_TOO_MUCH_WARNING /*For Resume log too much*/
+        if (log_in_resume) {
+            t1 = sched_clock();
+        }
+#endif
+
                if (seen_seq != log_next_seq) {
                        wake_klogd = true;
                        seen_seq = log_next_seq;
@@ -2065,8 +2203,41 @@ skip:
                raw_spin_unlock(&logbuf_lock);
 
                stop_critical_timings();        /* don't trace print latency */
-               call_console_drivers(level, text, len);
-               start_critical_timings();
+#ifdef LOG_TOO_MUCH_WARNING
+        /*
+           For uart console, 10us/per chars
+           400,000 chars = need to wait 4.0 sec
+                normal case: 4sec
+         */
+        if (log_in_resume) {
+            org_loglevel = console_loglevel;
+            console_loglevel = 4;
+        }
+        total_log_size += len;
+        if (total_log_size < console_log_max)
+                   call_console_drivers(level, text, len);
+        else if (!already_skip_log) {
+            sprintf(aee_str, "PRINTK too much:%lu", total_log_size);
+            aee_kernel_warning(aee_str, "Need to shrink kernel log");
+            already_skip_log = 1;
+        }
+        /**/
+        start_critical_timings();
+        /* For Resume log too much*/
+        if (log_in_resume) {
+            t2 = sched_clock();
+            console_loglevel = org_loglevel;
+            if (t2 - t1 > 100000000) {
+                sprintf( aee_str,"[RESUME CONSOLE too long:%lluns>100ms] s:%lluns, e:%lluns\n", t2 - t1, t1, t2);
+                aee_kernel_warning(aee_str, "Need to shrink kernel log");
+            }
+        }
+
+        /**/
+#else
+        start_critical_timings();
+        call_console_drivers(level, text, len);
+#endif
                local_irq_restore(flags);
        }
        console_locked = 0;
@@ -2262,6 +2433,8 @@ void register_console(struct console *newcon)
         */
        for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
                        i++) {
+               BUILD_BUG_ON(sizeof(console_cmdline[i].name) !=
+                            sizeof(newcon->name));
                if (strcmp(console_cmdline[i].name, newcon->name) != 0)
                        continue;
                if (newcon->index >= 0 &&
@@ -2428,6 +2601,7 @@ late_initcall(printk_late_init);
 
 static DEFINE_PER_CPU(int, printk_pending);
 static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf);
+static DEFINE_PER_CPU(int, printk_sched_length);
 
 static void wake_up_klogd_work_func(struct irq_work *irq_work)
 {
@@ -2435,7 +2609,10 @@ static void wake_up_klogd_work_func(struct irq_work *irq_work)
 
        if (pending & PRINTK_PENDING_SCHED) {
                char *buf = __get_cpu_var(printk_sched_buf);
-               printk(KERN_WARNING "[sched_delayed] %s", buf);
+               printk(KERN_WARNING "[printk_delayed:start]\n");
+               printk(KERN_WARNING "%s", buf);
+               printk(KERN_WARNING "[printk_delayed:done]\n");
+    __get_cpu_var(printk_sched_length) = 0;
        }
 
        if (pending & PRINTK_PENDING_WAKEUP)
@@ -2457,18 +2634,25 @@ void wake_up_klogd(void)
        preempt_enable();
 }
 
-int printk_sched(const char *fmt, ...)
+int printk_deferred(const char *fmt, ...)
 {
        unsigned long flags;
        va_list args;
        char *buf;
        int r;
-
+    int buf_length;
        local_irq_save(flags);
        buf = __get_cpu_var(printk_sched_buf);
+    buf_length = __get_cpu_var(printk_sched_length);
 
        va_start(args, fmt);
-       r = vsnprintf(buf, PRINTK_BUF_SIZE, fmt, args);
+    if(PRINTK_BUF_SIZE >= buf_length){
+           r = vsnprintf((buf_length + buf), PRINTK_BUF_SIZE-buf_length, fmt, args);
+        __get_cpu_var(printk_sched_length) += r;
+    }else{
+        printk("delayed log buf overflow,  size:%d\n", buf_length);
+        r = 0;
+    }
        va_end(args);
 
        __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED);
@@ -2832,4 +3016,71 @@ void kmsg_dump_rewind(struct kmsg_dumper *dumper)
        raw_spin_unlock_irqrestore(&logbuf_lock, flags);
 }
 EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
+
+static char dump_stack_arch_desc_str[128];
+
+/**
+ * dump_stack_set_arch_desc - set arch-specific str to show with task dumps
+ * @fmt: printf-style format string
+ * @...: arguments for the format string
+ *
+ * The configured string will be printed right after utsname during task
+ * dumps.  Usually used to add arch-specific system identifiers.  If an
+ * arch wants to make use of such an ID string, it should initialize this
+ * as soon as possible during boot.
+ */
+void __init dump_stack_set_arch_desc(const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       vsnprintf(dump_stack_arch_desc_str, sizeof(dump_stack_arch_desc_str),
+                 fmt, args);
+       va_end(args);
+}
+
+/**
+ * dump_stack_print_info - print generic debug info for dump_stack()
+ * @log_lvl: log level
+ *
+ * Arch-specific dump_stack() implementations can use this function to
+ * print out the same debug information as the generic dump_stack().
+ */
+void dump_stack_print_info(const char *log_lvl)
+{
+       printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\n",
+              log_lvl, raw_smp_processor_id(), current->pid, current->comm,
+              print_tainted(), init_utsname()->release,
+              (int)strcspn(init_utsname()->version, " "),
+              init_utsname()->version);
+
+       if (dump_stack_arch_desc_str[0] != '\0')
+               printk("%sHardware name: %s\n",
+                      log_lvl, dump_stack_arch_desc_str);
+
+       print_worker_info(log_lvl, current);
+}
+
+/**
+ * show_regs_print_info - print generic debug info for show_regs()
+ * @log_lvl: log level
+ *
+ * show_regs() implementations can use this function to print out generic
+ * debug information.
+ */
+void show_regs_print_info(const char *log_lvl)
+{
+       dump_stack_print_info(log_lvl);
+
+       printk("%stask: %p ti: %p task.ti: %p\n",
+              log_lvl, current, current_thread_info(),
+              task_thread_info(current));
+}
+
+void get_kernel_log_buffer(unsigned long *addr, unsigned long *size, unsigned long *start)
+{
+       *addr = (unsigned long)log_buf;
+       *size = log_buf_len;
+       *start = (unsigned long)&log_first_idx;
+}
 #endif