From owner-svn-src-projects@FreeBSD.ORG Wed Nov 2 20:55:56 2011 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 474DE106564A; Wed, 2 Nov 2011 20:55:56 +0000 (UTC) (envelope-from nwhitehorn@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 2BEEA8FC08; Wed, 2 Nov 2011 20:55:56 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id pA2Ktuj0037951; Wed, 2 Nov 2011 20:55:56 GMT (envelope-from nwhitehorn@svn.freebsd.org) Received: (from nwhitehorn@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id pA2KtuoW037948; Wed, 2 Nov 2011 20:55:56 GMT (envelope-from nwhitehorn@svn.freebsd.org) Message-Id: <201111022055.pA2KtuoW037948@svn.freebsd.org> From: Nathan Whitehorn Date: Wed, 2 Nov 2011 20:55:56 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r227033 - in projects/pseries: dev/uart powerpc/pseries X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 02 Nov 2011 20:55:56 -0000 Author: nwhitehorn Date: Wed Nov 2 20:55:55 2011 New Revision: 227033 URL: http://svn.freebsd.org/changeset/base/227033 Log: Turn the POWER hypervisor console into a kind of uart(4). When controlling actual serial ports via the hvterm-protocol interface, it has support for regular UARTy things like baud rates and flow control. Modified: projects/pseries/dev/uart/uart_cpu_powerpc.c projects/pseries/powerpc/pseries/phyp_console.c Modified: projects/pseries/dev/uart/uart_cpu_powerpc.c ============================================================================== --- projects/pseries/dev/uart/uart_cpu_powerpc.c Wed Nov 2 20:45:44 2011 (r227032) +++ projects/pseries/dev/uart/uart_cpu_powerpc.c Wed Nov 2 20:55:55 2011 (r227033) @@ -42,11 +42,18 @@ __FBSDID("$FreeBSD$"); bus_space_tag_t uart_bus_space_io = &bs_le_tag; bus_space_tag_t uart_bus_space_mem = &bs_le_tag; +extern struct uart_class uart_phyp_class __attribute__((weak)); + int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { - - return ((pmap_kextract(b1->bsh) == pmap_kextract(b2->bsh)) ? 1 : 0); + if (b1->bst == NULL && b2->bst == NULL) + return ((b1->bsh == b2->bsh) ? 1 : 0); + else if (b1->bst != NULL && b2->bst != NULL) + return ((pmap_kextract(b1->bsh) == pmap_kextract(b2->bsh)) ? + 1 : 0); + else + return (0); } static int @@ -54,16 +61,21 @@ ofw_get_uart_console(phandle_t opts, pha const char *outputdev) { char buf[64]; - phandle_t input; + phandle_t input, output; + *result = -1; if (OF_getprop(opts, inputdev, buf, sizeof(buf)) == -1) - return (ENXIO); + return (ENOENT); input = OF_finddevice(buf); if (input == -1) - return (ENXIO); + return (ENOENT); if (OF_getprop(opts, outputdev, buf, sizeof(buf)) == -1) - return (ENXIO); - if (OF_finddevice(buf) != input) + return (ENOENT); + output = OF_finddevice(buf); + if (output == -1) + return (ENOENT); + + if (input != output) /* UARTs are bidirectional */ return (ENXIO); *result = input; @@ -75,28 +87,42 @@ uart_cpu_getdev(int devtype, struct uart { char buf[64]; struct uart_class *class; - phandle_t input, opts; + ihandle_t stdout; + phandle_t input, opts, chosen; + cell_t reg; int error; - class = &uart_z8530_class; - if (class == NULL) - return (ENXIO); - if ((opts = OF_finddevice("/options")) == -1) return (ENXIO); + if ((chosen = OF_finddevice("/chosen")) == -1) + return (ENXIO); switch (devtype) { case UART_DEV_CONSOLE: - if (ofw_get_uart_console(opts, &input, "input-device", - "output-device")) { + do { + /* Check if OF has an active stdin/stdout */ + input = -1; + if (OF_getprop(chosen, "stdout", &stdout, + sizeof(stdout)) == sizeof(stdout) && stdout != 0) + input = OF_instance_to_package(stdout); + if (input != -1) + break; + + /* Guess what OF would have done had it had such */ + if (ofw_get_uart_console(opts, &input, "input-device", + "output-device") == 0) + break; + /* * At least some G5 Xserves require that we * probe input-device-1 as well */ - if (ofw_get_uart_console(opts, &input, "input-device-1", - "output-device-1")) - return (ENXIO); - } + "output-device-1") == 0) + break; + } while (0); + + if (input == -1) + return (ENXIO); break; case UART_DEV_DBGPORT: if (!getenv_string("hw.uart.dbgport", buf, sizeof(buf))) @@ -124,12 +150,24 @@ uart_cpu_getdev(int devtype, struct uart class = &uart_ns8250_class; di->bas.regshft = 0; di->bas.chan = 0; + } else if (strcmp(buf,"vty") == 0) { + class = &uart_phyp_class; + di->bas.regshft = 0; + di->bas.chan = input; } else return (ENXIO); - error = OF_decode_addr(input, 0, &di->bas.bst, &di->bas.bsh); - if (error) - return (error); + if (strcmp(buf,"vty") == 0) { + if (OF_getproplen(input, "reg") != sizeof(reg)) + return (ENXIO); + OF_getprop(input, "reg", ®, sizeof(reg)); + di->bas.bsh = reg; + di->bas.bst = NULL; + } else { + error = OF_decode_addr(input, 0, &di->bas.bst, &di->bas.bsh); + if (error) + return (error); + } di->ops = uart_getops(class); Modified: projects/pseries/powerpc/pseries/phyp_console.c ============================================================================== --- projects/pseries/powerpc/pseries/phyp_console.c Wed Nov 2 20:45:44 2011 (r227032) +++ projects/pseries/powerpc/pseries/phyp_console.c Wed Nov 2 20:55:55 2011 (r227033) @@ -25,8 +25,6 @@ #include __FBSDID("$FreeBSD: projects/pseries/powerpc/phyp/phyp_console.c 214348 2010-10-25 15:41:12Z nwhitehorn $"); -#include "opt_comconsole.h" - #include #include #include @@ -39,178 +37,133 @@ __FBSDID("$FreeBSD: projects/pseries/pow #include #include - -#include +#include +#include +#include #include "phyp-hvcall.h" +#include "uart_if.h" -static tsw_outwakeup_t phyptty_outwakeup; - -static struct ttydevsw phyp_ttydevsw = { - .tsw_flags = TF_NOPREFIX, - .tsw_outwakeup = phyptty_outwakeup, -}; - -static int polltime; -static cell_t termno; -static struct callout phyp_callout; static union { uint64_t u64[2]; char str[16]; } phyp_inbuf; static uint64_t phyp_inbuflen = 0; -static struct tty *tp = NULL; - -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) -static int alt_break_state; -#endif - -static void phyp_timeout(void *); - -static cn_probe_t phyp_cnprobe; -static cn_init_t phyp_cninit; -static cn_term_t phyp_cnterm; -static cn_getc_t phyp_cngetc; -static cn_putc_t phyp_cnputc; - -CONSOLE_DRIVER(phyp); - -static void -cn_drvinit(void *unused) -{ - phandle_t dev; - if (phyp_consdev.cn_pri != CN_DEAD && - phyp_consdev.cn_name[0] != '\0') { - dev = OF_finddevice("/vdevice/vty"); - if (dev == -1) - return; - - OF_getprop(dev, "reg", &termno, sizeof(termno)); - tp = tty_alloc(&phyp_ttydevsw, NULL); - tty_init_console(tp, 0); - tty_makedev(tp, NULL, "%s", "phypvty"); - - polltime = 1; - - callout_init(&phyp_callout, CALLOUT_MPSAFE); - callout_reset(&phyp_callout, polltime, phyp_timeout, NULL); - } -} - -SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL); - -static void -phyptty_outwakeup(struct tty *tp) -{ - int len, err; - uint64_t buf[2]; - - for (;;) { - len = ttydisc_getc(tp, buf, sizeof buf); - if (len == 0) - break; - - do { - err = phyp_hcall(H_PUT_TERM_CHAR, termno, - (register_t)len, buf[0], buf[1]); - } while (err == H_BUSY); - } -} - -static void -phyp_timeout(void *v) -{ - int c; +enum { + HVTERM1, HVTERMPROT +}; - tty_lock(tp); - while ((c = phyp_cngetc(NULL)) != -1) - ttydisc_rint(tp, c, 0); - ttydisc_rint_done(tp); - tty_unlock(tp); +/* + * Low-level UART interface + */ +static int phyp_uart_probe(struct uart_bas *bas); +static void phyp_uart_init(struct uart_bas *bas, int baudrate, int databits, + int stopbits, int parity); +static void phyp_uart_term(struct uart_bas *bas); +static void phyp_uart_putc(struct uart_bas *bas, int c); +static int phyp_uart_rxready(struct uart_bas *bas); +static int phyp_uart_getc(struct uart_bas *bas, struct mtx *hwmtx); + +static struct uart_ops phyp_uart_ops = { + .probe = phyp_uart_probe, + .init = phyp_uart_init, + .term = phyp_uart_term, + .putc = phyp_uart_putc, + .rxready = phyp_uart_rxready, + .getc = phyp_uart_getc, +}; - callout_reset(&phyp_callout, polltime, phyp_timeout, NULL); -} +struct uart_class uart_phyp_class = { + "uart", + NULL, + sizeof(struct uart_softc), + .uc_ops = &phyp_uart_ops, + .uc_range = 1, + .uc_rclk = 0x5bbc +}; -static void -phyp_cnprobe(struct consdev *cp) +static int +phyp_uart_probe(struct uart_bas *bas) { - phandle_t dev; - - dev = OF_finddevice("/vdevice/vty"); + phandle_t node = bas->chan; + char buf[64]; - if (dev == -1) { - cp->cn_pri = CN_DEAD; - return; + if (OF_getprop(node, "name", buf, sizeof(buf)) <= 0) + return (ENXIO); + if (strcmp(buf, "vty") != 0) + return (ENXIO); + + if (OF_getprop(node, "device_type", buf, sizeof(buf)) <= 0) + return (ENXIO); + if (strcmp(buf, "serial") != 0) + return (ENXIO); + + if (OF_getprop(node, "compatible", buf, sizeof(buf)) <= 0) + return (ENXIO); + if (strcmp(buf, "hvterm1") == 0) { + bas->regshft = HVTERM1; + return (0); + } else if (strcmp(buf, "hvterm-protocol") == 0) { + bas->regshft = HVTERMPROT; + return (0); } - - OF_getprop(dev, "reg", &termno, sizeof(termno)); - cp->cn_pri = CN_NORMAL; + + return (ENXIO); } static void -phyp_cninit(struct consdev *cp) +phyp_uart_init(struct uart_bas *bas, int baudrate __unused, + int databits __unused, int stopbits __unused, int parity __unused) { - - /* XXX: This is the alias, but that should be good enough */ - strcpy(cp->cn_name, "phypcons"); } static void -phyp_cnterm(struct consdev *cp) +phyp_uart_term(struct uart_bas *bas __unused) { } static int -phyp_cngetc(struct consdev *cp) +phyp_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) { int ch, err; -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) - int kdb_brk; -#endif - /* XXX: thread safety */ + uart_lock(hwmtx); if (phyp_inbuflen == 0) { - err = phyp_pft_hcall(H_GET_TERM_CHAR, termno, 0, 0, 0, - &phyp_inbuflen, &phyp_inbuf.u64[0], &phyp_inbuf.u64[1]); - if (err != H_SUCCESS) + err = phyp_pft_hcall(H_GET_TERM_CHAR, (uint64_t)bas->bsh, + 0, 0, 0, &phyp_inbuflen, &phyp_inbuf.u64[0], + &phyp_inbuf.u64[1]); + if (err != H_SUCCESS) { + uart_unlock(hwmtx); return (-1); + } } - if (phyp_inbuflen == 0) + if (phyp_inbuflen == 0) { + uart_unlock(hwmtx); return (-1); + } ch = phyp_inbuf.str[0]; phyp_inbuflen--; if (phyp_inbuflen > 0) memcpy(&phyp_inbuf.str[0], &phyp_inbuf.str[1], phyp_inbuflen); -#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER) - if ((kdb_brk = kdb_alt_break(ch, &alt_break_state)) != 0) { - switch (kdb_brk) { - case KDB_REQ_DEBUGGER: - kdb_enter(KDB_WHY_BREAK, - "Break sequence on console"); - break; - case KDB_REQ_PANIC: - kdb_panic("Panic sequence on console"); - break; - case KDB_REQ_REBOOT: - kdb_reboot(); - break; - - } - } -#endif + uart_unlock(hwmtx); return (ch); } static void -phyp_cnputc(struct consdev *cp, int c) +phyp_uart_putc(struct uart_bas *bas, int c) { uint64_t cbuf; cbuf = (uint64_t)c << 56; - phyp_hcall(H_PUT_TERM_CHAR, termno, 1UL, cbuf, 0); + phyp_hcall(H_PUT_TERM_CHAR, (uint64_t)bas->bsh, 1UL, cbuf, 0); } +static int +phyp_uart_rxready(struct uart_bas *bas) +{ + return (1); +}