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