From e3e12f52b214121840b44c91de5b3e5af5d3eb84 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 06 Nov 2023 03:04:41 +0000
Subject: [PATCH] rk3568 rt init

---
 kernel/kernel/printk/printk.c |  157 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 134 insertions(+), 23 deletions(-)

diff --git a/kernel/kernel/printk/printk.c b/kernel/kernel/printk/printk.c
index a1f5484..611c7c9 100644
--- a/kernel/kernel/printk/printk.c
+++ b/kernel/kernel/printk/printk.c
@@ -429,6 +429,65 @@
 		printk_safe_exit_irqrestore(flags);	\
 	} while (0)
 
+#ifdef CONFIG_EARLY_PRINTK
+struct console *early_console;
+
+static 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);
+}
+
+/*
+ * This is independent of any log levels - a global
+ * kill switch that turns off all of printk.
+ *
+ * Used by the NMI watchdog if early-printk is enabled.
+ */
+static bool __read_mostly printk_killswitch;
+
+static int __init force_early_printk_setup(char *str)
+{
+	printk_killswitch = true;
+	return 0;
+}
+early_param("force_early_printk", force_early_printk_setup);
+
+void printk_kill(void)
+{
+	printk_killswitch = true;
+}
+
+#ifdef CONFIG_PRINTK
+static int forced_early_printk(const char *fmt, va_list ap)
+{
+	if (!printk_killswitch)
+		return 0;
+	early_vprintk(fmt, ap);
+	return 1;
+}
+#endif
+
+#else
+static inline int forced_early_printk(const char *fmt, va_list ap)
+{
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_PRINTK
 DECLARE_WAIT_QUEUE_HEAD(log_wait);
 /* the next printk record to read by syslog(READ) or /proc/kmsg */
@@ -1517,12 +1576,23 @@
 	u64 next_seq;
 	u64 seq;
 	u32 idx;
+	int attempts = 0;
+	int num_msg;
 
 	text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL);
 	if (!text)
 		return -ENOMEM;
 
 	logbuf_lock_irq();
+
+try_again:
+	attempts++;
+	if (attempts > 10) {
+		len = -EBUSY;
+		goto out;
+	}
+	num_msg = 0;
+
 	/*
 	 * Find first record that fits, including all following records,
 	 * into the user-provided buffer for this dump.
@@ -1535,6 +1605,14 @@
 		len += msg_print_text(msg, true, NULL, 0);
 		idx = log_next(idx);
 		seq++;
+		num_msg++;
+		if (num_msg > 5) {
+			num_msg = 0;
+			logbuf_unlock_irq();
+			logbuf_lock_irq();
+			if (clear_seq < log_first_seq)
+				goto try_again;
+		}
 	}
 
 	/* move first record forward until length fits into the buffer */
@@ -1546,6 +1624,14 @@
 		len -= msg_print_text(msg, true, NULL, 0);
 		idx = log_next(idx);
 		seq++;
+		num_msg++;
+		if (num_msg > 5) {
+			num_msg = 0;
+			logbuf_unlock_irq();
+			logbuf_lock_irq();
+			if (clear_seq < log_first_seq)
+				goto try_again;
+		}
 	}
 
 	/* last message fitting into this dump */
@@ -1583,6 +1669,7 @@
 		clear_seq = log_next_seq;
 		clear_idx = log_next_idx;
 	}
+out:
 	logbuf_unlock_irq();
 
 	kfree(text);
@@ -1714,6 +1801,7 @@
 	return do_syslog(type, buf, len, SYSLOG_FROM_READER);
 }
 
