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. 38bf21cd93STycho Nightingale */ 39bf21cd93STycho Nightingale 40bf21cd93STycho Nightingale #include <sys/cdefs.h> 41bf21cd93STycho Nightingale 42bf21cd93STycho Nightingale #include <sys/param.h> 43bf21cd93STycho Nightingale #include <sys/linker_set.h> 44bf21cd93STycho Nightingale #include <sys/ioctl.h> 45bf21cd93STycho Nightingale #include <sys/viona_io.h> 46bf21cd93STycho Nightingale 47bf21cd93STycho Nightingale #include <errno.h> 48bf21cd93STycho Nightingale #include <fcntl.h> 49bf21cd93STycho Nightingale #include <stdio.h> 50bf21cd93STycho Nightingale #include <stdlib.h> 51bf21cd93STycho Nightingale #include <stdint.h> 52bf21cd93STycho Nightingale #include <string.h> 53bf21cd93STycho Nightingale #include <strings.h> 54bf21cd93STycho Nightingale #include <unistd.h> 55bf21cd93STycho Nightingale #include <assert.h> 56bf21cd93STycho Nightingale #include <pthread.h> 57bf21cd93STycho Nightingale #include <signal.h> 58bf21cd93STycho Nightingale #include <poll.h> 59bf21cd93STycho Nightingale #include <libdladm.h> 60bf21cd93STycho Nightingale #include <libdllink.h> 61bf21cd93STycho Nightingale #include <libdlvnic.h> 62bf21cd93STycho Nightingale 63bf21cd93STycho Nightingale #include <machine/vmm.h> 64bf21cd93STycho Nightingale #include <vmmapi.h> 65bf21cd93STycho Nightingale 66bf21cd93STycho Nightingale #include "bhyverun.h" 672b948146SAndy Fiddaman #include "config.h" 68bf21cd93STycho Nightingale #include "pci_emul.h" 69bf21cd93STycho Nightingale #include "virtio.h" 70bf21cd93STycho Nightingale 71bf21cd93STycho Nightingale #define VIONA_RINGSZ 1024 72bf21cd93STycho Nightingale 73bf21cd93STycho Nightingale /* 74bf21cd93STycho Nightingale * PCI config-space register offsets 75bf21cd93STycho Nightingale */ 76bf21cd93STycho Nightingale #define VIONA_R_CFG0 24 77bf21cd93STycho Nightingale #define VIONA_R_CFG1 25 78bf21cd93STycho Nightingale #define VIONA_R_CFG2 26 79bf21cd93STycho Nightingale #define VIONA_R_CFG3 27 80bf21cd93STycho Nightingale #define VIONA_R_CFG4 28 81bf21cd93STycho Nightingale #define VIONA_R_CFG5 29 82bf21cd93STycho Nightingale #define VIONA_R_CFG6 30 83bf21cd93STycho Nightingale #define VIONA_R_CFG7 31 84bf21cd93STycho Nightingale #define VIONA_R_MAX 31 85bf21cd93STycho Nightingale 86bf21cd93STycho Nightingale #define VIONA_REGSZ VIONA_R_MAX+1 87bf21cd93STycho Nightingale 88bf21cd93STycho Nightingale /* 89bf21cd93STycho Nightingale * Queue definitions. 90bf21cd93STycho Nightingale */ 91bf21cd93STycho Nightingale #define VIONA_RXQ 0 92bf21cd93STycho Nightingale #define VIONA_TXQ 1 93bf21cd93STycho Nightingale #define VIONA_CTLQ 2 94bf21cd93STycho Nightingale 95bf21cd93STycho Nightingale #define VIONA_MAXQ 3 96bf21cd93STycho Nightingale 97bf21cd93STycho Nightingale /* 98bf21cd93STycho Nightingale * Debug printf 99bf21cd93STycho Nightingale */ 100b22a70abSPatrick Mooney static volatile int pci_viona_debug; 101bf21cd93STycho Nightingale #define DPRINTF(params) if (pci_viona_debug) printf params 102bf21cd93STycho Nightingale #define WPRINTF(params) printf params 103bf21cd93STycho Nightingale 104bf21cd93STycho Nightingale /* 105bf21cd93STycho Nightingale * Per-device softc 106bf21cd93STycho Nightingale */ 107bf21cd93STycho Nightingale struct pci_viona_softc { 108bf21cd93STycho Nightingale struct pci_devinst *vsc_pi; 109bf21cd93STycho Nightingale pthread_mutex_t vsc_mtx; 110bf21cd93STycho Nightingale 111bf21cd93STycho Nightingale int vsc_curq; 112bf21cd93STycho Nightingale int vsc_status; 113bf21cd93STycho Nightingale int vsc_isr; 114bf21cd93STycho Nightingale 115bf21cd93STycho Nightingale datalink_id_t vsc_linkid; 116bf21cd93STycho Nightingale int vsc_vnafd; 117bf21cd93STycho Nightingale 118b22a70abSPatrick Mooney /* Configurable parameters */ 119b22a70abSPatrick Mooney char vsc_linkname[MAXLINKNAMELEN]; 120b22a70abSPatrick Mooney uint32_t vsc_feature_mask; 121b22a70abSPatrick Mooney uint16_t vsc_vq_size; 122b22a70abSPatrick Mooney 123bf21cd93STycho Nightingale uint32_t vsc_features; 124bf21cd93STycho Nightingale uint8_t vsc_macaddr[6]; 125bf21cd93STycho Nightingale 126bf21cd93STycho Nightingale uint64_t vsc_pfn[VIONA_MAXQ]; 127bf21cd93STycho Nightingale uint16_t vsc_msix_table_idx[VIONA_MAXQ]; 128b22a70abSPatrick Mooney boolean_t vsc_msix_active; 129bf21cd93STycho Nightingale }; 130bf21cd93STycho Nightingale 131bf21cd93STycho Nightingale /* 132bf21cd93STycho Nightingale * Return the size of IO BAR that maps virtio header and device specific 133bf21cd93STycho Nightingale * region. The size would vary depending on whether MSI-X is enabled or 134bf21cd93STycho Nightingale * not. 135bf21cd93STycho Nightingale */ 136bf21cd93STycho Nightingale static uint64_t 137bf21cd93STycho Nightingale pci_viona_iosize(struct pci_devinst *pi) 138bf21cd93STycho Nightingale { 1392b948146SAndy Fiddaman if (pci_msix_enabled(pi)) { 140bf21cd93STycho Nightingale return (VIONA_REGSZ); 1412b948146SAndy Fiddaman } else { 1422b948146SAndy Fiddaman return (VIONA_REGSZ - 1432b948146SAndy Fiddaman (VIRTIO_PCI_CONFIG_OFF(1) - VIRTIO_PCI_CONFIG_OFF(0))); 1442b948146SAndy Fiddaman } 145bf21cd93STycho Nightingale } 146bf21cd93STycho Nightingale 147bf21cd93STycho Nightingale static uint16_t 148b22a70abSPatrick Mooney pci_viona_qsize(struct pci_viona_softc *sc, int qnum) 149bf21cd93STycho Nightingale { 150bf21cd93STycho Nightingale /* XXX no ctl queue currently */ 151bf21cd93STycho Nightingale if (qnum == VIONA_CTLQ) { 152bf21cd93STycho Nightingale return (0); 153bf21cd93STycho Nightingale } 154bf21cd93STycho Nightingale 155b22a70abSPatrick Mooney return (sc->vsc_vq_size); 156bf21cd93STycho Nightingale } 157bf21cd93STycho Nightingale 158bf21cd93STycho Nightingale static void 159bf21cd93STycho Nightingale pci_viona_ring_reset(struct pci_viona_softc *sc, int ring) 160bf21cd93STycho Nightingale { 161bf21cd93STycho Nightingale assert(ring < VIONA_MAXQ); 162bf21cd93STycho Nightingale 163bf21cd93STycho Nightingale switch (ring) { 164bf21cd93STycho Nightingale case VIONA_RXQ: 165bf21cd93STycho Nightingale case VIONA_TXQ: 166bf21cd93STycho Nightingale break; 167bf21cd93STycho Nightingale case VIONA_CTLQ: 168bf21cd93STycho Nightingale default: 169b22a70abSPatrick Mooney return; 170bf21cd93STycho Nightingale } 171b22a70abSPatrick Mooney 172b22a70abSPatrick Mooney for (;;) { 173b22a70abSPatrick Mooney int res; 174b22a70abSPatrick Mooney 175b22a70abSPatrick Mooney res = ioctl(sc->vsc_vnafd, VNA_IOC_RING_RESET, ring); 176b22a70abSPatrick Mooney if (res == 0) { 177b22a70abSPatrick Mooney break; 178b22a70abSPatrick Mooney } else if (errno != EINTR) { 179b22a70abSPatrick Mooney WPRINTF(("ioctl viona ring %d reset failed %d\n", 180b22a70abSPatrick Mooney ring, errno)); 181b22a70abSPatrick Mooney return; 182b22a70abSPatrick Mooney } 183b22a70abSPatrick Mooney } 184b22a70abSPatrick Mooney 185b22a70abSPatrick Mooney sc->vsc_pfn[ring] = 0; 186bf21cd93STycho Nightingale } 187bf21cd93STycho Nightingale 188bf21cd93STycho Nightingale static void 189bf21cd93STycho Nightingale pci_viona_update_status(struct pci_viona_softc *sc, uint32_t value) 190bf21cd93STycho Nightingale { 191bf21cd93STycho Nightingale 192bf21cd93STycho Nightingale if (value == 0) { 193bf21cd93STycho Nightingale DPRINTF(("viona: device reset requested !\n")); 194bf21cd93STycho Nightingale pci_viona_ring_reset(sc, VIONA_RXQ); 195bf21cd93STycho Nightingale pci_viona_ring_reset(sc, VIONA_TXQ); 196bf21cd93STycho Nightingale } 197bf21cd93STycho Nightingale 198bf21cd93STycho Nightingale sc->vsc_status = value; 199bf21cd93STycho Nightingale } 200bf21cd93STycho Nightingale 201bf21cd93STycho Nightingale static void * 202bf21cd93STycho Nightingale pci_viona_poll_thread(void *param) 203bf21cd93STycho Nightingale { 204bf21cd93STycho Nightingale struct pci_viona_softc *sc = param; 205bf21cd93STycho Nightingale pollfd_t pollset; 206b22a70abSPatrick Mooney const int fd = sc->vsc_vnafd; 207bf21cd93STycho Nightingale 208b22a70abSPatrick Mooney pollset.fd = fd; 209b22a70abSPatrick Mooney pollset.events = POLLRDBAND; 210bf21cd93STycho Nightingale 211bf21cd93STycho Nightingale for (;;) { 212bf21cd93STycho Nightingale if (poll(&pollset, 1, -1) < 0) { 213bf21cd93STycho Nightingale if (errno == EINTR || errno == EAGAIN) { 214bf21cd93STycho Nightingale continue; 215bf21cd93STycho Nightingale } else { 216bf21cd93STycho Nightingale WPRINTF(("pci_viona_poll_thread poll()" 217bf21cd93STycho Nightingale "error %d\n", errno)); 218bf21cd93STycho Nightingale break; 219bf21cd93STycho Nightingale } 220bf21cd93STycho Nightingale } 221b22a70abSPatrick Mooney if (pollset.revents & POLLRDBAND) { 222b22a70abSPatrick Mooney vioc_intr_poll_t vip; 223b22a70abSPatrick Mooney uint_t i; 224b22a70abSPatrick Mooney int res; 225b22a70abSPatrick Mooney boolean_t assert_lintr = B_FALSE; 226b22a70abSPatrick Mooney const boolean_t do_msix = pci_msix_enabled(sc->vsc_pi); 227bf21cd93STycho Nightingale 228b22a70abSPatrick Mooney res = ioctl(fd, VNA_IOC_INTR_POLL, &vip); 229b22a70abSPatrick Mooney for (i = 0; res > 0 && i < VIONA_VQ_MAX; i++) { 230b22a70abSPatrick Mooney if (vip.vip_status[i] == 0) { 231b22a70abSPatrick Mooney continue; 232b22a70abSPatrick Mooney } 233b22a70abSPatrick Mooney if (do_msix) { 234bf21cd93STycho Nightingale pci_generate_msix(sc->vsc_pi, 235b22a70abSPatrick Mooney sc->vsc_msix_table_idx[i]); 236b22a70abSPatrick Mooney } else { 237b22a70abSPatrick Mooney assert_lintr = B_TRUE; 238b22a70abSPatrick Mooney } 239b22a70abSPatrick Mooney res = ioctl(fd, VNA_IOC_RING_INTR_CLR, i); 240b22a70abSPatrick Mooney if (res != 0) { 241b22a70abSPatrick Mooney WPRINTF(("ioctl viona vq %d intr " 242b22a70abSPatrick Mooney "clear failed %d\n", i, errno)); 243b22a70abSPatrick Mooney } 244b22a70abSPatrick Mooney } 245b22a70abSPatrick Mooney if (assert_lintr) { 246b22a70abSPatrick Mooney pthread_mutex_lock(&sc->vsc_mtx); 247b22a70abSPatrick Mooney sc->vsc_isr |= VTCFG_ISR_QUEUES; 248b22a70abSPatrick Mooney pci_lintr_assert(sc->vsc_pi); 249b22a70abSPatrick Mooney pthread_mutex_unlock(&sc->vsc_mtx); 250bf21cd93STycho Nightingale } 251bf21cd93STycho Nightingale } 252bf21cd93STycho Nightingale } 253bf21cd93STycho Nightingale 254bf21cd93STycho Nightingale pthread_exit(NULL); 255bf21cd93STycho Nightingale } 256bf21cd93STycho Nightingale 257bf21cd93STycho Nightingale static void 258bf21cd93STycho Nightingale pci_viona_ring_init(struct pci_viona_softc *sc, uint64_t pfn) 259bf21cd93STycho Nightingale { 260bf21cd93STycho Nightingale int qnum = sc->vsc_curq; 261bf21cd93STycho Nightingale vioc_ring_init_t vna_ri; 262bf21cd93STycho Nightingale int error; 263bf21cd93STycho Nightingale 264bf21cd93STycho Nightingale assert(qnum < VIONA_MAXQ); 265bf21cd93STycho Nightingale 266b22a70abSPatrick Mooney if (qnum == VIONA_CTLQ) { 267b22a70abSPatrick Mooney return; 268b22a70abSPatrick Mooney } 269b22a70abSPatrick Mooney 270bf21cd93STycho Nightingale sc->vsc_pfn[qnum] = (pfn << VRING_PFN); 271bf21cd93STycho Nightingale 272b22a70abSPatrick Mooney vna_ri.ri_index = qnum; 273b22a70abSPatrick Mooney vna_ri.ri_qsize = pci_viona_qsize(sc, qnum); 274bf21cd93STycho Nightingale vna_ri.ri_qaddr = (pfn << VRING_PFN); 275b22a70abSPatrick Mooney error = ioctl(sc->vsc_vnafd, VNA_IOC_RING_INIT, &vna_ri); 276bf21cd93STycho Nightingale 277bf21cd93STycho Nightingale if (error != 0) { 278b22a70abSPatrick Mooney WPRINTF(("ioctl viona ring %u init failed %d\n", qnum, errno)); 279bf21cd93STycho Nightingale } 280bf21cd93STycho Nightingale } 281bf21cd93STycho Nightingale 282bf21cd93STycho Nightingale static int 283bf21cd93STycho Nightingale pci_viona_viona_init(struct vmctx *ctx, struct pci_viona_softc *sc) 284bf21cd93STycho Nightingale { 285bf21cd93STycho Nightingale vioc_create_t vna_create; 286bf21cd93STycho Nightingale int error; 287bf21cd93STycho Nightingale 288b22a70abSPatrick Mooney sc->vsc_vnafd = open("/dev/viona", O_RDWR | O_EXCL); 289bf21cd93STycho Nightingale if (sc->vsc_vnafd == -1) { 290b22a70abSPatrick Mooney WPRINTF(("open viona ctl failed: %d\n", errno)); 291bf21cd93STycho Nightingale return (-1); 292bf21cd93STycho Nightingale } 293bf21cd93STycho Nightingale 294bf21cd93STycho Nightingale vna_create.c_linkid = sc->vsc_linkid; 295b22a70abSPatrick Mooney vna_create.c_vmfd = vm_get_device_fd(ctx); 296bf21cd93STycho Nightingale error = ioctl(sc->vsc_vnafd, VNA_IOC_CREATE, &vna_create); 297bf21cd93STycho Nightingale if (error != 0) { 298b22a70abSPatrick Mooney (void) close(sc->vsc_vnafd); 299b22a70abSPatrick Mooney WPRINTF(("ioctl viona create failed %d\n", errno)); 300bf21cd93STycho Nightingale return (-1); 301bf21cd93STycho Nightingale } 302bf21cd93STycho Nightingale 303bf21cd93STycho Nightingale return (0); 304bf21cd93STycho Nightingale } 305bf21cd93STycho Nightingale 306bf21cd93STycho Nightingale static int 3072b948146SAndy Fiddaman pci_viona_legacy_config(nvlist_t *nvl, const char *opt) 308b22a70abSPatrick Mooney { 3092b948146SAndy Fiddaman char *config, *name, *tofree, *value; 3102b948146SAndy Fiddaman 3112b948146SAndy Fiddaman if (opt == NULL) 3122b948146SAndy Fiddaman return (0); 3132b948146SAndy Fiddaman 3142b948146SAndy Fiddaman config = tofree = strdup(opt); 3152b948146SAndy Fiddaman while ((name = strsep(&config, ",")) != NULL) { 3162b948146SAndy Fiddaman value = strchr(name, '='); 3172b948146SAndy Fiddaman if (value != NULL) { 3182b948146SAndy Fiddaman *value++ = '\0'; 3192b948146SAndy Fiddaman set_config_value_node(nvl, name, value); 3202b948146SAndy Fiddaman } else { 3212b948146SAndy Fiddaman set_config_value_node(nvl, "vnic", name); 3222b948146SAndy Fiddaman } 3232b948146SAndy Fiddaman } 3242b948146SAndy Fiddaman free(tofree); 3252b948146SAndy Fiddaman return (0); 3262b948146SAndy Fiddaman } 3272b948146SAndy Fiddaman 3282b948146SAndy Fiddaman static int 3292b948146SAndy Fiddaman pci_viona_parse_opts(struct pci_viona_softc *sc, nvlist_t *nvl) 3302b948146SAndy Fiddaman { 3312b948146SAndy Fiddaman const char *value; 332b22a70abSPatrick Mooney int err = 0; 333b22a70abSPatrick Mooney 334b22a70abSPatrick Mooney sc->vsc_vq_size = VIONA_RINGSZ; 335b22a70abSPatrick Mooney sc->vsc_feature_mask = 0; 3362b948146SAndy Fiddaman sc->vsc_linkname[0] = '\0'; 337b22a70abSPatrick Mooney 3382b948146SAndy Fiddaman value = get_config_value_node(nvl, "feature_mask"); 3392b948146SAndy Fiddaman if (value != NULL) { 340b22a70abSPatrick Mooney long num; 341b22a70abSPatrick Mooney 342b22a70abSPatrick Mooney errno = 0; 3432b948146SAndy Fiddaman num = strtol(value, NULL, 0); 344b22a70abSPatrick Mooney if (errno != 0 || num < 0) { 345b22a70abSPatrick Mooney fprintf(stderr, 3462b948146SAndy Fiddaman "viona: invalid mask '%s'", value); 347b22a70abSPatrick Mooney } else { 348b22a70abSPatrick Mooney sc->vsc_feature_mask = num; 349b22a70abSPatrick Mooney } 3502b948146SAndy Fiddaman } 3512b948146SAndy Fiddaman 3522b948146SAndy Fiddaman value = get_config_value_node(nvl, "vqsize"); 3532b948146SAndy Fiddaman if (value != NULL) { 354b22a70abSPatrick Mooney long num; 355b22a70abSPatrick Mooney 356b22a70abSPatrick Mooney errno = 0; 3572b948146SAndy Fiddaman num = strtol(value, NULL, 0); 358b22a70abSPatrick Mooney if (errno != 0) { 359b22a70abSPatrick Mooney fprintf(stderr, 3602b948146SAndy Fiddaman "viona: invalid vsqize '%s'", value); 361b22a70abSPatrick Mooney err = -1; 362b22a70abSPatrick Mooney } else if (num <= 2 || num > 32768) { 363b22a70abSPatrick Mooney fprintf(stderr, 364b22a70abSPatrick Mooney "viona: vqsize out of range", num); 365b22a70abSPatrick Mooney err = -1; 366b22a70abSPatrick Mooney } else if ((1 << (ffs(num) - 1)) != num) { 367b22a70abSPatrick Mooney fprintf(stderr, 368b22a70abSPatrick Mooney "viona: vqsize must be power of 2", num); 369b22a70abSPatrick Mooney err = -1; 370b22a70abSPatrick Mooney } else { 371b22a70abSPatrick Mooney sc->vsc_vq_size = num; 372b22a70abSPatrick Mooney } 373b22a70abSPatrick Mooney } 3742b948146SAndy Fiddaman 3752b948146SAndy Fiddaman value = get_config_value_node(nvl, "vnic"); 3762b948146SAndy Fiddaman if (value == NULL) { 377b22a70abSPatrick Mooney fprintf(stderr, "viona: vnic name required"); 378b22a70abSPatrick Mooney err = -1; 379b22a70abSPatrick Mooney } else { 3802b948146SAndy Fiddaman (void) strlcpy(sc->vsc_linkname, value, MAXLINKNAMELEN); 381b22a70abSPatrick Mooney } 382b22a70abSPatrick Mooney 383b22a70abSPatrick Mooney DPRINTF(("viona=%p dev=%s vqsize=%x feature_mask=%x\n", sc, 384b22a70abSPatrick Mooney sc->vsc_linkname, sc->vsc_vq_size, sc->vsc_feature_mask)); 385b22a70abSPatrick Mooney return (err); 386b22a70abSPatrick Mooney } 387b22a70abSPatrick Mooney 388b22a70abSPatrick Mooney static int 3892b948146SAndy Fiddaman pci_viona_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) 390bf21cd93STycho Nightingale { 391bf21cd93STycho Nightingale dladm_handle_t handle; 392bf21cd93STycho Nightingale dladm_status_t status; 393bf21cd93STycho Nightingale dladm_vnic_attr_t attr; 394bf21cd93STycho Nightingale char errmsg[DLADM_STRSIZE]; 395*39eba7d4SAndy Fiddaman char tname[MAXCOMLEN + 1]; 396b22a70abSPatrick Mooney int error, i; 397bf21cd93STycho Nightingale struct pci_viona_softc *sc; 398b22a70abSPatrick Mooney uint64_t ioport; 3992b948146SAndy Fiddaman const char *vnic; 400*39eba7d4SAndy 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 455*39eba7d4SAndy Fiddaman error = pthread_create(&tid, NULL, pci_viona_poll_thread, sc); 456bf21cd93STycho Nightingale assert(error == 0); 457*39eba7d4SAndy Fiddaman snprintf(tname, sizeof (tname), "vionapoll:%s", vnic); 458*39eba7d4SAndy 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 485b22a70abSPatrick Mooney /* Install ioport hook for virtqueue notification */ 4862b948146SAndy Fiddaman ioport = pi->pi_bar[0].addr + VIRTIO_PCI_QUEUE_NOTIFY; 487b22a70abSPatrick Mooney error = ioctl(sc->vsc_vnafd, VNA_IOC_SET_NOTIFY_IOP, ioport); 488b22a70abSPatrick Mooney if (error != 0) { 489b22a70abSPatrick Mooney WPRINTF(("could not install ioport hook at %x\n", ioport)); 490b22a70abSPatrick Mooney free(sc); 491b22a70abSPatrick Mooney return (1); 492bf21cd93STycho Nightingale } 493bf21cd93STycho Nightingale 494bf21cd93STycho Nightingale /* 495b22a70abSPatrick Mooney * Need a legacy interrupt for virtio compliance, even though MSI-X 496b22a70abSPatrick Mooney * operation is _strongly_ suggested for adequate performance. 497bf21cd93STycho Nightingale */ 498b22a70abSPatrick Mooney pci_lintr_request(pi); 499b22a70abSPatrick Mooney 500b22a70abSPatrick Mooney return (0); 501b22a70abSPatrick Mooney } 502bf21cd93STycho Nightingale 503bf21cd93STycho Nightingale static uint64_t 504bf21cd93STycho Nightingale viona_adjust_offset(struct pci_devinst *pi, uint64_t offset) 505bf21cd93STycho Nightingale { 506bf21cd93STycho Nightingale /* 507bf21cd93STycho Nightingale * Device specific offsets used by guest would change based on 508bf21cd93STycho Nightingale * whether MSI-X capability is enabled or not 509bf21cd93STycho Nightingale */ 510bf21cd93STycho Nightingale if (!pci_msix_enabled(pi)) { 5112b948146SAndy Fiddaman if (offset >= VIRTIO_PCI_CONFIG_OFF(0)) { 5122b948146SAndy Fiddaman return (offset + (VIRTIO_PCI_CONFIG_OFF(1) - 5132b948146SAndy Fiddaman VIRTIO_PCI_CONFIG_OFF(0))); 5142b948146SAndy Fiddaman } 515bf21cd93STycho Nightingale } 516bf21cd93STycho Nightingale 517bf21cd93STycho Nightingale return (offset); 518bf21cd93STycho Nightingale } 519bf21cd93STycho Nightingale 520bf21cd93STycho Nightingale static void 521b22a70abSPatrick Mooney pci_viona_ring_set_msix(struct pci_devinst *pi, uint_t ring) 522b22a70abSPatrick Mooney { 523b22a70abSPatrick Mooney struct pci_viona_softc *sc = pi->pi_arg; 524b22a70abSPatrick Mooney struct msix_table_entry mte; 525b22a70abSPatrick Mooney uint16_t tab_index; 526b22a70abSPatrick Mooney vioc_ring_msi_t vrm; 527b22a70abSPatrick Mooney int res; 528b22a70abSPatrick Mooney 529b22a70abSPatrick Mooney assert(ring <= VIONA_VQ_TX); 530b22a70abSPatrick Mooney 531b22a70abSPatrick Mooney vrm.rm_index = ring; 532b22a70abSPatrick Mooney vrm.rm_addr = 0; 533b22a70abSPatrick Mooney vrm.rm_msg = 0; 534b22a70abSPatrick Mooney tab_index = sc->vsc_msix_table_idx[ring]; 535b22a70abSPatrick Mooney 536b22a70abSPatrick Mooney if (tab_index != VIRTIO_MSI_NO_VECTOR && sc->vsc_msix_active) { 537b22a70abSPatrick Mooney mte = pi->pi_msix.table[tab_index]; 538b22a70abSPatrick Mooney if ((mte.vector_control & PCIM_MSIX_VCTRL_MASK) == 0) { 539b22a70abSPatrick Mooney vrm.rm_addr = mte.addr; 540b22a70abSPatrick Mooney vrm.rm_msg = mte.msg_data; 541b22a70abSPatrick Mooney } 542b22a70abSPatrick Mooney } 543b22a70abSPatrick Mooney 544b22a70abSPatrick Mooney res = ioctl(sc->vsc_vnafd, VNA_IOC_RING_SET_MSI, &vrm); 545b22a70abSPatrick Mooney if (res != 0) { 546b22a70abSPatrick Mooney WPRINTF(("ioctl viona set_msi %d failed %d\n", ring, errno)); 547b22a70abSPatrick Mooney } 548b22a70abSPatrick Mooney } 549b22a70abSPatrick Mooney 550b22a70abSPatrick Mooney static void 551b22a70abSPatrick Mooney pci_viona_lintrupdate(struct pci_devinst *pi) 552b22a70abSPatrick Mooney { 553b22a70abSPatrick Mooney struct pci_viona_softc *sc = pi->pi_arg; 554b22a70abSPatrick Mooney boolean_t msix_on = B_FALSE; 555b22a70abSPatrick Mooney 556b22a70abSPatrick Mooney pthread_mutex_lock(&sc->vsc_mtx); 557b22a70abSPatrick Mooney msix_on = pci_msix_enabled(pi) && (pi->pi_msix.function_mask == 0); 558b22a70abSPatrick Mooney if ((sc->vsc_msix_active && !msix_on) || 559b22a70abSPatrick Mooney (msix_on && !sc->vsc_msix_active)) { 560b22a70abSPatrick Mooney uint_t i; 561b22a70abSPatrick Mooney 562b22a70abSPatrick Mooney sc->vsc_msix_active = msix_on; 563b22a70abSPatrick Mooney /* Update in-kernel ring configs */ 564b22a70abSPatrick Mooney for (i = 0; i <= VIONA_VQ_TX; i++) { 565b22a70abSPatrick Mooney pci_viona_ring_set_msix(pi, i); 566b22a70abSPatrick Mooney } 567b22a70abSPatrick Mooney } 568b22a70abSPatrick Mooney pthread_mutex_unlock(&sc->vsc_mtx); 569b22a70abSPatrick Mooney } 570b22a70abSPatrick Mooney 571b22a70abSPatrick Mooney static void 572b22a70abSPatrick Mooney pci_viona_msix_update(struct pci_devinst *pi, uint64_t offset) 573b22a70abSPatrick Mooney { 574b22a70abSPatrick Mooney struct pci_viona_softc *sc = pi->pi_arg; 575b22a70abSPatrick Mooney uint_t tab_index, i; 576b22a70abSPatrick Mooney 577b22a70abSPatrick Mooney pthread_mutex_lock(&sc->vsc_mtx); 578b22a70abSPatrick Mooney if (!sc->vsc_msix_active) { 579b22a70abSPatrick Mooney pthread_mutex_unlock(&sc->vsc_mtx); 580b22a70abSPatrick Mooney return; 581b22a70abSPatrick Mooney } 582b22a70abSPatrick Mooney 583b22a70abSPatrick Mooney /* 584b22a70abSPatrick Mooney * Rather than update every possible MSI-X vector, cheat and use the 585b22a70abSPatrick Mooney * offset to calculate the entry within the table. Since this should 586b22a70abSPatrick Mooney * only be called when a write to the table succeeds, the index should 587b22a70abSPatrick Mooney * be valid. 588b22a70abSPatrick Mooney */ 589b22a70abSPatrick Mooney tab_index = offset / MSIX_TABLE_ENTRY_SIZE; 590b22a70abSPatrick Mooney 591b22a70abSPatrick Mooney for (i = 0; i <= VIONA_VQ_TX; i++) { 592b22a70abSPatrick Mooney if (sc->vsc_msix_table_idx[i] != tab_index) { 593b22a70abSPatrick Mooney continue; 594b22a70abSPatrick Mooney } 595b22a70abSPatrick Mooney pci_viona_ring_set_msix(pi, i); 596b22a70abSPatrick Mooney } 597b22a70abSPatrick Mooney 598b22a70abSPatrick Mooney pthread_mutex_unlock(&sc->vsc_mtx); 599b22a70abSPatrick Mooney } 600b22a70abSPatrick Mooney 601b22a70abSPatrick Mooney static void 602b22a70abSPatrick Mooney pci_viona_qnotify(struct pci_viona_softc *sc, int ring) 603b22a70abSPatrick Mooney { 604b22a70abSPatrick Mooney int error; 605b22a70abSPatrick Mooney 606b22a70abSPatrick Mooney switch (ring) { 607b22a70abSPatrick Mooney case VIONA_TXQ: 608b22a70abSPatrick Mooney case VIONA_RXQ: 609b22a70abSPatrick Mooney error = ioctl(sc->vsc_vnafd, VNA_IOC_RING_KICK, ring); 610b22a70abSPatrick Mooney if (error != 0) { 611b22a70abSPatrick Mooney WPRINTF(("ioctl viona ring %d kick failed %d\n", 612b22a70abSPatrick Mooney ring, errno)); 613b22a70abSPatrick Mooney } 614b22a70abSPatrick Mooney break; 615b22a70abSPatrick Mooney case VIONA_CTLQ: 616b22a70abSPatrick Mooney DPRINTF(("viona: control qnotify!\n")); 617b22a70abSPatrick Mooney break; 618b22a70abSPatrick Mooney default: 619b22a70abSPatrick Mooney break; 620b22a70abSPatrick Mooney } 621b22a70abSPatrick Mooney } 622b22a70abSPatrick Mooney 623b22a70abSPatrick Mooney static void 624bf21cd93STycho Nightingale pci_viona_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 625bf21cd93STycho Nightingale int baridx, uint64_t offset, int size, uint64_t value) 626bf21cd93STycho Nightingale { 627bf21cd93STycho Nightingale struct pci_viona_softc *sc = pi->pi_arg; 628bf21cd93STycho Nightingale void *ptr; 629bf21cd93STycho Nightingale int err = 0; 630bf21cd93STycho Nightingale 631bf21cd93STycho Nightingale if (baridx == pci_msix_table_bar(pi) || 632bf21cd93STycho Nightingale baridx == pci_msix_pba_bar(pi)) { 633b22a70abSPatrick Mooney if (pci_emul_msix_twrite(pi, offset, size, value) == 0) { 634b22a70abSPatrick Mooney pci_viona_msix_update(pi, offset); 635b22a70abSPatrick Mooney } 636bf21cd93STycho Nightingale return; 637bf21cd93STycho Nightingale } 638bf21cd93STycho Nightingale 639bf21cd93STycho Nightingale assert(baridx == 0); 640bf21cd93STycho Nightingale 641bf21cd93STycho Nightingale if (offset + size > pci_viona_iosize(pi)) { 642bf21cd93STycho Nightingale DPRINTF(("viona_write: 2big, offset %ld size %d\n", 643bf21cd93STycho Nightingale offset, size)); 644bf21cd93STycho Nightingale return; 645bf21cd93STycho Nightingale } 646bf21cd93STycho Nightingale 647bf21cd93STycho Nightingale pthread_mutex_lock(&sc->vsc_mtx); 648bf21cd93STycho Nightingale 649bf21cd93STycho Nightingale offset = viona_adjust_offset(pi, offset); 650bf21cd93STycho Nightingale 651bf21cd93STycho Nightingale switch (offset) { 6522b948146SAndy Fiddaman case VIRTIO_PCI_GUEST_FEATURES: 653bf21cd93STycho Nightingale assert(size == 4); 654b22a70abSPatrick Mooney value &= ~(sc->vsc_feature_mask); 655bf21cd93STycho Nightingale err = ioctl(sc->vsc_vnafd, VNA_IOC_SET_FEATURES, &value); 656b22a70abSPatrick Mooney if (err != 0) { 657bf21cd93STycho Nightingale WPRINTF(("ioctl feature negotiation returned" 658b22a70abSPatrick Mooney " err = %d\n", errno)); 659b22a70abSPatrick Mooney } else { 660b22a70abSPatrick Mooney sc->vsc_features = value; 661b22a70abSPatrick Mooney } 662bf21cd93STycho Nightingale break; 6632b948146SAndy Fiddaman case VIRTIO_PCI_QUEUE_PFN: 664bf21cd93STycho Nightingale assert(size == 4); 665bf21cd93STycho Nightingale pci_viona_ring_init(sc, value); 666bf21cd93STycho Nightingale break; 6672b948146SAndy Fiddaman case VIRTIO_PCI_QUEUE_SEL: 668bf21cd93STycho Nightingale assert(size == 2); 669bf21cd93STycho Nightingale assert(value < VIONA_MAXQ); 670bf21cd93STycho Nightingale sc->vsc_curq = value; 671bf21cd93STycho Nightingale break; 6722b948146SAndy Fiddaman case VIRTIO_PCI_QUEUE_NOTIFY: 673bf21cd93STycho Nightingale assert(size == 2); 674bf21cd93STycho Nightingale assert(value < VIONA_MAXQ); 675b22a70abSPatrick Mooney pci_viona_qnotify(sc, value); 676bf21cd93STycho Nightingale break; 6772b948146SAndy Fiddaman case VIRTIO_PCI_STATUS: 678bf21cd93STycho Nightingale assert(size == 1); 679bf21cd93STycho Nightingale pci_viona_update_status(sc, value); 680bf21cd93STycho Nightingale break; 6812b948146SAndy Fiddaman case VIRTIO_MSI_CONFIG_VECTOR: 682bf21cd93STycho Nightingale assert(size == 2); 683bf21cd93STycho Nightingale sc->vsc_msix_table_idx[VIONA_CTLQ] = value; 684bf21cd93STycho Nightingale break; 6852b948146SAndy Fiddaman case VIRTIO_MSI_QUEUE_VECTOR: 686bf21cd93STycho Nightingale assert(size == 2); 687bf21cd93STycho Nightingale assert(sc->vsc_curq != VIONA_CTLQ); 688bf21cd93STycho Nightingale sc->vsc_msix_table_idx[sc->vsc_curq] = value; 689b22a70abSPatrick Mooney pci_viona_ring_set_msix(pi, sc->vsc_curq); 690bf21cd93STycho Nightingale break; 691bf21cd93STycho Nightingale case VIONA_R_CFG0: 692bf21cd93STycho Nightingale case VIONA_R_CFG1: 693bf21cd93STycho Nightingale case VIONA_R_CFG2: 694bf21cd93STycho Nightingale case VIONA_R_CFG3: 695bf21cd93STycho Nightingale case VIONA_R_CFG4: 696bf21cd93STycho Nightingale case VIONA_R_CFG5: 697bf21cd93STycho Nightingale assert((size + offset) <= (VIONA_R_CFG5 + 1)); 698bf21cd93STycho Nightingale ptr = &sc->vsc_macaddr[offset - VIONA_R_CFG0]; 699bf21cd93STycho Nightingale /* 700bf21cd93STycho Nightingale * The driver is allowed to change the MAC address 701bf21cd93STycho Nightingale */ 702bf21cd93STycho Nightingale sc->vsc_macaddr[offset - VIONA_R_CFG0] = value; 703bf21cd93STycho Nightingale if (size == 1) { 704bf21cd93STycho Nightingale *(uint8_t *)ptr = value; 705bf21cd93STycho Nightingale } else if (size == 2) { 706bf21cd93STycho Nightingale *(uint16_t *)ptr = value; 707bf21cd93STycho Nightingale } else { 708bf21cd93STycho Nightingale *(uint32_t *)ptr = value; 709bf21cd93STycho Nightingale } 710bf21cd93STycho Nightingale break; 7112b948146SAndy Fiddaman case VIRTIO_PCI_HOST_FEATURES: 7122b948146SAndy Fiddaman case VIRTIO_PCI_QUEUE_NUM: 7132b948146SAndy Fiddaman case VIRTIO_PCI_ISR: 714bf21cd93STycho Nightingale case VIONA_R_CFG6: 715bf21cd93STycho Nightingale case VIONA_R_CFG7: 716bf21cd93STycho Nightingale DPRINTF(("viona: write to readonly reg %ld\n\r", offset)); 717bf21cd93STycho Nightingale break; 718bf21cd93STycho Nightingale default: 719bf21cd93STycho Nightingale DPRINTF(("viona: unknown i/o write offset %ld\n\r", offset)); 720bf21cd93STycho Nightingale value = 0; 721bf21cd93STycho Nightingale break; 722bf21cd93STycho Nightingale } 723bf21cd93STycho Nightingale 724bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->vsc_mtx); 725bf21cd93STycho Nightingale } 726bf21cd93STycho Nightingale 727b22a70abSPatrick Mooney static uint64_t 728bf21cd93STycho Nightingale pci_viona_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 729bf21cd93STycho Nightingale int baridx, uint64_t offset, int size) 730bf21cd93STycho Nightingale { 731bf21cd93STycho Nightingale struct pci_viona_softc *sc = pi->pi_arg; 732bf21cd93STycho Nightingale void *ptr; 733bf21cd93STycho Nightingale uint64_t value; 734bf21cd93STycho Nightingale int err = 0; 735bf21cd93STycho Nightingale 736bf21cd93STycho Nightingale if (baridx == pci_msix_table_bar(pi) || 737bf21cd93STycho Nightingale baridx == pci_msix_pba_bar(pi)) { 738bf21cd93STycho Nightingale return (pci_emul_msix_tread(pi, offset, size)); 739bf21cd93STycho Nightingale } 740bf21cd93STycho Nightingale 741bf21cd93STycho Nightingale assert(baridx == 0); 742bf21cd93STycho Nightingale 743bf21cd93STycho Nightingale if (offset + size > pci_viona_iosize(pi)) { 744bf21cd93STycho Nightingale DPRINTF(("viona_read: 2big, offset %ld size %d\n", 745bf21cd93STycho Nightingale offset, size)); 746bf21cd93STycho Nightingale return (0); 747bf21cd93STycho Nightingale } 748bf21cd93STycho Nightingale 749bf21cd93STycho Nightingale pthread_mutex_lock(&sc->vsc_mtx); 750bf21cd93STycho Nightingale 751bf21cd93STycho Nightingale offset = viona_adjust_offset(pi, offset); 752bf21cd93STycho Nightingale 753bf21cd93STycho Nightingale switch (offset) { 7542b948146SAndy Fiddaman case VIRTIO_PCI_HOST_FEATURES: 755bf21cd93STycho Nightingale assert(size == 4); 756bf21cd93STycho Nightingale err = ioctl(sc->vsc_vnafd, VNA_IOC_GET_FEATURES, &value); 757b22a70abSPatrick Mooney if (err != 0) { 758bf21cd93STycho Nightingale WPRINTF(("ioctl get host features returned" 759b22a70abSPatrick Mooney " err = %d\n", errno)); 760b22a70abSPatrick Mooney } 761b22a70abSPatrick Mooney value &= ~sc->vsc_feature_mask; 762bf21cd93STycho Nightingale break; 7632b948146SAndy Fiddaman case VIRTIO_PCI_GUEST_FEATURES: 764bf21cd93STycho Nightingale assert(size == 4); 765bf21cd93STycho Nightingale value = sc->vsc_features; /* XXX never read ? */ 766bf21cd93STycho Nightingale break; 7672b948146SAndy Fiddaman case VIRTIO_PCI_QUEUE_PFN: 768bf21cd93STycho Nightingale assert(size == 4); 769bf21cd93STycho Nightingale value = sc->vsc_pfn[sc->vsc_curq] >> VRING_PFN; 770bf21cd93STycho Nightingale break; 7712b948146SAndy Fiddaman case VIRTIO_PCI_QUEUE_NUM: 772bf21cd93STycho Nightingale assert(size == 2); 773b22a70abSPatrick Mooney value = pci_viona_qsize(sc, sc->vsc_curq); 774bf21cd93STycho Nightingale break; 7752b948146SAndy Fiddaman case VIRTIO_PCI_QUEUE_SEL: 776bf21cd93STycho Nightingale assert(size == 2); 777bf21cd93STycho Nightingale value = sc->vsc_curq; /* XXX never read ? */ 778bf21cd93STycho Nightingale break; 7792b948146SAndy Fiddaman case VIRTIO_PCI_QUEUE_NOTIFY: 780bf21cd93STycho Nightingale assert(size == 2); 781bf21cd93STycho Nightingale value = sc->vsc_curq; /* XXX never read ? */ 782bf21cd93STycho Nightingale break; 7832b948146SAndy Fiddaman case VIRTIO_PCI_STATUS: 784bf21cd93STycho Nightingale assert(size == 1); 785bf21cd93STycho Nightingale value = sc->vsc_status; 786bf21cd93STycho Nightingale break; 7872b948146SAndy Fiddaman case VIRTIO_PCI_ISR: 788bf21cd93STycho Nightingale assert(size == 1); 789bf21cd93STycho Nightingale value = sc->vsc_isr; 790bf21cd93STycho Nightingale sc->vsc_isr = 0; /* a read clears this flag */ 791b22a70abSPatrick Mooney if (value != 0) { 792b22a70abSPatrick Mooney pci_lintr_deassert(pi); 793b22a70abSPatrick Mooney } 794bf21cd93STycho Nightingale break; 7952b948146SAndy Fiddaman case VIRTIO_MSI_CONFIG_VECTOR: 796bf21cd93STycho Nightingale assert(size == 2); 797bf21cd93STycho Nightingale value = sc->vsc_msix_table_idx[VIONA_CTLQ]; 798bf21cd93STycho Nightingale break; 7992b948146SAndy Fiddaman case VIRTIO_MSI_QUEUE_VECTOR: 800bf21cd93STycho Nightingale assert(size == 2); 801bf21cd93STycho Nightingale assert(sc->vsc_curq != VIONA_CTLQ); 802bf21cd93STycho Nightingale value = sc->vsc_msix_table_idx[sc->vsc_curq]; 803bf21cd93STycho Nightingale break; 804bf21cd93STycho Nightingale case VIONA_R_CFG0: 805bf21cd93STycho Nightingale case VIONA_R_CFG1: 806bf21cd93STycho Nightingale case VIONA_R_CFG2: 807bf21cd93STycho Nightingale case VIONA_R_CFG3: 808bf21cd93STycho Nightingale case VIONA_R_CFG4: 809bf21cd93STycho Nightingale case VIONA_R_CFG5: 810bf21cd93STycho Nightingale assert((size + offset) <= (VIONA_R_CFG5 + 1)); 811bf21cd93STycho Nightingale ptr = &sc->vsc_macaddr[offset - VIONA_R_CFG0]; 812bf21cd93STycho Nightingale if (size == 1) { 813bf21cd93STycho Nightingale value = *(uint8_t *)ptr; 814bf21cd93STycho Nightingale } else if (size == 2) { 815bf21cd93STycho Nightingale value = *(uint16_t *)ptr; 816bf21cd93STycho Nightingale } else { 817bf21cd93STycho Nightingale value = *(uint32_t *)ptr; 818bf21cd93STycho Nightingale } 819bf21cd93STycho Nightingale break; 820bf21cd93STycho Nightingale case VIONA_R_CFG6: 821bf21cd93STycho Nightingale assert(size != 4); 822bf21cd93STycho Nightingale value = 0x01; /* XXX link always up */ 823bf21cd93STycho Nightingale break; 824bf21cd93STycho Nightingale case VIONA_R_CFG7: 825bf21cd93STycho Nightingale assert(size == 1); 826bf21cd93STycho Nightingale value = 0; /* XXX link status in LSB */ 827bf21cd93STycho Nightingale break; 828bf21cd93STycho Nightingale default: 829bf21cd93STycho Nightingale DPRINTF(("viona: unknown i/o read offset %ld\n\r", offset)); 830bf21cd93STycho Nightingale value = 0; 831bf21cd93STycho Nightingale break; 832bf21cd93STycho Nightingale } 833bf21cd93STycho Nightingale 834bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->vsc_mtx); 835bf21cd93STycho Nightingale 836bf21cd93STycho Nightingale return (value); 837bf21cd93STycho Nightingale } 838bf21cd93STycho Nightingale 839bf21cd93STycho Nightingale struct pci_devemu pci_de_viona = { 840bf21cd93STycho Nightingale .pe_emu = "virtio-net-viona", 841bf21cd93STycho Nightingale .pe_init = pci_viona_init, 8422b948146SAndy Fiddaman .pe_legacy_config = pci_viona_legacy_config, 843bf21cd93STycho Nightingale .pe_barwrite = pci_viona_write, 844b22a70abSPatrick Mooney .pe_barread = pci_viona_read, 845b22a70abSPatrick Mooney .pe_lintrupdate = pci_viona_lintrupdate 846bf21cd93STycho Nightingale }; 847bf21cd93STycho Nightingale PCI_EMUL_SET(pci_de_viona); 848