* 01Mar01 Andrew Morton
*/
+
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/tty.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/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>
+/* 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 */
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
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;
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;
{
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;
/* 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;
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)
{
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);
}
{
struct console *con;
- trace_console(text, len);
+ trace_console_rcuidle(text, len);
if (level >= console_loglevel && !ignore_loglevel)
return;
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))
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();
}
}
+#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,
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
*
* 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];
unsigned long flags;
bool wake_klogd = false;
bool do_cond_resched, 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);
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;
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);
if (do_cond_resched)
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)
{
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)
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);
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