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