diff options
-rw-r--r-- | arch/powerpc/Kconfig.debug | 23 | ||||
-rw-r--r-- | arch/powerpc/include/asm/udbg.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/udbg.c | 3 | ||||
-rw-r--r-- | arch/powerpc/sysdev/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/sysdev/udbg_memcons.c | 105 |
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 | ||
265 | config 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. | ||
265 | endchoice | 272 | endchoice |
266 | 273 | ||
274 | config 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 | |||
282 | config 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 | |||
267 | config PPC_EARLY_DEBUG_OPAL | 290 | config 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); | |||
52 | extern void __init udbg_init_cpm(void); | 52 | extern void __init udbg_init_cpm(void); |
53 | extern void __init udbg_init_usbgecko(void); | 53 | extern void __init udbg_init_usbgecko(void); |
54 | extern void __init udbg_init_wsp(void); | 54 | extern void __init udbg_init_wsp(void); |
55 | extern void __init udbg_init_memcons(void); | ||
55 | extern void __init udbg_init_ehv_bc(void); | 56 | extern void __init udbg_init_ehv_bc(void); |
56 | extern void __init udbg_init_ps3gelic(void); | 57 | extern void __init udbg_init_ps3gelic(void); |
57 | extern void __init udbg_init_debug_opal_raw(void); | 58 | extern 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 | ||
65 | obj-$(CONFIG_PPC_SCOM) += scom.o | 65 | obj-$(CONFIG_PPC_SCOM) += scom.o |
66 | 66 | ||
67 | obj-$(CONFIG_PPC_EARLY_DEBUG_MEMCONS) += udbg_memcons.o | ||
68 | |||
67 | subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror | 69 | subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror |
68 | 70 | ||
69 | obj-$(CONFIG_PPC_XICS) += xics/ | 71 | obj-$(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 | |||
28 | struct 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 | |||
37 | static char memcons_output[CONFIG_PPC_MEMCONS_OUTPUT_SIZE]; | ||
38 | static char memcons_input[CONFIG_PPC_MEMCONS_INPUT_SIZE]; | ||
39 | |||
40 | struct 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 | |||
49 | void 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 | |||
62 | int 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 | |||
85 | int 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 | |||
100 | void udbg_init_memcons(void) | ||
101 | { | ||
102 | udbg_putc = memcons_putc; | ||
103 | udbg_getc = memcons_getc; | ||
104 | udbg_getc_poll = memcons_getc_poll; | ||
105 | } | ||