12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
230650239SAlistair Popple /*
330650239SAlistair Popple  * A udbg backend which logs messages and reads input from in memory
430650239SAlistair Popple  * buffers.
530650239SAlistair Popple  *
630650239SAlistair Popple  * The console output can be read from memcons_output which is a
730650239SAlistair Popple  * circular buffer whose next write position is stored in memcons.output_pos.
830650239SAlistair Popple  *
930650239SAlistair Popple  * Input may be passed by writing into the memcons_input buffer when it is
1030650239SAlistair Popple  * empty. The input buffer is empty when both input_pos == input_start and
1130650239SAlistair Popple  * *input_start == '\0'.
1230650239SAlistair Popple  *
1330650239SAlistair Popple  * Copyright (C) 2003-2005 Anton Blanchard and Milton Miller, IBM Corp
1430650239SAlistair Popple  * Copyright (C) 2013 Alistair Popple, IBM Corp
1530650239SAlistair Popple  */
1630650239SAlistair Popple 
1730650239SAlistair Popple #include <linux/kernel.h>
1830650239SAlistair Popple #include <asm/barrier.h>
1930650239SAlistair Popple #include <asm/page.h>
2030650239SAlistair Popple #include <asm/processor.h>
2130650239SAlistair Popple #include <asm/udbg.h>
2230650239SAlistair Popple 
2330650239SAlistair Popple struct memcons {
2430650239SAlistair Popple 	char *output_start;
2530650239SAlistair Popple 	char *output_pos;
2630650239SAlistair Popple 	char *output_end;
2730650239SAlistair Popple 	char *input_start;
2830650239SAlistair Popple 	char *input_pos;
2930650239SAlistair Popple 	char *input_end;
3030650239SAlistair Popple };
3130650239SAlistair Popple 
3230650239SAlistair Popple static char memcons_output[CONFIG_PPC_MEMCONS_OUTPUT_SIZE];
3330650239SAlistair Popple static char memcons_input[CONFIG_PPC_MEMCONS_INPUT_SIZE];
3430650239SAlistair Popple 
3530650239SAlistair Popple struct memcons memcons = {
3630650239SAlistair Popple 	.output_start = memcons_output,
3730650239SAlistair Popple 	.output_pos = memcons_output,
3830650239SAlistair Popple 	.output_end = &memcons_output[CONFIG_PPC_MEMCONS_OUTPUT_SIZE],
3930650239SAlistair Popple 	.input_start = memcons_input,
4030650239SAlistair Popple 	.input_pos = memcons_input,
4130650239SAlistair Popple 	.input_end = &memcons_input[CONFIG_PPC_MEMCONS_INPUT_SIZE],
4230650239SAlistair Popple };
4330650239SAlistair Popple 
memcons_putc(char c)4430650239SAlistair Popple void memcons_putc(char c)
4530650239SAlistair Popple {
4630650239SAlistair Popple 	char *new_output_pos;
4730650239SAlistair Popple 
4830650239SAlistair Popple 	*memcons.output_pos = c;
4930650239SAlistair Popple 	wmb();
5030650239SAlistair Popple 	new_output_pos = memcons.output_pos + 1;
5130650239SAlistair Popple 	if (new_output_pos >= memcons.output_end)
5230650239SAlistair Popple 		new_output_pos = memcons.output_start;
5330650239SAlistair Popple 
5430650239SAlistair Popple 	memcons.output_pos = new_output_pos;
5530650239SAlistair Popple }
5630650239SAlistair Popple 
memcons_getc_poll(void)5730650239SAlistair Popple int memcons_getc_poll(void)
5830650239SAlistair Popple {
5930650239SAlistair Popple 	char c;
6030650239SAlistair Popple 	char *new_input_pos;
6130650239SAlistair Popple 
6230650239SAlistair Popple 	if (*memcons.input_pos) {
6330650239SAlistair Popple 		c = *memcons.input_pos;
6430650239SAlistair Popple 
6530650239SAlistair Popple 		new_input_pos = memcons.input_pos + 1;
6630650239SAlistair Popple 		if (new_input_pos >= memcons.input_end)
6730650239SAlistair Popple 			new_input_pos = memcons.input_start;
6830650239SAlistair Popple 		else if (*new_input_pos == '\0')
6930650239SAlistair Popple 			new_input_pos = memcons.input_start;
7030650239SAlistair Popple 
7130650239SAlistair Popple 		*memcons.input_pos = '\0';
7230650239SAlistair Popple 		wmb();
7330650239SAlistair Popple 		memcons.input_pos = new_input_pos;
7430650239SAlistair Popple 		return c;
7530650239SAlistair Popple 	}
7630650239SAlistair Popple 
7730650239SAlistair Popple 	return -1;
7830650239SAlistair Popple }
7930650239SAlistair Popple 
memcons_getc(void)8030650239SAlistair Popple int memcons_getc(void)
8130650239SAlistair Popple {
8230650239SAlistair Popple 	int c;
8330650239SAlistair Popple 
8430650239SAlistair Popple 	while (1) {
8530650239SAlistair Popple 		c = memcons_getc_poll();
8630650239SAlistair Popple 		if (c == -1)
8730650239SAlistair Popple 			cpu_relax();
8830650239SAlistair Popple 		else
8930650239SAlistair Popple 			break;
9030650239SAlistair Popple 	}
9130650239SAlistair Popple 
9230650239SAlistair Popple 	return c;
9330650239SAlistair Popple }
9430650239SAlistair Popple 
udbg_init_memcons(void)95*6c552983SNick Child void __init udbg_init_memcons(void)
9630650239SAlistair Popple {
9730650239SAlistair Popple 	udbg_putc = memcons_putc;
9830650239SAlistair Popple 	udbg_getc = memcons_getc;
9930650239SAlistair Popple 	udbg_getc_poll = memcons_getc_poll;
10030650239SAlistair Popple }
101