aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlistair Popple <alistair@popple.id.au>2013-04-29 14:07:47 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-05-07 16:36:49 -0400
commit30650239adc9e4e9439256d6988e521518dccbb3 (patch)
tree2a4879c3742d62ea14dc3584988acbe0a10f6669
parent5737789c8340620d7b542d1d4e9b197de8eb2801 (diff)
powerpc: Add an in memory udbg console
This patch adds a new udbg early debug console which utilises statically defined input and output buffers stored within the kernel BSS. It is primarily designed to assist with bring up of new hardware which may not have a working console but which has a method of reading/writing kernel memory. This version incorporates comments made by Ben H (thanks!). Changes from v1: - Add memory barriers. - Ensure updating of read/write positions is atomic. Signed-off-by: Alistair Popple <alistair@popple.id.au> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/Kconfig.debug23
-rw-r--r--arch/powerpc/include/asm/udbg.h1
-rw-r--r--arch/powerpc/kernel/udbg.c3
-rw-r--r--arch/powerpc/sysdev/Makefile2
-rw-r--r--arch/powerpc/sysdev/udbg_memcons.c105
5 files changed, 134 insertions, 0 deletions
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index 5416e28a7538..863d877e0b5f 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -262,8 +262,31 @@ config PPC_EARLY_DEBUG_OPAL_HVSI
262 Select this to enable early debugging for the PowerNV platform 262 Select this to enable early debugging for the PowerNV platform
263 using an "hvsi" console 263 using an "hvsi" console
264 264
265config PPC_EARLY_DEBUG_MEMCONS
266 bool "In memory console"
267 help
268 Select this to enable early debugging using an in memory console.
269 This console provides input and output buffers stored within the
270 kernel BSS and should be safe to select on any system. A debugger
271 can then be used to read kernel output or send input to the console.
265endchoice 272endchoice
266 273
274config PPC_MEMCONS_OUTPUT_SIZE
275 int "In memory console output buffer size"
276 depends on PPC_EARLY_DEBUG_MEMCONS
277 default 4096
278 help
279 Selects the size of the output buffer (in bytes) of the in memory
280 console.
281
282config PPC_MEMCONS_INPUT_SIZE
283 int "In memory console input buffer size"
284 depends on PPC_EARLY_DEBUG_MEMCONS
285 default 128
286 help
287 Selects the size of the input buffer (in bytes) of the in memory
288 console.
289
267config PPC_EARLY_DEBUG_OPAL 290config PPC_EARLY_DEBUG_OPAL
268 def_bool y 291 def_bool y
269 depends on PPC_EARLY_DEBUG_OPAL_RAW || PPC_EARLY_DEBUG_OPAL_HVSI 292 depends on PPC_EARLY_DEBUG_OPAL_RAW || PPC_EARLY_DEBUG_OPAL_HVSI
diff --git a/arch/powerpc/include/asm/udbg.h b/arch/powerpc/include/asm/udbg.h
index 5a7510e9d09d..dc590919f8eb 100644
--- a/arch/powerpc/include/asm/udbg.h
+++ b/arch/powerpc/include/asm/udbg.h
@@ -52,6 +52,7 @@ extern void __init udbg_init_40x_realmode(void);
52extern void __init udbg_init_cpm(void); 52extern void __init udbg_init_cpm(void);
53extern void __init udbg_init_usbgecko(void); 53extern void __init udbg_init_usbgecko(void);
54extern void __init udbg_init_wsp(void); 54extern void __init udbg_init_wsp(void);
55extern void __init udbg_init_memcons(void);
55extern void __init udbg_init_ehv_bc(void); 56extern void __init udbg_init_ehv_bc(void);
56extern void __init udbg_init_ps3gelic(void); 57extern void __init udbg_init_ps3gelic(void);
57extern void __init udbg_init_debug_opal_raw(void); 58extern void __init udbg_init_debug_opal_raw(void);
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index 13b867093499..9d3fdcd66290 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -64,6 +64,9 @@ void __init udbg_early_init(void)
64 udbg_init_usbgecko(); 64 udbg_init_usbgecko();
65#elif defined(CONFIG_PPC_EARLY_DEBUG_WSP) 65#elif defined(CONFIG_PPC_EARLY_DEBUG_WSP)
66 udbg_init_wsp(); 66 udbg_init_wsp();
67#elif defined(CONFIG_PPC_EARLY_DEBUG_MEMCONS)
68 /* In memory console */
69 udbg_init_memcons();
67#elif defined(CONFIG_PPC_EARLY_DEBUG_EHV_BC) 70#elif defined(CONFIG_PPC_EARLY_DEBUG_EHV_BC)
68 udbg_init_ehv_bc(); 71 udbg_init_ehv_bc();
69#elif defined(CONFIG_PPC_EARLY_DEBUG_PS3GELIC) 72#elif defined(CONFIG_PPC_EARLY_DEBUG_PS3GELIC)
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index b0a518e97599..99464a7bdb3b 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -64,6 +64,8 @@ endif
64 64
65obj-$(CONFIG_PPC_SCOM) += scom.o 65obj-$(CONFIG_PPC_SCOM) += scom.o
66 66
67obj-$(CONFIG_PPC_EARLY_DEBUG_MEMCONS) += udbg_memcons.o
68
67subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror 69subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
68 70
69obj-$(CONFIG_PPC_XICS) += xics/ 71obj-$(CONFIG_PPC_XICS) += xics/
diff --git a/arch/powerpc/sysdev/udbg_memcons.c b/arch/powerpc/sysdev/udbg_memcons.c
new file mode 100644
index 000000000000..ce5a7b489e4b
--- /dev/null
+++ b/arch/powerpc/sysdev/udbg_memcons.c
@@ -0,0 +1,105 @@
1/*
2 * A udbg backend which logs messages and reads input from in memory
3 * buffers.
4 *
5 * The console output can be read from memcons_output which is a
6 * circular buffer whose next write position is stored in memcons.output_pos.
7 *
8 * Input may be passed by writing into the memcons_input buffer when it is
9 * empty. The input buffer is empty when both input_pos == input_start and
10 * *input_start == '\0'.
11 *
12 * Copyright (C) 2003-2005 Anton Blanchard and Milton Miller, IBM Corp
13 * Copyright (C) 2013 Alistair Popple, IBM Corp
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version
18 * 2 of the License, or (at your option) any later version.
19 */
20
21#include <linux/init.h>
22#include <linux/kernel.h>
23#include <asm/barrier.h>
24#include <asm/page.h>
25#include <asm/processor.h>
26#include <asm/udbg.h>
27
28struct memcons {
29 char *output_start;
30 char *output_pos;
31 char *output_end;
32 char *input_start;
33 char *input_pos;
34 char *input_end;
35};
36
37static char memcons_output[CONFIG_PPC_MEMCONS_OUTPUT_SIZE];
38static char memcons_input[CONFIG_PPC_MEMCONS_INPUT_SIZE];
39
40struct memcons memcons = {
41 .output_start = memcons_output,
42 .output_pos = memcons_output,
43 .output_end = &memcons_output[CONFIG_PPC_MEMCONS_OUTPUT_SIZE],
44 .input_start = memcons_input,
45 .input_pos = memcons_input,
46 .input_end = &memcons_input[CONFIG_PPC_MEMCONS_INPUT_SIZE],
47};
48
49void memcons_putc(char c)
50{
51 char *new_output_pos;
52
53 *memcons.output_pos = c;
54 wmb();
55 new_output_pos = memcons.output_pos + 1;
56 if (new_output_pos >= memcons.output_end)
57 new_output_pos = memcons.output_start;
58
59 memcons.output_pos = new_output_pos;
60}
61
62int memcons_getc_poll(void)
63{
64 char c;
65 char *new_input_pos;
66
67 if (*memcons.input_pos) {
68 c = *memcons.input_pos;
69
70 new_input_pos = memcons.input_pos + 1;
71 if (new_input_pos >= memcons.input_end)
72 new_input_pos = memcons.input_start;
73 else if (*new_input_pos == '\0')
74 new_input_pos = memcons.input_start;
75
76 *memcons.input_pos = '\0';
77 wmb();
78 memcons.input_pos = new_input_pos;
79 return c;
80 }
81
82 return -1;
83}
84
85int memcons_getc(void)
86{
87 int c;
88
89 while (1) {
90 c = memcons_getc_poll();
91 if (c == -1)
92 cpu_relax();
93 else
94 break;
95 }
96
97 return c;
98}
99
100void udbg_init_memcons(void)
101{
102 udbg_putc = memcons_putc;
103 udbg_getc = memcons_getc;
104 udbg_getc_poll = memcons_getc_poll;
105}