From owner-svn-src-projects@FreeBSD.ORG Wed Jan 25 01:54:28 2012 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 B6A7510657D7; Wed, 25 Jan 2012 01:54:28 +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 A48758FC17; Wed, 25 Jan 2012 01:54:28 +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 q0P1sSh6001697; Wed, 25 Jan 2012 01:54:28 GMT (envelope-from nwhitehorn@svn.freebsd.org) Received: (from nwhitehorn@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q0P1sS59001694; Wed, 25 Jan 2012 01:54:28 GMT (envelope-from nwhitehorn@svn.freebsd.org) Message-Id: <201201250154.q0P1sS59001694@svn.freebsd.org> From: Nathan Whitehorn Date: Wed, 25 Jan 2012 01:54:28 +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: r230519 - projects/pseries/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, 25 Jan 2012 01:54:28 -0000 Author: nwhitehorn Date: Wed Jan 25 01:54:28 2012 New Revision: 230519 URL: http://svn.freebsd.org/changeset/base/230519 Log: Undo the uart integration, as the PAPR VTY protocol doesn't mesh with it at all naturally. With some exceptions (below), this all works nicely now and I can boot FreeBSD multiuser on QEMU's emulated POWER7 with hypervisor. Exceptions: 1. Interrupt-driven mode doesn't seem to work for obscure reasons. 2. Input for hvterm-prot terminals is not implemented. Modified: projects/pseries/powerpc/pseries/phyp_console.c projects/pseries/powerpc/pseries/vdevice.c Modified: projects/pseries/powerpc/pseries/phyp_console.c ============================================================================== --- projects/pseries/powerpc/pseries/phyp_console.c Wed Jan 25 01:45:19 2012 (r230518) +++ projects/pseries/powerpc/pseries/phyp_console.c Wed Jan 25 01:54:28 2012 (r230519) @@ -34,7 +34,6 @@ __FBSDID("$FreeBSD: projects/pseries/pow #include #include #include -#include #include #include @@ -48,12 +47,33 @@ __FBSDID("$FreeBSD: projects/pseries/pow #include "phyp-hvcall.h" #include "uart_if.h" -static union { - uint64_t u64[2]; - char str[16]; -} phyp_inbuf; -static uint64_t phyp_inbuflen = 0; -static uint8_t phyp_outseqno = 0; +struct uart_phyp_softc { + device_t dev; + phandle_t node; + int vtermid; + + struct tty *tp; + struct resource *irqres; + int irqrid; + struct callout callout; + void *sc_icookie; + int polltime; + + struct mtx sc_mtx; + int protocol; + + union { + uint64_t u64[2]; + char str[16]; + } phyp_inbuf; + uint64_t inbuflen; + uint8_t outseqno; +}; + +static struct uart_phyp_softc *console_sc = NULL; +#if defined(KDB) +static int alt_break_state; +#endif enum { HVTERM1, HVTERMPROT @@ -69,87 +89,53 @@ enum { #define VSV_SEND_MODEM_CTL_STATUS 0x02 #define VS_QUERY_RESPONSE_PACKET_HEADER 0xfc -/* - * High-level interface - */ - static int uart_phyp_probe(device_t dev); -static int phyp_uart_bus_probe(struct uart_softc *); -static int phyp_uart_bus_attach(struct uart_softc *); -static int phyp_uart_bus_transmit(struct uart_softc *sc); -static int phyp_uart_bus_receive(struct uart_softc *sc); -static int phyp_uart_bus_ipend(struct uart_softc *sc); -static int phyp_uart_bus_flush(struct uart_softc *, int); -static int phyp_uart_bus_getsig(struct uart_softc *); -static int phyp_uart_bus_ioctl(struct uart_softc *, int, intptr_t); -static int phyp_uart_bus_param(struct uart_softc *, int, int, int, int); -static int phyp_uart_bus_setsig(struct uart_softc *, int); +static int uart_phyp_attach(device_t dev); +static void uart_phyp_intr(void *v); static device_method_t uart_phyp_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_phyp_probe), - DEVMETHOD(device_attach, uart_bus_attach), + DEVMETHOD(device_attach, uart_phyp_attach), DEVMETHOD_END }; static driver_t uart_phyp_driver = { - uart_driver_name, + "uart", uart_phyp_methods, - sizeof(struct uart_softc), + sizeof(struct uart_phyp_softc), }; -DRIVER_MODULE(uart, vdevice, uart_phyp_driver, uart_devclass, 0, 0); - -/* - * 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, -}; +DRIVER_MODULE(uart_phyp, vdevice, uart_phyp_driver, uart_devclass, 0, 0); -static kobj_method_t phyp_uart_methods[] = { - KOBJMETHOD(uart_probe, phyp_uart_bus_probe), - KOBJMETHOD(uart_attach, phyp_uart_bus_attach), - KOBJMETHOD(uart_transmit, phyp_uart_bus_transmit), - KOBJMETHOD(uart_receive, phyp_uart_bus_receive), - KOBJMETHOD(uart_ipend, phyp_uart_bus_ipend), - KOBJMETHOD(uart_flush, phyp_uart_bus_flush), - KOBJMETHOD(uart_getsig, phyp_uart_bus_getsig), - KOBJMETHOD(uart_ioctl, phyp_uart_bus_ioctl), - KOBJMETHOD(uart_param, phyp_uart_bus_param), - KOBJMETHOD(uart_setsig, phyp_uart_bus_setsig), - { 0, 0 } -}; - -struct uart_class uart_phyp_class = { - "uart", - phyp_uart_methods, - sizeof(struct uart_softc), - .uc_ops = &phyp_uart_ops, - .uc_range = 1, - .uc_rclk = 0x5bbc +static cn_probe_t uart_phyp_cnprobe; +static cn_init_t uart_phyp_cninit; +static cn_term_t uart_phyp_cnterm; +static cn_getc_t uart_phyp_cngetc; +static cn_putc_t uart_phyp_cnputc; +static cn_grab_t uart_phyp_cngrab; +static cn_ungrab_t uart_phyp_cnungrab; + +CONSOLE_DRIVER(uart_phyp); + +static void uart_phyp_ttyoutwakeup(struct tty *tp); + +static struct ttydevsw uart_phyp_tty_class = { + .tsw_flags = TF_INITLOCK|TF_CALLOUT, + .tsw_outwakeup = uart_phyp_ttyoutwakeup, }; static int -phyp_uart_probe(struct uart_bas *bas) +uart_phyp_probe_node(struct uart_phyp_softc *sc) { - phandle_t node = bas->chan; + phandle_t node = sc->node; + uint32_t reg; char buf[64]; + sc->inbuflen = 0; + sc->outseqno = 0; + if (OF_getprop(node, "name", buf, sizeof(buf)) <= 0) return (ENXIO); if (strcmp(buf, "vty") != 0) @@ -160,92 +146,180 @@ phyp_uart_probe(struct uart_bas *bas) if (strcmp(buf, "serial") != 0) return (ENXIO); + reg = -1; + OF_getprop(node, "reg", ®, sizeof(reg)); + if (reg == -1) + return (ENXIO); + sc->node = node; + if (OF_getprop(node, "compatible", buf, sizeof(buf)) <= 0) return (ENXIO); if (strcmp(buf, "hvterm1") == 0) { - bas->regshft = HVTERM1; + sc->protocol = HVTERM1; return (0); } else if (strcmp(buf, "hvterm-protocol") == 0) { - bas->regshft = HVTERMPROT; + sc->protocol = HVTERMPROT; return (0); } - - return (ENXIO); -} -static int -phyp_uart_bus_probe(struct uart_softc *sc) -{ - return (phyp_uart_probe(&sc->sc_bas)); + return (ENXIO); } static int uart_phyp_probe(device_t dev) { const char *name; - struct uart_softc *sc; - cell_t reg; + struct uart_phyp_softc sc; + int err; name = ofw_bus_get_name(dev); if (name == NULL || strcmp(name, "vty") != 0) return (ENXIO); - sc = device_get_softc(dev); - sc->sc_class = &uart_phyp_class; - OF_getprop(ofw_bus_get_node(dev), "reg", ®, sizeof(reg)); - sc->sc_bas.bsh = reg; - sc->sc_bas.bst = NULL; - sc->sc_bas.chan = ofw_bus_get_node(dev); + sc.node = ofw_bus_get_node(dev); + err = uart_phyp_probe_node(&sc); + if (err != 0) + return (err); device_set_desc(dev, "POWER Hypervisor Virtual Serial Port"); - return (uart_bus_probe(dev, 0, 0, 0, ofw_bus_get_node(dev))); + return (err); } +static void +uart_phyp_cnprobe(struct consdev *cp) +{ + char buf[64]; + ihandle_t stdout; + phandle_t input, opts, chosen; + static struct uart_phyp_softc sc; + + if ((opts = OF_finddevice("/options")) == -1) + goto fail; + if ((chosen = OF_finddevice("/chosen")) == -1) + goto fail; + + /* 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) + goto fail; + + if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1) + goto fail; + if (strcmp(buf, "serial") != 0) + goto fail; + + sc.node = input; + if (uart_phyp_probe_node(&sc) != 0) + goto fail; + mtx_init(&sc.sc_mtx, "uart_phyp", NULL, MTX_SPIN | MTX_QUIET | + MTX_NOWITNESS); + + cp->cn_pri = CN_NORMAL; + console_sc = ≻ + return; + +fail: + cp->cn_pri = CN_DEAD; + return; +} + +static int +uart_phyp_attach(device_t dev) +{ + struct uart_phyp_softc *sc; + int unit; + + sc = device_get_softc(dev); + sc->dev = dev; + sc->node = ofw_bus_get_node(dev); + uart_phyp_probe_node(sc); + + unit = device_get_unit(dev); + sc->tp = tty_alloc(&uart_phyp_tty_class, sc); + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, + MTX_SPIN | MTX_QUIET | MTX_NOWITNESS); + + if (console_sc != NULL && console_sc->vtermid == sc->vtermid) { + sc->outseqno = console_sc->outseqno; + console_sc = sc; + sprintf(uart_phyp_consdev.cn_name, "ttyu%r", unit); + tty_init_console(sc->tp, 0); + } + + sc->irqrid = 0; +#ifdef NOTYET + sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqrid, + RF_ACTIVE | RF_SHAREABLE); +#else + sc->irqres = NULL; +#endif + if (sc->irqres != NULL) { + bus_setup_intr(dev, sc->irqres, INTR_TYPE_TTY | INTR_MPSAFE, + NULL, uart_phyp_intr, sc, &sc->sc_icookie); + } else { + callout_init(&sc->callout, CALLOUT_MPSAFE); + sc->polltime = hz / 20; + if (sc->polltime < 1) + sc->polltime = 1; + callout_reset(&sc->callout, sc->polltime, uart_phyp_intr, sc); + } + + tty_makedev(sc->tp, NULL, "u%r", unit); + + return (0); +} static void -phyp_uart_init(struct uart_bas *bas, int baudrate __unused, - int databits __unused, int stopbits __unused, int parity __unused) +uart_phyp_cninit(struct consdev *cp) { + + strcpy(cp->cn_name, "phypcons"); } static void -phyp_uart_term(struct uart_bas *bas __unused) +uart_phyp_cnterm(struct consdev *cp) { } static int -phyp_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) +uart_phyp_get(struct uart_phyp_softc *sc, void *buffer, size_t bufsize) { - int ch, err; + int err; - uart_lock(hwmtx); - if (phyp_inbuflen == 0) { - 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]); + uart_lock(&sc->sc_mtx); + if (sc->inbuflen == 0) { + err = phyp_pft_hcall(H_GET_TERM_CHAR, sc->vtermid, + 0, 0, 0, &sc->inbuflen, &sc->phyp_inbuf.u64[0], + &sc->phyp_inbuf.u64[1]); if (err != H_SUCCESS) { - uart_unlock(hwmtx); + uart_unlock(&sc->sc_mtx); return (-1); } } - if (phyp_inbuflen == 0) { - uart_unlock(hwmtx); - return (-1); + if (sc->inbuflen == 0) { + uart_unlock(&sc->sc_mtx); + return (0); } - ch = phyp_inbuf.str[0]; - phyp_inbuflen--; - if (phyp_inbuflen > 0) - memcpy(&phyp_inbuf.str[0], &phyp_inbuf.str[1], phyp_inbuflen); + if (bufsize > sc->inbuflen) + bufsize = sc->inbuflen; + memcpy(buffer, sc->phyp_inbuf.str, bufsize); + sc->inbuflen -= bufsize; + if (sc->inbuflen > 0) + memmove(&sc->phyp_inbuf.str[0], &sc->phyp_inbuf.str[bufsize], + sc->inbuflen); - uart_unlock(hwmtx); - return (ch); + uart_unlock(&sc->sc_mtx); + return (bufsize); } -static void -phyp_uart_putc(struct uart_bas *bas, int c) +static int +uart_phyp_put(struct uart_phyp_softc *sc, void *buffer, size_t bufsize) { uint16_t seqno; uint64_t len = 0; @@ -254,93 +328,93 @@ phyp_uart_putc(struct uart_bas *bas, int char bytes[8]; } cbuf; - switch (bas->regshft) { + uart_lock(&sc->sc_mtx); + switch (sc->protocol) { case HVTERM1: - cbuf.bytes[0] = c; - len = 1; + if (bufsize > 8) + bufsize = 8; + memcpy(&cbuf, buffer, bufsize); + len = bufsize; break; case HVTERMPROT: - seqno = phyp_outseqno++; + if (bufsize > 4) + bufsize = 4; + seqno = sc->outseqno++; cbuf.bytes[0] = VS_DATA_PACKET_HEADER; - cbuf.bytes[1] = 5; /* total length */ + cbuf.bytes[1] = 4 + bufsize; /* total length */ cbuf.bytes[2] = (seqno >> 8) & 0xff; cbuf.bytes[3] = seqno & 0xff; - cbuf.bytes[4] = c; - len = 5; + memcpy(&cbuf.bytes[4], buffer, bufsize); + len = 4 + bufsize; break; } - phyp_hcall(H_PUT_TERM_CHAR, (uint64_t)bas->bsh, len, cbuf.u64, 0); -} - -static int -phyp_uart_rxready(struct uart_bas *bas) -{ - return (1); -} + phyp_hcall(H_PUT_TERM_CHAR, sc->vtermid, len, cbuf.u64, 0); + uart_unlock(&sc->sc_mtx); -static int -phyp_uart_bus_attach(struct uart_softc *sc) -{ - return (0); + return (bufsize); } static int -phyp_uart_bus_transmit(struct uart_softc *sc) +uart_phyp_cngetc(struct consdev *cp) { - int i; - - uart_lock(sc->sc_hwmtx); - for (i = 0; i < sc->sc_txdatasz; i++) - phyp_uart_putc(&sc->sc_bas, sc->sc_txbuf[i]); - uart_unlock(sc->sc_hwmtx); - - return (0); -} + unsigned char c; + int retval; -static int -phyp_uart_bus_receive(struct uart_softc *sc) -{ - int c; - while ((c = phyp_uart_getc(&sc->sc_bas, sc->sc_hwmtx)) != -1) - uart_rx_put(sc, c); + retval = uart_phyp_get(console_sc, &c, 1); + if (retval != 1) + return (-1); +#if defined(KDB) + kdb_alt_break(c, &alt_break_state); +#endif - return (0); + return (c); } -static int -phyp_uart_bus_ipend(struct uart_softc *sc) +static void +uart_phyp_cnputc(struct consdev *cp, int c) { - return (0); + unsigned char ch = c; + uart_phyp_put(console_sc, &ch, 1); } -static int -phyp_uart_bus_flush(struct uart_softc *sc, int what) +static void +uart_phyp_cngrab(struct consdev *cp) { - return (0); } -static int -phyp_uart_bus_getsig(struct uart_softc *sc) +static void +uart_phyp_cnungrab(struct consdev *cp) { - return (0); } -static int -phyp_uart_bus_ioctl(struct uart_softc *sc, int req, intptr_t data) +static void +uart_phyp_ttyoutwakeup(struct tty *tp) { - return (EINVAL); + struct uart_phyp_softc *sc; + char buffer[8]; + int len; + + sc = tty_softc(tp); + + while ((len = ttydisc_getc(tp, buffer, sizeof(buffer))) != 0) + uart_phyp_put(sc, buffer, len); } -static int -phyp_uart_bus_param(struct uart_softc *sc, int baud, int db, int sb, int par) +static void +uart_phyp_intr(void *v) { - return (0); -} + struct uart_phyp_softc *sc = v; + struct tty *tp = sc->tp; + unsigned char c; + int len; + + tty_lock(tp); + while ((len = uart_phyp_get(sc, &c, 1)) > 0) + ttydisc_rint(tp, c, 0); + ttydisc_rint_done(tp); + tty_unlock(tp); -static int -phyp_uart_bus_setsig(struct uart_softc *sc, int sig) -{ - return (0); + if (sc->irqres == NULL) + callout_reset(&sc->callout, sc->polltime, uart_phyp_intr, sc); } - Modified: projects/pseries/powerpc/pseries/vdevice.c ============================================================================== --- projects/pseries/powerpc/pseries/vdevice.c Wed Jan 25 01:45:19 2012 (r230518) +++ projects/pseries/powerpc/pseries/vdevice.c Wed Jan 25 01:54:28 2012 (r230519) @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -44,6 +45,16 @@ static int vdevice_probe(device_t); static int vdevice_attach(device_t); static const struct ofw_bus_devinfo *vdevice_get_devinfo(device_t dev, device_t child); +static int vdevice_print_child(device_t dev, device_t child); +static struct resource_list *vdevice_get_resource_list (device_t, device_t); + +/* + * VDevice devinfo + */ +struct vdevice_devinfo { + struct ofw_bus_devinfo mdi_obdinfo; + struct resource_list mdi_resources; +}; static device_method_t vdevice_methods[] = { /* Device interface */ @@ -53,6 +64,14 @@ static device_method_t vdevice_methods[] /* Bus interface */ DEVMETHOD(bus_add_child, bus_generic_add_child), DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), + DEVMETHOD(bus_print_child, vdevice_print_child), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_get_resource_list, vdevice_get_resource_list), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, vdevice_get_devinfo), @@ -98,22 +117,46 @@ vdevice_attach(device_t dev) { phandle_t root, child; device_t cdev; - struct ofw_bus_devinfo *dinfo; + int icells, i, nintr, *intr; + phandle_t iparent; + struct vdevice_devinfo *dinfo; root = ofw_bus_get_node(dev); for (child = OF_child(root); child != 0; child = OF_peer(child)) { dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO); - if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) { + if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo, + child) != 0) { free(dinfo, M_DEVBUF); continue; } + resource_list_init(&dinfo->mdi_resources); + + if (OF_searchprop(child, "#interrupt-cells", &icells, + sizeof(icells)) <= 0) + icells = 2; + if (OF_getprop(child, "interrupt-parent", &iparent, + sizeof(iparent)) <= 0) + iparent = -1; + nintr = OF_getprop_alloc(child, "interrupts", sizeof(*intr), + (void **)&intr); + if (nintr > 0) { + for (i = 0; i < nintr; i += icells) { + u_int irq = intr[i]; + if (iparent != -1) + irq = MAP_IRQ(iparent, intr[i]); + + resource_list_add(&dinfo->mdi_resources, + SYS_RES_IRQ, i, irq, irq, i); + } + } + cdev = device_add_child(dev, NULL, -1); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", - dinfo->obd_name); - ofw_bus_gen_destroy_devinfo(dinfo); + dinfo->mdi_obdinfo.obd_name); + ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo); free(dinfo, M_DEVBUF); continue; } @@ -129,3 +172,31 @@ vdevice_get_devinfo(device_t dev, device return (device_get_ivars(child)); } +static int +vdevice_print_child(device_t dev, device_t child) +{ + struct vdevice_devinfo *dinfo; + struct resource_list *rl; + int retval = 0; + + dinfo = device_get_ivars(child); + rl = &dinfo->mdi_resources; + + retval += bus_print_child_header(dev, child); + + retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); + + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +static struct resource_list * +vdevice_get_resource_list (device_t dev, device_t child) +{ + struct vdevice_devinfo *dinfo; + + dinfo = device_get_ivars(child); + return (&dinfo->mdi_resources); +} +