1 /* 2 * Copyright (c) 2011 NetApp, Inc. 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, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 /* 27 * This file and its contents are supplied under the terms of the 28 * Common Development and Distribution License ("CDDL"), version 1.0. 29 * You may only use this file in accordance with the terms of version 30 * 1.0 of the CDDL. 31 * 32 * A full copy of the text of the CDDL should have accompanied this 33 * source. A copy of the CDDL is also available via the Internet at 34 * http://www.illumos.org/license/CDDL. 35 * 36 * Copyright 2015 Pluribus Networks Inc. 37 * Copyright 2019 Joyent, Inc. 38 */ 39 40 #include <sys/cdefs.h> 41 42 #include <sys/param.h> 43 #include <sys/linker_set.h> 44 #include <sys/ioctl.h> 45 #include <sys/viona_io.h> 46 47 #include <errno.h> 48 #include <fcntl.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <stdint.h> 52 #include <string.h> 53 #include <strings.h> 54 #include <unistd.h> 55 #include <assert.h> 56 #include <pthread.h> 57 #include <signal.h> 58 #include <poll.h> 59 #include <libdladm.h> 60 #include <libdllink.h> 61 #include <libdlvnic.h> 62 63 #include <machine/vmm.h> 64 #include <vmmapi.h> 65 66 #include "bhyverun.h" 67 #include "pci_emul.h" 68 #include "virtio.h" 69 70 #define VIONA_RINGSZ 1024 71 72 /* 73 * PCI config-space register offsets 74 */ 75 #define VIONA_R_CFG0 24 76 #define VIONA_R_CFG1 25 77 #define VIONA_R_CFG2 26 78 #define VIONA_R_CFG3 27 79 #define VIONA_R_CFG4 28 80 #define VIONA_R_CFG5 29 81 #define VIONA_R_CFG6 30 82 #define VIONA_R_CFG7 31 83 #define VIONA_R_MAX 31 84 85 #define VIONA_REGSZ VIONA_R_MAX+1 86 87 /* 88 * Queue definitions. 89 */ 90 #define VIONA_RXQ 0 91 #define VIONA_TXQ 1 92 #define VIONA_CTLQ 2 93 94 #define VIONA_MAXQ 3 95 96 /* 97 * Debug printf 98 */ 99 static volatile int pci_viona_debug; 100 #define DPRINTF(params) if (pci_viona_debug) printf params 101 #define WPRINTF(params) printf params 102 103 /* 104 * Per-device softc 105 */ 106 struct pci_viona_softc { 107 struct pci_devinst *vsc_pi; 108 pthread_mutex_t vsc_mtx; 109 110 int vsc_curq; 111 int vsc_status; 112 int vsc_isr; 113 114 datalink_id_t vsc_linkid; 115 int vsc_vnafd; 116 117 /* Configurable parameters */ 118 char vsc_linkname[MAXLINKNAMELEN]; 119 uint32_t vsc_feature_mask; 120 uint16_t vsc_vq_size; 121 122 uint32_t vsc_features; 123 uint8_t vsc_macaddr[6]; 124 125 uint64_t vsc_pfn[VIONA_MAXQ]; 126 uint16_t vsc_msix_table_idx[VIONA_MAXQ]; 127 boolean_t vsc_msix_active; 128 }; 129 130 /* 131 * Return the size of IO BAR that maps virtio header and device specific 132 * region. The size would vary depending on whether MSI-X is enabled or 133 * not. 134 */ 135 static uint64_t 136 pci_viona_iosize(struct pci_devinst *pi) 137 { 138 if (pci_msix_enabled(pi)) 139 return (VIONA_REGSZ); 140 else 141 return (VIONA_REGSZ - (VTCFG_R_CFG1 - VTCFG_R_MSIX)); 142 } 143 144 static uint16_t 145 pci_viona_qsize(struct pci_viona_softc *sc, int qnum) 146 { 147 /* XXX no ctl queue currently */ 148 if (qnum == VIONA_CTLQ) { 149 return (0); 150 } 151 152 return (sc->vsc_vq_size); 153 } 154 155 static void 156 pci_viona_ring_reset(struct pci_viona_softc *sc, int ring) 157 { 158 assert(ring < VIONA_MAXQ); 159 160 switch (ring) { 161 case VIONA_RXQ: 162 case VIONA_TXQ: 163 break; 164 case VIONA_CTLQ: 165 default: 166 return; 167 } 168 169 for (;;) { 170 int res; 171 172 res = ioctl(sc->vsc_vnafd, VNA_IOC_RING_RESET, ring); 173 if (res == 0) { 174 break; 175 } else if (errno != EINTR) { 176 WPRINTF(("ioctl viona ring %d reset failed %d\n", 177 ring, errno)); 178 return; 179 } 180 } 181 182 sc->vsc_pfn[ring] = 0; 183 } 184 185 static void 186 pci_viona_update_status(struct pci_viona_softc *sc, uint32_t value) 187 { 188 189 if (value == 0) { 190 DPRINTF(("viona: device reset requested !\n")); 191 pci_viona_ring_reset(sc, VIONA_RXQ); 192 pci_viona_ring_reset(sc, VIONA_TXQ); 193 } 194 195 sc->vsc_status = value; 196 } 197 198 static void * 199 pci_viona_poll_thread(void *param) 200 { 201 struct pci_viona_softc *sc = param; 202 pollfd_t pollset; 203 const int fd = sc->vsc_vnafd; 204 205 pollset.fd = fd; 206 pollset.events = POLLRDBAND; 207 208 for (;;) { 209 if (poll(&pollset, 1, -1) < 0) { 210 if (errno == EINTR || errno == EAGAIN) { 211 continue; 212 } else { 213 WPRINTF(("pci_viona_poll_thread poll()" 214 "error %d\n", errno)); 215 break; 216 } 217 } 218 if (pollset.revents & POLLRDBAND) { 219 vioc_intr_poll_t vip; 220 uint_t i; 221 int res; 222 boolean_t assert_lintr = B_FALSE; 223 const boolean_t do_msix = pci_msix_enabled(sc->vsc_pi); 224 225 res = ioctl(fd, VNA_IOC_INTR_POLL, &vip); 226 for (i = 0; res > 0 && i < VIONA_VQ_MAX; i++) { 227 if (vip.vip_status[i] == 0) { 228 continue; 229 } 230 if (do_msix) { 231 pci_generate_msix(sc->vsc_pi, 232 sc->vsc_msix_table_idx[i]); 233 } else { 234 assert_lintr = B_TRUE; 235 } 236 res = ioctl(fd, VNA_IOC_RING_INTR_CLR, i); 237 if (res != 0) { 238 WPRINTF(("ioctl viona vq %d intr " 239 "clear failed %d\n", i, errno)); 240 } 241 } 242 if (assert_lintr) { 243 pthread_mutex_lock(&sc->vsc_mtx); 244 sc->vsc_isr |= VTCFG_ISR_QUEUES; 245 pci_lintr_assert(sc->vsc_pi); 246 pthread_mutex_unlock(&sc->vsc_mtx); 247 } 248 } 249 } 250 251 pthread_exit(NULL); 252 } 253 254 static void 255 pci_viona_ring_init(struct pci_viona_softc *sc, uint64_t pfn) 256 { 257 int qnum = sc->vsc_curq; 258 vioc_ring_init_t vna_ri; 259 int error; 260 261 assert(qnum < VIONA_MAXQ); 262 263 if (qnum == VIONA_CTLQ) { 264 return; 265 } 266 267 sc->vsc_pfn[qnum] = (pfn << VRING_PFN); 268 269 vna_ri.ri_index = qnum; 270 vna_ri.ri_qsize = pci_viona_qsize(sc, qnum); 271 vna_ri.ri_qaddr = (pfn << VRING_PFN); 272 error = ioctl(sc->vsc_vnafd, VNA_IOC_RING_INIT, &vna_ri); 273 274 if (error != 0) { 275 WPRINTF(("ioctl viona ring %u init failed %d\n", qnum, errno)); 276 } 277 } 278 279 static int 280 pci_viona_viona_init(struct vmctx *ctx, struct pci_viona_softc *sc) 281 { 282 vioc_create_t vna_create; 283 int error; 284 285 sc->vsc_vnafd = open("/dev/viona", O_RDWR | O_EXCL); 286 if (sc->vsc_vnafd == -1) { 287 WPRINTF(("open viona ctl failed: %d\n", errno)); 288 return (-1); 289 } 290 291 vna_create.c_linkid = sc->vsc_linkid; 292 vna_create.c_vmfd = vm_get_device_fd(ctx); 293 error = ioctl(sc->vsc_vnafd, VNA_IOC_CREATE, &vna_create); 294 if (error != 0) { 295 (void) close(sc->vsc_vnafd); 296 WPRINTF(("ioctl viona create failed %d\n", errno)); 297 return (-1); 298 } 299 300 return (0); 301 } 302 303 static int 304 pci_viona_parse_opts(struct pci_viona_softc *sc, char *opts) 305 { 306 char *next, *cp, *vnic = NULL; 307 int err = 0; 308 309 sc->vsc_vq_size = VIONA_RINGSZ; 310 sc->vsc_feature_mask = 0; 311 312 for (; opts != NULL && *opts != '\0'; opts = next) { 313 char *val; 314 315 if ((cp = strchr(opts, ',')) != NULL) { 316 *cp = '\0'; 317 next = cp + 1; 318 } else { 319 next = NULL; 320 } 321 322 if ((cp = strchr(opts, '=')) == NULL) { 323 /* vnic chosen with bare name */ 324 if (vnic != NULL) { 325 fprintf(stderr, 326 "viona: unexpected vnic name '%s'", opts); 327 err = -1; 328 } else { 329 vnic = opts; 330 } 331 continue; 332 } 333 334 /* <param>=<value> handling */ 335 val = cp + 1; 336 *cp = '\0'; 337 if (strcmp(opts, "feature_mask") == 0) { 338 long num; 339 340 errno = 0; 341 num = strtol(val, NULL, 0); 342 if (errno != 0 || num < 0) { 343 fprintf(stderr, 344 "viona: invalid mask '%s'", val); 345 } else { 346 sc->vsc_feature_mask = num; 347 } 348 } else if (strcmp(opts, "vqsize") == 0) { 349 long num; 350 351 errno = 0; 352 num = strtol(val, NULL, 0); 353 if (errno != 0) { 354 fprintf(stderr, 355 "viona: invalid vsqize '%s'", val); 356 err = -1; 357 } else if (num <= 2 || num > 32768) { 358 fprintf(stderr, 359 "viona: vqsize out of range", num); 360 err = -1; 361 } else if ((1 << (ffs(num) - 1)) != num) { 362 fprintf(stderr, 363 "viona: vqsize must be power of 2", num); 364 err = -1; 365 } else { 366 sc->vsc_vq_size = num; 367 } 368 } else { 369 fprintf(stderr, 370 "viona: unrecognized option '%s'", opts); 371 err = -1; 372 } 373 } 374 if (vnic == NULL) { 375 fprintf(stderr, "viona: vnic name required"); 376 sc->vsc_linkname[0] = '\0'; 377 err = -1; 378 } else { 379 (void) strlcpy(sc->vsc_linkname, vnic, MAXLINKNAMELEN); 380 } 381 382 DPRINTF(("viona=%p dev=%s vqsize=%x feature_mask=%x\n", sc, 383 sc->vsc_linkname, sc->vsc_vq_size, sc->vsc_feature_mask)); 384 return (err); 385 } 386 387 static int 388 pci_viona_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) 389 { 390 dladm_handle_t handle; 391 dladm_status_t status; 392 dladm_vnic_attr_t attr; 393 char errmsg[DLADM_STRSIZE]; 394 int error, i; 395 struct pci_viona_softc *sc; 396 uint64_t ioport; 397 398 if (opts == NULL) { 399 printf("virtio-viona: vnic required\n"); 400 return (1); 401 } 402 403 sc = malloc(sizeof (struct pci_viona_softc)); 404 memset(sc, 0, sizeof (struct pci_viona_softc)); 405 406 pi->pi_arg = sc; 407 sc->vsc_pi = pi; 408 409 pthread_mutex_init(&sc->vsc_mtx, NULL); 410 411 if (pci_viona_parse_opts(sc, opts) != 0) { 412 free(sc); 413 return (1); 414 } 415 416 if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) { 417 WPRINTF(("could not open /dev/dld")); 418 free(sc); 419 return (1); 420 } 421 422 if (dladm_name2info(handle, sc->vsc_linkname, &sc->vsc_linkid, 423 NULL, NULL, NULL) != DLADM_STATUS_OK) { 424 WPRINTF(("dladm_name2info() for %s failed: %s\n", opts, 425 dladm_status2str(status, errmsg))); 426 dladm_close(handle); 427 free(sc); 428 return (1); 429 } 430 431 if (dladm_vnic_info(handle, sc->vsc_linkid, &attr, 432 DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) { 433 WPRINTF(("dladm_vnic_info() for %s failed: %s\n", opts, 434 dladm_status2str(status, errmsg))); 435 dladm_close(handle); 436 free(sc); 437 return (1); 438 } 439 440 memcpy(sc->vsc_macaddr, attr.va_mac_addr, ETHERADDRL); 441 442 dladm_close(handle); 443 444 error = pci_viona_viona_init(ctx, sc); 445 if (error != 0) { 446 free(sc); 447 return (1); 448 } 449 450 error = pthread_create(NULL, NULL, pci_viona_poll_thread, sc); 451 assert(error == 0); 452 453 /* initialize config space */ 454 pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET); 455 pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); 456 pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK); 457 pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET); 458 pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); 459 460 /* MSI-X support */ 461 for (i = 0; i < VIONA_MAXQ; i++) 462 sc->vsc_msix_table_idx[i] = VIRTIO_MSI_NO_VECTOR; 463 464 /* BAR 1 used to map MSI-X table and PBA */ 465 if (pci_emul_add_msixcap(pi, VIONA_MAXQ, 1)) { 466 free(sc); 467 return (1); 468 } 469 470 /* BAR 0 for legacy-style virtio register access. */ 471 error = pci_emul_alloc_bar(pi, 0, PCIBAR_IO, VIONA_REGSZ); 472 if (error != 0) { 473 WPRINTF(("could not allocate virtio BAR\n")); 474 free(sc); 475 return (1); 476 } 477 478 /* Install ioport hook for virtqueue notification */ 479 ioport = pi->pi_bar[0].addr + VTCFG_R_QNOTIFY; 480 error = ioctl(sc->vsc_vnafd, VNA_IOC_SET_NOTIFY_IOP, ioport); 481 if (error != 0) { 482 WPRINTF(("could not install ioport hook at %x\n", ioport)); 483 free(sc); 484 return (1); 485 } 486 487 /* 488 * Need a legacy interrupt for virtio compliance, even though MSI-X 489 * operation is _strongly_ suggested for adequate performance. 490 */ 491 pci_lintr_request(pi); 492 493 return (0); 494 } 495 496 static uint64_t 497 viona_adjust_offset(struct pci_devinst *pi, uint64_t offset) 498 { 499 /* 500 * Device specific offsets used by guest would change based on 501 * whether MSI-X capability is enabled or not 502 */ 503 if (!pci_msix_enabled(pi)) { 504 if (offset >= VTCFG_R_MSIX) 505 return (offset + (VTCFG_R_CFG1 - VTCFG_R_MSIX)); 506 } 507 508 return (offset); 509 } 510 511 static void 512 pci_viona_ring_set_msix(struct pci_devinst *pi, uint_t ring) 513 { 514 struct pci_viona_softc *sc = pi->pi_arg; 515 struct msix_table_entry mte; 516 uint16_t tab_index; 517 vioc_ring_msi_t vrm; 518 int res; 519 520 assert(ring <= VIONA_VQ_TX); 521 522 vrm.rm_index = ring; 523 vrm.rm_addr = 0; 524 vrm.rm_msg = 0; 525 tab_index = sc->vsc_msix_table_idx[ring]; 526 527 if (tab_index != VIRTIO_MSI_NO_VECTOR && sc->vsc_msix_active) { 528 mte = pi->pi_msix.table[tab_index]; 529 if ((mte.vector_control & PCIM_MSIX_VCTRL_MASK) == 0) { 530 vrm.rm_addr = mte.addr; 531 vrm.rm_msg = mte.msg_data; 532 } 533 } 534 535 res = ioctl(sc->vsc_vnafd, VNA_IOC_RING_SET_MSI, &vrm); 536 if (res != 0) { 537 WPRINTF(("ioctl viona set_msi %d failed %d\n", ring, errno)); 538 } 539 } 540 541 static void 542 pci_viona_lintrupdate(struct pci_devinst *pi) 543 { 544 struct pci_viona_softc *sc = pi->pi_arg; 545 boolean_t msix_on = B_FALSE; 546 547 pthread_mutex_lock(&sc->vsc_mtx); 548 msix_on = pci_msix_enabled(pi) && (pi->pi_msix.function_mask == 0); 549 if ((sc->vsc_msix_active && !msix_on) || 550 (msix_on && !sc->vsc_msix_active)) { 551 uint_t i; 552 553 sc->vsc_msix_active = msix_on; 554 /* Update in-kernel ring configs */ 555 for (i = 0; i <= VIONA_VQ_TX; i++) { 556 pci_viona_ring_set_msix(pi, i); 557 } 558 } 559 pthread_mutex_unlock(&sc->vsc_mtx); 560 } 561 562 static void 563 pci_viona_msix_update(struct pci_devinst *pi, uint64_t offset) 564 { 565 struct pci_viona_softc *sc = pi->pi_arg; 566 uint_t tab_index, i; 567 568 pthread_mutex_lock(&sc->vsc_mtx); 569 if (!sc->vsc_msix_active) { 570 pthread_mutex_unlock(&sc->vsc_mtx); 571 return; 572 } 573 574 /* 575 * Rather than update every possible MSI-X vector, cheat and use the 576 * offset to calculate the entry within the table. Since this should 577 * only be called when a write to the table succeeds, the index should 578 * be valid. 579 */ 580 tab_index = offset / MSIX_TABLE_ENTRY_SIZE; 581 582 for (i = 0; i <= VIONA_VQ_TX; i++) { 583 if (sc->vsc_msix_table_idx[i] != tab_index) { 584 continue; 585 } 586 pci_viona_ring_set_msix(pi, i); 587 } 588 589 pthread_mutex_unlock(&sc->vsc_mtx); 590 } 591 592 static void 593 pci_viona_qnotify(struct pci_viona_softc *sc, int ring) 594 { 595 int error; 596 597 switch (ring) { 598 case VIONA_TXQ: 599 case VIONA_RXQ: 600 error = ioctl(sc->vsc_vnafd, VNA_IOC_RING_KICK, ring); 601 if (error != 0) { 602 WPRINTF(("ioctl viona ring %d kick failed %d\n", 603 ring, errno)); 604 } 605 break; 606 case VIONA_CTLQ: 607 DPRINTF(("viona: control qnotify!\n")); 608 break; 609 default: 610 break; 611 } 612 } 613 614 static void 615 pci_viona_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 616 int baridx, uint64_t offset, int size, uint64_t value) 617 { 618 struct pci_viona_softc *sc = pi->pi_arg; 619 void *ptr; 620 int err = 0; 621 622 if (baridx == pci_msix_table_bar(pi) || 623 baridx == pci_msix_pba_bar(pi)) { 624 if (pci_emul_msix_twrite(pi, offset, size, value) == 0) { 625 pci_viona_msix_update(pi, offset); 626 } 627 return; 628 } 629 630 assert(baridx == 0); 631 632 if (offset + size > pci_viona_iosize(pi)) { 633 DPRINTF(("viona_write: 2big, offset %ld size %d\n", 634 offset, size)); 635 return; 636 } 637 638 pthread_mutex_lock(&sc->vsc_mtx); 639 640 offset = viona_adjust_offset(pi, offset); 641 642 switch (offset) { 643 case VTCFG_R_GUESTCAP: 644 assert(size == 4); 645 value &= ~(sc->vsc_feature_mask); 646 err = ioctl(sc->vsc_vnafd, VNA_IOC_SET_FEATURES, &value); 647 if (err != 0) { 648 WPRINTF(("ioctl feature negotiation returned" 649 " err = %d\n", errno)); 650 } else { 651 sc->vsc_features = value; 652 } 653 break; 654 case VTCFG_R_PFN: 655 assert(size == 4); 656 pci_viona_ring_init(sc, value); 657 break; 658 case VTCFG_R_QSEL: 659 assert(size == 2); 660 assert(value < VIONA_MAXQ); 661 sc->vsc_curq = value; 662 break; 663 case VTCFG_R_QNOTIFY: 664 assert(size == 2); 665 assert(value < VIONA_MAXQ); 666 pci_viona_qnotify(sc, value); 667 break; 668 case VTCFG_R_STATUS: 669 assert(size == 1); 670 pci_viona_update_status(sc, value); 671 break; 672 case VTCFG_R_CFGVEC: 673 assert(size == 2); 674 sc->vsc_msix_table_idx[VIONA_CTLQ] = value; 675 break; 676 case VTCFG_R_QVEC: 677 assert(size == 2); 678 assert(sc->vsc_curq != VIONA_CTLQ); 679 sc->vsc_msix_table_idx[sc->vsc_curq] = value; 680 pci_viona_ring_set_msix(pi, sc->vsc_curq); 681 break; 682 case VIONA_R_CFG0: 683 case VIONA_R_CFG1: 684 case VIONA_R_CFG2: 685 case VIONA_R_CFG3: 686 case VIONA_R_CFG4: 687 case VIONA_R_CFG5: 688 assert((size + offset) <= (VIONA_R_CFG5 + 1)); 689 ptr = &sc->vsc_macaddr[offset - VIONA_R_CFG0]; 690 /* 691 * The driver is allowed to change the MAC address 692 */ 693 sc->vsc_macaddr[offset - VIONA_R_CFG0] = value; 694 if (size == 1) { 695 *(uint8_t *)ptr = value; 696 } else if (size == 2) { 697 *(uint16_t *)ptr = value; 698 } else { 699 *(uint32_t *)ptr = value; 700 } 701 break; 702 case VTCFG_R_HOSTCAP: 703 case VTCFG_R_QNUM: 704 case VTCFG_R_ISR: 705 case VIONA_R_CFG6: 706 case VIONA_R_CFG7: 707 DPRINTF(("viona: write to readonly reg %ld\n\r", offset)); 708 break; 709 default: 710 DPRINTF(("viona: unknown i/o write offset %ld\n\r", offset)); 711 value = 0; 712 break; 713 } 714 715 pthread_mutex_unlock(&sc->vsc_mtx); 716 } 717 718 static uint64_t 719 pci_viona_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 720 int baridx, uint64_t offset, int size) 721 { 722 struct pci_viona_softc *sc = pi->pi_arg; 723 void *ptr; 724 uint64_t value; 725 int err = 0; 726 727 if (baridx == pci_msix_table_bar(pi) || 728 baridx == pci_msix_pba_bar(pi)) { 729 return (pci_emul_msix_tread(pi, offset, size)); 730 } 731 732 assert(baridx == 0); 733 734 if (offset + size > pci_viona_iosize(pi)) { 735 DPRINTF(("viona_read: 2big, offset %ld size %d\n", 736 offset, size)); 737 return (0); 738 } 739 740 pthread_mutex_lock(&sc->vsc_mtx); 741 742 offset = viona_adjust_offset(pi, offset); 743 744 switch (offset) { 745 case VTCFG_R_HOSTCAP: 746 assert(size == 4); 747 err = ioctl(sc->vsc_vnafd, VNA_IOC_GET_FEATURES, &value); 748 if (err != 0) { 749 WPRINTF(("ioctl get host features returned" 750 " err = %d\n", errno)); 751 } 752 value &= ~sc->vsc_feature_mask; 753 break; 754 case VTCFG_R_GUESTCAP: 755 assert(size == 4); 756 value = sc->vsc_features; /* XXX never read ? */ 757 break; 758 case VTCFG_R_PFN: 759 assert(size == 4); 760 value = sc->vsc_pfn[sc->vsc_curq] >> VRING_PFN; 761 break; 762 case VTCFG_R_QNUM: 763 assert(size == 2); 764 value = pci_viona_qsize(sc, sc->vsc_curq); 765 break; 766 case VTCFG_R_QSEL: 767 assert(size == 2); 768 value = sc->vsc_curq; /* XXX never read ? */ 769 break; 770 case VTCFG_R_QNOTIFY: 771 assert(size == 2); 772 value = sc->vsc_curq; /* XXX never read ? */ 773 break; 774 case VTCFG_R_STATUS: 775 assert(size == 1); 776 value = sc->vsc_status; 777 break; 778 case VTCFG_R_ISR: 779 assert(size == 1); 780 value = sc->vsc_isr; 781 sc->vsc_isr = 0; /* a read clears this flag */ 782 if (value != 0) { 783 pci_lintr_deassert(pi); 784 } 785 break; 786 case VTCFG_R_CFGVEC: 787 assert(size == 2); 788 value = sc->vsc_msix_table_idx[VIONA_CTLQ]; 789 break; 790 case VTCFG_R_QVEC: 791 assert(size == 2); 792 assert(sc->vsc_curq != VIONA_CTLQ); 793 value = sc->vsc_msix_table_idx[sc->vsc_curq]; 794 break; 795 case VIONA_R_CFG0: 796 case VIONA_R_CFG1: 797 case VIONA_R_CFG2: 798 case VIONA_R_CFG3: 799 case VIONA_R_CFG4: 800 case VIONA_R_CFG5: 801 assert((size + offset) <= (VIONA_R_CFG5 + 1)); 802 ptr = &sc->vsc_macaddr[offset - VIONA_R_CFG0]; 803 if (size == 1) { 804 value = *(uint8_t *)ptr; 805 } else if (size == 2) { 806 value = *(uint16_t *)ptr; 807 } else { 808 value = *(uint32_t *)ptr; 809 } 810 break; 811 case VIONA_R_CFG6: 812 assert(size != 4); 813 value = 0x01; /* XXX link always up */ 814 break; 815 case VIONA_R_CFG7: 816 assert(size == 1); 817 value = 0; /* XXX link status in LSB */ 818 break; 819 default: 820 DPRINTF(("viona: unknown i/o read offset %ld\n\r", offset)); 821 value = 0; 822 break; 823 } 824 825 pthread_mutex_unlock(&sc->vsc_mtx); 826 827 return (value); 828 } 829 830 struct pci_devemu pci_de_viona = { 831 .pe_emu = "virtio-net-viona", 832 .pe_init = pci_viona_init, 833 .pe_barwrite = pci_viona_write, 834 .pe_barread = pci_viona_read, 835 .pe_lintrupdate = pci_viona_lintrupdate 836 }; 837 PCI_EMUL_SET(pci_de_viona); 838