From 00707e9398c8397b6a90acc50634c2b538f6ab67 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 15 Nov 2018 13:18:53 +0800 Subject: [PATCH] MLK-20373-5 serial: serial_xen: support normal uboot console Support output/input using `xl console [domid]`. Signed-off-by: Peng Fan Reviewed-by: Flynn xu (cherry picked from commit 75a9833506aa13c1d5a8641c81ac951c41ced55e) (cherry picked from commit 5a495c39679b6641d369fc0c9cfdadafd8a408f6) (cherry picked from commit 6f3cc8513ac1afe0cf679422ae82c4a5930a8c64) --- drivers/serial/Kconfig | 5 ++ drivers/serial/serial_xen.c | 204 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 181 insertions(+), 28 deletions(-) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 21597b7..31cf28e 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -187,6 +187,9 @@ choice depends on DEBUG_UART default DEBUG_UART_NS16550 +config DEBUG_UART_XEN + bool "debug uart xen" + config DEBUG_UART_ALTERA_JTAGUART bool "Altera JTAG UART" help @@ -394,6 +397,7 @@ config DEBUG_UART_BASE hex "Base address of UART" depends on DEBUG_UART default 0 if DEBUG_UART_SANDBOX + default 0 if DEBUG_UART_XEN help This is the base address of your UART for memory-mapped UARTs. @@ -404,6 +408,7 @@ config DEBUG_UART_CLOCK int "UART input clock" depends on DEBUG_UART default 0 if DEBUG_UART_SANDBOX + default 0 if DEBUG_UART_XEN help The UART input clock determines the speed of the internal UART circuitry. The baud rate is derived from this by dividing the input diff --git a/drivers/serial/serial_xen.c b/drivers/serial/serial_xen.c index ce0c363..416d0ac 100644 --- a/drivers/serial/serial_xen.c +++ b/drivers/serial/serial_xen.c @@ -5,66 +5,214 @@ */ #include +#include #include #include +#include +#include #include -extern void xenprintf(const char *buf); -extern void xenprintc(const char c); -#ifndef CONFIG_DM_SERIAL +#include +#include +#include +#include +#include +#include +#include -static void xen_debug_serial_putc(const char c) +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_DM_SERIAL +struct xen_uart_priv { + struct xencons_interface *intf; + u32 evtchn; + int vtermno; + struct hvc_struct *hvc; + grant_ref_t gntref; +}; + +int xen_serial_setbrg(struct udevice *dev, int baudrate) { - /* If \n, also do \r */ - if (c == '\n') - serial_putc('\r'); + return 0; +} - xenprintc(c); +static int xen_serial_probe(struct udevice *dev) +{ + struct xen_uart_priv *priv = dev_get_priv(dev); + u64 v = 0; + unsigned long gfn; + int r; + + r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v); + if (r < 0 || v == 0) + return r; + + priv->evtchn = v; + + r = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v); + if (r < 0 || v == 0) + return -ENODEV; + + gfn = v; + + priv->intf = (struct xencons_interface *)(gfn << XEN_PAGE_SHIFT); + if (!priv->intf) + return -EINVAL; + + return 0; } -static void xen_debug_serial_puts(const char *buf) +static int xen_serial_pending(struct udevice *dev, bool input) { - xenprintf(buf); + struct xen_uart_priv *priv = dev_get_priv(dev); + struct xencons_interface *intf = priv->intf; + + if (!input || intf->in_cons == intf->in_prod) + return 0; + + return 1; } -static int xen_debug_serial_start(void) +static int xen_serial_getc(struct udevice *dev) { - return 0; + struct xen_uart_priv *priv = dev_get_priv(dev); + struct xencons_interface *intf = priv->intf; + XENCONS_RING_IDX cons; + char c; + + while (intf->in_cons == intf->in_prod) { + mb(); /* wait */ + } + + cons = intf->in_cons; + mb(); /* get pointers before reading ring */ + + c = intf->in[MASK_XENCONS_IDX(cons++, intf->in)]; + + mb(); /* read ring before consuming */ + intf->in_cons = cons; + + notify_remote_via_evtchn(priv->evtchn); + + return c; } -static void xen_debug_serial_setbrg(void) +static int __write_console(struct udevice *dev, const char *data, int len) { + struct xen_uart_priv *priv = dev_get_priv(dev); + struct xencons_interface *intf = priv->intf; + XENCONS_RING_IDX cons, prod; + int sent = 0; + + cons = intf->out_cons; + prod = intf->out_prod; + mb(); /* Update pointer */ + + WARN_ON((prod - cons) > sizeof(intf->out)); + + while ((sent < len) && ((prod - cons) < sizeof(intf->out))) + intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++]; + + mb(); /* Update data before pointer */ + intf->out_prod = prod; + + if (sent) + notify_remote_via_evtchn(priv->evtchn); + if (data[sent - 1] == '\n') + serial_puts("\r"); + + return sent; +} + +static int write_console(struct udevice *dev, const char *data, int len) +{ + /* + * Make sure the whole buffer is emitted, polling if + * necessary. We don't ever want to rely on the hvc daemon + * because the most interesting console output is when the + * kernel is crippled. + */ + while (len) { + int sent = __write_console(dev, data, len); + + data += sent; + len -= sent; + + if (unlikely(len)) + HYPERVISOR_sched_op(SCHEDOP_yield, NULL); + } + + return 0; } -static int xen_debug_serial_getc(void) +static int xen_serial_puts(struct udevice *dev, const char *str) { +#ifdef CONFIG_SPL_BUILD + (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(str), str); +#else + write_console(dev, str, strlen(str)); +#endif + return 0; } -static int xen_debug_serial_tstc(void) +static int xen_serial_putc(struct udevice *dev, const char ch) { +#ifdef CONFIG_SPL_BUILD + (void)HYPERVISOR_console_io(CONSOLEIO_write, 1, &ch); +#else + write_console(dev, &ch, 1); +#endif + return 0; } -static struct serial_device xen_debug_serial_drv = { - .name = "xen_debug_serial", - .start = xen_debug_serial_start, - .stop = NULL, - .setbrg = xen_debug_serial_setbrg, - .putc = xen_debug_serial_putc, - .puts = xen_debug_serial_puts, - .getc = xen_debug_serial_getc, - .tstc = xen_debug_serial_tstc, +static const struct dm_serial_ops xen_serial_ops = { + .puts = xen_serial_puts, + .putc = xen_serial_putc, + .getc = xen_serial_getc, + .pending = xen_serial_pending, +}; + +static const struct udevice_id xen_serial_ids[] = { + { .compatible = "xen,xen" }, + { } }; -void xen_debug_serial_initialize(void) +U_BOOT_DRIVER(serial_xen) = { + .name = "serial_xen", + .id = UCLASS_SERIAL, + .of_match = xen_serial_ids, + .priv_auto_alloc_size = sizeof(struct xen_uart_priv), + .probe = xen_serial_probe, + .ops = &xen_serial_ops, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_IGNORE_DEFAULT_CLKS, +}; +#else +__weak struct serial_device *default_serial_console(void) { - serial_register(&xen_debug_serial_drv); + return NULL; } -__weak struct serial_device *default_serial_console(void) +#endif + +#ifdef CONFIG_DEBUG_UART_XEN +void _debug_uart_init(void) +{ +} + +void _debug_uart_putc(int ch) { - return &xen_debug_serial_drv; + /* If \n, also do \r */ + if (ch == '\n') + serial_putc('\r'); + + (void)HYPERVISOR_console_io(CONSOLEIO_write, 1, &ch); + + return; } + +DEBUG_UART_FUNCS + #endif -- 1.9.1