Commit 75a9833506aa13c1d5a8641c81ac951c41ced55e

Authored by Peng Fan
1 parent c96a9844cd

MLK-20373-5 serial: serial_xen: support normal uboot console

Support output/input using `xl console [domid]`.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Flynn xu <flynn.xu@nxp.com>

Showing 1 changed file with 168 additions and 28 deletions Inline Diff

drivers/serial/serial_xen.c
1 /* 1 /*
2 * Copyright 2018 NXP 2 * Copyright 2018 NXP
3 * 3 *
4 * SPDX-License-Identifier: GPL-2.0+ 4 * SPDX-License-Identifier: GPL-2.0+
5 */ 5 */
6 6
7 #include <common.h> 7 #include <common.h>
8 #include <debug_uart.h>
8 #include <dm.h> 9 #include <dm.h>
9 #include <errno.h> 10 #include <errno.h>
11 #include <fdtdec.h>
12 #include <linux/compiler.h>
10 #include <serial.h> 13 #include <serial.h>
11 14
12 extern void xenprintf(const char *buf); 15 #include <xen/events.h>
13 extern void xenprintc(const char c); 16 #include <xen/hvm.h>
14 #ifndef CONFIG_DM_SERIAL 17 #include <xen/interface/sched.h>
18 #include <xen/interface/hvm/hvm_op.h>
19 #include <xen/interface/hvm/params.h>
20 #include <xen/interface/io/console.h>
21 #include <xen/interface/io/ring.h>
15 22
16 static void xen_debug_serial_putc(const char c) 23 DECLARE_GLOBAL_DATA_PTR;
24
25 #ifdef CONFIG_DM_SERIAL
26 struct xen_uart_priv {
27 struct xencons_interface *intf;
28 u32 evtchn;
29 int vtermno;
30 struct hvc_struct *hvc;
31 grant_ref_t gntref;
32 };
33
34 int xen_serial_setbrg(struct udevice *dev, int baudrate)
17 { 35 {
18 /* If \n, also do \r */ 36 return 0;
19 if (c == '\n') 37 }
20 serial_putc('\r');
21 38
22 xenprintc(c); 39 static int xen_serial_probe(struct udevice *dev)
40 {
41 struct xen_uart_priv *priv = dev_get_priv(dev);
42 u64 v = 0;
43 unsigned long gfn;
44 int r;
45
46 r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
47 if (r < 0 || v == 0)
48 return r;
49
50 priv->evtchn = v;
51
52 r = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v);
53 if (r < 0 || v == 0)
54 return -ENODEV;
55
56 gfn = v;
57
58 priv->intf = (struct xencons_interface *)(gfn << XEN_PAGE_SHIFT);
59 if (!priv->intf)
60 return -EINVAL;
61
62 return 0;
23 } 63 }
24 64
25 static void xen_debug_serial_puts(const char *buf) 65 static int xen_serial_pending(struct udevice *dev, bool input)
26 { 66 {
27 xenprintf(buf); 67 struct xen_uart_priv *priv = dev_get_priv(dev);
68 struct xencons_interface *intf = priv->intf;
69
70 if (!input || intf->in_cons == intf->in_prod)
71 return 0;
72
73 return 1;
28 } 74 }
29 75
30 static int xen_debug_serial_start(void) 76 static int xen_serial_getc(struct udevice *dev)
31 { 77 {
32 return 0; 78 struct xen_uart_priv *priv = dev_get_priv(dev);
79 struct xencons_interface *intf = priv->intf;
80 XENCONS_RING_IDX cons;
81 char c;
82
83 while (intf->in_cons == intf->in_prod) {
84 mb(); /* wait */
85 }
86
87 cons = intf->in_cons;
88 mb(); /* get pointers before reading ring */
89
90 c = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
91
92 mb(); /* read ring before consuming */
93 intf->in_cons = cons;
94
95 notify_remote_via_evtchn(priv->evtchn);
96
97 return c;
33 } 98 }
34 99
35 static void xen_debug_serial_setbrg(void) 100 static int __write_console(struct udevice *dev, const char *data, int len)
36 { 101 {
102 struct xen_uart_priv *priv = dev_get_priv(dev);
103 struct xencons_interface *intf = priv->intf;
104 XENCONS_RING_IDX cons, prod;
105 int sent = 0;
37 106
107 cons = intf->out_cons;
108 prod = intf->out_prod;
109 mb(); /* Update pointer */
110
111 WARN_ON((prod - cons) > sizeof(intf->out));
112
113 while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
114 intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
115
116 mb(); /* Update data before pointer */
117 intf->out_prod = prod;
118
119 if (sent)
120 notify_remote_via_evtchn(priv->evtchn);
121
122 if (data[sent - 1] == '\n')
123 serial_puts("\r");
124
125 return sent;
38 } 126 }
39 127
40 static int xen_debug_serial_getc(void) 128 static int write_console(struct udevice *dev, const char *data, int len)
41 { 129 {
130 /*
131 * Make sure the whole buffer is emitted, polling if
132 * necessary. We don't ever want to rely on the hvc daemon
133 * because the most interesting console output is when the
134 * kernel is crippled.
135 */
136 while (len) {
137 int sent = __write_console(dev, data, len);
138
139 data += sent;
140 len -= sent;
141
142 if (unlikely(len))
143 HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
144 }
145
42 return 0; 146 return 0;
43 } 147 }
44 148
45 static int xen_debug_serial_tstc(void) 149 static int xen_serial_puts(struct udevice *dev, const char *str)
46 { 150 {
151 write_console(dev, str, strlen(str));
152
47 return 0; 153 return 0;
48 } 154 }
49 155
50 static struct serial_device xen_debug_serial_drv = { 156 static int xen_serial_putc(struct udevice *dev, const char ch)
51 .name = "xen_debug_serial", 157 {
52 .start = xen_debug_serial_start, 158 write_console(dev, &ch, 1);
53 .stop = NULL, 159
54 .setbrg = xen_debug_serial_setbrg, 160 return 0;
55 .putc = xen_debug_serial_putc, 161 }
56 .puts = xen_debug_serial_puts, 162
57 .getc = xen_debug_serial_getc, 163 static const struct dm_serial_ops xen_serial_ops = {
58 .tstc = xen_debug_serial_tstc, 164 .puts = xen_serial_puts,
165 .putc = xen_serial_putc,
166 .getc = xen_serial_getc,
167 .pending = xen_serial_pending,
59 }; 168 };
60 169
61 void xen_debug_serial_initialize(void) 170 static const struct udevice_id xen_serial_ids[] = {
171 { .compatible = "xen,xen" },
172 { }
173 };
174
175 U_BOOT_DRIVER(serial_xen) = {
176 .name = "serial_xen",
177 .id = UCLASS_SERIAL,
178 .of_match = xen_serial_ids,
179 .priv_auto_alloc_size = sizeof(struct xen_uart_priv),
180 .probe = xen_serial_probe,
181 .ops = &xen_serial_ops,
182 .flags = DM_FLAG_PRE_RELOC,
183 };
184 #else
185 __weak struct serial_device *default_serial_console(void)
62 { 186 {
63 serial_register(&xen_debug_serial_drv); 187 return NULL;
64 } 188 }
65 189
66 __weak struct serial_device *default_serial_console(void) 190 #endif
191
192 #ifdef CONFIG_DEBUG_UART_XEN
193 void _debug_uart_init(void)
67 { 194 {
68 return &xen_debug_serial_drv;
69 } 195 }
196
197 void _debug_uart_putc(int ch)
198 {
199 /* If \n, also do \r */
200 if (ch == '\n')
201 serial_putc('\r');
202
203 (void)HYPERVISOR_console_io(CONSOLEIO_write, 1, &ch);
204
205 return;
206 }
207
208 DEBUG_UART_FUNCS
209