phyp_console.c revision 255895
1255643Snwhitehorn/*- 2255643Snwhitehorn * Copyright (C) 2011 by Nathan Whitehorn. All rights reserved. 3255643Snwhitehorn * 4255643Snwhitehorn * Redistribution and use in source and binary forms, with or without 5255643Snwhitehorn * modification, are permitted provided that the following conditions 6255643Snwhitehorn * are met: 7255643Snwhitehorn * 1. Redistributions of source code must retain the above copyright 8255643Snwhitehorn * notice, this list of conditions and the following disclaimer. 9255643Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 10255643Snwhitehorn * notice, this list of conditions and the following disclaimer in the 11255643Snwhitehorn * documentation and/or other materials provided with the distribution. 12255643Snwhitehorn * 13255643Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14255643Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15255643Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16255643Snwhitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 17255643Snwhitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 18255643Snwhitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 19255643Snwhitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 20255643Snwhitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 21255643Snwhitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22255643Snwhitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23255643Snwhitehorn */ 24255643Snwhitehorn 25255643Snwhitehorn#include <sys/cdefs.h> 26255643Snwhitehorn__FBSDID("$FreeBSD: head/sys/powerpc/pseries/phyp_console.c 255895 2013-09-26 18:01:32Z nwhitehorn $"); 27255643Snwhitehorn 28255643Snwhitehorn#include <sys/param.h> 29255643Snwhitehorn#include <sys/kdb.h> 30255643Snwhitehorn#include <sys/kernel.h> 31255643Snwhitehorn#include <sys/priv.h> 32255643Snwhitehorn#include <sys/systm.h> 33255643Snwhitehorn#include <sys/module.h> 34255643Snwhitehorn#include <sys/types.h> 35255643Snwhitehorn#include <sys/conf.h> 36255643Snwhitehorn#include <sys/cons.h> 37255643Snwhitehorn#include <sys/tty.h> 38255643Snwhitehorn#include <machine/bus.h> 39255643Snwhitehorn 40255643Snwhitehorn#include <dev/ofw/openfirm.h> 41255643Snwhitehorn#include <dev/ofw/ofw_bus.h> 42255643Snwhitehorn#include <dev/ofw/ofw_bus_subr.h> 43255643Snwhitehorn#include <dev/uart/uart.h> 44255643Snwhitehorn#include <dev/uart/uart_cpu.h> 45255643Snwhitehorn#include <dev/uart/uart_bus.h> 46255643Snwhitehorn 47255643Snwhitehorn#include "phyp-hvcall.h" 48255643Snwhitehorn#include "uart_if.h" 49255643Snwhitehorn 50255643Snwhitehornstruct uart_phyp_softc { 51255643Snwhitehorn device_t dev; 52255643Snwhitehorn phandle_t node; 53255643Snwhitehorn int vtermid; 54255643Snwhitehorn 55255643Snwhitehorn struct tty *tp; 56255643Snwhitehorn struct resource *irqres; 57255643Snwhitehorn int irqrid; 58255643Snwhitehorn struct callout callout; 59255643Snwhitehorn void *sc_icookie; 60255643Snwhitehorn int polltime; 61255643Snwhitehorn 62255643Snwhitehorn struct mtx sc_mtx; 63255643Snwhitehorn int protocol; 64255643Snwhitehorn 65255643Snwhitehorn union { 66255643Snwhitehorn uint64_t u64[2]; 67255643Snwhitehorn char str[16]; 68255643Snwhitehorn } phyp_inbuf; 69255643Snwhitehorn uint64_t inbuflen; 70255643Snwhitehorn uint8_t outseqno; 71255643Snwhitehorn}; 72255643Snwhitehorn 73255643Snwhitehornstatic struct uart_phyp_softc *console_sc = NULL; 74255643Snwhitehorn#if defined(KDB) 75255643Snwhitehornstatic int alt_break_state; 76255643Snwhitehorn#endif 77255643Snwhitehorn 78255643Snwhitehornenum { 79255643Snwhitehorn HVTERM1, HVTERMPROT 80255643Snwhitehorn}; 81255643Snwhitehorn 82255643Snwhitehorn#define VS_DATA_PACKET_HEADER 0xff 83255643Snwhitehorn#define VS_CONTROL_PACKET_HEADER 0xfe 84255643Snwhitehorn#define VSV_SET_MODEM_CTL 0x01 85255643Snwhitehorn#define VSV_MODEM_CTL_UPDATE 0x02 86255643Snwhitehorn#define VSV_RENEGOTIATE_CONNECTION 0x03 87255643Snwhitehorn#define VS_QUERY_PACKET_HEADER 0xfd 88255643Snwhitehorn#define VSV_SEND_VERSION_NUMBER 0x01 89255643Snwhitehorn#define VSV_SEND_MODEM_CTL_STATUS 0x02 90255643Snwhitehorn#define VS_QUERY_RESPONSE_PACKET_HEADER 0xfc 91255643Snwhitehorn 92255643Snwhitehornstatic int uart_phyp_probe(device_t dev); 93255643Snwhitehornstatic int uart_phyp_attach(device_t dev); 94255643Snwhitehornstatic void uart_phyp_intr(void *v); 95255643Snwhitehorn 96255643Snwhitehornstatic device_method_t uart_phyp_methods[] = { 97255643Snwhitehorn /* Device interface */ 98255643Snwhitehorn DEVMETHOD(device_probe, uart_phyp_probe), 99255643Snwhitehorn DEVMETHOD(device_attach, uart_phyp_attach), 100255643Snwhitehorn 101255643Snwhitehorn DEVMETHOD_END 102255643Snwhitehorn}; 103255643Snwhitehorn 104255643Snwhitehornstatic driver_t uart_phyp_driver = { 105255643Snwhitehorn "uart", 106255643Snwhitehorn uart_phyp_methods, 107255643Snwhitehorn sizeof(struct uart_phyp_softc), 108255643Snwhitehorn}; 109255643Snwhitehorn 110255643SnwhitehornDRIVER_MODULE(uart_phyp, vdevice, uart_phyp_driver, uart_devclass, 0, 0); 111255643Snwhitehorn 112255643Snwhitehornstatic cn_probe_t uart_phyp_cnprobe; 113255643Snwhitehornstatic cn_init_t uart_phyp_cninit; 114255643Snwhitehornstatic cn_term_t uart_phyp_cnterm; 115255643Snwhitehornstatic cn_getc_t uart_phyp_cngetc; 116255643Snwhitehornstatic cn_putc_t uart_phyp_cnputc; 117255643Snwhitehornstatic cn_grab_t uart_phyp_cngrab; 118255643Snwhitehornstatic cn_ungrab_t uart_phyp_cnungrab; 119255643Snwhitehorn 120255643SnwhitehornCONSOLE_DRIVER(uart_phyp); 121255643Snwhitehorn 122255643Snwhitehornstatic void uart_phyp_ttyoutwakeup(struct tty *tp); 123255643Snwhitehorn 124255643Snwhitehornstatic struct ttydevsw uart_phyp_tty_class = { 125255643Snwhitehorn .tsw_flags = TF_INITLOCK|TF_CALLOUT, 126255643Snwhitehorn .tsw_outwakeup = uart_phyp_ttyoutwakeup, 127255643Snwhitehorn}; 128255643Snwhitehorn 129255643Snwhitehornstatic int 130255643Snwhitehornuart_phyp_probe_node(struct uart_phyp_softc *sc) 131255643Snwhitehorn{ 132255643Snwhitehorn phandle_t node = sc->node; 133255643Snwhitehorn uint32_t reg; 134255643Snwhitehorn char buf[64]; 135255643Snwhitehorn 136255643Snwhitehorn sc->inbuflen = 0; 137255643Snwhitehorn sc->outseqno = 0; 138255643Snwhitehorn 139255643Snwhitehorn if (OF_getprop(node, "name", buf, sizeof(buf)) <= 0) 140255643Snwhitehorn return (ENXIO); 141255643Snwhitehorn if (strcmp(buf, "vty") != 0) 142255643Snwhitehorn return (ENXIO); 143255643Snwhitehorn 144255643Snwhitehorn if (OF_getprop(node, "device_type", buf, sizeof(buf)) <= 0) 145255643Snwhitehorn return (ENXIO); 146255643Snwhitehorn if (strcmp(buf, "serial") != 0) 147255643Snwhitehorn return (ENXIO); 148255643Snwhitehorn 149255643Snwhitehorn reg = -1; 150255643Snwhitehorn OF_getprop(node, "reg", ®, sizeof(reg)); 151255643Snwhitehorn if (reg == -1) 152255643Snwhitehorn return (ENXIO); 153255895Snwhitehorn sc->vtermid = reg; 154255643Snwhitehorn sc->node = node; 155255643Snwhitehorn 156255643Snwhitehorn if (OF_getprop(node, "compatible", buf, sizeof(buf)) <= 0) 157255643Snwhitehorn return (ENXIO); 158255643Snwhitehorn if (strcmp(buf, "hvterm1") == 0) { 159255643Snwhitehorn sc->protocol = HVTERM1; 160255643Snwhitehorn return (0); 161255643Snwhitehorn } else if (strcmp(buf, "hvterm-protocol") == 0) { 162255643Snwhitehorn sc->protocol = HVTERMPROT; 163255643Snwhitehorn return (0); 164255643Snwhitehorn } 165255643Snwhitehorn 166255643Snwhitehorn return (ENXIO); 167255643Snwhitehorn} 168255643Snwhitehorn 169255643Snwhitehornstatic int 170255643Snwhitehornuart_phyp_probe(device_t dev) 171255643Snwhitehorn{ 172255643Snwhitehorn const char *name; 173255643Snwhitehorn struct uart_phyp_softc sc; 174255643Snwhitehorn int err; 175255643Snwhitehorn 176255643Snwhitehorn name = ofw_bus_get_name(dev); 177255643Snwhitehorn if (name == NULL || strcmp(name, "vty") != 0) 178255643Snwhitehorn return (ENXIO); 179255643Snwhitehorn 180255643Snwhitehorn sc.node = ofw_bus_get_node(dev); 181255643Snwhitehorn err = uart_phyp_probe_node(&sc); 182255643Snwhitehorn if (err != 0) 183255643Snwhitehorn return (err); 184255643Snwhitehorn 185255643Snwhitehorn device_set_desc(dev, "POWER Hypervisor Virtual Serial Port"); 186255643Snwhitehorn 187255643Snwhitehorn return (err); 188255643Snwhitehorn} 189255643Snwhitehorn 190255643Snwhitehornstatic void 191255643Snwhitehornuart_phyp_cnprobe(struct consdev *cp) 192255643Snwhitehorn{ 193255643Snwhitehorn char buf[64]; 194255643Snwhitehorn ihandle_t stdout; 195255643Snwhitehorn phandle_t input, opts, chosen; 196255643Snwhitehorn static struct uart_phyp_softc sc; 197255643Snwhitehorn 198255643Snwhitehorn if ((opts = OF_finddevice("/options")) == -1) 199255643Snwhitehorn goto fail; 200255643Snwhitehorn if ((chosen = OF_finddevice("/chosen")) == -1) 201255643Snwhitehorn goto fail; 202255643Snwhitehorn 203255643Snwhitehorn /* Check if OF has an active stdin/stdout */ 204255643Snwhitehorn input = -1; 205255643Snwhitehorn if (OF_getprop(chosen, "stdout", &stdout, 206255643Snwhitehorn sizeof(stdout)) == sizeof(stdout) && stdout != 0) 207255643Snwhitehorn input = OF_instance_to_package(stdout); 208255643Snwhitehorn if (input == -1) 209255643Snwhitehorn goto fail; 210255643Snwhitehorn 211255643Snwhitehorn if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1) 212255643Snwhitehorn goto fail; 213255643Snwhitehorn if (strcmp(buf, "serial") != 0) 214255643Snwhitehorn goto fail; 215255643Snwhitehorn 216255643Snwhitehorn sc.node = input; 217255643Snwhitehorn if (uart_phyp_probe_node(&sc) != 0) 218255643Snwhitehorn goto fail; 219255643Snwhitehorn mtx_init(&sc.sc_mtx, "uart_phyp", NULL, MTX_SPIN | MTX_QUIET | 220255643Snwhitehorn MTX_NOWITNESS); 221255643Snwhitehorn 222255643Snwhitehorn cp->cn_pri = CN_NORMAL; 223255643Snwhitehorn console_sc = ≻ 224255643Snwhitehorn return; 225255643Snwhitehorn 226255643Snwhitehornfail: 227255643Snwhitehorn cp->cn_pri = CN_DEAD; 228255643Snwhitehorn return; 229255643Snwhitehorn} 230255643Snwhitehorn 231255643Snwhitehornstatic int 232255643Snwhitehornuart_phyp_attach(device_t dev) 233255643Snwhitehorn{ 234255643Snwhitehorn struct uart_phyp_softc *sc; 235255643Snwhitehorn int unit; 236255643Snwhitehorn 237255643Snwhitehorn sc = device_get_softc(dev); 238255643Snwhitehorn sc->dev = dev; 239255643Snwhitehorn sc->node = ofw_bus_get_node(dev); 240255643Snwhitehorn uart_phyp_probe_node(sc); 241255643Snwhitehorn 242255643Snwhitehorn unit = device_get_unit(dev); 243255643Snwhitehorn sc->tp = tty_alloc(&uart_phyp_tty_class, sc); 244255643Snwhitehorn mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, 245255643Snwhitehorn MTX_SPIN | MTX_QUIET | MTX_NOWITNESS); 246255643Snwhitehorn 247255643Snwhitehorn if (console_sc != NULL && console_sc->vtermid == sc->vtermid) { 248255643Snwhitehorn sc->outseqno = console_sc->outseqno; 249255643Snwhitehorn console_sc = sc; 250255643Snwhitehorn sprintf(uart_phyp_consdev.cn_name, "ttyu%r", unit); 251255643Snwhitehorn tty_init_console(sc->tp, 0); 252255643Snwhitehorn } 253255643Snwhitehorn 254255643Snwhitehorn sc->irqrid = 0; 255255643Snwhitehorn sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqrid, 256255643Snwhitehorn RF_ACTIVE | RF_SHAREABLE); 257255643Snwhitehorn if (sc->irqres != NULL) { 258255643Snwhitehorn bus_setup_intr(dev, sc->irqres, INTR_TYPE_TTY | INTR_MPSAFE, 259255643Snwhitehorn NULL, uart_phyp_intr, sc, &sc->sc_icookie); 260255643Snwhitehorn } else { 261255643Snwhitehorn callout_init(&sc->callout, CALLOUT_MPSAFE); 262255643Snwhitehorn sc->polltime = hz / 20; 263255643Snwhitehorn if (sc->polltime < 1) 264255643Snwhitehorn sc->polltime = 1; 265255643Snwhitehorn callout_reset(&sc->callout, sc->polltime, uart_phyp_intr, sc); 266255643Snwhitehorn } 267255643Snwhitehorn 268255643Snwhitehorn tty_makedev(sc->tp, NULL, "u%r", unit); 269255643Snwhitehorn 270255643Snwhitehorn return (0); 271255643Snwhitehorn} 272255643Snwhitehorn 273255643Snwhitehornstatic void 274255643Snwhitehornuart_phyp_cninit(struct consdev *cp) 275255643Snwhitehorn{ 276255643Snwhitehorn 277255643Snwhitehorn strcpy(cp->cn_name, "phypcons"); 278255643Snwhitehorn} 279255643Snwhitehorn 280255643Snwhitehornstatic void 281255643Snwhitehornuart_phyp_cnterm(struct consdev *cp) 282255643Snwhitehorn{ 283255643Snwhitehorn} 284255643Snwhitehorn 285255643Snwhitehornstatic int 286255643Snwhitehornuart_phyp_get(struct uart_phyp_softc *sc, void *buffer, size_t bufsize) 287255643Snwhitehorn{ 288255643Snwhitehorn int err; 289255643Snwhitehorn 290255643Snwhitehorn uart_lock(&sc->sc_mtx); 291255643Snwhitehorn if (sc->inbuflen == 0) { 292255643Snwhitehorn err = phyp_pft_hcall(H_GET_TERM_CHAR, sc->vtermid, 293255643Snwhitehorn 0, 0, 0, &sc->inbuflen, &sc->phyp_inbuf.u64[0], 294255643Snwhitehorn &sc->phyp_inbuf.u64[1]); 295255643Snwhitehorn if (err != H_SUCCESS) { 296255643Snwhitehorn uart_unlock(&sc->sc_mtx); 297255643Snwhitehorn return (-1); 298255643Snwhitehorn } 299255643Snwhitehorn } 300255643Snwhitehorn 301255643Snwhitehorn if (sc->inbuflen == 0) { 302255643Snwhitehorn uart_unlock(&sc->sc_mtx); 303255643Snwhitehorn return (0); 304255643Snwhitehorn } 305255643Snwhitehorn 306255643Snwhitehorn if (bufsize > sc->inbuflen) 307255643Snwhitehorn bufsize = sc->inbuflen; 308255643Snwhitehorn memcpy(buffer, sc->phyp_inbuf.str, bufsize); 309255643Snwhitehorn sc->inbuflen -= bufsize; 310255643Snwhitehorn if (sc->inbuflen > 0) 311255643Snwhitehorn memmove(&sc->phyp_inbuf.str[0], &sc->phyp_inbuf.str[bufsize], 312255643Snwhitehorn sc->inbuflen); 313255643Snwhitehorn 314255643Snwhitehorn uart_unlock(&sc->sc_mtx); 315255643Snwhitehorn return (bufsize); 316255643Snwhitehorn} 317255643Snwhitehorn 318255643Snwhitehornstatic int 319255643Snwhitehornuart_phyp_put(struct uart_phyp_softc *sc, void *buffer, size_t bufsize) 320255643Snwhitehorn{ 321255643Snwhitehorn uint16_t seqno; 322255643Snwhitehorn uint64_t len = 0; 323255643Snwhitehorn union { 324255643Snwhitehorn uint64_t u64; 325255643Snwhitehorn char bytes[8]; 326255643Snwhitehorn } cbuf; 327255643Snwhitehorn 328255643Snwhitehorn uart_lock(&sc->sc_mtx); 329255643Snwhitehorn switch (sc->protocol) { 330255643Snwhitehorn case HVTERM1: 331255643Snwhitehorn if (bufsize > 8) 332255643Snwhitehorn bufsize = 8; 333255643Snwhitehorn memcpy(&cbuf, buffer, bufsize); 334255643Snwhitehorn len = bufsize; 335255643Snwhitehorn break; 336255643Snwhitehorn case HVTERMPROT: 337255643Snwhitehorn if (bufsize > 4) 338255643Snwhitehorn bufsize = 4; 339255643Snwhitehorn seqno = sc->outseqno++; 340255643Snwhitehorn cbuf.bytes[0] = VS_DATA_PACKET_HEADER; 341255643Snwhitehorn cbuf.bytes[1] = 4 + bufsize; /* total length */ 342255643Snwhitehorn cbuf.bytes[2] = (seqno >> 8) & 0xff; 343255643Snwhitehorn cbuf.bytes[3] = seqno & 0xff; 344255643Snwhitehorn memcpy(&cbuf.bytes[4], buffer, bufsize); 345255643Snwhitehorn len = 4 + bufsize; 346255643Snwhitehorn break; 347255643Snwhitehorn } 348255643Snwhitehorn phyp_hcall(H_PUT_TERM_CHAR, sc->vtermid, len, cbuf.u64, 0); 349255643Snwhitehorn uart_unlock(&sc->sc_mtx); 350255643Snwhitehorn 351255643Snwhitehorn return (bufsize); 352255643Snwhitehorn} 353255643Snwhitehorn 354255643Snwhitehornstatic int 355255643Snwhitehornuart_phyp_cngetc(struct consdev *cp) 356255643Snwhitehorn{ 357255643Snwhitehorn unsigned char c; 358255643Snwhitehorn int retval; 359255643Snwhitehorn 360255643Snwhitehorn retval = uart_phyp_get(console_sc, &c, 1); 361255643Snwhitehorn if (retval != 1) 362255643Snwhitehorn return (-1); 363255643Snwhitehorn#if defined(KDB) 364255643Snwhitehorn kdb_alt_break(c, &alt_break_state); 365255643Snwhitehorn#endif 366255643Snwhitehorn 367255643Snwhitehorn return (c); 368255643Snwhitehorn} 369255643Snwhitehorn 370255643Snwhitehornstatic void 371255643Snwhitehornuart_phyp_cnputc(struct consdev *cp, int c) 372255643Snwhitehorn{ 373255643Snwhitehorn unsigned char ch = c; 374255643Snwhitehorn uart_phyp_put(console_sc, &ch, 1); 375255643Snwhitehorn} 376255643Snwhitehorn 377255643Snwhitehornstatic void 378255643Snwhitehornuart_phyp_cngrab(struct consdev *cp) 379255643Snwhitehorn{ 380255643Snwhitehorn} 381255643Snwhitehorn 382255643Snwhitehornstatic void 383255643Snwhitehornuart_phyp_cnungrab(struct consdev *cp) 384255643Snwhitehorn{ 385255643Snwhitehorn} 386255643Snwhitehorn 387255643Snwhitehornstatic void 388255643Snwhitehornuart_phyp_ttyoutwakeup(struct tty *tp) 389255643Snwhitehorn{ 390255643Snwhitehorn struct uart_phyp_softc *sc; 391255643Snwhitehorn char buffer[8]; 392255643Snwhitehorn int len; 393255643Snwhitehorn 394255643Snwhitehorn sc = tty_softc(tp); 395255643Snwhitehorn 396255643Snwhitehorn while ((len = ttydisc_getc(tp, buffer, sizeof(buffer))) != 0) 397255643Snwhitehorn uart_phyp_put(sc, buffer, len); 398255643Snwhitehorn} 399255643Snwhitehorn 400255643Snwhitehornstatic void 401255643Snwhitehornuart_phyp_intr(void *v) 402255643Snwhitehorn{ 403255643Snwhitehorn struct uart_phyp_softc *sc = v; 404255643Snwhitehorn struct tty *tp = sc->tp; 405255643Snwhitehorn unsigned char c; 406255643Snwhitehorn int len; 407255643Snwhitehorn 408255643Snwhitehorn tty_lock(tp); 409255643Snwhitehorn while ((len = uart_phyp_get(sc, &c, 1)) > 0) 410255643Snwhitehorn ttydisc_rint(tp, c, 0); 411255643Snwhitehorn ttydisc_rint_done(tp); 412255643Snwhitehorn tty_unlock(tp); 413255643Snwhitehorn 414255643Snwhitehorn if (sc->irqres == NULL) 415255643Snwhitehorn callout_reset(&sc->callout, sc->polltime, uart_phyp_intr, sc); 416255643Snwhitehorn} 417255643Snwhitehorn 418