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 Side-by-side Diff

drivers/serial/serial_xen.c
... ... @@ -5,67 +5,207 @@
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 + write_console(dev, str, strlen(str));
  152 +
47 153 return 0;
48 154 }
49 155  
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,
  156 +static int xen_serial_putc(struct udevice *dev, const char ch)
  157 +{
  158 + write_console(dev, &ch, 1);
  159 +
  160 + return 0;
  161 +}
  162 +
  163 +static const struct dm_serial_ops xen_serial_ops = {
  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 +
70 210 #endif