aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2016-09-22 11:55:13 +0200
committerPeter Zijlstra <peterz@infradead.org>2023-11-29 09:22:04 +0100
commit06e4529f78bc08293fe8b459715e5aa24cd3ebb7 (patch)
tree37fe7d9d4b9587008cdffb3dc928ee5e3d51b7ed
parent84628b60f98e97c85be54273bf529452a88e5dc8 (diff)
downloadqueue-debug/experimental.tar.gz
early_printk: Add simple serialization to early_vprintk()debug/experimental
In order to avoid multiple CPUs banging on the serial port at the same time, add simple serialization. This explicitly deals with nested contexts (like IRQs etc.). Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
-rw-r--r--kernel/printk/printk.c35
1 files changed, 34 insertions, 1 deletions
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 8908142cbe3bda..c64f365a9896d8 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -72,14 +72,47 @@ static int __init force_early_printk_setup(char *str)
}
early_param("force_early_printk", force_early_printk_setup);
+static int early_printk_cpu = -1;
+
static int early_vprintk(const char *fmt, va_list args)
{
+ int n, cpu, old;
char buf[512];
- int n;
+
+ cpu = get_cpu();
+ /*
+ * Test-and-Set inter-cpu spinlock with recursion.
+ */
+ for (;;) {
+ /*
+ * c-cas to avoid the exclusive bouncing on spin.
+ * Depends on the memory barrier implied by cmpxchg
+ * for ACQUIRE semantics.
+ */
+ old = READ_ONCE(early_printk_cpu);
+ if (old == -1) {
+ old = cmpxchg(&early_printk_cpu, -1, cpu);
+ if (old == -1)
+ break;
+ }
+ /*
+ * Allow recursion for interrupts and the like.
+ */
+ if (old == cpu)
+ break;
+
+ cpu_relax();
+ }
n = vscnprintf(buf, sizeof(buf), fmt, args);
early_console->write(early_console, buf, n);
+ /*
+ * Unlock -- in case @old == @cpu, this is a no-op.
+ */
+ smp_store_release(&early_printk_cpu, old);
+ put_cpu();
+
return n;
}