1 /*- 2 * Copyright (c) 2014, Bryan Venteicher <bryanv@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * 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 THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 /* Driver for VirtIO console devices. */ 28 29 #include <sys/param.h> 30 #include <sys/ctype.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/malloc.h> 34 #include <sys/module.h> 35 #include <sys/kdb.h> 36 #include <sys/lock.h> 37 #include <sys/mutex.h> 38 #include <sys/sglist.h> 39 #include <sys/sysctl.h> 40 #include <sys/taskqueue.h> 41 #include <sys/queue.h> 42 43 #include <sys/conf.h> 44 #include <sys/cons.h> 45 #include <sys/tty.h> 46 47 #include <machine/bus.h> 48 #include <machine/resource.h> 49 #include <sys/bus.h> 50 51 #include <dev/virtio/virtio.h> 52 #include <dev/virtio/virtqueue.h> 53 #include <dev/virtio/console/virtio_console.h> 54 55 #include "virtio_if.h" 56 57 #define VTCON_MAX_PORTS 32 58 #define VTCON_TTY_PREFIX "V" 59 #define VTCON_TTY_ALIAS_PREFIX "vtcon" 60 #define VTCON_BULK_BUFSZ 128 61 #define VTCON_CTRL_BUFSZ 128 62 63 /* 64 * The buffers cannot cross more than one page boundary due to the 65 * size of the sglist segment array used. 66 */ 67 CTASSERT(VTCON_BULK_BUFSZ <= PAGE_SIZE); 68 CTASSERT(VTCON_CTRL_BUFSZ <= PAGE_SIZE); 69 70 CTASSERT(sizeof(struct virtio_console_config) <= VTCON_CTRL_BUFSZ); 71 72 struct vtcon_softc; 73 struct vtcon_softc_port; 74 75 struct vtcon_port { 76 struct mtx vtcport_mtx; 77 struct vtcon_softc *vtcport_sc; 78 struct vtcon_softc_port *vtcport_scport; 79 struct tty *vtcport_tty; 80 struct virtqueue *vtcport_invq; 81 struct virtqueue *vtcport_outvq; 82 int vtcport_id; 83 int vtcport_flags; 84 #define VTCON_PORT_FLAG_GONE 0x01 85 #define VTCON_PORT_FLAG_CONSOLE 0x02 86 #define VTCON_PORT_FLAG_ALIAS 0x04 87 88 #if defined(KDB) 89 int vtcport_alt_break_state; 90 #endif 91 }; 92 93 #define VTCON_PORT_LOCK(_port) mtx_lock(&(_port)->vtcport_mtx) 94 #define VTCON_PORT_UNLOCK(_port) mtx_unlock(&(_port)->vtcport_mtx) 95 96 struct vtcon_softc_port { 97 struct vtcon_softc *vcsp_sc; 98 struct vtcon_port *vcsp_port; 99 struct virtqueue *vcsp_invq; 100 struct virtqueue *vcsp_outvq; 101 }; 102 103 struct vtcon_softc { 104 device_t vtcon_dev; 105 struct mtx vtcon_mtx; 106 uint64_t vtcon_features; 107 uint32_t vtcon_max_ports; 108 uint32_t vtcon_flags; 109 #define VTCON_FLAG_DETACHED 0x01 110 #define VTCON_FLAG_SIZE 0x02 111 #define VTCON_FLAG_MULTIPORT 0x04 112 113 /* 114 * Ports can be added and removed during runtime, but we have 115 * to allocate all the virtqueues during attach. This array is 116 * indexed by the port ID. 117 */ 118 struct vtcon_softc_port *vtcon_ports; 119 120 struct task vtcon_ctrl_task; 121 struct virtqueue *vtcon_ctrl_rxvq; 122 struct virtqueue *vtcon_ctrl_txvq; 123 struct mtx vtcon_ctrl_tx_mtx; 124 }; 125 126 #define VTCON_LOCK(_sc) mtx_lock(&(_sc)->vtcon_mtx) 127 #define VTCON_UNLOCK(_sc) mtx_unlock(&(_sc)->vtcon_mtx) 128 #define VTCON_LOCK_ASSERT(_sc) \ 129 mtx_assert(&(_sc)->vtcon_mtx, MA_OWNED) 130 #define VTCON_LOCK_ASSERT_NOTOWNED(_sc) \ 131 mtx_assert(&(_sc)->vtcon_mtx, MA_NOTOWNED) 132 133 #define VTCON_CTRL_TX_LOCK(_sc) mtx_lock(&(_sc)->vtcon_ctrl_tx_mtx) 134 #define VTCON_CTRL_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->vtcon_ctrl_tx_mtx) 135 136 #define VTCON_ASSERT_VALID_PORTID(_sc, _id) \ 137 KASSERT((_id) >= 0 && (_id) < (_sc)->vtcon_max_ports, \ 138 ("%s: port ID %d out of range", __func__, _id)) 139 140 #define VTCON_FEATURES \ 141 (VIRTIO_CONSOLE_F_SIZE | \ 142 VIRTIO_CONSOLE_F_MULTIPORT) 143 144 static struct virtio_feature_desc vtcon_feature_desc[] = { 145 { VIRTIO_CONSOLE_F_SIZE, "ConsoleSize" }, 146 { VIRTIO_CONSOLE_F_MULTIPORT, "MultiplePorts" }, 147 { VIRTIO_CONSOLE_F_EMERG_WRITE, "EmergencyWrite" }, 148 { 0, NULL } 149 }; 150 151 static int vtcon_modevent(module_t, int, void *); 152 static void vtcon_drain_all(void); 153 154 static int vtcon_probe(device_t); 155 static int vtcon_attach(device_t); 156 static int vtcon_detach(device_t); 157 static int vtcon_config_change(device_t); 158 159 static int vtcon_setup_features(struct vtcon_softc *); 160 static int vtcon_negotiate_features(struct vtcon_softc *); 161 static int vtcon_alloc_scports(struct vtcon_softc *); 162 static int vtcon_alloc_virtqueues(struct vtcon_softc *); 163 static void vtcon_read_config(struct vtcon_softc *, 164 struct virtio_console_config *); 165 166 static void vtcon_determine_max_ports(struct vtcon_softc *, 167 struct virtio_console_config *); 168 static void vtcon_destroy_ports(struct vtcon_softc *); 169 static void vtcon_stop(struct vtcon_softc *); 170 171 static int vtcon_ctrl_event_enqueue(struct vtcon_softc *, 172 struct virtio_console_control *); 173 static int vtcon_ctrl_event_create(struct vtcon_softc *); 174 static void vtcon_ctrl_event_requeue(struct vtcon_softc *, 175 struct virtio_console_control *); 176 static int vtcon_ctrl_event_populate(struct vtcon_softc *); 177 static void vtcon_ctrl_event_drain(struct vtcon_softc *); 178 static int vtcon_ctrl_init(struct vtcon_softc *); 179 static void vtcon_ctrl_deinit(struct vtcon_softc *); 180 static void vtcon_ctrl_port_add_event(struct vtcon_softc *, int); 181 static void vtcon_ctrl_port_remove_event(struct vtcon_softc *, int); 182 static void vtcon_ctrl_port_console_event(struct vtcon_softc *, int); 183 static void vtcon_ctrl_port_open_event(struct vtcon_softc *, int); 184 static void vtcon_ctrl_port_resize_event(struct vtcon_softc *, int, 185 const void *, size_t); 186 static void vtcon_ctrl_port_name_event(struct vtcon_softc *, int, 187 const char *, size_t); 188 static void vtcon_ctrl_process_event(struct vtcon_softc *, 189 struct virtio_console_control *, void *, size_t); 190 static void vtcon_ctrl_task_cb(void *, int); 191 static void vtcon_ctrl_event_intr(void *); 192 static void vtcon_ctrl_poll(struct vtcon_softc *, 193 struct virtio_console_control *control); 194 static void vtcon_ctrl_send_control(struct vtcon_softc *, uint32_t, 195 uint16_t, uint16_t); 196 197 static int vtcon_port_enqueue_buf(struct vtcon_port *, void *, size_t); 198 static int vtcon_port_create_buf(struct vtcon_port *); 199 static void vtcon_port_requeue_buf(struct vtcon_port *, void *); 200 static int vtcon_port_populate(struct vtcon_port *); 201 static void vtcon_port_destroy(struct vtcon_port *); 202 static int vtcon_port_create(struct vtcon_softc *, int); 203 static void vtcon_port_dev_alias(struct vtcon_port *, const char *, 204 size_t); 205 static void vtcon_port_drain_bufs(struct virtqueue *); 206 static void vtcon_port_drain(struct vtcon_port *); 207 static void vtcon_port_teardown(struct vtcon_port *); 208 static void vtcon_port_change_size(struct vtcon_port *, uint16_t, 209 uint16_t); 210 static void vtcon_port_update_console_size(struct vtcon_softc *); 211 static void vtcon_port_enable_intr(struct vtcon_port *); 212 static void vtcon_port_disable_intr(struct vtcon_port *); 213 static void vtcon_port_in(struct vtcon_port *); 214 static void vtcon_port_intr(void *); 215 static void vtcon_port_out(struct vtcon_port *, void *, int); 216 static void vtcon_port_submit_event(struct vtcon_port *, uint16_t, 217 uint16_t); 218 219 static int vtcon_tty_open(struct tty *); 220 static void vtcon_tty_close(struct tty *); 221 static void vtcon_tty_outwakeup(struct tty *); 222 static void vtcon_tty_free(void *); 223 224 static void vtcon_get_console_size(struct vtcon_softc *, uint16_t *, 225 uint16_t *); 226 227 static void vtcon_enable_interrupts(struct vtcon_softc *); 228 static void vtcon_disable_interrupts(struct vtcon_softc *); 229 230 #define vtcon_modern(_sc) (((_sc)->vtcon_features & VIRTIO_F_VERSION_1) != 0) 231 #define vtcon_htog16(_sc, _val) virtio_htog16(vtcon_modern(_sc), _val) 232 #define vtcon_htog32(_sc, _val) virtio_htog32(vtcon_modern(_sc), _val) 233 #define vtcon_htog64(_sc, _val) virtio_htog64(vtcon_modern(_sc), _val) 234 #define vtcon_gtoh16(_sc, _val) virtio_gtoh16(vtcon_modern(_sc), _val) 235 #define vtcon_gtoh32(_sc, _val) virtio_gtoh32(vtcon_modern(_sc), _val) 236 #define vtcon_gtoh64(_sc, _val) virtio_gtoh64(vtcon_modern(_sc), _val) 237 238 static int vtcon_pending_free; 239 240 static struct ttydevsw vtcon_tty_class = { 241 .tsw_flags = 0, 242 .tsw_open = vtcon_tty_open, 243 .tsw_close = vtcon_tty_close, 244 .tsw_outwakeup = vtcon_tty_outwakeup, 245 .tsw_free = vtcon_tty_free, 246 }; 247 248 static device_method_t vtcon_methods[] = { 249 /* Device methods. */ 250 DEVMETHOD(device_probe, vtcon_probe), 251 DEVMETHOD(device_attach, vtcon_attach), 252 DEVMETHOD(device_detach, vtcon_detach), 253 254 /* VirtIO methods. */ 255 DEVMETHOD(virtio_config_change, vtcon_config_change), 256 257 DEVMETHOD_END 258 }; 259 260 static driver_t vtcon_driver = { 261 "vtcon", 262 vtcon_methods, 263 sizeof(struct vtcon_softc) 264 }; 265 266 VIRTIO_DRIVER_MODULE(virtio_console, vtcon_driver, vtcon_modevent, NULL); 267 MODULE_VERSION(virtio_console, 1); 268 MODULE_DEPEND(virtio_console, virtio, 1, 1, 1); 269 270 VIRTIO_SIMPLE_PNPINFO(virtio_console, VIRTIO_ID_CONSOLE, 271 "VirtIO Console Adapter"); 272 273 static int 274 vtcon_modevent(module_t mod, int type, void *unused) 275 { 276 int error; 277 278 switch (type) { 279 case MOD_LOAD: 280 error = 0; 281 break; 282 case MOD_QUIESCE: 283 error = 0; 284 break; 285 case MOD_UNLOAD: 286 vtcon_drain_all(); 287 error = 0; 288 break; 289 case MOD_SHUTDOWN: 290 error = 0; 291 break; 292 default: 293 error = EOPNOTSUPP; 294 break; 295 } 296 297 return (error); 298 } 299 300 static void 301 vtcon_drain_all(void) 302 { 303 int first; 304 305 for (first = 1; vtcon_pending_free != 0; first = 0) { 306 if (first != 0) { 307 printf("virtio_console: Waiting for all detached TTY " 308 "devices to have open fds closed.\n"); 309 } 310 pause("vtcondra", hz); 311 } 312 } 313 314 static int 315 vtcon_probe(device_t dev) 316 { 317 return (VIRTIO_SIMPLE_PROBE(dev, virtio_console)); 318 } 319 320 static int 321 vtcon_attach(device_t dev) 322 { 323 struct vtcon_softc *sc; 324 struct virtio_console_config concfg; 325 int error; 326 327 sc = device_get_softc(dev); 328 sc->vtcon_dev = dev; 329 virtio_set_feature_desc(dev, vtcon_feature_desc); 330 331 mtx_init(&sc->vtcon_mtx, "vtconmtx", NULL, MTX_DEF); 332 mtx_init(&sc->vtcon_ctrl_tx_mtx, "vtconctrlmtx", NULL, MTX_DEF); 333 334 error = vtcon_setup_features(sc); 335 if (error) { 336 device_printf(dev, "cannot setup features\n"); 337 goto fail; 338 } 339 340 vtcon_read_config(sc, &concfg); 341 vtcon_determine_max_ports(sc, &concfg); 342 343 error = vtcon_alloc_scports(sc); 344 if (error) { 345 device_printf(dev, "cannot allocate softc port structures\n"); 346 goto fail; 347 } 348 349 error = vtcon_alloc_virtqueues(sc); 350 if (error) { 351 device_printf(dev, "cannot allocate virtqueues\n"); 352 goto fail; 353 } 354 355 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) { 356 TASK_INIT(&sc->vtcon_ctrl_task, 0, vtcon_ctrl_task_cb, sc); 357 error = vtcon_ctrl_init(sc); 358 if (error) 359 goto fail; 360 } else { 361 error = vtcon_port_create(sc, 0); 362 if (error) 363 goto fail; 364 if (sc->vtcon_flags & VTCON_FLAG_SIZE) 365 vtcon_port_update_console_size(sc); 366 } 367 368 error = virtio_setup_intr(dev, INTR_TYPE_TTY); 369 if (error) { 370 device_printf(dev, "cannot setup virtqueue interrupts\n"); 371 goto fail; 372 } 373 374 vtcon_enable_interrupts(sc); 375 376 vtcon_ctrl_send_control(sc, VIRTIO_CONSOLE_BAD_ID, 377 VIRTIO_CONSOLE_DEVICE_READY, 1); 378 379 fail: 380 if (error) 381 vtcon_detach(dev); 382 383 return (error); 384 } 385 386 static int 387 vtcon_detach(device_t dev) 388 { 389 struct vtcon_softc *sc; 390 391 sc = device_get_softc(dev); 392 393 VTCON_LOCK(sc); 394 sc->vtcon_flags |= VTCON_FLAG_DETACHED; 395 if (device_is_attached(dev)) 396 vtcon_stop(sc); 397 VTCON_UNLOCK(sc); 398 399 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) { 400 taskqueue_drain(taskqueue_thread, &sc->vtcon_ctrl_task); 401 vtcon_ctrl_deinit(sc); 402 } 403 404 vtcon_destroy_ports(sc); 405 mtx_destroy(&sc->vtcon_mtx); 406 mtx_destroy(&sc->vtcon_ctrl_tx_mtx); 407 408 return (0); 409 } 410 411 static int 412 vtcon_config_change(device_t dev) 413 { 414 struct vtcon_softc *sc; 415 416 sc = device_get_softc(dev); 417 418 /* 419 * When the multiport feature is negotiated, all configuration 420 * changes are done through control virtqueue events. 421 */ 422 if ((sc->vtcon_flags & VTCON_FLAG_MULTIPORT) == 0) { 423 if (sc->vtcon_flags & VTCON_FLAG_SIZE) 424 vtcon_port_update_console_size(sc); 425 } 426 427 return (0); 428 } 429 430 static int 431 vtcon_negotiate_features(struct vtcon_softc *sc) 432 { 433 device_t dev; 434 uint64_t features; 435 436 dev = sc->vtcon_dev; 437 features = VTCON_FEATURES; 438 439 sc->vtcon_features = virtio_negotiate_features(dev, features); 440 return (virtio_finalize_features(dev)); 441 } 442 443 static int 444 vtcon_setup_features(struct vtcon_softc *sc) 445 { 446 device_t dev; 447 int error; 448 449 dev = sc->vtcon_dev; 450 451 error = vtcon_negotiate_features(sc); 452 if (error) 453 return (error); 454 455 if (virtio_with_feature(dev, VIRTIO_CONSOLE_F_SIZE)) 456 sc->vtcon_flags |= VTCON_FLAG_SIZE; 457 if (virtio_with_feature(dev, VIRTIO_CONSOLE_F_MULTIPORT)) 458 sc->vtcon_flags |= VTCON_FLAG_MULTIPORT; 459 460 return (0); 461 } 462 463 #define VTCON_GET_CONFIG(_dev, _feature, _field, _cfg) \ 464 if (virtio_with_feature(_dev, _feature)) { \ 465 virtio_read_device_config(_dev, \ 466 offsetof(struct virtio_console_config, _field), \ 467 &(_cfg)->_field, sizeof((_cfg)->_field)); \ 468 } 469 470 static void 471 vtcon_read_config(struct vtcon_softc *sc, struct virtio_console_config *concfg) 472 { 473 device_t dev; 474 int gen; 475 476 dev = sc->vtcon_dev; 477 478 do { 479 gen = virtio_config_generation(dev); 480 bzero(concfg, sizeof(struct virtio_console_config)); 481 482 VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_SIZE, cols, concfg); 483 VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_SIZE, rows, concfg); 484 VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_MULTIPORT, max_nr_ports, 485 concfg); 486 } while (gen != virtio_config_generation(dev)); 487 } 488 489 #undef VTCON_GET_CONFIG 490 491 static int 492 vtcon_alloc_scports(struct vtcon_softc *sc) 493 { 494 struct vtcon_softc_port *scport; 495 int max, i; 496 497 max = sc->vtcon_max_ports; 498 499 sc->vtcon_ports = malloc(sizeof(struct vtcon_softc_port) * max, 500 M_DEVBUF, M_NOWAIT | M_ZERO); 501 if (sc->vtcon_ports == NULL) 502 return (ENOMEM); 503 504 for (i = 0; i < max; i++) { 505 scport = &sc->vtcon_ports[i]; 506 scport->vcsp_sc = sc; 507 } 508 509 return (0); 510 } 511 512 static int 513 vtcon_alloc_virtqueues(struct vtcon_softc *sc) 514 { 515 device_t dev; 516 struct vq_alloc_info *info; 517 struct vtcon_softc_port *scport; 518 int i, idx, portidx, nvqs, error; 519 520 dev = sc->vtcon_dev; 521 522 nvqs = sc->vtcon_max_ports * 2; 523 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) 524 nvqs += 2; 525 526 info = malloc(sizeof(struct vq_alloc_info) * nvqs, M_TEMP, M_NOWAIT); 527 if (info == NULL) 528 return (ENOMEM); 529 530 for (i = 0, idx = 0, portidx = 0; i < nvqs / 2; i++, idx += 2) { 531 if (i == 1) { 532 /* The control virtqueues are after the first port. */ 533 VQ_ALLOC_INFO_INIT(&info[idx], 0, 534 vtcon_ctrl_event_intr, sc, &sc->vtcon_ctrl_rxvq, 535 "%s-control rx", device_get_nameunit(dev)); 536 VQ_ALLOC_INFO_INIT(&info[idx+1], 0, 537 NULL, sc, &sc->vtcon_ctrl_txvq, 538 "%s-control tx", device_get_nameunit(dev)); 539 continue; 540 } 541 542 scport = &sc->vtcon_ports[portidx]; 543 544 VQ_ALLOC_INFO_INIT(&info[idx], 0, vtcon_port_intr, 545 scport, &scport->vcsp_invq, "%s-port%d in", 546 device_get_nameunit(dev), i); 547 VQ_ALLOC_INFO_INIT(&info[idx+1], 0, NULL, 548 NULL, &scport->vcsp_outvq, "%s-port%d out", 549 device_get_nameunit(dev), i); 550 551 portidx++; 552 } 553 554 error = virtio_alloc_virtqueues(dev, nvqs, info); 555 free(info, M_TEMP); 556 557 return (error); 558 } 559 560 static void 561 vtcon_determine_max_ports(struct vtcon_softc *sc, 562 struct virtio_console_config *concfg) 563 { 564 565 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) { 566 sc->vtcon_max_ports = 567 min(concfg->max_nr_ports, VTCON_MAX_PORTS); 568 if (sc->vtcon_max_ports == 0) 569 sc->vtcon_max_ports = 1; 570 } else 571 sc->vtcon_max_ports = 1; 572 } 573 574 static void 575 vtcon_destroy_ports(struct vtcon_softc *sc) 576 { 577 struct vtcon_softc_port *scport; 578 struct vtcon_port *port; 579 struct virtqueue *vq; 580 int i; 581 582 if (sc->vtcon_ports == NULL) 583 return; 584 585 VTCON_LOCK(sc); 586 for (i = 0; i < sc->vtcon_max_ports; i++) { 587 scport = &sc->vtcon_ports[i]; 588 589 port = scport->vcsp_port; 590 if (port != NULL) { 591 scport->vcsp_port = NULL; 592 VTCON_PORT_LOCK(port); 593 VTCON_UNLOCK(sc); 594 vtcon_port_teardown(port); 595 VTCON_LOCK(sc); 596 } 597 598 vq = scport->vcsp_invq; 599 if (vq != NULL) 600 vtcon_port_drain_bufs(vq); 601 } 602 VTCON_UNLOCK(sc); 603 604 free(sc->vtcon_ports, M_DEVBUF); 605 sc->vtcon_ports = NULL; 606 } 607 608 static void 609 vtcon_stop(struct vtcon_softc *sc) 610 { 611 612 vtcon_disable_interrupts(sc); 613 virtio_stop(sc->vtcon_dev); 614 } 615 616 static int 617 vtcon_ctrl_event_enqueue(struct vtcon_softc *sc, 618 struct virtio_console_control *control) 619 { 620 struct sglist_seg segs[2]; 621 struct sglist sg; 622 struct virtqueue *vq; 623 int error __diagused; 624 625 vq = sc->vtcon_ctrl_rxvq; 626 627 sglist_init(&sg, 2, segs); 628 error = sglist_append(&sg, control, VTCON_CTRL_BUFSZ); 629 KASSERT(error == 0, ("%s: error %d adding control to sglist", 630 __func__, error)); 631 632 return (virtqueue_enqueue(vq, control, &sg, 0, sg.sg_nseg)); 633 } 634 635 static int 636 vtcon_ctrl_event_create(struct vtcon_softc *sc) 637 { 638 struct virtio_console_control *control; 639 int error; 640 641 control = malloc(VTCON_CTRL_BUFSZ, M_DEVBUF, M_ZERO | M_NOWAIT); 642 if (control == NULL) 643 return (ENOMEM); 644 645 error = vtcon_ctrl_event_enqueue(sc, control); 646 if (error) 647 free(control, M_DEVBUF); 648 649 return (error); 650 } 651 652 static void 653 vtcon_ctrl_event_requeue(struct vtcon_softc *sc, 654 struct virtio_console_control *control) 655 { 656 int error __diagused; 657 658 bzero(control, VTCON_CTRL_BUFSZ); 659 660 error = vtcon_ctrl_event_enqueue(sc, control); 661 KASSERT(error == 0, 662 ("%s: cannot requeue control buffer %d", __func__, error)); 663 } 664 665 static int 666 vtcon_ctrl_event_populate(struct vtcon_softc *sc) 667 { 668 struct virtqueue *vq; 669 int nbufs, error; 670 671 vq = sc->vtcon_ctrl_rxvq; 672 error = ENOSPC; 673 674 for (nbufs = 0; !virtqueue_full(vq); nbufs++) { 675 error = vtcon_ctrl_event_create(sc); 676 if (error) 677 break; 678 } 679 680 if (nbufs > 0) { 681 virtqueue_notify(vq); 682 error = 0; 683 } 684 685 return (error); 686 } 687 688 static void 689 vtcon_ctrl_event_drain(struct vtcon_softc *sc) 690 { 691 struct virtio_console_control *control; 692 struct virtqueue *vq; 693 int last; 694 695 vq = sc->vtcon_ctrl_rxvq; 696 last = 0; 697 698 if (vq == NULL) 699 return; 700 701 VTCON_LOCK(sc); 702 while ((control = virtqueue_drain(vq, &last)) != NULL) 703 free(control, M_DEVBUF); 704 VTCON_UNLOCK(sc); 705 } 706 707 static int 708 vtcon_ctrl_init(struct vtcon_softc *sc) 709 { 710 int error; 711 712 error = vtcon_ctrl_event_populate(sc); 713 714 return (error); 715 } 716 717 static void 718 vtcon_ctrl_deinit(struct vtcon_softc *sc) 719 { 720 721 vtcon_ctrl_event_drain(sc); 722 } 723 724 static void 725 vtcon_ctrl_port_add_event(struct vtcon_softc *sc, int id) 726 { 727 device_t dev; 728 int error; 729 730 dev = sc->vtcon_dev; 731 732 /* This single thread only way for ports to be created. */ 733 if (sc->vtcon_ports[id].vcsp_port != NULL) { 734 device_printf(dev, "%s: adding port %d, but already exists\n", 735 __func__, id); 736 return; 737 } 738 739 error = vtcon_port_create(sc, id); 740 if (error) { 741 device_printf(dev, "%s: cannot create port %d: %d\n", 742 __func__, id, error); 743 vtcon_ctrl_send_control(sc, id, VIRTIO_CONSOLE_PORT_READY, 0); 744 return; 745 } 746 } 747 748 static void 749 vtcon_ctrl_port_remove_event(struct vtcon_softc *sc, int id) 750 { 751 device_t dev; 752 struct vtcon_softc_port *scport; 753 struct vtcon_port *port; 754 755 dev = sc->vtcon_dev; 756 scport = &sc->vtcon_ports[id]; 757 758 VTCON_LOCK(sc); 759 port = scport->vcsp_port; 760 if (port == NULL) { 761 VTCON_UNLOCK(sc); 762 device_printf(dev, "%s: remove port %d, but does not exist\n", 763 __func__, id); 764 return; 765 } 766 767 scport->vcsp_port = NULL; 768 VTCON_PORT_LOCK(port); 769 VTCON_UNLOCK(sc); 770 vtcon_port_teardown(port); 771 } 772 773 static void 774 vtcon_ctrl_port_console_event(struct vtcon_softc *sc, int id) 775 { 776 device_t dev; 777 struct vtcon_softc_port *scport; 778 struct vtcon_port *port; 779 780 dev = sc->vtcon_dev; 781 scport = &sc->vtcon_ports[id]; 782 783 VTCON_LOCK(sc); 784 port = scport->vcsp_port; 785 if (port == NULL) { 786 VTCON_UNLOCK(sc); 787 device_printf(dev, "%s: console port %d, but does not exist\n", 788 __func__, id); 789 return; 790 } 791 792 VTCON_PORT_LOCK(port); 793 VTCON_UNLOCK(sc); 794 port->vtcport_flags |= VTCON_PORT_FLAG_CONSOLE; 795 vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1); 796 VTCON_PORT_UNLOCK(port); 797 } 798 799 static void 800 vtcon_ctrl_port_open_event(struct vtcon_softc *sc, int id) 801 { 802 device_t dev; 803 struct vtcon_softc_port *scport; 804 struct vtcon_port *port; 805 806 dev = sc->vtcon_dev; 807 scport = &sc->vtcon_ports[id]; 808 809 VTCON_LOCK(sc); 810 port = scport->vcsp_port; 811 if (port == NULL) { 812 VTCON_UNLOCK(sc); 813 device_printf(dev, "%s: open port %d, but does not exist\n", 814 __func__, id); 815 return; 816 } 817 818 VTCON_PORT_LOCK(port); 819 VTCON_UNLOCK(sc); 820 vtcon_port_enable_intr(port); 821 VTCON_PORT_UNLOCK(port); 822 } 823 824 static void 825 vtcon_ctrl_port_resize_event(struct vtcon_softc *sc, int id, const void *data, 826 size_t len) 827 { 828 device_t dev; 829 struct vtcon_softc_port *scport; 830 struct vtcon_port *port; 831 struct virtio_console_resize resize; 832 833 dev = sc->vtcon_dev; 834 scport = &sc->vtcon_ports[id]; 835 836 if (data == NULL || len < sizeof(resize)) { 837 device_printf(dev, "%s: resize port %d, but no size\n", 838 __func__, id); 839 return; 840 } 841 memcpy(&resize, data, sizeof(resize)); 842 843 VTCON_LOCK(sc); 844 port = scport->vcsp_port; 845 if (port == NULL) { 846 VTCON_UNLOCK(sc); 847 device_printf(dev, "%s: resize port %d, but does not exist\n", 848 __func__, id); 849 return; 850 } 851 852 VTCON_PORT_LOCK(port); 853 VTCON_UNLOCK(sc); 854 vtcon_port_change_size(port, vtcon_htog16(sc, resize.cols), 855 vtcon_htog16(sc, resize.rows)); 856 VTCON_PORT_UNLOCK(port); 857 } 858 859 static void 860 vtcon_ctrl_port_name_event(struct vtcon_softc *sc, int id, const char *name, 861 size_t len) 862 { 863 device_t dev; 864 struct vtcon_softc_port *scport; 865 struct vtcon_port *port; 866 867 dev = sc->vtcon_dev; 868 scport = &sc->vtcon_ports[id]; 869 870 /* 871 * The VirtIO specification says the NUL terminator is not included in 872 * the length, but QEMU includes it. Adjust the length if needed. 873 */ 874 if (name == NULL || len == 0) 875 return; 876 if (name[len - 1] == '\0') { 877 len--; 878 if (len == 0) 879 return; 880 } 881 882 VTCON_LOCK(sc); 883 port = scport->vcsp_port; 884 if (port == NULL) { 885 VTCON_UNLOCK(sc); 886 device_printf(dev, "%s: name port %d, but does not exist\n", 887 __func__, id); 888 return; 889 } 890 891 VTCON_PORT_LOCK(port); 892 VTCON_UNLOCK(sc); 893 vtcon_port_dev_alias(port, name, len); 894 VTCON_PORT_UNLOCK(port); 895 } 896 897 static void 898 vtcon_ctrl_process_event(struct vtcon_softc *sc, 899 struct virtio_console_control *control, void *data, size_t data_len) 900 { 901 device_t dev; 902 uint32_t id; 903 uint16_t event; 904 905 dev = sc->vtcon_dev; 906 id = vtcon_htog32(sc, control->id); 907 event = vtcon_htog16(sc, control->event); 908 909 if (id >= sc->vtcon_max_ports) { 910 device_printf(dev, "%s: event %d invalid port ID %d\n", 911 __func__, event, id); 912 return; 913 } 914 915 switch (event) { 916 case VIRTIO_CONSOLE_PORT_ADD: 917 vtcon_ctrl_port_add_event(sc, id); 918 break; 919 920 case VIRTIO_CONSOLE_PORT_REMOVE: 921 vtcon_ctrl_port_remove_event(sc, id); 922 break; 923 924 case VIRTIO_CONSOLE_CONSOLE_PORT: 925 vtcon_ctrl_port_console_event(sc, id); 926 break; 927 928 case VIRTIO_CONSOLE_RESIZE: 929 vtcon_ctrl_port_resize_event(sc, id, data, data_len); 930 break; 931 932 case VIRTIO_CONSOLE_PORT_OPEN: 933 vtcon_ctrl_port_open_event(sc, id); 934 break; 935 936 case VIRTIO_CONSOLE_PORT_NAME: 937 vtcon_ctrl_port_name_event(sc, id, (const char *)data, data_len); 938 break; 939 } 940 } 941 942 static void 943 vtcon_ctrl_task_cb(void *xsc, int pending) 944 { 945 struct vtcon_softc *sc; 946 struct virtqueue *vq; 947 struct virtio_console_control *control; 948 void *data; 949 size_t data_len; 950 int detached; 951 uint32_t len; 952 953 sc = xsc; 954 vq = sc->vtcon_ctrl_rxvq; 955 956 VTCON_LOCK(sc); 957 958 while ((detached = (sc->vtcon_flags & VTCON_FLAG_DETACHED)) == 0) { 959 control = virtqueue_dequeue(vq, &len); 960 if (control == NULL) 961 break; 962 963 len = min(len, VTCON_CTRL_BUFSZ); 964 if (len > sizeof(struct virtio_console_control)) { 965 data = (void *) &control[1]; 966 data_len = len - sizeof(struct virtio_console_control); 967 } else { 968 data = NULL; 969 data_len = 0; 970 } 971 972 VTCON_UNLOCK(sc); 973 vtcon_ctrl_process_event(sc, control, data, data_len); 974 VTCON_LOCK(sc); 975 vtcon_ctrl_event_requeue(sc, control); 976 } 977 978 if (!detached) { 979 virtqueue_notify(vq); 980 if (virtqueue_enable_intr(vq) != 0) 981 taskqueue_enqueue(taskqueue_thread, 982 &sc->vtcon_ctrl_task); 983 } 984 985 VTCON_UNLOCK(sc); 986 } 987 988 static void 989 vtcon_ctrl_event_intr(void *xsc) 990 { 991 struct vtcon_softc *sc; 992 993 sc = xsc; 994 995 /* 996 * Only some events require us to potentially block, but it 997 * easier to just defer all event handling to the taskqueue. 998 */ 999 taskqueue_enqueue(taskqueue_thread, &sc->vtcon_ctrl_task); 1000 } 1001 1002 static void 1003 vtcon_ctrl_poll(struct vtcon_softc *sc, 1004 struct virtio_console_control *control) 1005 { 1006 struct sglist_seg segs[2]; 1007 struct sglist sg; 1008 struct virtqueue *vq; 1009 int error; 1010 1011 vq = sc->vtcon_ctrl_txvq; 1012 1013 sglist_init(&sg, 2, segs); 1014 error = sglist_append(&sg, control, 1015 sizeof(struct virtio_console_control)); 1016 KASSERT(error == 0, ("%s: error %d adding control to sglist", 1017 __func__, error)); 1018 1019 /* 1020 * We cannot use the softc lock to serialize access to this 1021 * virtqueue since this is called from the tty layer with the 1022 * port lock held. Acquiring the softc would violate our lock 1023 * ordering. 1024 */ 1025 VTCON_CTRL_TX_LOCK(sc); 1026 KASSERT(virtqueue_empty(vq), 1027 ("%s: virtqueue is not empty", __func__)); 1028 error = virtqueue_enqueue(vq, control, &sg, sg.sg_nseg, 0); 1029 if (error == 0) { 1030 virtqueue_notify(vq); 1031 virtqueue_poll(vq, NULL); 1032 } 1033 VTCON_CTRL_TX_UNLOCK(sc); 1034 } 1035 1036 static void 1037 vtcon_ctrl_send_control(struct vtcon_softc *sc, uint32_t portid, 1038 uint16_t event, uint16_t value) 1039 { 1040 struct virtio_console_control control; 1041 1042 if ((sc->vtcon_flags & VTCON_FLAG_MULTIPORT) == 0) 1043 return; 1044 1045 control.id = vtcon_gtoh32(sc, portid); 1046 control.event = vtcon_gtoh16(sc, event); 1047 control.value = vtcon_gtoh16(sc, value); 1048 1049 vtcon_ctrl_poll(sc, &control); 1050 } 1051 1052 static int 1053 vtcon_port_enqueue_buf(struct vtcon_port *port, void *buf, size_t len) 1054 { 1055 struct sglist_seg segs[2]; 1056 struct sglist sg; 1057 struct virtqueue *vq; 1058 int error; 1059 1060 vq = port->vtcport_invq; 1061 1062 sglist_init(&sg, 2, segs); 1063 error = sglist_append(&sg, buf, len); 1064 KASSERT(error == 0, 1065 ("%s: error %d adding buffer to sglist", __func__, error)); 1066 1067 error = virtqueue_enqueue(vq, buf, &sg, 0, sg.sg_nseg); 1068 1069 return (error); 1070 } 1071 1072 static int 1073 vtcon_port_create_buf(struct vtcon_port *port) 1074 { 1075 void *buf; 1076 int error; 1077 1078 buf = malloc(VTCON_BULK_BUFSZ, M_DEVBUF, M_ZERO | M_NOWAIT); 1079 if (buf == NULL) 1080 return (ENOMEM); 1081 1082 error = vtcon_port_enqueue_buf(port, buf, VTCON_BULK_BUFSZ); 1083 if (error) 1084 free(buf, M_DEVBUF); 1085 1086 return (error); 1087 } 1088 1089 static void 1090 vtcon_port_requeue_buf(struct vtcon_port *port, void *buf) 1091 { 1092 int error __diagused; 1093 1094 error = vtcon_port_enqueue_buf(port, buf, VTCON_BULK_BUFSZ); 1095 KASSERT(error == 0, 1096 ("%s: cannot requeue input buffer %d", __func__, error)); 1097 } 1098 1099 static int 1100 vtcon_port_populate(struct vtcon_port *port) 1101 { 1102 struct virtqueue *vq; 1103 int nbufs, error; 1104 1105 vq = port->vtcport_invq; 1106 error = ENOSPC; 1107 1108 for (nbufs = 0; !virtqueue_full(vq); nbufs++) { 1109 error = vtcon_port_create_buf(port); 1110 if (error) 1111 break; 1112 } 1113 1114 if (nbufs > 0) { 1115 virtqueue_notify(vq); 1116 error = 0; 1117 } 1118 1119 return (error); 1120 } 1121 1122 static void 1123 vtcon_port_destroy(struct vtcon_port *port) 1124 { 1125 1126 port->vtcport_sc = NULL; 1127 port->vtcport_scport = NULL; 1128 port->vtcport_invq = NULL; 1129 port->vtcport_outvq = NULL; 1130 port->vtcport_id = -1; 1131 mtx_destroy(&port->vtcport_mtx); 1132 free(port, M_DEVBUF); 1133 } 1134 1135 static int 1136 vtcon_port_init_vqs(struct vtcon_port *port) 1137 { 1138 struct vtcon_softc_port *scport; 1139 int error; 1140 1141 scport = port->vtcport_scport; 1142 1143 port->vtcport_invq = scport->vcsp_invq; 1144 port->vtcport_outvq = scport->vcsp_outvq; 1145 1146 /* 1147 * Free any data left over from when this virtqueue was in use by a 1148 * prior port. We have not yet notified the host that the port is 1149 * ready, so assume nothing in the virtqueue can be for us. 1150 */ 1151 vtcon_port_drain(port); 1152 1153 KASSERT(virtqueue_empty(port->vtcport_invq), 1154 ("%s: in virtqueue is not empty", __func__)); 1155 KASSERT(virtqueue_empty(port->vtcport_outvq), 1156 ("%s: out virtqueue is not empty", __func__)); 1157 1158 error = vtcon_port_populate(port); 1159 if (error) 1160 return (error); 1161 1162 return (0); 1163 } 1164 1165 static int 1166 vtcon_port_create(struct vtcon_softc *sc, int id) 1167 { 1168 device_t dev; 1169 struct vtcon_softc_port *scport; 1170 struct vtcon_port *port; 1171 int error; 1172 1173 dev = sc->vtcon_dev; 1174 scport = &sc->vtcon_ports[id]; 1175 1176 VTCON_ASSERT_VALID_PORTID(sc, id); 1177 MPASS(scport->vcsp_port == NULL); 1178 1179 port = malloc(sizeof(struct vtcon_port), M_DEVBUF, M_NOWAIT | M_ZERO); 1180 if (port == NULL) 1181 return (ENOMEM); 1182 1183 port->vtcport_sc = sc; 1184 port->vtcport_scport = scport; 1185 port->vtcport_id = id; 1186 mtx_init(&port->vtcport_mtx, "vtcpmtx", NULL, MTX_DEF); 1187 port->vtcport_tty = tty_alloc_mutex(&vtcon_tty_class, port, 1188 &port->vtcport_mtx); 1189 1190 error = vtcon_port_init_vqs(port); 1191 if (error) { 1192 VTCON_PORT_LOCK(port); 1193 vtcon_port_teardown(port); 1194 return (error); 1195 } 1196 1197 VTCON_LOCK(sc); 1198 VTCON_PORT_LOCK(port); 1199 scport->vcsp_port = port; 1200 vtcon_port_enable_intr(port); 1201 vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_READY, 1); 1202 VTCON_PORT_UNLOCK(port); 1203 VTCON_UNLOCK(sc); 1204 1205 tty_makedev(port->vtcport_tty, NULL, "%s%r.%r", VTCON_TTY_PREFIX, 1206 device_get_unit(dev), id); 1207 1208 return (0); 1209 } 1210 1211 static void 1212 vtcon_port_dev_alias(struct vtcon_port *port, const char *name, size_t len) 1213 { 1214 struct vtcon_softc *sc; 1215 struct cdev *pdev; 1216 struct tty *tp; 1217 int i, error; 1218 1219 sc = port->vtcport_sc; 1220 tp = port->vtcport_tty; 1221 1222 if (port->vtcport_flags & VTCON_PORT_FLAG_ALIAS) 1223 return; 1224 1225 /* Port name is UTF-8, but we can only handle ASCII. */ 1226 for (i = 0; i < len; i++) { 1227 if (!isascii(name[i])) 1228 return; 1229 } 1230 1231 /* 1232 * Port name may not conform to the devfs requirements so we cannot use 1233 * tty_makealias() because the MAKEDEV_CHECKNAME flag must be specified. 1234 */ 1235 error = make_dev_alias_p(MAKEDEV_NOWAIT | MAKEDEV_CHECKNAME, &pdev, 1236 tp->t_dev, "%s/%*s", VTCON_TTY_ALIAS_PREFIX, (int)len, name); 1237 if (error) { 1238 device_printf(sc->vtcon_dev, 1239 "%s: cannot make dev alias (%s/%*s) error %d\n", __func__, 1240 VTCON_TTY_ALIAS_PREFIX, (int)len, name, error); 1241 } else 1242 port->vtcport_flags |= VTCON_PORT_FLAG_ALIAS; 1243 } 1244 1245 static void 1246 vtcon_port_drain_bufs(struct virtqueue *vq) 1247 { 1248 void *buf; 1249 int last; 1250 1251 last = 0; 1252 1253 while ((buf = virtqueue_drain(vq, &last)) != NULL) 1254 free(buf, M_DEVBUF); 1255 } 1256 1257 static void 1258 vtcon_port_drain(struct vtcon_port *port) 1259 { 1260 1261 vtcon_port_drain_bufs(port->vtcport_invq); 1262 } 1263 1264 static void 1265 vtcon_port_teardown(struct vtcon_port *port) 1266 { 1267 struct tty *tp; 1268 1269 tp = port->vtcport_tty; 1270 1271 port->vtcport_flags |= VTCON_PORT_FLAG_GONE; 1272 1273 if (tp != NULL) { 1274 atomic_add_int(&vtcon_pending_free, 1); 1275 tty_rel_gone(tp); 1276 } else 1277 vtcon_port_destroy(port); 1278 } 1279 1280 static void 1281 vtcon_port_change_size(struct vtcon_port *port, uint16_t cols, uint16_t rows) 1282 { 1283 struct tty *tp; 1284 struct winsize sz; 1285 1286 tp = port->vtcport_tty; 1287 1288 if (tp == NULL) 1289 return; 1290 1291 bzero(&sz, sizeof(struct winsize)); 1292 sz.ws_col = cols; 1293 sz.ws_row = rows; 1294 1295 tty_set_winsize(tp, &sz); 1296 } 1297 1298 static void 1299 vtcon_port_update_console_size(struct vtcon_softc *sc) 1300 { 1301 struct vtcon_port *port; 1302 struct vtcon_softc_port *scport; 1303 uint16_t cols, rows; 1304 1305 vtcon_get_console_size(sc, &cols, &rows); 1306 1307 /* 1308 * For now, assume the first (only) port is the console. Note 1309 * QEMU does not implement this feature yet. 1310 */ 1311 scport = &sc->vtcon_ports[0]; 1312 1313 VTCON_LOCK(sc); 1314 port = scport->vcsp_port; 1315 1316 if (port != NULL) { 1317 VTCON_PORT_LOCK(port); 1318 VTCON_UNLOCK(sc); 1319 vtcon_port_change_size(port, cols, rows); 1320 VTCON_PORT_UNLOCK(port); 1321 } else 1322 VTCON_UNLOCK(sc); 1323 } 1324 1325 static void 1326 vtcon_port_enable_intr(struct vtcon_port *port) 1327 { 1328 1329 /* 1330 * NOTE: The out virtqueue is always polled, so its interrupt 1331 * kept disabled. 1332 */ 1333 virtqueue_enable_intr(port->vtcport_invq); 1334 } 1335 1336 static void 1337 vtcon_port_disable_intr(struct vtcon_port *port) 1338 { 1339 1340 if (port->vtcport_invq != NULL) 1341 virtqueue_disable_intr(port->vtcport_invq); 1342 if (port->vtcport_outvq != NULL) 1343 virtqueue_disable_intr(port->vtcport_outvq); 1344 } 1345 1346 static void 1347 vtcon_port_in(struct vtcon_port *port) 1348 { 1349 struct virtqueue *vq; 1350 struct tty *tp; 1351 char *buf; 1352 uint32_t len; 1353 int i, deq; 1354 1355 tp = port->vtcport_tty; 1356 vq = port->vtcport_invq; 1357 1358 again: 1359 deq = 0; 1360 1361 while ((buf = virtqueue_dequeue(vq, &len)) != NULL) { 1362 len = min(len, VTCON_BULK_BUFSZ); 1363 for (i = 0; i < len; i++) { 1364 #if defined(KDB) 1365 if (port->vtcport_flags & VTCON_PORT_FLAG_CONSOLE) 1366 kdb_alt_break(buf[i], 1367 &port->vtcport_alt_break_state); 1368 #endif 1369 ttydisc_rint(tp, buf[i], 0); 1370 } 1371 vtcon_port_requeue_buf(port, buf); 1372 deq++; 1373 } 1374 ttydisc_rint_done(tp); 1375 1376 if (deq > 0) 1377 virtqueue_notify(vq); 1378 1379 if (virtqueue_enable_intr(vq) != 0) 1380 goto again; 1381 } 1382 1383 static void 1384 vtcon_port_intr(void *scportx) 1385 { 1386 struct vtcon_softc_port *scport; 1387 struct vtcon_softc *sc; 1388 struct vtcon_port *port; 1389 1390 scport = scportx; 1391 sc = scport->vcsp_sc; 1392 1393 VTCON_LOCK(sc); 1394 port = scport->vcsp_port; 1395 if (port == NULL) { 1396 VTCON_UNLOCK(sc); 1397 return; 1398 } 1399 VTCON_PORT_LOCK(port); 1400 VTCON_UNLOCK(sc); 1401 if ((port->vtcport_flags & VTCON_PORT_FLAG_GONE) == 0) 1402 vtcon_port_in(port); 1403 VTCON_PORT_UNLOCK(port); 1404 } 1405 1406 static void 1407 vtcon_port_out(struct vtcon_port *port, void *buf, int bufsize) 1408 { 1409 struct sglist_seg segs[2]; 1410 struct sglist sg; 1411 struct virtqueue *vq; 1412 int error; 1413 1414 vq = port->vtcport_outvq; 1415 KASSERT(virtqueue_empty(vq), 1416 ("%s: port %p out virtqueue not empty", __func__, port)); 1417 1418 sglist_init(&sg, 2, segs); 1419 error = sglist_append(&sg, buf, bufsize); 1420 KASSERT(error == 0, ("%s: error %d adding buffer to sglist", 1421 __func__, error)); 1422 1423 error = virtqueue_enqueue(vq, buf, &sg, sg.sg_nseg, 0); 1424 if (error == 0) { 1425 virtqueue_notify(vq); 1426 virtqueue_poll(vq, NULL); 1427 } 1428 } 1429 1430 static void 1431 vtcon_port_submit_event(struct vtcon_port *port, uint16_t event, 1432 uint16_t value) 1433 { 1434 struct vtcon_softc *sc; 1435 1436 sc = port->vtcport_sc; 1437 1438 vtcon_ctrl_send_control(sc, port->vtcport_id, event, value); 1439 } 1440 1441 static int 1442 vtcon_tty_open(struct tty *tp) 1443 { 1444 struct vtcon_port *port; 1445 1446 port = tty_softc(tp); 1447 1448 if (port->vtcport_flags & VTCON_PORT_FLAG_GONE) 1449 return (ENXIO); 1450 1451 vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1); 1452 1453 return (0); 1454 } 1455 1456 static void 1457 vtcon_tty_close(struct tty *tp) 1458 { 1459 struct vtcon_port *port; 1460 1461 port = tty_softc(tp); 1462 1463 if (port->vtcport_flags & VTCON_PORT_FLAG_GONE) 1464 return; 1465 1466 vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_OPEN, 0); 1467 } 1468 1469 static void 1470 vtcon_tty_outwakeup(struct tty *tp) 1471 { 1472 struct vtcon_port *port; 1473 char buf[VTCON_BULK_BUFSZ]; 1474 int len; 1475 1476 port = tty_softc(tp); 1477 1478 if (port->vtcport_flags & VTCON_PORT_FLAG_GONE) 1479 return; 1480 1481 while ((len = ttydisc_getc(tp, buf, sizeof(buf))) != 0) 1482 vtcon_port_out(port, buf, len); 1483 } 1484 1485 static void 1486 vtcon_tty_free(void *xport) 1487 { 1488 struct vtcon_port *port; 1489 1490 port = xport; 1491 1492 vtcon_port_destroy(port); 1493 atomic_subtract_int(&vtcon_pending_free, 1); 1494 } 1495 1496 static void 1497 vtcon_get_console_size(struct vtcon_softc *sc, uint16_t *cols, uint16_t *rows) 1498 { 1499 struct virtio_console_config concfg; 1500 1501 KASSERT(sc->vtcon_flags & VTCON_FLAG_SIZE, 1502 ("%s: size feature not negotiated", __func__)); 1503 1504 vtcon_read_config(sc, &concfg); 1505 1506 *cols = concfg.cols; 1507 *rows = concfg.rows; 1508 } 1509 1510 static void 1511 vtcon_enable_interrupts(struct vtcon_softc *sc) 1512 { 1513 struct vtcon_softc_port *scport; 1514 struct vtcon_port *port; 1515 int i; 1516 1517 VTCON_LOCK(sc); 1518 1519 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) 1520 virtqueue_enable_intr(sc->vtcon_ctrl_rxvq); 1521 1522 for (i = 0; i < sc->vtcon_max_ports; i++) { 1523 scport = &sc->vtcon_ports[i]; 1524 1525 port = scport->vcsp_port; 1526 if (port == NULL) 1527 continue; 1528 1529 VTCON_PORT_LOCK(port); 1530 vtcon_port_enable_intr(port); 1531 VTCON_PORT_UNLOCK(port); 1532 } 1533 1534 VTCON_UNLOCK(sc); 1535 } 1536 1537 static void 1538 vtcon_disable_interrupts(struct vtcon_softc *sc) 1539 { 1540 struct vtcon_softc_port *scport; 1541 struct vtcon_port *port; 1542 int i; 1543 1544 VTCON_LOCK_ASSERT(sc); 1545 1546 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) 1547 virtqueue_disable_intr(sc->vtcon_ctrl_rxvq); 1548 1549 for (i = 0; i < sc->vtcon_max_ports; i++) { 1550 scport = &sc->vtcon_ports[i]; 1551 1552 port = scport->vcsp_port; 1553 if (port == NULL) 1554 continue; 1555 1556 VTCON_PORT_LOCK(port); 1557 vtcon_port_disable_intr(port); 1558 VTCON_PORT_UNLOCK(port); 1559 } 1560 } 1561