+#ifndef CONFIG_PREEMPT_RT_FULL
 /*
  * Special console_lock variants that help to reduce the risk of soft-lockups.
  * They allow to pass console_lock to another printk() call using a busy wait.
@@ -1854,6 +1942,15 @@
 	return 1;
 }
 
+#else
+
+static int console_trylock_spinning(void)
+{
+	return console_trylock();
+}
+
+#endif
+
 /*
  * Call the console drivers, asking them to write out
  * log_buf[start] to log_buf[end - 1].
@@ -1872,6 +1969,12 @@
 	if (!console_drivers)
 		return;
 
+	if (IS_ENABLED(CONFIG_PREEMPT_RT_BASE)) {
+		if (in_irq() || in_nmi())
+			return;
+	}
+
+	migrate_disable();
 	for_each_console(con) {
 		if (exclusive_console && con != exclusive_console)
 			continue;
@@ -1887,6 +1990,7 @@
 		else
 			con->write(con, text, len);
 	}
+	migrate_enable();
 }
 
 int printk_delay_msec __read_mostly;
@@ -2057,6 +2161,13 @@
 	unsigned long flags;
 	u64 curr_log_seq;
 
+	/*
+	 * Fall back to early_printk if a debugging subsystem has
+	 * killed printk output
+	 */
+	if (unlikely(forced_early_printk(fmt, args)))
+		return 1;
+
 	if (level == LOGLEVEL_SCHED) {
 		level = LOGLEVEL_DEFAULT;
 		in_sched = true;
@@ -2074,20 +2185,30 @@
 
 	/* If called from the scheduler, we can not call up(). */
 	if (!in_sched && pending_output) {
+		int may_trylock = 1;
+
+#ifdef CONFIG_PREEMPT_RT_FULL
+		/*
+		 * we can't take a sleeping lock with IRQs or preeption disabled
+		 * so we can't print in these contexts
+		 */
+		if (!(preempt_count() == 0 && !irqs_disabled()))
+			may_trylock = 0;
+#endif
 		/*
 		 * Disable preemption to avoid being preempted while holding
 		 * console_sem which would prevent anyone from printing to
 		 * console
 		 */
-		preempt_disable();
+		migrate_disable();
 		/*
 		 * Try to acquire and then immediately release the console
 		 * semaphore.  The release will print out buffers and wake up
 		 * /dev/kmsg and syslog() users.
 		 */
-		if (console_trylock_spinning())
+		if (may_trylock && console_trylock_spinning())
 			console_unlock();
-		preempt_enable();
+		migrate_enable();
 	}
 
 	if (pending_output)
@@ -2200,26 +2321,6 @@
 static bool suppress_message_printing(int level) { return false; }
 
 #endif /* CONFIG_PRINTK */
-
-#ifdef CONFIG_EARLY_PRINTK
-struct console *early_console;
-
-asmlinkage __visible void early_printk(const char *fmt, ...)
-{
-	va_list ap;
-	char buf[512];
-	int n;
-
-	if (!early_console)
-		return;
-
-	va_start(ap, fmt);
-	n = vscnprintf(buf, sizeof(buf), fmt, ap);
-	va_end(ap);
-
-	early_console->write(early_console, buf, n);
-}
-#endif
 
 static int __add_preferred_console(char *name, int idx, char *options,
 				   char *brl_options)
@@ -2579,6 +2680,10 @@
 		console_seq++;
 		raw_spin_unlock(&logbuf_lock);
 
+#ifdef CONFIG_PREEMPT_RT_FULL
+		printk_safe_exit_irqrestore(flags);
+		call_console_drivers(ext_text, ext_len, text, len);
+#else
 		/*
 		 * While actively printing out messages, if another printk()
 		 * were to occur on another CPU, it may wait for this one to
@@ -2601,6 +2706,7 @@
 		}
 
 		printk_safe_exit_irqrestore(flags);
+#endif
 
 		if (do_cond_resched)
 			cond_resched();
@@ -2648,6 +2754,11 @@
 {
 	struct console *c;
 
+	if (IS_ENABLED(CONFIG_PREEMPT_RT_BASE)) {
+		if (in_irq() || in_nmi())
+			return;
+	}
+
 	/*
 	 * console_unblank can no longer be called in interrupt context unless
 	 * oops_in_progress is set to 1..

--
Gitblit v1.6.2