Commit 00707e9398c8397b6a90acc50634c2b538f6ab67

Authored by Peng Fan
1 parent c35bf3b38c

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: Flynn xu <flynn.xu@nxp.com>
(cherry picked from commit 75a9833506aa13c1d5a8641c81ac951c41ced55e)
(cherry picked from commit 5a495c39679b6641d369fc0c9cfdadafd8a408f6)
(cherry picked from commit 6f3cc8513ac1afe0cf679422ae82c4a5930a8c64)

Showing 2 changed files with 181 additions and 28 deletions Side-by-side Diff

drivers/serial/Kconfig
... ... @@ -187,6 +187,9 @@
187 187 depends on DEBUG_UART
188 188 default DEBUG_UART_NS16550
189 189  
  190 +config DEBUG_UART_XEN
  191 + bool "debug uart xen"
  192 +
190 193 config DEBUG_UART_ALTERA_JTAGUART
191 194 bool "Altera JTAG UART"
192 195 help
... ... @@ -394,6 +397,7 @@
394 397 hex "Base address of UART"
395 398 depends on DEBUG_UART
396 399 default 0 if DEBUG_UART_SANDBOX
  400 + default 0 if DEBUG_UART_XEN
397 401 help
398 402 This is the base address of your UART for memory-mapped UARTs.
399 403  
... ... @@ -404,6 +408,7 @@
404 408 int "UART input clock"
405 409 depends on DEBUG_UART
406 410 default 0 if DEBUG_UART_SANDBOX
  411 + default 0 if DEBUG_UART_XEN
407 412 help
408 413 The UART input clock determines the speed of the internal UART
409 414 circuitry. The baud rate is derived from this by dividing the input
drivers/serial/serial_xen.c
... ... @@ -5,67 +5,215 @@
5 5 */
6 6  
7 7 #include <common.h>
  8 +#include <debug_uart.h>
8 9 #include <dm.h>
9 10 #include <errno.h>
  11 +#include <fdtdec.h>
  12 +#include <linux/compiler.h>
10 13 #include <serial.h>
11 14  
12   -extern void xenprintf(const char *buf);
13   -extern void xenprintc(const char c);
14   -#ifndef CONFIG_DM_SERIAL
  15 +#include <xen/events.h>
  16 +#include <xen/hvm.h>
  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 */
19   - if (c == '\n')
20   - serial_putc('\r');
  36 + return 0;
  37 +}
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 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 +#ifdef CONFIG_SPL_BUILD
  152 + (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(str), str);
  153 +#else
  154 + write_console(dev, str, strlen(str));
  155 +#endif
  156 +
47 157 return 0;
48 158 }
49 159  
50   -static struct serial_device xen_debug_serial_drv = {
51   - .name = "xen_debug_serial",
52   - .start = xen_debug_serial_start,
53   - .stop = NULL,
54   - .setbrg = xen_debug_serial_setbrg,
55   - .putc = xen_debug_serial_putc,
56   - .puts = xen_debug_serial_puts,
57   - .getc = xen_debug_serial_getc,
58   - .tstc = xen_debug_serial_tstc,
  160 +static int xen_serial_putc(struct udevice *dev, const char ch)
  161 +{
  162 +#ifdef CONFIG_SPL_BUILD
  163 + (void)HYPERVISOR_console_io(CONSOLEIO_write, 1, &ch);
  164 +#else
  165 + write_console(dev, &ch, 1);
  166 +#endif
  167 +
  168 + return 0;
  169 +}
  170 +
  171 +static const struct dm_serial_ops xen_serial_ops = {
  172 + .puts = xen_serial_puts,
  173 + .putc = xen_serial_putc,
  174 + .getc = xen_serial_getc,
  175 + .pending = xen_serial_pending,
59 176 };
60 177  
61   -void xen_debug_serial_initialize(void)
  178 +static const struct udevice_id xen_serial_ids[] = {
  179 + { .compatible = "xen,xen" },
  180 + { }
  181 +};
  182 +
  183 +U_BOOT_DRIVER(serial_xen) = {
  184 + .name = "serial_xen",
  185 + .id = UCLASS_SERIAL,
  186 + .of_match = xen_serial_ids,
  187 + .priv_auto_alloc_size = sizeof(struct xen_uart_priv),
  188 + .probe = xen_serial_probe,
  189 + .ops = &xen_serial_ops,
  190 + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_IGNORE_DEFAULT_CLKS,
  191 +};
  192 +#else
  193 +__weak struct serial_device *default_serial_console(void)
62 194 {
63   - serial_register(&xen_debug_serial_drv);
  195 + return NULL;
64 196 }
65 197  
66   -__weak struct serial_device *default_serial_console(void)
  198 +#endif
  199 +
  200 +#ifdef CONFIG_DEBUG_UART_XEN
  201 +void _debug_uart_init(void)
67 202 {
68   - return &xen_debug_serial_drv;
69 203 }
  204 +
  205 +void _debug_uart_putc(int ch)
  206 +{
  207 + /* If \n, also do \r */
  208 + if (ch == '\n')
  209 + serial_putc('\r');
  210 +
  211 + (void)HYPERVISOR_console_io(CONSOLEIO_write, 1, &ch);
  212 +
  213 + return;
  214 +}
  215 +
  216 +DEBUG_UART_FUNCS
  217 +
70 218 #endif