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 * Copyright 2022 OmniOS Community Edition (OmniOSce) Association. 39 */ 40 41 #include <sys/cdefs.h> 42 43 #include <sys/param.h> 44 #include <sys/linker_set.h> 45 #include <sys/ioctl.h> 46 #include <sys/viona_io.h> 47 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <stdint.h> 53 #include <string.h> 54 #include <strings.h> 55 #include <unistd.h> 56 #include <assert.h> 57 #include <pthread.h> 58 #include <signal.h> 59 #include <poll.h> 60 #include <libdladm.h> 61 #include <libdllink.h> 62 #include <libdlvnic.h> 63 64 #include <machine/vmm.h> 65 #include <vmmapi.h> 66 67 #include "bhyverun.h" 68 #include "config.h" 69 #include "pci_emul.h" 70 #include "virtio.h" 71 72 #define VIONA_RINGSZ 1024 73 74 /* 75 * PCI config-space register offsets 76 */ 77 #define VIONA_R_CFG0 24 78 #define VIONA_R_CFG1 25 79 #define VIONA_R_CFG2 26 80 #define VIONA_R_CFG3 27 81 #define VIONA_R_CFG4 28 82 #define VIONA_R_CFG5 29 83 #define VIONA_R_CFG6 30 84 #define VIONA_R_CFG7 31 85 #define VIONA_R_MAX 31 86 87 #define VIONA_REGSZ VIONA_R_MAX+1 88 89 /* 90 * Queue definitions. 91 */ 92 #define VIONA_RXQ 0 93 #define VIONA_TXQ 1 94 #define VIONA_CTLQ 2 95 96 #define VIONA_MAXQ 3 97 98 /* 99 * Debug printf 100 */ 101 static volatile int pci_viona_debug; 102 #define DPRINTF(params) if (pci_viona_debug) printf params 103 #define WPRINTF(params) printf params 104 105 /* 106 * Per-device softc 107 */ 108 struct pci_viona_softc { 109 struct pci_devinst *vsc_pi; 110 pthread_mutex_t vsc_mtx; 111 112 int vsc_curq; 113 int vsc_status; 114 int vsc_isr; 115 116 datalink_id_t vsc_linkid; 117 int vsc_vnafd; 118 119 /* Configurable parameters */ 120 char vsc_linkname[MAXLINKNAMELEN]; 121 uint32_t vsc_feature_mask; 122 uint16_t vsc_vq_size; 123 124 uint32_t vsc_features; 125 uint8_t vsc_macaddr[6]; 126 127 uint64_t vsc_pfn[VIONA_MAXQ]; 128 uint16_t vsc_msix_table_idx[VIONA_MAXQ]; 129 boolean_t vsc_msix_active; 130 }; 131 132 /* 133 * Return the size of IO BAR that maps virtio header and device specific 134 * region. The size would vary depending on whether MSI-X is enabled or 135 * not. 136 */ 137 static uint64_t 138 pci_viona_iosize(struct pci_devinst *pi) 139 { 140 if (pci_msix_enabled(pi)) { 141 return (VIONA_REGSZ); 142 } else { 143 return (VIONA_REGSZ - 144 (VIRTIO_PCI_CONFIG_OFF(1) - VIRTIO_PCI_CONFIG_OFF(0))); 145 } 146 } 147 148 static uint16_t 149 pci_viona_qsize(struct pci_viona_softc *sc, int qnum) 150 { 151 /* XXX no ctl queue currently */ 152 if (qnum == VIONA_CTLQ) { 153 return (0); 154 } 155 156 return (sc->vsc_vq_size); 157 } 158 159 static void 160 pci_viona_ring_reset(struct pci_viona_softc *sc, int ring) 161 { 162 assert(ring < VIONA_MAXQ); 163 164 switch (ring) { 165 case VIONA_RXQ: 166 case VIONA_TXQ: 167 break; 168 case VIONA_CTLQ: 169 default: 170 return; 171 } 172 173 for (;;) { 174 int res; 175 176 res = ioctl(sc->vsc_vnafd, VNA_IOC_RING_RESET, ring); 177 if (res == 0) { 178 break; 179 } else if (errno != EINTR) { 180 WPRINTF(("ioctl viona ring %d reset failed %d\n", 181 ring, errno)); 182 return; 183 } 184 } 185 186 sc->vsc_pfn[ring] = 0; 187 } 188 189 static void 190 pci_viona_update_status(struct pci_viona_softc *sc, uint32_t value) 191 { 192 193 if (value == 0) { 194 DPRINTF(("viona: device reset requested !\n")); 195 pci_viona_ring_reset(sc, VIONA_RXQ); 196 pci_viona_ring_reset(sc, VIONA_TXQ); 197 } 198 199 sc->vsc_status = value; 200 } 201 202 static void * 203 pci_viona_poll_thread(void *param) 204 { 205 struct pci_viona_softc *sc = param; 206 pollfd_t pollset; 207 const int fd = sc->vsc_vnafd; 208 209 pollset.fd = fd; 210 pollset.events = POLLRDBAND; 211 212 for (;;) { 213 if (poll(&pollset, 1, -1) < 0) { 214 if (errno == EINTR || errno == EAGAIN) { 215 continue; 216 } else { 217 WPRINTF(("pci_viona_poll_thread poll()" 218 "error %d\n", errno)); 219 break; 220 } 221 } 222 if (pollset.revents & POLLRDBAND) { 223 vioc_intr_poll_t vip; 224 uint_t i; 225 int res; 226 boolean_t assert_lintr = B_FALSE; 227 const boolean_t do_msix = pci_msix_enabled(sc->vsc_pi); 228 229 res = ioctl(fd, VNA_IOC_INTR_POLL, &vip); 230 for (i = 0; res > 0 && i < VIONA_VQ_MAX; i++) { 231 if (vip.vip_status[i] == 0) { 232 continue; 233 } 234 if (do_msix) { 235 pci_generate_msix(sc->vsc_pi, 236 sc->vsc_msix_table_idx[i]); 237 } else { 238 assert_lintr = B_TRUE; 239 } 240 res = ioctl(fd, VNA_IOC_RING_INTR_CLR, i); 241 if (res != 0) { 242 WPRINTF(("ioctl viona vq %d intr " 243 "clear failed %d\n", i, errno)); 244 } 245 } 246 if (assert_lintr) { 247 pthread_mutex_lock(&sc->vsc_mtx); 248 sc->vsc_isr |= VIRTIO_PCI_ISR_INTR; 249 pci_lintr_assert(sc->vsc_pi); 250 pthread_mutex_unlock(&sc->vsc_mtx); 251 } 252 } 253 } 254 255 pthread_exit(NULL); 256 } 257 258 static void 259 pci_viona_ring_init(struct pci_viona_softc *sc, uint64_t pfn) 260 { 261 int qnum = sc->vsc_curq; 262 vioc_ring_init_t vna_ri; 263 int error; 264 265 assert(qnum < VIONA_MAXQ); 266 267 if (qnum == VIONA_CTLQ) { 268 return; 269 } 270 271 sc->vsc_pfn[qnum] = (pfn << VRING_PFN); 272 273 vna_ri.ri_index = qnum; 274 vna_ri.ri_qsize = pci_viona_qsize(sc, qnum); 275 vna_ri.ri_qaddr = (pfn << VRING_PFN); 276 error = ioctl(sc->vsc_vnafd, VNA_IOC_RING_INIT, &vna_ri); 277 278 if (error != 0) { 279 WPRINTF(("ioctl viona ring %u init failed %d\n", qnum, errno)); 280 } 281 } 282 283 static int 284 pci_viona_viona_init(struct vmctx *ctx, struct pci_viona_softc *sc) 285 { 286 vioc_create_t vna_create; 287 int error; 288 289 sc->vsc_vnafd = open("/dev/viona", O_RDWR | O_EXCL); 290 if (sc->vsc_vnafd == -1) { 291 WPRINTF(("open viona ctl failed: %d\n", errno)); 292 return (-1); 293 } 294 295 vna_create.c_linkid = sc->vsc_linkid; 296 vna_create.c_vmfd = vm_get_device_fd(ctx); 297 error = ioctl(sc->vsc_vnafd, VNA_IOC_CREATE, &vna_create); 298 if (error != 0) { 299 (void) close(sc->vsc_vnafd); 300 WPRINTF(("ioctl viona create failed %d\n", errno)); 301 return (-1); 302 } 303 304 return (0); 305 } 306 307 static int 308 pci_viona_legacy_config(nvlist_t *nvl, const char *opt) 309 { 310 char *config, *name, *tofree, *value; 311 312 if (opt == NULL) 313 return (0); 314 315 config = tofree = strdup(opt); 316 while ((name = strsep(&config, ",")) != NULL) { 317 value = strchr(name, '='); 318 if (value != NULL) { 319 *value++ = '\0'; 320 set_config_value_node(nvl, name, value); 321 } else { 322 set_config_value_node(nvl, "vnic", name); 323 } 324 } 325 free(tofree); 326 return (0); 327 } 328 329 static int 330 pci_viona_parse_opts(struct pci_viona_softc *sc, nvlist_t *nvl) 331 { 332 const char *value; 333 int err = 0; 334 335 sc->vsc_vq_size = VIONA_RINGSZ; 336 sc->vsc_feature_mask = 0; 337 sc->vsc_linkname[0] = '\0'; 338 339 value = get_config_value_node(nvl, "feature_mask"); 340 if (value != NULL) { 341 long num; 342 343 errno = 0; 344 num = strtol(value, NULL, 0); 345 if (errno != 0 || num < 0) { 346 fprintf(stderr, 347 "viona: invalid mask '%s'", value); 348 } else { 349 sc->vsc_feature_mask = num; 350 } 351 } 352 353 value = get_config_value_node(nvl, "vqsize"); 354 if (value != NULL) { 355 long num; 356 357 errno = 0; 358 num = strtol(value, NULL, 0); 359 if (errno != 0) { 360 fprintf(stderr, 361 "viona: invalid vsqize '%s'", value); 362 err = -1; 363 } else if (num <= 2 || num > 32768) { 364 fprintf(stderr, 365 "viona: vqsize out of range", num); 366 err = -1; 367 } else if ((1 << (ffs(num) - 1)) != num) { 368 fprintf(stderr, 369 "viona: vqsize must be power of 2", num); 370 err = -1; 371 } else { 372 sc->vsc_vq_size = num; 373 } 374 } 375 376 value = get_config_value_node(nvl, "vnic"); 377 if (value == NULL) { 378 fprintf(stderr, "viona: vnic name required"); 379 err = -1; 380 } else { 381 (void) strlcpy(sc->vsc_linkname, value, MAXLINKNAMELEN); 382 } 383 384 DPRINTF(("viona=%p dev=%s vqsize=%x feature_mask=%x\n", sc, 385 sc->vsc_linkname, sc->vsc_vq_size, sc->vsc_feature_mask)); 386 return (err); 387 } 388 389 static int 390 pci_viona_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) 391 { 392 dladm_handle_t handle; 393 dladm_status_t status; 394 dladm_vnic_attr_t attr; 395 char errmsg[DLADM_STRSIZE]; 396 char tname[MAXCOMLEN + 1]; 397 int error, i; 398 struct pci_viona_softc *sc; 399 const char *vnic; 400 pthread_t tid; 401 402 vnic = get_config_value_node(nvl, "vnic"); 403 if (vnic == NULL) { 404 printf("virtio-viona: vnic required\n"); 405 return (1); 406 } 407 408 sc = malloc(sizeof (struct pci_viona_softc)); 409 memset(sc, 0, sizeof (struct pci_viona_softc)); 410 411 pi->pi_arg = sc; 412 sc->vsc_pi = pi; 413 414 pthread_mutex_init(&sc->vsc_mtx, NULL); 415 416 if (pci_viona_parse_opts(sc, nvl) != 0) { 417 free(sc); 418 return (1); 419 } 420 421 if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) { 422 WPRINTF(("could not open /dev/dld")); 423 free(sc); 424 return (1); 425 } 426 427 if ((status = dladm_name2info(handle, sc->vsc_linkname, &sc->vsc_linkid, 428 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 429 WPRINTF(("dladm_name2info() for %s failed: %s\n", vnic, 430 dladm_status2str(status, errmsg))); 431 dladm_close(handle); 432 free(sc); 433 return (1); 434 } 435 436 if ((status = dladm_vnic_info(handle, sc->vsc_linkid, &attr, 437 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 438 WPRINTF(("dladm_vnic_info() for %s failed: %s\n", vnic, 439 dladm_status2str(status, errmsg))); 440 dladm_close(handle); 441 free(sc); 442 return (1); 443 } 444 445 memcpy(sc->vsc_macaddr, attr.va_mac_addr, ETHERADDRL); 446 447 dladm_close(handle); 448 449 error = pci_viona_viona_init(ctx, sc); 450 if (error != 0) { 451 free(sc); 452 return (1); 453 } 454 455 error = pthread_create(&tid, NULL, pci_viona_poll_thread, sc); 456 assert(error == 0); 457 snprintf(tname, sizeof (tname), "vionapoll:%s", vnic); 458 pthread_set_name_np(tid, tname); 459 460 /* initialize config space */ 461 pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET); 462 pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); 463 pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK); 464 pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_NETWORK); 465 pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); 466 467 /* MSI-X support */ 468 for (i = 0; i < VIONA_MAXQ; i++) 469 sc->vsc_msix_table_idx[i] = VIRTIO_MSI_NO_VECTOR; 470 471 /* BAR 1 used to map MSI-X table and PBA */ 472 if (pci_emul_add_msixcap(pi, VIONA_MAXQ, 1)) { 473 free(sc); 474 return (1); 475 } 476 477 /* BAR 0 for legacy-style virtio register access. */ 478 error = pci_emul_alloc_bar(pi, 0, PCIBAR_IO, VIONA_REGSZ); 479 if (error != 0) { 480 WPRINTF(("could not allocate virtio BAR\n")); 481 free(sc); 482 return (1); 483 } 484 485 /* 486 * Need a legacy interrupt for virtio compliance, even though MSI-X 487 * operation is _strongly_ suggested for adequate performance. 488 */ 489 pci_lintr_request(pi); 490 491 return (0); 492 } 493 494 static uint64_t 495 viona_adjust_offset(struct pci_devinst *pi, uint64_t offset) 496 { 497 /* 498 * Device specific offsets used by guest would change based on 499 * whether MSI-X capability is enabled or not 500 */ 501 if (!pci_msix_enabled(pi)) { 502 if (offset >= VIRTIO_PCI_CONFIG_OFF(0)) { 503 return (offset + (VIRTIO_PCI_CONFIG_OFF(1) - 504 VIRTIO_PCI_CONFIG_OFF(0))); 505 } 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_baraddr(struct vmctx *ctx, struct pci_devinst *pi, int baridx, 616 int enabled, uint64_t address) 617 { 618 struct pci_viona_softc *sc = pi->pi_arg; 619 uint64_t ioport; 620 int error; 621 622 if (baridx != 0) 623 return; 624 625 if (enabled == 0) { 626 error = ioctl(sc->vsc_vnafd, VNA_IOC_SET_NOTIFY_IOP, 0); 627 if (error != 0) 628 WPRINTF(("uninstall ioport hook failed %d\n", errno)); 629 return; 630 } 631 632 /* 633 * Install ioport hook for virtqueue notification. 634 * This is part of the virtio common configuration area so the 635 * address does not change with MSI-X status. 636 */ 637 ioport = address + VIRTIO_PCI_QUEUE_NOTIFY; 638 error = ioctl(sc->vsc_vnafd, VNA_IOC_SET_NOTIFY_IOP, ioport); 639 if (error != 0) { 640 WPRINTF(("install ioport hook at %x failed %d\n", 641 ioport, errno)); 642 } 643 } 644 645 static void 646 pci_viona_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 647 int baridx, uint64_t offset, int size, uint64_t value) 648 { 649 struct pci_viona_softc *sc = pi->pi_arg; 650 void *ptr; 651 int err = 0; 652 653 if (baridx == pci_msix_table_bar(pi) || 654 baridx == pci_msix_pba_bar(pi)) { 655 if (pci_emul_msix_twrite(pi, offset, size, value) == 0) { 656 pci_viona_msix_update(pi, offset); 657 } 658 return; 659 } 660 661 assert(baridx == 0); 662 663 if (offset + size > pci_viona_iosize(pi)) { 664 DPRINTF(("viona_write: 2big, offset %ld size %d\n", 665 offset, size)); 666 return; 667 } 668 669 pthread_mutex_lock(&sc->vsc_mtx); 670 671 offset = viona_adjust_offset(pi, offset); 672 673 switch (offset) { 674 case VIRTIO_PCI_GUEST_FEATURES: 675 assert(size == 4); 676 value &= ~(sc->vsc_feature_mask); 677 err = ioctl(sc->vsc_vnafd, VNA_IOC_SET_FEATURES, &value); 678 if (err != 0) { 679 WPRINTF(("ioctl feature negotiation returned" 680 " err = %d\n", errno)); 681 } else { 682 sc->vsc_features = value; 683 } 684 break; 685 case VIRTIO_PCI_QUEUE_PFN: 686 assert(size == 4); 687 pci_viona_ring_init(sc, value); 688 break; 689 case VIRTIO_PCI_QUEUE_SEL: 690 assert(size == 2); 691 assert(value < VIONA_MAXQ); 692 sc->vsc_curq = value; 693 break; 694 case VIRTIO_PCI_QUEUE_NOTIFY: 695 assert(size == 2); 696 assert(value < VIONA_MAXQ); 697 pci_viona_qnotify(sc, value); 698 break; 699 case VIRTIO_PCI_STATUS: 700 assert(size == 1); 701 pci_viona_update_status(sc, value); 702 break; 703 case VIRTIO_MSI_CONFIG_VECTOR: 704 assert(size == 2); 705 sc->vsc_msix_table_idx[VIONA_CTLQ] = value; 706 break; 707 case VIRTIO_MSI_QUEUE_VECTOR: 708 assert(size == 2); 709 assert(sc->vsc_curq != VIONA_CTLQ); 710 sc->vsc_msix_table_idx[sc->vsc_curq] = value; 711 pci_viona_ring_set_msix(pi, sc->vsc_curq); 712 break; 713 case VIONA_R_CFG0: 714 case VIONA_R_CFG1: 715 case VIONA_R_CFG2: 716 case VIONA_R_CFG3: 717 case VIONA_R_CFG4: 718 case VIONA_R_CFG5: 719 assert((size + offset) <= (VIONA_R_CFG5 + 1)); 720 ptr = &sc->vsc_macaddr[offset - VIONA_R_CFG0]; 721 /* 722 * The driver is allowed to change the MAC address 723 */ 724 sc->vsc_macaddr[offset - VIONA_R_CFG0] = value; 725 if (size == 1) { 726 *(uint8_t *)ptr = value; 727 } else if (size == 2) { 728 *(uint16_t *)ptr = value; 729 } else { 730 *(uint32_t *)ptr = value; 731 } 732 break; 733 case VIRTIO_PCI_HOST_FEATURES: 734 case VIRTIO_PCI_QUEUE_NUM: 735 case VIRTIO_PCI_ISR: 736 case VIONA_R_CFG6: 737 case VIONA_R_CFG7: 738 DPRINTF(("viona: write to readonly reg %ld\n\r", offset)); 739 break; 740 default: 741 DPRINTF(("viona: unknown i/o write offset %ld\n\r", offset)); 742 value = 0; 743 break; 744 } 745 746 pthread_mutex_unlock(&sc->vsc_mtx); 747 } 748 749 static uint64_t 750 pci_viona_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 751 int baridx, uint64_t offset, int size) 752 { 753 struct pci_viona_softc *sc = pi->pi_arg; 754 void *ptr; 755 uint64_t value; 756 int err = 0; 757 758 if (baridx == pci_msix_table_bar(pi) || 759 baridx == pci_msix_pba_bar(pi)) { 760 return (pci_emul_msix_tread(pi, offset, size)); 761 } 762 763 assert(baridx == 0); 764 765 if (offset + size > pci_viona_iosize(pi)) { 766 DPRINTF(("viona_read: 2big, offset %ld size %d\n", 767 offset, size)); 768 return (0); 769 } 770 771 pthread_mutex_lock(&sc->vsc_mtx); 772 773 offset = viona_adjust_offset(pi, offset); 774 775 switch (offset) { 776 case VIRTIO_PCI_HOST_FEATURES: 777 assert(size == 4); 778 err = ioctl(sc->vsc_vnafd, VNA_IOC_GET_FEATURES, &value); 779 if (err != 0) { 780 WPRINTF(("ioctl get host features returned" 781 " err = %d\n", errno)); 782 } 783 value &= ~sc->vsc_feature_mask; 784 break; 785 case VIRTIO_PCI_GUEST_FEATURES: 786 assert(size == 4); 787 value = sc->vsc_features; /* XXX never read ? */ 788 break; 789 case VIRTIO_PCI_QUEUE_PFN: 790 assert(size == 4); 791 value = sc->vsc_pfn[sc->vsc_curq] >> VRING_PFN; 792 break; 793 case VIRTIO_PCI_QUEUE_NUM: 794 assert(size == 2); 795 value = pci_viona_qsize(sc, sc->vsc_curq); 796 break; 797 case VIRTIO_PCI_QUEUE_SEL: 798 assert(size == 2); 799 value = sc->vsc_curq; /* XXX never read ? */ 800 break; 801 case VIRTIO_PCI_QUEUE_NOTIFY: 802 assert(size == 2); 803 value = sc->vsc_curq; /* XXX never read ? */ 804 break; 805 case VIRTIO_PCI_STATUS: 806 assert(size == 1); 807 value = sc->vsc_status; 808 break; 809 case VIRTIO_PCI_ISR: 810 assert(size == 1); 811 value = sc->vsc_isr; 812 sc->vsc_isr = 0; /* a read clears this flag */ 813 if (value != 0) { 814 pci_lintr_deassert(pi); 815 } 816 break; 817 case VIRTIO_MSI_CONFIG_VECTOR: 818 assert(size == 2); 819 value = sc->vsc_msix_table_idx[VIONA_CTLQ]; 820 break; 821 case VIRTIO_MSI_QUEUE_VECTOR: 822 assert(size == 2); 823 assert(sc->vsc_curq != VIONA_CTLQ); 824 value = sc->vsc_msix_table_idx[sc->vsc_curq]; 825 break; 826 case VIONA_R_CFG0: 827 case VIONA_R_CFG1: 828 case VIONA_R_CFG2: 829 case VIONA_R_CFG3: 830 case VIONA_R_CFG4: 831 case VIONA_R_CFG5: 832 assert((size + offset) <= (VIONA_R_CFG5 + 1)); 833 ptr = &sc->vsc_macaddr[offset - VIONA_R_CFG0]; 834 if (size == 1) { 835 value = *(uint8_t *)ptr; 836 } else if (size == 2) { 837 value = *(uint16_t *)ptr; 838 } else { 839 value = *(uint32_t *)ptr; 840 } 841 break; 842 case VIONA_R_CFG6: 843 assert(size != 4); 844 value = 0x01; /* XXX link always up */ 845 break; 846 case VIONA_R_CFG7: 847 assert(size == 1); 848 value = 0; /* XXX link status in LSB */ 849 break; 850 default: 851 DPRINTF(("viona: unknown i/o read offset %ld\n\r", offset)); 852 value = 0; 853 break; 854 } 855 856 pthread_mutex_unlock(&sc->vsc_mtx); 857 858 return (value); 859 } 860 861 struct pci_devemu pci_de_viona = { 862 .pe_emu = "virtio-net-viona", 863 .pe_init = pci_viona_init, 864 .pe_legacy_config = pci_viona_legacy_config, 865 .pe_barwrite = pci_viona_write, 866 .pe_barread = pci_viona_read, 867 .pe_baraddr = pci_viona_baraddr, 868 .pe_lintrupdate = pci_viona_lintrupdate 869 }; 870 PCI_EMUL_SET(pci_de_viona); 871