1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (C) 2011 by Nathan Whitehorn. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 #include <sys/endian.h> 29 #include <sys/param.h> 30 #include <sys/kdb.h> 31 #include <sys/kernel.h> 32 #include <sys/priv.h> 33 #include <sys/systm.h> 34 #include <sys/module.h> 35 #include <sys/types.h> 36 #include <sys/conf.h> 37 #include <sys/cons.h> 38 #include <sys/tty.h> 39 #include <machine/bus.h> 40 41 #include <dev/ofw/openfirm.h> 42 #include <dev/ofw/ofw_bus.h> 43 #include <dev/ofw/ofw_bus_subr.h> 44 #include <dev/uart/uart.h> 45 #include <dev/uart/uart_cpu.h> 46 #include <dev/uart/uart_bus.h> 47 48 #include "phyp-hvcall.h" 49 #include "uart_if.h" 50 51 struct uart_phyp_softc { 52 device_t dev; 53 phandle_t node; 54 int vtermid; 55 56 struct tty *tp; 57 struct resource *irqres; 58 int irqrid; 59 struct callout callout; 60 void *sc_icookie; 61 int polltime; 62 63 struct mtx sc_mtx; 64 int protocol; 65 66 union { 67 uint64_t u64[2]; 68 char str[16]; 69 } phyp_inbuf; 70 uint64_t inbuflen; 71 uint8_t outseqno; 72 }; 73 74 static struct uart_phyp_softc *console_sc = NULL; 75 #if defined(KDB) 76 static int alt_break_state; 77 #endif 78 79 enum { 80 HVTERM1, HVTERMPROT 81 }; 82 83 #define VS_DATA_PACKET_HEADER 0xff 84 #define VS_CONTROL_PACKET_HEADER 0xfe 85 #define VSV_SET_MODEM_CTL 0x01 86 #define VSV_MODEM_CTL_UPDATE 0x02 87 #define VSV_RENEGOTIATE_CONNECTION 0x03 88 #define VS_QUERY_PACKET_HEADER 0xfd 89 #define VSV_SEND_VERSION_NUMBER 0x01 90 #define VSV_SEND_MODEM_CTL_STATUS 0x02 91 #define VS_QUERY_RESPONSE_PACKET_HEADER 0xfc 92 93 static int uart_phyp_probe(device_t dev); 94 static int uart_phyp_attach(device_t dev); 95 static void uart_phyp_intr(void *v); 96 97 static device_method_t uart_phyp_methods[] = { 98 /* Device interface */ 99 DEVMETHOD(device_probe, uart_phyp_probe), 100 DEVMETHOD(device_attach, uart_phyp_attach), 101 102 DEVMETHOD_END 103 }; 104 105 static driver_t uart_phyp_driver = { 106 "uart", 107 uart_phyp_methods, 108 sizeof(struct uart_phyp_softc), 109 }; 110 111 DRIVER_MODULE(uart_phyp, vdevice, uart_phyp_driver, 0, 0); 112 113 static cn_probe_t uart_phyp_cnprobe; 114 static cn_init_t uart_phyp_cninit; 115 static cn_term_t uart_phyp_cnterm; 116 static cn_getc_t uart_phyp_cngetc; 117 static cn_putc_t uart_phyp_cnputc; 118 static cn_grab_t uart_phyp_cngrab; 119 static cn_ungrab_t uart_phyp_cnungrab; 120 121 CONSOLE_DRIVER(uart_phyp); 122 123 static void uart_phyp_ttyoutwakeup(struct tty *tp); 124 125 static struct ttydevsw uart_phyp_tty_class = { 126 .tsw_flags = TF_INITLOCK|TF_CALLOUT, 127 .tsw_outwakeup = uart_phyp_ttyoutwakeup, 128 }; 129 130 static int 131 uart_phyp_probe_node(struct uart_phyp_softc *sc) 132 { 133 phandle_t node = sc->node; 134 uint32_t reg; 135 char buf[64]; 136 137 sc->inbuflen = 0; 138 sc->outseqno = 0; 139 140 if (OF_getprop(node, "name", buf, sizeof(buf)) <= 0) 141 return (ENXIO); 142 if (strcmp(buf, "vty") != 0) 143 return (ENXIO); 144 145 if (OF_getprop(node, "device_type", buf, sizeof(buf)) <= 0) 146 return (ENXIO); 147 if (strcmp(buf, "serial") != 0) 148 return (ENXIO); 149 150 reg = -1; 151 OF_getencprop(node, "reg", ®, sizeof(reg)); 152 if (reg == -1) 153 return (ENXIO); 154 sc->vtermid = reg; 155 sc->node = node; 156 157 if (OF_getprop(node, "compatible", buf, sizeof(buf)) <= 0) 158 return (ENXIO); 159 if (strcmp(buf, "hvterm1") == 0) { 160 sc->protocol = HVTERM1; 161 return (0); 162 } else if (strcmp(buf, "hvterm-protocol") == 0) { 163 sc->protocol = HVTERMPROT; 164 return (0); 165 } 166 167 return (ENXIO); 168 } 169 170 static int 171 uart_phyp_probe(device_t dev) 172 { 173 const char *name; 174 struct uart_phyp_softc sc; 175 int err; 176 177 name = ofw_bus_get_name(dev); 178 if (name == NULL || strcmp(name, "vty") != 0) 179 return (ENXIO); 180 181 sc.node = ofw_bus_get_node(dev); 182 err = uart_phyp_probe_node(&sc); 183 if (err != 0) 184 return (err); 185 186 device_set_desc(dev, "POWER Hypervisor Virtual Serial Port"); 187 188 return (err); 189 } 190 191 static void 192 uart_phyp_cnprobe(struct consdev *cp) 193 { 194 char buf[64]; 195 ihandle_t stdout; 196 phandle_t input, chosen; 197 static struct uart_phyp_softc sc; 198 199 if ((chosen = OF_finddevice("/chosen")) == -1) 200 goto fail; 201 202 /* Check if OF has an active stdin/stdout */ 203 input = -1; 204 if (OF_getencprop(chosen, "stdout", &stdout, 205 sizeof(stdout)) == sizeof(stdout) && stdout != 0) 206 input = OF_instance_to_package(stdout); 207 if (input == -1) 208 goto fail; 209 210 if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1) 211 goto fail; 212 if (strcmp(buf, "serial") != 0) 213 goto fail; 214 215 sc.node = input; 216 if (uart_phyp_probe_node(&sc) != 0) 217 goto fail; 218 mtx_init(&sc.sc_mtx, "uart_phyp", NULL, MTX_SPIN | MTX_QUIET | 219 MTX_NOWITNESS); 220 221 cp->cn_pri = CN_NORMAL; 222 console_sc = ≻ 223 return; 224 225 fail: 226 cp->cn_pri = CN_DEAD; 227 return; 228 } 229 230 static int 231 uart_phyp_attach(device_t dev) 232 { 233 struct uart_phyp_softc *sc; 234 int unit; 235 236 sc = device_get_softc(dev); 237 sc->dev = dev; 238 sc->node = ofw_bus_get_node(dev); 239 uart_phyp_probe_node(sc); 240 241 unit = device_get_unit(dev); 242 sc->tp = tty_alloc(&uart_phyp_tty_class, sc); 243 mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, 244 MTX_SPIN | MTX_QUIET | MTX_NOWITNESS); 245 246 if (console_sc != NULL && console_sc->vtermid == sc->vtermid) { 247 sc->outseqno = console_sc->outseqno; 248 console_sc = sc; 249 sprintf(uart_phyp_consdev.cn_name, "ttyu%r", unit); 250 tty_init_console(sc->tp, 0); 251 } 252 253 sc->irqrid = 0; 254 sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqrid, 255 RF_ACTIVE | RF_SHAREABLE); 256 if (sc->irqres != NULL) { 257 bus_setup_intr(dev, sc->irqres, INTR_TYPE_TTY | INTR_MPSAFE, 258 NULL, uart_phyp_intr, sc, &sc->sc_icookie); 259 } else { 260 callout_init(&sc->callout, 1); 261 sc->polltime = hz / 20; 262 if (sc->polltime < 1) 263 sc->polltime = 1; 264 callout_reset(&sc->callout, sc->polltime, uart_phyp_intr, sc); 265 } 266 267 tty_makedev(sc->tp, NULL, "u%r", unit); 268 269 return (0); 270 } 271 272 static void 273 uart_phyp_cninit(struct consdev *cp) 274 { 275 276 strcpy(cp->cn_name, "phypcons"); 277 } 278 279 static void 280 uart_phyp_cnterm(struct consdev *cp) 281 { 282 } 283 284 static int 285 uart_phyp_get(struct uart_phyp_softc *sc, void *buffer, size_t bufsize) 286 { 287 int err; 288 int hdr = 0; 289 uint64_t i, j; 290 291 uart_lock(&sc->sc_mtx); 292 if (sc->inbuflen == 0) { 293 err = phyp_pft_hcall(H_GET_TERM_CHAR, sc->vtermid, 294 0, 0, 0, &sc->inbuflen, &sc->phyp_inbuf.u64[0], 295 &sc->phyp_inbuf.u64[1]); 296 #if BYTE_ORDER == LITTLE_ENDIAN 297 sc->phyp_inbuf.u64[0] = be64toh(sc->phyp_inbuf.u64[0]); 298 sc->phyp_inbuf.u64[1] = be64toh(sc->phyp_inbuf.u64[1]); 299 #endif 300 if (err != H_SUCCESS) { 301 uart_unlock(&sc->sc_mtx); 302 return (-1); 303 } 304 hdr = 1; 305 } 306 307 if (sc->inbuflen == 0) { 308 uart_unlock(&sc->sc_mtx); 309 return (0); 310 } 311 312 if ((sc->protocol == HVTERMPROT) && (hdr == 1)) { 313 sc->inbuflen = sc->inbuflen - 4; 314 /* The VTERM protocol has a 4 byte header, skip it here. */ 315 memmove(&sc->phyp_inbuf.str[0], &sc->phyp_inbuf.str[4], 316 sc->inbuflen); 317 } 318 319 /* 320 * Since version 2.11.0, QEMU became bug-compatible with 321 * PowerVM's vty implementation, by inserting a \0 after 322 * every \r going to the guest. Guests are expected to 323 * workaround this issue by removing every \0 immediately 324 * following a \r. 325 */ 326 if (hdr == 1) { 327 for (i = 0, j = 0; i < sc->inbuflen; i++, j++) { 328 if (i > j) 329 sc->phyp_inbuf.str[j] = sc->phyp_inbuf.str[i]; 330 331 if (sc->phyp_inbuf.str[i] == '\r' && 332 i < sc->inbuflen - 1 && 333 sc->phyp_inbuf.str[i + 1] == '\0') 334 i++; 335 } 336 sc->inbuflen -= i - j; 337 } 338 339 if (bufsize > sc->inbuflen) 340 bufsize = sc->inbuflen; 341 342 memcpy(buffer, sc->phyp_inbuf.str, bufsize); 343 sc->inbuflen -= bufsize; 344 if (sc->inbuflen > 0) 345 memmove(&sc->phyp_inbuf.str[0], &sc->phyp_inbuf.str[bufsize], 346 sc->inbuflen); 347 348 uart_unlock(&sc->sc_mtx); 349 return (bufsize); 350 } 351 352 static int 353 uart_phyp_put(struct uart_phyp_softc *sc, void *buffer, size_t bufsize) 354 { 355 uint16_t seqno; 356 uint64_t len = 0; 357 int err; 358 359 union { 360 uint64_t u64[2]; 361 char bytes[16]; 362 } cbuf; 363 364 uart_lock(&sc->sc_mtx); 365 switch (sc->protocol) { 366 case HVTERM1: 367 if (bufsize > 16) 368 bufsize = 16; 369 memcpy(&cbuf, buffer, bufsize); 370 len = bufsize; 371 break; 372 case HVTERMPROT: 373 if (bufsize > 12) 374 bufsize = 12; 375 seqno = sc->outseqno++; 376 cbuf.bytes[0] = VS_DATA_PACKET_HEADER; 377 cbuf.bytes[1] = 4 + bufsize; /* total length, max 16 bytes */ 378 cbuf.bytes[2] = (seqno >> 8) & 0xff; 379 cbuf.bytes[3] = seqno & 0xff; 380 memcpy(&cbuf.bytes[4], buffer, bufsize); 381 len = 4 + bufsize; 382 break; 383 } 384 385 do { 386 err = phyp_hcall(H_PUT_TERM_CHAR, sc->vtermid, len, htobe64(cbuf.u64[0]), 387 htobe64(cbuf.u64[1])); 388 DELAY(100); 389 } while (err == H_BUSY); 390 391 uart_unlock(&sc->sc_mtx); 392 393 return (bufsize); 394 } 395 396 static int 397 uart_phyp_cngetc(struct consdev *cp) 398 { 399 unsigned char c; 400 int retval; 401 402 retval = uart_phyp_get(console_sc, &c, 1); 403 if (retval != 1) 404 return (-1); 405 #if defined(KDB) 406 kdb_alt_break(c, &alt_break_state); 407 #endif 408 409 return (c); 410 } 411 412 static void 413 uart_phyp_cnputc(struct consdev *cp, int c) 414 { 415 unsigned char ch = c; 416 uart_phyp_put(console_sc, &ch, 1); 417 } 418 419 static void 420 uart_phyp_cngrab(struct consdev *cp) 421 { 422 } 423 424 static void 425 uart_phyp_cnungrab(struct consdev *cp) 426 { 427 } 428 429 static void 430 uart_phyp_ttyoutwakeup(struct tty *tp) 431 { 432 struct uart_phyp_softc *sc; 433 char buffer[8]; 434 int len; 435 436 sc = tty_softc(tp); 437 438 while ((len = ttydisc_getc(tp, buffer, sizeof(buffer))) != 0) 439 uart_phyp_put(sc, buffer, len); 440 } 441 442 static void 443 uart_phyp_intr(void *v) 444 { 445 struct uart_phyp_softc *sc = v; 446 struct tty *tp = sc->tp; 447 unsigned char c; 448 int len; 449 450 tty_lock(tp); 451 while ((len = uart_phyp_get(sc, &c, 1)) > 0) 452 ttydisc_rint(tp, c, 0); 453 ttydisc_rint_done(tp); 454 tty_unlock(tp); 455 456 if (sc->irqres == NULL) 457 callout_reset(&sc->callout, sc->polltime, uart_phyp_intr, sc); 458 } 459