hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * A udbg backend which logs messages and reads input from in memory
 * buffers.
 *
 * The console output can be read from memcons_output which is a
 * circular buffer whose next write position is stored in memcons.output_pos.
 *
 * Input may be passed by writing into the memcons_input buffer when it is
 * empty. The input buffer is empty when both input_pos == input_start and
 * *input_start == '\0'.
 *
 * Copyright (C) 2003-2005 Anton Blanchard and Milton Miller, IBM Corp
 * Copyright (C) 2013 Alistair Popple, IBM Corp
 */
 
#include <linux/kernel.h>
#include <asm/barrier.h>
#include <asm/page.h>
#include <asm/processor.h>
#include <asm/udbg.h>
 
struct memcons {
   char *output_start;
   char *output_pos;
   char *output_end;
   char *input_start;
   char *input_pos;
   char *input_end;
};
 
static char memcons_output[CONFIG_PPC_MEMCONS_OUTPUT_SIZE];
static char memcons_input[CONFIG_PPC_MEMCONS_INPUT_SIZE];
 
struct memcons memcons = {
   .output_start = memcons_output,
   .output_pos = memcons_output,
   .output_end = &memcons_output[CONFIG_PPC_MEMCONS_OUTPUT_SIZE],
   .input_start = memcons_input,
   .input_pos = memcons_input,
   .input_end = &memcons_input[CONFIG_PPC_MEMCONS_INPUT_SIZE],
};
 
void memcons_putc(char c)
{
   char *new_output_pos;
 
   *memcons.output_pos = c;
   wmb();
   new_output_pos = memcons.output_pos + 1;
   if (new_output_pos >= memcons.output_end)
       new_output_pos = memcons.output_start;
 
   memcons.output_pos = new_output_pos;
}
 
int memcons_getc_poll(void)
{
   char c;
   char *new_input_pos;
 
   if (*memcons.input_pos) {
       c = *memcons.input_pos;
 
       new_input_pos = memcons.input_pos + 1;
       if (new_input_pos >= memcons.input_end)
           new_input_pos = memcons.input_start;
       else if (*new_input_pos == '\0')
           new_input_pos = memcons.input_start;
 
       *memcons.input_pos = '\0';
       wmb();
       memcons.input_pos = new_input_pos;
       return c;
   }
 
   return -1;
}
 
int memcons_getc(void)
{
   int c;
 
   while (1) {
       c = memcons_getc_poll();
       if (c == -1)
           cpu_relax();
       else
           break;
   }
 
   return c;
}
 
void udbg_init_memcons(void)
{
   udbg_putc = memcons_putc;
   udbg_getc = memcons_getc;
   udbg_getc_poll = memcons_getc_poll;
}