aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/udbg_memcons.c
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 /arch/powerpc/sysdev/udbg_memcons.c
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>
Diffstat (limited to 'arch/powerpc/sysdev/udbg_memcons.c')
-rw-r--r--arch/powerpc/sysdev/udbg_memcons.c105
1 files changed, 105 insertions, 0 deletions
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}