1 /*- 2 * Copyright (C) 2011,2015 by Nathan Whitehorn. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 17 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 18 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 19 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 20 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 21 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #include <sys/cdefs.h> 26 __FBSDID("$FreeBSD$"); 27 28 #include <sys/param.h> 29 #include <sys/kdb.h> 30 #include <sys/kernel.h> 31 #include <sys/priv.h> 32 #include <sys/systm.h> 33 #include <sys/module.h> 34 #include <sys/types.h> 35 #include <sys/conf.h> 36 #include <sys/cons.h> 37 #include <sys/proc.h> 38 #include <sys/tty.h> 39 40 #include <vm/vm.h> 41 #include <vm/pmap.h> 42 43 #include <machine/bus.h> 44 45 #include <dev/ofw/openfirm.h> 46 #include <dev/ofw/ofw_bus.h> 47 #include <dev/ofw/ofw_bus_subr.h> 48 #include <dev/uart/uart.h> 49 #include <dev/uart/uart_cpu.h> 50 #include <dev/uart/uart_bus.h> 51 52 #include "opal.h" 53 #include "uart_if.h" 54 55 struct uart_opal_softc { 56 device_t dev; 57 phandle_t node; 58 int vtermid; 59 60 struct tty *tp; 61 struct resource *irqres; 62 int irqrid; 63 struct callout callout; 64 void *sc_icookie; 65 int polltime; 66 67 struct mtx sc_mtx; 68 int protocol; 69 70 char opal_inbuf[16]; 71 uint64_t inbuflen; 72 uint8_t outseqno; 73 }; 74 75 static struct uart_opal_softc *console_sc = NULL; 76 77 #if defined(KDB) 78 static int alt_break_state; 79 #endif 80 81 enum { 82 OPAL_RAW, OPAL_HVSI 83 }; 84 85 #define VS_DATA_PACKET_HEADER 0xff 86 #define VS_CONTROL_PACKET_HEADER 0xfe 87 #define VSV_SET_MODEM_CTL 0x01 88 #define VSV_MODEM_CTL_UPDATE 0x02 89 #define VSV_RENEGOTIATE_CONNECTION 0x03 90 #define VS_QUERY_PACKET_HEADER 0xfd 91 #define VSV_SEND_VERSION_NUMBER 0x01 92 #define VSV_SEND_MODEM_CTL_STATUS 0x02 93 #define VS_QUERY_RESPONSE_PACKET_HEADER 0xfc 94 95 static int uart_opal_probe(device_t dev); 96 static int uart_opal_attach(device_t dev); 97 static void uart_opal_intr(void *v); 98 99 static device_method_t uart_opal_methods[] = { 100 /* Device interface */ 101 DEVMETHOD(device_probe, uart_opal_probe), 102 DEVMETHOD(device_attach, uart_opal_attach), 103 104 DEVMETHOD_END 105 }; 106 107 static driver_t uart_opal_driver = { 108 "uart", 109 uart_opal_methods, 110 sizeof(struct uart_opal_softc), 111 }; 112 113 DRIVER_MODULE(uart_opal, opalcons, uart_opal_driver, uart_devclass, 0, 0); 114 115 static cn_probe_t uart_opal_cnprobe; 116 static cn_init_t uart_opal_cninit; 117 static cn_term_t uart_opal_cnterm; 118 static cn_getc_t uart_opal_cngetc; 119 static cn_putc_t uart_opal_cnputc; 120 static cn_grab_t uart_opal_cngrab; 121 static cn_ungrab_t uart_opal_cnungrab; 122 123 CONSOLE_DRIVER(uart_opal); 124 125 static void uart_opal_ttyoutwakeup(struct tty *tp); 126 127 static struct ttydevsw uart_opal_tty_class = { 128 .tsw_flags = TF_INITLOCK|TF_CALLOUT, 129 .tsw_outwakeup = uart_opal_ttyoutwakeup, 130 }; 131 132 static struct { 133 char tmpbuf[16]; 134 uint64_t size; 135 struct mtx mtx; 136 } opalcons_buffer; 137 138 static void 139 uart_opal_real_map_outbuffer(uint64_t *bufferp, uint64_t *lenp) 140 { 141 142 if (!mtx_initialized(&opalcons_buffer.mtx)) 143 mtx_init(&opalcons_buffer.mtx, "uart_opal", NULL, 144 MTX_SPIN | MTX_QUIET | MTX_NOWITNESS); 145 146 if (!pmap_bootstrapped) 147 return; 148 149 mtx_lock_spin(&opalcons_buffer.mtx); 150 151 opalcons_buffer.size = *(uint64_t *)(*lenp) = 152 min(sizeof(opalcons_buffer.tmpbuf), *(uint64_t *)(*lenp)); 153 memcpy(opalcons_buffer.tmpbuf, (void *)(*bufferp), 154 *(uint64_t *)(*lenp)); 155 *bufferp = (uint64_t)opalcons_buffer.tmpbuf; 156 *lenp = (uint64_t)&opalcons_buffer.size; 157 } 158 159 static void 160 uart_opal_real_unmap_outbuffer(uint64_t *len) 161 { 162 163 if (!pmap_bootstrapped) 164 return; 165 166 mtx_assert(&opalcons_buffer.mtx, MA_OWNED); 167 *len = opalcons_buffer.size; 168 mtx_unlock_spin(&opalcons_buffer.mtx); 169 } 170 171 static int 172 uart_opal_probe_node(struct uart_opal_softc *sc) 173 { 174 phandle_t node = sc->node; 175 uint32_t reg; 176 char buf[64]; 177 178 sc->inbuflen = 0; 179 sc->outseqno = 0; 180 181 if (OF_getprop(node, "device_type", buf, sizeof(buf)) <= 0) 182 return (ENXIO); 183 if (strcmp(buf, "serial") != 0) 184 return (ENXIO); 185 186 reg = -1; 187 OF_getencprop(node, "reg", ®, sizeof(reg)); 188 if (reg == -1) 189 return (ENXIO); 190 sc->vtermid = reg; 191 sc->node = node; 192 193 if (OF_getprop(node, "compatible", buf, sizeof(buf)) <= 0) 194 return (ENXIO); 195 if (strcmp(buf, "ibm,opal-console-raw") == 0) { 196 sc->protocol = OPAL_RAW; 197 return (0); 198 } else if (strcmp(buf, "ibm,opal-console-hvsi") == 0) { 199 sc->protocol = OPAL_HVSI; 200 return (0); 201 } 202 203 return (ENXIO); 204 } 205 206 static int 207 uart_opal_probe(device_t dev) 208 { 209 struct uart_opal_softc sc; 210 int err; 211 212 sc.node = ofw_bus_get_node(dev); 213 err = uart_opal_probe_node(&sc); 214 if (err != 0) 215 return (err); 216 217 device_set_desc(dev, "OPAL Serial Port"); 218 219 return (err); 220 } 221 222 static void 223 uart_opal_cnprobe(struct consdev *cp) 224 { 225 char buf[64]; 226 phandle_t input, chosen; 227 static struct uart_opal_softc sc; 228 229 if (opal_check() != 0) 230 goto fail; 231 232 if ((chosen = OF_finddevice("/chosen")) == -1) 233 goto fail; 234 235 /* Check if OF has an active stdin/stdout */ 236 if (OF_getprop(chosen, "linux,stdout-path", buf, sizeof(buf)) <= 0) 237 goto fail; 238 239 input = OF_finddevice(buf); 240 if (input == -1) 241 goto fail; 242 243 sc.node = input; 244 if (uart_opal_probe_node(&sc) != 0) 245 goto fail; 246 mtx_init(&sc.sc_mtx, "uart_opal", NULL, MTX_SPIN | MTX_QUIET | 247 MTX_NOWITNESS); 248 249 cp->cn_pri = CN_NORMAL; 250 console_sc = ≻ 251 return; 252 253 fail: 254 cp->cn_pri = CN_DEAD; 255 return; 256 } 257 258 static int 259 uart_opal_attach(device_t dev) 260 { 261 struct uart_opal_softc *sc; 262 int unit; 263 264 sc = device_get_softc(dev); 265 sc->dev = dev; 266 sc->node = ofw_bus_get_node(dev); 267 uart_opal_probe_node(sc); 268 269 unit = device_get_unit(dev); 270 sc->tp = tty_alloc(&uart_opal_tty_class, sc); 271 mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, 272 MTX_SPIN | MTX_QUIET | MTX_NOWITNESS); 273 274 if (console_sc != NULL && console_sc->vtermid == sc->vtermid) { 275 device_printf(dev, "console\n"); 276 sc->outseqno = console_sc->outseqno; 277 console_sc = sc; 278 sprintf(uart_opal_consdev.cn_name, "ttyu%r", unit); 279 tty_init_console(sc->tp, 0); 280 } 281 282 sc->irqrid = 0; 283 sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqrid, 284 RF_ACTIVE | RF_SHAREABLE); 285 if (sc->irqres != NULL) { 286 bus_setup_intr(dev, sc->irqres, INTR_TYPE_TTY | INTR_MPSAFE, 287 NULL, uart_opal_intr, sc, &sc->sc_icookie); 288 } else { 289 callout_init(&sc->callout, CALLOUT_MPSAFE); 290 sc->polltime = hz / 20; 291 if (sc->polltime < 1) 292 sc->polltime = 1; 293 callout_reset(&sc->callout, sc->polltime, uart_opal_intr, sc); 294 } 295 296 tty_makedev(sc->tp, NULL, "u%r", unit); 297 298 return (0); 299 } 300 301 static void 302 uart_opal_cninit(struct consdev *cp) 303 { 304 305 strcpy(cp->cn_name, "opalcons"); 306 } 307 308 static void 309 uart_opal_cnterm(struct consdev *cp) 310 { 311 } 312 313 static int 314 uart_opal_get(struct uart_opal_softc *sc, void *buffer, size_t bufsize) 315 { 316 int err; 317 int hdr = 0; 318 319 if (sc->protocol == OPAL_RAW) { 320 uint64_t len = bufsize; 321 uint64_t olen = (uint64_t)&len; 322 uint64_t obuf = (uint64_t)buffer; 323 324 if (pmap_bootstrapped) { 325 olen = vtophys(&len); 326 obuf = vtophys(buffer); 327 } 328 329 err = opal_call(OPAL_CONSOLE_READ, sc->vtermid, olen, obuf); 330 if (err != OPAL_SUCCESS) 331 return (-1); 332 333 bufsize = len; 334 } else { 335 uart_lock(&sc->sc_mtx); 336 if (sc->inbuflen == 0) { 337 err = opal_call(OPAL_CONSOLE_READ, sc->vtermid, 338 &sc->inbuflen, sc->opal_inbuf); 339 if (err != OPAL_SUCCESS) { 340 uart_unlock(&sc->sc_mtx); 341 return (-1); 342 } 343 hdr = 1; 344 } 345 346 if (sc->inbuflen == 0) { 347 uart_unlock(&sc->sc_mtx); 348 return (0); 349 } 350 351 if (bufsize > sc->inbuflen) 352 bufsize = sc->inbuflen; 353 354 if (hdr == 1) { 355 sc->inbuflen = sc->inbuflen - 4; 356 /* The HVSI protocol has a 4 byte header, skip it */ 357 memmove(&sc->opal_inbuf[0], &sc->opal_inbuf[4], 358 sc->inbuflen); 359 } 360 361 memcpy(buffer, sc->opal_inbuf, bufsize); 362 sc->inbuflen -= bufsize; 363 if (sc->inbuflen > 0) 364 memmove(&sc->opal_inbuf[0], &sc->opal_inbuf[bufsize], 365 sc->inbuflen); 366 367 uart_unlock(&sc->sc_mtx); 368 } 369 370 return (bufsize); 371 } 372 373 static int 374 uart_opal_put(struct uart_opal_softc *sc, void *buffer, size_t bufsize) 375 { 376 uint16_t seqno; 377 uint64_t len; 378 char cbuf[16]; 379 int err; 380 uint64_t olen = (uint64_t)&len; 381 uint64_t obuf = (uint64_t)cbuf; 382 383 if (sc->protocol == OPAL_RAW) { 384 obuf = (uint64_t)buffer; 385 len = bufsize; 386 387 uart_opal_real_map_outbuffer(&obuf, &olen); 388 err = opal_call(OPAL_CONSOLE_WRITE, sc->vtermid, olen, obuf); 389 uart_opal_real_unmap_outbuffer(&len); 390 } else { 391 uart_lock(&sc->sc_mtx); 392 if (bufsize > 12) 393 bufsize = 12; 394 seqno = sc->outseqno++; 395 cbuf[0] = VS_DATA_PACKET_HEADER; 396 cbuf[1] = 4 + bufsize; /* total length */ 397 cbuf[2] = (seqno >> 8) & 0xff; 398 cbuf[3] = seqno & 0xff; 399 memcpy(&cbuf[4], buffer, bufsize); 400 len = 4 + bufsize; 401 402 uart_opal_real_map_outbuffer(&obuf, &olen); 403 err = opal_call(OPAL_CONSOLE_WRITE, sc->vtermid, olen, obuf); 404 uart_opal_real_unmap_outbuffer(&len); 405 406 uart_unlock(&sc->sc_mtx); 407 408 len -= 4; 409 } 410 411 #if 0 412 if (err != OPAL_SUCCESS) 413 len = 0; 414 #endif 415 416 return (len); 417 } 418 419 static int 420 uart_opal_cngetc(struct consdev *cp) 421 { 422 unsigned char c; 423 int retval; 424 425 retval = uart_opal_get(console_sc, &c, 1); 426 if (retval != 1) 427 return (-1); 428 #if defined(KDB) 429 kdb_alt_break(c, &alt_break_state); 430 #endif 431 432 return (c); 433 } 434 435 static void 436 uart_opal_cnputc(struct consdev *cp, int c) 437 { 438 unsigned char ch = c; 439 int a; 440 441 if (1) { 442 /* Clear FIFO if needed. Must be repeated few times. */ 443 for (a = 0; a < 20; a++) { 444 opal_call(OPAL_POLL_EVENTS, NULL); 445 } 446 } 447 uart_opal_put(console_sc, &ch, 1); 448 } 449 450 static void 451 uart_opal_cngrab(struct consdev *cp) 452 { 453 } 454 455 static void 456 uart_opal_cnungrab(struct consdev *cp) 457 { 458 } 459 460 static void 461 uart_opal_ttyoutwakeup(struct tty *tp) 462 { 463 struct uart_opal_softc *sc; 464 char buffer[8]; 465 int len; 466 467 sc = tty_softc(tp); 468 469 while ((len = ttydisc_getc(tp, buffer, sizeof(buffer))) != 0) 470 uart_opal_put(sc, buffer, len); 471 } 472 473 static void 474 uart_opal_intr(void *v) 475 { 476 struct uart_opal_softc *sc = v; 477 struct tty *tp = sc->tp; 478 int c; 479 480 tty_lock(tp); 481 while ((c = uart_opal_cngetc(NULL)) > 0) 482 ttydisc_rint(tp, c, 0); 483 ttydisc_rint_done(tp); 484 tty_unlock(tp); 485 486 opal_call(OPAL_POLL_EVENTS, NULL); 487 488 if (sc->irqres == NULL) 489 callout_reset(&sc->callout, sc->polltime, uart_opal_intr, sc); 490 } 491 492 static int 493 opalcons_probe(device_t dev) 494 { 495 const char *name; 496 497 name = ofw_bus_get_name(dev); 498 if (name == NULL || strcmp(name, "consoles") != 0) 499 return (ENXIO); 500 501 device_set_desc(dev, "OPAL Consoles"); 502 return (BUS_PROBE_SPECIFIC); 503 } 504 505 static int 506 opalcons_attach(device_t dev) 507 { 508 phandle_t child; 509 device_t cdev; 510 struct ofw_bus_devinfo *dinfo; 511 512 for (child = OF_child(ofw_bus_get_node(dev)); child != 0; 513 child = OF_peer(child)) { 514 dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO); 515 if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) { 516 free(dinfo, M_DEVBUF); 517 continue; 518 } 519 cdev = device_add_child(dev, NULL, -1); 520 if (cdev == NULL) { 521 device_printf(dev, "<%s>: device_add_child failed\n", 522 dinfo->obd_name); 523 ofw_bus_gen_destroy_devinfo(dinfo); 524 free(dinfo, M_DEVBUF); 525 continue; 526 } 527 device_set_ivars(cdev, dinfo); 528 } 529 530 return (bus_generic_attach(dev)); 531 } 532 533 static const struct ofw_bus_devinfo * 534 opalcons_get_devinfo(device_t dev, device_t child) 535 { 536 return (device_get_ivars(child)); 537 } 538 539 static device_method_t opalcons_methods[] = { 540 /* Device interface */ 541 DEVMETHOD(device_probe, opalcons_probe), 542 DEVMETHOD(device_attach, opalcons_attach), 543 544 /* ofw_bus interface */ 545 DEVMETHOD(ofw_bus_get_devinfo, opalcons_get_devinfo), 546 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 547 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 548 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 549 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 550 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 551 552 DEVMETHOD_END 553 }; 554 555 static driver_t opalcons_driver = { 556 "opalcons", 557 opalcons_methods, 558 0 559 }; 560 561 static devclass_t opalcons_devclass; 562 563 DRIVER_MODULE(opalcons, opal, opalcons_driver, opalcons_devclass, 0, 0); 564 565