diff options
author | Peter Zijlstra <peterz@infradead.org> | 2016-09-22 11:55:13 +0200 |
---|---|---|
committer | Peter Zijlstra <peterz@infradead.org> | 2023-11-29 09:22:04 +0100 |
commit | 06e4529f78bc08293fe8b459715e5aa24cd3ebb7 (patch) | |
tree | 37fe7d9d4b9587008cdffb3dc928ee5e3d51b7ed | |
parent | 84628b60f98e97c85be54273bf529452a88e5dc8 (diff) | |
download | queue-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.c | 35 |
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; } |