1*bf21cd93STycho Nightingale /*- 2*bf21cd93STycho Nightingale * Copyright (c) 2013 Chris Torek <torek @ torek net> 3*bf21cd93STycho Nightingale * All rights reserved. 4*bf21cd93STycho Nightingale * 5*bf21cd93STycho Nightingale * Redistribution and use in source and binary forms, with or without 6*bf21cd93STycho Nightingale * modification, are permitted provided that the following conditions 7*bf21cd93STycho Nightingale * are met: 8*bf21cd93STycho Nightingale * 1. Redistributions of source code must retain the above copyright 9*bf21cd93STycho Nightingale * notice, this list of conditions and the following disclaimer. 10*bf21cd93STycho Nightingale * 2. Redistributions in binary form must reproduce the above copyright 11*bf21cd93STycho Nightingale * notice, this list of conditions and the following disclaimer in the 12*bf21cd93STycho Nightingale * documentation and/or other materials provided with the distribution. 13*bf21cd93STycho Nightingale * 14*bf21cd93STycho Nightingale * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*bf21cd93STycho Nightingale * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*bf21cd93STycho Nightingale * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*bf21cd93STycho Nightingale * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*bf21cd93STycho Nightingale * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*bf21cd93STycho Nightingale * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*bf21cd93STycho Nightingale * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*bf21cd93STycho Nightingale * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*bf21cd93STycho Nightingale * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*bf21cd93STycho Nightingale * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*bf21cd93STycho Nightingale * SUCH DAMAGE. 25*bf21cd93STycho Nightingale */ 26*bf21cd93STycho Nightingale 27*bf21cd93STycho Nightingale #include <sys/cdefs.h> 28*bf21cd93STycho Nightingale __FBSDID("$FreeBSD: head/usr.sbin/bhyve/virtio.c 270326 2014-08-22 13:01:22Z tychon $"); 29*bf21cd93STycho Nightingale 30*bf21cd93STycho Nightingale #include <sys/param.h> 31*bf21cd93STycho Nightingale #include <sys/uio.h> 32*bf21cd93STycho Nightingale 33*bf21cd93STycho Nightingale #include <stdio.h> 34*bf21cd93STycho Nightingale #include <stdint.h> 35*bf21cd93STycho Nightingale #include <pthread.h> 36*bf21cd93STycho Nightingale #include <pthread_np.h> 37*bf21cd93STycho Nightingale 38*bf21cd93STycho Nightingale #include "bhyverun.h" 39*bf21cd93STycho Nightingale #include "pci_emul.h" 40*bf21cd93STycho Nightingale #include "virtio.h" 41*bf21cd93STycho Nightingale 42*bf21cd93STycho Nightingale /* 43*bf21cd93STycho Nightingale * Functions for dealing with generalized "virtual devices" as 44*bf21cd93STycho Nightingale * defined by <https://www.google.com/#output=search&q=virtio+spec> 45*bf21cd93STycho Nightingale */ 46*bf21cd93STycho Nightingale 47*bf21cd93STycho Nightingale /* 48*bf21cd93STycho Nightingale * In case we decide to relax the "virtio softc comes at the 49*bf21cd93STycho Nightingale * front of virtio-based device softc" constraint, let's use 50*bf21cd93STycho Nightingale * this to convert. 51*bf21cd93STycho Nightingale */ 52*bf21cd93STycho Nightingale #define DEV_SOFTC(vs) ((void *)(vs)) 53*bf21cd93STycho Nightingale 54*bf21cd93STycho Nightingale /* 55*bf21cd93STycho Nightingale * Link a virtio_softc to its constants, the device softc, and 56*bf21cd93STycho Nightingale * the PCI emulation. 57*bf21cd93STycho Nightingale */ 58*bf21cd93STycho Nightingale void 59*bf21cd93STycho Nightingale vi_softc_linkup(struct virtio_softc *vs, struct virtio_consts *vc, 60*bf21cd93STycho Nightingale void *dev_softc, struct pci_devinst *pi, 61*bf21cd93STycho Nightingale struct vqueue_info *queues) 62*bf21cd93STycho Nightingale { 63*bf21cd93STycho Nightingale int i; 64*bf21cd93STycho Nightingale 65*bf21cd93STycho Nightingale /* vs and dev_softc addresses must match */ 66*bf21cd93STycho Nightingale assert((void *)vs == dev_softc); 67*bf21cd93STycho Nightingale vs->vs_vc = vc; 68*bf21cd93STycho Nightingale vs->vs_pi = pi; 69*bf21cd93STycho Nightingale pi->pi_arg = vs; 70*bf21cd93STycho Nightingale 71*bf21cd93STycho Nightingale vs->vs_queues = queues; 72*bf21cd93STycho Nightingale for (i = 0; i < vc->vc_nvq; i++) { 73*bf21cd93STycho Nightingale queues[i].vq_vs = vs; 74*bf21cd93STycho Nightingale queues[i].vq_num = i; 75*bf21cd93STycho Nightingale } 76*bf21cd93STycho Nightingale } 77*bf21cd93STycho Nightingale 78*bf21cd93STycho Nightingale /* 79*bf21cd93STycho Nightingale * Reset device (device-wide). This erases all queues, i.e., 80*bf21cd93STycho Nightingale * all the queues become invalid (though we don't wipe out the 81*bf21cd93STycho Nightingale * internal pointers, we just clear the VQ_ALLOC flag). 82*bf21cd93STycho Nightingale * 83*bf21cd93STycho Nightingale * It resets negotiated features to "none". 84*bf21cd93STycho Nightingale * 85*bf21cd93STycho Nightingale * If MSI-X is enabled, this also resets all the vectors to NO_VECTOR. 86*bf21cd93STycho Nightingale */ 87*bf21cd93STycho Nightingale void 88*bf21cd93STycho Nightingale vi_reset_dev(struct virtio_softc *vs) 89*bf21cd93STycho Nightingale { 90*bf21cd93STycho Nightingale struct vqueue_info *vq; 91*bf21cd93STycho Nightingale int i, nvq; 92*bf21cd93STycho Nightingale 93*bf21cd93STycho Nightingale if (vs->vs_mtx) 94*bf21cd93STycho Nightingale assert(pthread_mutex_isowned_np(vs->vs_mtx)); 95*bf21cd93STycho Nightingale 96*bf21cd93STycho Nightingale nvq = vs->vs_vc->vc_nvq; 97*bf21cd93STycho Nightingale for (vq = vs->vs_queues, i = 0; i < nvq; vq++, i++) { 98*bf21cd93STycho Nightingale vq->vq_flags = 0; 99*bf21cd93STycho Nightingale vq->vq_last_avail = 0; 100*bf21cd93STycho Nightingale vq->vq_pfn = 0; 101*bf21cd93STycho Nightingale vq->vq_msix_idx = VIRTIO_MSI_NO_VECTOR; 102*bf21cd93STycho Nightingale } 103*bf21cd93STycho Nightingale vs->vs_negotiated_caps = 0; 104*bf21cd93STycho Nightingale vs->vs_curq = 0; 105*bf21cd93STycho Nightingale /* vs->vs_status = 0; -- redundant */ 106*bf21cd93STycho Nightingale if (vs->vs_isr) 107*bf21cd93STycho Nightingale pci_lintr_deassert(vs->vs_pi); 108*bf21cd93STycho Nightingale vs->vs_isr = 0; 109*bf21cd93STycho Nightingale vs->vs_msix_cfg_idx = VIRTIO_MSI_NO_VECTOR; 110*bf21cd93STycho Nightingale } 111*bf21cd93STycho Nightingale 112*bf21cd93STycho Nightingale /* 113*bf21cd93STycho Nightingale * Set I/O BAR (usually 0) to map PCI config registers. 114*bf21cd93STycho Nightingale */ 115*bf21cd93STycho Nightingale void 116*bf21cd93STycho Nightingale vi_set_io_bar(struct virtio_softc *vs, int barnum) 117*bf21cd93STycho Nightingale { 118*bf21cd93STycho Nightingale size_t size; 119*bf21cd93STycho Nightingale 120*bf21cd93STycho Nightingale /* 121*bf21cd93STycho Nightingale * ??? should we use CFG0 if MSI-X is disabled? 122*bf21cd93STycho Nightingale * Existing code did not... 123*bf21cd93STycho Nightingale */ 124*bf21cd93STycho Nightingale size = VTCFG_R_CFG1 + vs->vs_vc->vc_cfgsize; 125*bf21cd93STycho Nightingale pci_emul_alloc_bar(vs->vs_pi, barnum, PCIBAR_IO, size); 126*bf21cd93STycho Nightingale } 127*bf21cd93STycho Nightingale 128*bf21cd93STycho Nightingale /* 129*bf21cd93STycho Nightingale * Initialize MSI-X vector capabilities if we're to use MSI-X, 130*bf21cd93STycho Nightingale * or MSI capabilities if not. 131*bf21cd93STycho Nightingale * 132*bf21cd93STycho Nightingale * We assume we want one MSI-X vector per queue, here, plus one 133*bf21cd93STycho Nightingale * for the config vec. 134*bf21cd93STycho Nightingale */ 135*bf21cd93STycho Nightingale int 136*bf21cd93STycho Nightingale vi_intr_init(struct virtio_softc *vs, int barnum, int use_msix) 137*bf21cd93STycho Nightingale { 138*bf21cd93STycho Nightingale int nvec; 139*bf21cd93STycho Nightingale 140*bf21cd93STycho Nightingale if (use_msix) { 141*bf21cd93STycho Nightingale vs->vs_flags |= VIRTIO_USE_MSIX; 142*bf21cd93STycho Nightingale VS_LOCK(vs); 143*bf21cd93STycho Nightingale vi_reset_dev(vs); /* set all vectors to NO_VECTOR */ 144*bf21cd93STycho Nightingale VS_UNLOCK(vs); 145*bf21cd93STycho Nightingale nvec = vs->vs_vc->vc_nvq + 1; 146*bf21cd93STycho Nightingale if (pci_emul_add_msixcap(vs->vs_pi, nvec, barnum)) 147*bf21cd93STycho Nightingale return (1); 148*bf21cd93STycho Nightingale } else 149*bf21cd93STycho Nightingale vs->vs_flags &= ~VIRTIO_USE_MSIX; 150*bf21cd93STycho Nightingale /* Only 1 MSI vector for bhyve */ 151*bf21cd93STycho Nightingale pci_emul_add_msicap(vs->vs_pi, 1); 152*bf21cd93STycho Nightingale return (0); 153*bf21cd93STycho Nightingale } 154*bf21cd93STycho Nightingale 155*bf21cd93STycho Nightingale /* 156*bf21cd93STycho Nightingale * Initialize the currently-selected virtio queue (vs->vs_curq). 157*bf21cd93STycho Nightingale * The guest just gave us a page frame number, from which we can 158*bf21cd93STycho Nightingale * calculate the addresses of the queue. 159*bf21cd93STycho Nightingale */ 160*bf21cd93STycho Nightingale void 161*bf21cd93STycho Nightingale vi_vq_init(struct virtio_softc *vs, uint32_t pfn) 162*bf21cd93STycho Nightingale { 163*bf21cd93STycho Nightingale struct vqueue_info *vq; 164*bf21cd93STycho Nightingale uint64_t phys; 165*bf21cd93STycho Nightingale size_t size; 166*bf21cd93STycho Nightingale char *base; 167*bf21cd93STycho Nightingale 168*bf21cd93STycho Nightingale vq = &vs->vs_queues[vs->vs_curq]; 169*bf21cd93STycho Nightingale vq->vq_pfn = pfn; 170*bf21cd93STycho Nightingale phys = (uint64_t)pfn << VRING_PFN; 171*bf21cd93STycho Nightingale size = vring_size(vq->vq_qsize); 172*bf21cd93STycho Nightingale base = paddr_guest2host(vs->vs_pi->pi_vmctx, phys, size); 173*bf21cd93STycho Nightingale 174*bf21cd93STycho Nightingale /* First page(s) are descriptors... */ 175*bf21cd93STycho Nightingale vq->vq_desc = (struct virtio_desc *)base; 176*bf21cd93STycho Nightingale base += vq->vq_qsize * sizeof(struct virtio_desc); 177*bf21cd93STycho Nightingale 178*bf21cd93STycho Nightingale /* ... immediately followed by "avail" ring (entirely uint16_t's) */ 179*bf21cd93STycho Nightingale vq->vq_avail = (struct vring_avail *)base; 180*bf21cd93STycho Nightingale base += (2 + vq->vq_qsize + 1) * sizeof(uint16_t); 181*bf21cd93STycho Nightingale 182*bf21cd93STycho Nightingale /* Then it's rounded up to the next page... */ 183*bf21cd93STycho Nightingale base = (char *)roundup2((uintptr_t)base, VRING_ALIGN); 184*bf21cd93STycho Nightingale 185*bf21cd93STycho Nightingale /* ... and the last page(s) are the used ring. */ 186*bf21cd93STycho Nightingale vq->vq_used = (struct vring_used *)base; 187*bf21cd93STycho Nightingale 188*bf21cd93STycho Nightingale /* Mark queue as allocated, and start at 0 when we use it. */ 189*bf21cd93STycho Nightingale vq->vq_flags = VQ_ALLOC; 190*bf21cd93STycho Nightingale vq->vq_last_avail = 0; 191*bf21cd93STycho Nightingale } 192*bf21cd93STycho Nightingale 193*bf21cd93STycho Nightingale /* 194*bf21cd93STycho Nightingale * Helper inline for vq_getchain(): record the i'th "real" 195*bf21cd93STycho Nightingale * descriptor. 196*bf21cd93STycho Nightingale */ 197*bf21cd93STycho Nightingale static inline void 198*bf21cd93STycho Nightingale _vq_record(int i, volatile struct virtio_desc *vd, struct vmctx *ctx, 199*bf21cd93STycho Nightingale struct iovec *iov, int n_iov, uint16_t *flags) { 200*bf21cd93STycho Nightingale 201*bf21cd93STycho Nightingale if (i >= n_iov) 202*bf21cd93STycho Nightingale return; 203*bf21cd93STycho Nightingale iov[i].iov_base = paddr_guest2host(ctx, vd->vd_addr, vd->vd_len); 204*bf21cd93STycho Nightingale iov[i].iov_len = vd->vd_len; 205*bf21cd93STycho Nightingale if (flags != NULL) 206*bf21cd93STycho Nightingale flags[i] = vd->vd_flags; 207*bf21cd93STycho Nightingale } 208*bf21cd93STycho Nightingale #define VQ_MAX_DESCRIPTORS 512 /* see below */ 209*bf21cd93STycho Nightingale 210*bf21cd93STycho Nightingale /* 211*bf21cd93STycho Nightingale * Examine the chain of descriptors starting at the "next one" to 212*bf21cd93STycho Nightingale * make sure that they describe a sensible request. If so, return 213*bf21cd93STycho Nightingale * the number of "real" descriptors that would be needed/used in 214*bf21cd93STycho Nightingale * acting on this request. This may be smaller than the number of 215*bf21cd93STycho Nightingale * available descriptors, e.g., if there are two available but 216*bf21cd93STycho Nightingale * they are two separate requests, this just returns 1. Or, it 217*bf21cd93STycho Nightingale * may be larger: if there are indirect descriptors involved, 218*bf21cd93STycho Nightingale * there may only be one descriptor available but it may be an 219*bf21cd93STycho Nightingale * indirect pointing to eight more. We return 8 in this case, 220*bf21cd93STycho Nightingale * i.e., we do not count the indirect descriptors, only the "real" 221*bf21cd93STycho Nightingale * ones. 222*bf21cd93STycho Nightingale * 223*bf21cd93STycho Nightingale * Basically, this vets the vd_flags and vd_next field of each 224*bf21cd93STycho Nightingale * descriptor and tells you how many are involved. Since some may 225*bf21cd93STycho Nightingale * be indirect, this also needs the vmctx (in the pci_devinst 226*bf21cd93STycho Nightingale * at vs->vs_pi) so that it can find indirect descriptors. 227*bf21cd93STycho Nightingale * 228*bf21cd93STycho Nightingale * As we process each descriptor, we copy and adjust it (guest to 229*bf21cd93STycho Nightingale * host address wise, also using the vmtctx) into the given iov[] 230*bf21cd93STycho Nightingale * array (of the given size). If the array overflows, we stop 231*bf21cd93STycho Nightingale * placing values into the array but keep processing descriptors, 232*bf21cd93STycho Nightingale * up to VQ_MAX_DESCRIPTORS, before giving up and returning -1. 233*bf21cd93STycho Nightingale * So you, the caller, must not assume that iov[] is as big as the 234*bf21cd93STycho Nightingale * return value (you can process the same thing twice to allocate 235*bf21cd93STycho Nightingale * a larger iov array if needed, or supply a zero length to find 236*bf21cd93STycho Nightingale * out how much space is needed). 237*bf21cd93STycho Nightingale * 238*bf21cd93STycho Nightingale * If you want to verify the WRITE flag on each descriptor, pass a 239*bf21cd93STycho Nightingale * non-NULL "flags" pointer to an array of "uint16_t" of the same size 240*bf21cd93STycho Nightingale * as n_iov and we'll copy each vd_flags field after unwinding any 241*bf21cd93STycho Nightingale * indirects. 242*bf21cd93STycho Nightingale * 243*bf21cd93STycho Nightingale * If some descriptor(s) are invalid, this prints a diagnostic message 244*bf21cd93STycho Nightingale * and returns -1. If no descriptors are ready now it simply returns 0. 245*bf21cd93STycho Nightingale * 246*bf21cd93STycho Nightingale * You are assumed to have done a vq_ring_ready() if needed (note 247*bf21cd93STycho Nightingale * that vq_has_descs() does one). 248*bf21cd93STycho Nightingale */ 249*bf21cd93STycho Nightingale int 250*bf21cd93STycho Nightingale vq_getchain(struct vqueue_info *vq, 251*bf21cd93STycho Nightingale struct iovec *iov, int n_iov, uint16_t *flags) 252*bf21cd93STycho Nightingale { 253*bf21cd93STycho Nightingale int i; 254*bf21cd93STycho Nightingale u_int ndesc, n_indir; 255*bf21cd93STycho Nightingale u_int idx, head, next; 256*bf21cd93STycho Nightingale volatile struct virtio_desc *vdir, *vindir, *vp; 257*bf21cd93STycho Nightingale struct vmctx *ctx; 258*bf21cd93STycho Nightingale struct virtio_softc *vs; 259*bf21cd93STycho Nightingale const char *name; 260*bf21cd93STycho Nightingale 261*bf21cd93STycho Nightingale vs = vq->vq_vs; 262*bf21cd93STycho Nightingale name = vs->vs_vc->vc_name; 263*bf21cd93STycho Nightingale 264*bf21cd93STycho Nightingale /* 265*bf21cd93STycho Nightingale * Note: it's the responsibility of the guest not to 266*bf21cd93STycho Nightingale * update vq->vq_avail->va_idx until all of the descriptors 267*bf21cd93STycho Nightingale * the guest has written are valid (including all their 268*bf21cd93STycho Nightingale * vd_next fields and vd_flags). 269*bf21cd93STycho Nightingale * 270*bf21cd93STycho Nightingale * Compute (last_avail - va_idx) in integers mod 2**16. This is 271*bf21cd93STycho Nightingale * the number of descriptors the device has made available 272*bf21cd93STycho Nightingale * since the last time we updated vq->vq_last_avail. 273*bf21cd93STycho Nightingale * 274*bf21cd93STycho Nightingale * We just need to do the subtraction as an unsigned int, 275*bf21cd93STycho Nightingale * then trim off excess bits. 276*bf21cd93STycho Nightingale */ 277*bf21cd93STycho Nightingale idx = vq->vq_last_avail; 278*bf21cd93STycho Nightingale ndesc = (uint16_t)((u_int)vq->vq_avail->va_idx - idx); 279*bf21cd93STycho Nightingale if (ndesc == 0) 280*bf21cd93STycho Nightingale return (0); 281*bf21cd93STycho Nightingale if (ndesc > vq->vq_qsize) { 282*bf21cd93STycho Nightingale /* XXX need better way to diagnose issues */ 283*bf21cd93STycho Nightingale fprintf(stderr, 284*bf21cd93STycho Nightingale "%s: ndesc (%u) out of range, driver confused?\r\n", 285*bf21cd93STycho Nightingale name, (u_int)ndesc); 286*bf21cd93STycho Nightingale return (-1); 287*bf21cd93STycho Nightingale } 288*bf21cd93STycho Nightingale 289*bf21cd93STycho Nightingale /* 290*bf21cd93STycho Nightingale * Now count/parse "involved" descriptors starting from 291*bf21cd93STycho Nightingale * the head of the chain. 292*bf21cd93STycho Nightingale * 293*bf21cd93STycho Nightingale * To prevent loops, we could be more complicated and 294*bf21cd93STycho Nightingale * check whether we're re-visiting a previously visited 295*bf21cd93STycho Nightingale * index, but we just abort if the count gets excessive. 296*bf21cd93STycho Nightingale */ 297*bf21cd93STycho Nightingale ctx = vs->vs_pi->pi_vmctx; 298*bf21cd93STycho Nightingale head = vq->vq_avail->va_ring[idx & (vq->vq_qsize - 1)]; 299*bf21cd93STycho Nightingale next = head; 300*bf21cd93STycho Nightingale for (i = 0; i < VQ_MAX_DESCRIPTORS; next = vdir->vd_next) { 301*bf21cd93STycho Nightingale if (next >= vq->vq_qsize) { 302*bf21cd93STycho Nightingale fprintf(stderr, 303*bf21cd93STycho Nightingale "%s: descriptor index %u out of range, " 304*bf21cd93STycho Nightingale "driver confused?\r\n", 305*bf21cd93STycho Nightingale name, next); 306*bf21cd93STycho Nightingale return (-1); 307*bf21cd93STycho Nightingale } 308*bf21cd93STycho Nightingale vdir = &vq->vq_desc[next]; 309*bf21cd93STycho Nightingale if ((vdir->vd_flags & VRING_DESC_F_INDIRECT) == 0) { 310*bf21cd93STycho Nightingale _vq_record(i, vdir, ctx, iov, n_iov, flags); 311*bf21cd93STycho Nightingale i++; 312*bf21cd93STycho Nightingale } else if ((vs->vs_negotiated_caps & 313*bf21cd93STycho Nightingale VIRTIO_RING_F_INDIRECT_DESC) == 0) { 314*bf21cd93STycho Nightingale fprintf(stderr, 315*bf21cd93STycho Nightingale "%s: descriptor has forbidden INDIRECT flag, " 316*bf21cd93STycho Nightingale "driver confused?\r\n", 317*bf21cd93STycho Nightingale name); 318*bf21cd93STycho Nightingale return (-1); 319*bf21cd93STycho Nightingale } else { 320*bf21cd93STycho Nightingale n_indir = vdir->vd_len / 16; 321*bf21cd93STycho Nightingale if ((vdir->vd_len & 0xf) || n_indir == 0) { 322*bf21cd93STycho Nightingale fprintf(stderr, 323*bf21cd93STycho Nightingale "%s: invalid indir len 0x%x, " 324*bf21cd93STycho Nightingale "driver confused?\r\n", 325*bf21cd93STycho Nightingale name, (u_int)vdir->vd_len); 326*bf21cd93STycho Nightingale return (-1); 327*bf21cd93STycho Nightingale } 328*bf21cd93STycho Nightingale vindir = paddr_guest2host(ctx, 329*bf21cd93STycho Nightingale vdir->vd_addr, vdir->vd_len); 330*bf21cd93STycho Nightingale /* 331*bf21cd93STycho Nightingale * Indirects start at the 0th, then follow 332*bf21cd93STycho Nightingale * their own embedded "next"s until those run 333*bf21cd93STycho Nightingale * out. Each one's indirect flag must be off 334*bf21cd93STycho Nightingale * (we don't really have to check, could just 335*bf21cd93STycho Nightingale * ignore errors...). 336*bf21cd93STycho Nightingale */ 337*bf21cd93STycho Nightingale next = 0; 338*bf21cd93STycho Nightingale for (;;) { 339*bf21cd93STycho Nightingale vp = &vindir[next]; 340*bf21cd93STycho Nightingale if (vp->vd_flags & VRING_DESC_F_INDIRECT) { 341*bf21cd93STycho Nightingale fprintf(stderr, 342*bf21cd93STycho Nightingale "%s: indirect desc has INDIR flag," 343*bf21cd93STycho Nightingale " driver confused?\r\n", 344*bf21cd93STycho Nightingale name); 345*bf21cd93STycho Nightingale return (-1); 346*bf21cd93STycho Nightingale } 347*bf21cd93STycho Nightingale _vq_record(i, vp, ctx, iov, n_iov, flags); 348*bf21cd93STycho Nightingale if (++i > VQ_MAX_DESCRIPTORS) 349*bf21cd93STycho Nightingale goto loopy; 350*bf21cd93STycho Nightingale if ((vp->vd_flags & VRING_DESC_F_NEXT) == 0) 351*bf21cd93STycho Nightingale break; 352*bf21cd93STycho Nightingale next = vp->vd_next; 353*bf21cd93STycho Nightingale if (next >= n_indir) { 354*bf21cd93STycho Nightingale fprintf(stderr, 355*bf21cd93STycho Nightingale "%s: invalid next %u > %u, " 356*bf21cd93STycho Nightingale "driver confused?\r\n", 357*bf21cd93STycho Nightingale name, (u_int)next, n_indir); 358*bf21cd93STycho Nightingale return (-1); 359*bf21cd93STycho Nightingale } 360*bf21cd93STycho Nightingale } 361*bf21cd93STycho Nightingale } 362*bf21cd93STycho Nightingale if ((vdir->vd_flags & VRING_DESC_F_NEXT) == 0) 363*bf21cd93STycho Nightingale return (i); 364*bf21cd93STycho Nightingale } 365*bf21cd93STycho Nightingale loopy: 366*bf21cd93STycho Nightingale fprintf(stderr, 367*bf21cd93STycho Nightingale "%s: descriptor loop? count > %d - driver confused?\r\n", 368*bf21cd93STycho Nightingale name, i); 369*bf21cd93STycho Nightingale return (-1); 370*bf21cd93STycho Nightingale } 371*bf21cd93STycho Nightingale 372*bf21cd93STycho Nightingale /* 373*bf21cd93STycho Nightingale * Return the currently-first request chain to the guest, setting 374*bf21cd93STycho Nightingale * its I/O length to the provided value. 375*bf21cd93STycho Nightingale * 376*bf21cd93STycho Nightingale * (This chain is the one you handled when you called vq_getchain() 377*bf21cd93STycho Nightingale * and used its positive return value.) 378*bf21cd93STycho Nightingale */ 379*bf21cd93STycho Nightingale void 380*bf21cd93STycho Nightingale vq_relchain(struct vqueue_info *vq, uint32_t iolen) 381*bf21cd93STycho Nightingale { 382*bf21cd93STycho Nightingale uint16_t head, uidx, mask; 383*bf21cd93STycho Nightingale volatile struct vring_used *vuh; 384*bf21cd93STycho Nightingale volatile struct virtio_used *vue; 385*bf21cd93STycho Nightingale 386*bf21cd93STycho Nightingale /* 387*bf21cd93STycho Nightingale * Notes: 388*bf21cd93STycho Nightingale * - mask is N-1 where N is a power of 2 so computes x % N 389*bf21cd93STycho Nightingale * - vuh points to the "used" data shared with guest 390*bf21cd93STycho Nightingale * - vue points to the "used" ring entry we want to update 391*bf21cd93STycho Nightingale * - head is the same value we compute in vq_iovecs(). 392*bf21cd93STycho Nightingale * 393*bf21cd93STycho Nightingale * (I apologize for the two fields named vu_idx; the 394*bf21cd93STycho Nightingale * virtio spec calls the one that vue points to, "id"...) 395*bf21cd93STycho Nightingale */ 396*bf21cd93STycho Nightingale mask = vq->vq_qsize - 1; 397*bf21cd93STycho Nightingale vuh = vq->vq_used; 398*bf21cd93STycho Nightingale head = vq->vq_avail->va_ring[vq->vq_last_avail++ & mask]; 399*bf21cd93STycho Nightingale 400*bf21cd93STycho Nightingale uidx = vuh->vu_idx; 401*bf21cd93STycho Nightingale vue = &vuh->vu_ring[uidx++ & mask]; 402*bf21cd93STycho Nightingale vue->vu_idx = head; /* ie, vue->id = head */ 403*bf21cd93STycho Nightingale vue->vu_tlen = iolen; 404*bf21cd93STycho Nightingale vuh->vu_idx = uidx; 405*bf21cd93STycho Nightingale } 406*bf21cd93STycho Nightingale 407*bf21cd93STycho Nightingale /* 408*bf21cd93STycho Nightingale * Driver has finished processing "available" chains and calling 409*bf21cd93STycho Nightingale * vq_relchain on each one. If driver used all the available 410*bf21cd93STycho Nightingale * chains, used_all should be set. 411*bf21cd93STycho Nightingale * 412*bf21cd93STycho Nightingale * If the "used" index moved we may need to inform the guest, i.e., 413*bf21cd93STycho Nightingale * deliver an interrupt. Even if the used index did NOT move we 414*bf21cd93STycho Nightingale * may need to deliver an interrupt, if the avail ring is empty and 415*bf21cd93STycho Nightingale * we are supposed to interrupt on empty. 416*bf21cd93STycho Nightingale * 417*bf21cd93STycho Nightingale * Note that used_all_avail is provided by the caller because it's 418*bf21cd93STycho Nightingale * a snapshot of the ring state when he decided to finish interrupt 419*bf21cd93STycho Nightingale * processing -- it's possible that descriptors became available after 420*bf21cd93STycho Nightingale * that point. (It's also typically a constant 1/True as well.) 421*bf21cd93STycho Nightingale */ 422*bf21cd93STycho Nightingale void 423*bf21cd93STycho Nightingale vq_endchains(struct vqueue_info *vq, int used_all_avail) 424*bf21cd93STycho Nightingale { 425*bf21cd93STycho Nightingale struct virtio_softc *vs; 426*bf21cd93STycho Nightingale uint16_t event_idx, new_idx, old_idx; 427*bf21cd93STycho Nightingale int intr; 428*bf21cd93STycho Nightingale 429*bf21cd93STycho Nightingale /* 430*bf21cd93STycho Nightingale * Interrupt generation: if we're using EVENT_IDX, 431*bf21cd93STycho Nightingale * interrupt if we've crossed the event threshold. 432*bf21cd93STycho Nightingale * Otherwise interrupt is generated if we added "used" entries, 433*bf21cd93STycho Nightingale * but suppressed by VRING_AVAIL_F_NO_INTERRUPT. 434*bf21cd93STycho Nightingale * 435*bf21cd93STycho Nightingale * In any case, though, if NOTIFY_ON_EMPTY is set and the 436*bf21cd93STycho Nightingale * entire avail was processed, we need to interrupt always. 437*bf21cd93STycho Nightingale */ 438*bf21cd93STycho Nightingale vs = vq->vq_vs; 439*bf21cd93STycho Nightingale new_idx = vq->vq_used->vu_idx; 440*bf21cd93STycho Nightingale old_idx = vq->vq_save_used; 441*bf21cd93STycho Nightingale if (used_all_avail && 442*bf21cd93STycho Nightingale (vs->vs_negotiated_caps & VIRTIO_F_NOTIFY_ON_EMPTY)) 443*bf21cd93STycho Nightingale intr = 1; 444*bf21cd93STycho Nightingale else if (vs->vs_negotiated_caps & VIRTIO_RING_F_EVENT_IDX) { 445*bf21cd93STycho Nightingale event_idx = VQ_USED_EVENT_IDX(vq); 446*bf21cd93STycho Nightingale /* 447*bf21cd93STycho Nightingale * This calculation is per docs and the kernel 448*bf21cd93STycho Nightingale * (see src/sys/dev/virtio/virtio_ring.h). 449*bf21cd93STycho Nightingale */ 450*bf21cd93STycho Nightingale intr = (uint16_t)(new_idx - event_idx - 1) < 451*bf21cd93STycho Nightingale (uint16_t)(new_idx - old_idx); 452*bf21cd93STycho Nightingale } else { 453*bf21cd93STycho Nightingale intr = new_idx != old_idx && 454*bf21cd93STycho Nightingale !(vq->vq_avail->va_flags & VRING_AVAIL_F_NO_INTERRUPT); 455*bf21cd93STycho Nightingale } 456*bf21cd93STycho Nightingale if (intr) 457*bf21cd93STycho Nightingale vq_interrupt(vs, vq); 458*bf21cd93STycho Nightingale } 459*bf21cd93STycho Nightingale 460*bf21cd93STycho Nightingale /* Note: these are in sorted order to make for a fast search */ 461*bf21cd93STycho Nightingale static struct config_reg { 462*bf21cd93STycho Nightingale uint16_t cr_offset; /* register offset */ 463*bf21cd93STycho Nightingale uint8_t cr_size; /* size (bytes) */ 464*bf21cd93STycho Nightingale uint8_t cr_ro; /* true => reg is read only */ 465*bf21cd93STycho Nightingale const char *cr_name; /* name of reg */ 466*bf21cd93STycho Nightingale } config_regs[] = { 467*bf21cd93STycho Nightingale { VTCFG_R_HOSTCAP, 4, 1, "HOSTCAP" }, 468*bf21cd93STycho Nightingale { VTCFG_R_GUESTCAP, 4, 0, "GUESTCAP" }, 469*bf21cd93STycho Nightingale { VTCFG_R_PFN, 4, 0, "PFN" }, 470*bf21cd93STycho Nightingale { VTCFG_R_QNUM, 2, 1, "QNUM" }, 471*bf21cd93STycho Nightingale { VTCFG_R_QSEL, 2, 0, "QSEL" }, 472*bf21cd93STycho Nightingale { VTCFG_R_QNOTIFY, 2, 0, "QNOTIFY" }, 473*bf21cd93STycho Nightingale { VTCFG_R_STATUS, 1, 0, "STATUS" }, 474*bf21cd93STycho Nightingale { VTCFG_R_ISR, 1, 0, "ISR" }, 475*bf21cd93STycho Nightingale { VTCFG_R_CFGVEC, 2, 0, "CFGVEC" }, 476*bf21cd93STycho Nightingale { VTCFG_R_QVEC, 2, 0, "QVEC" }, 477*bf21cd93STycho Nightingale }; 478*bf21cd93STycho Nightingale 479*bf21cd93STycho Nightingale static inline struct config_reg * 480*bf21cd93STycho Nightingale vi_find_cr(int offset) { 481*bf21cd93STycho Nightingale u_int hi, lo, mid; 482*bf21cd93STycho Nightingale struct config_reg *cr; 483*bf21cd93STycho Nightingale 484*bf21cd93STycho Nightingale lo = 0; 485*bf21cd93STycho Nightingale hi = sizeof(config_regs) / sizeof(*config_regs) - 1; 486*bf21cd93STycho Nightingale while (hi >= lo) { 487*bf21cd93STycho Nightingale mid = (hi + lo) >> 1; 488*bf21cd93STycho Nightingale cr = &config_regs[mid]; 489*bf21cd93STycho Nightingale if (cr->cr_offset == offset) 490*bf21cd93STycho Nightingale return (cr); 491*bf21cd93STycho Nightingale if (cr->cr_offset < offset) 492*bf21cd93STycho Nightingale lo = mid + 1; 493*bf21cd93STycho Nightingale else 494*bf21cd93STycho Nightingale hi = mid - 1; 495*bf21cd93STycho Nightingale } 496*bf21cd93STycho Nightingale return (NULL); 497*bf21cd93STycho Nightingale } 498*bf21cd93STycho Nightingale 499*bf21cd93STycho Nightingale /* 500*bf21cd93STycho Nightingale * Handle pci config space reads. 501*bf21cd93STycho Nightingale * If it's to the MSI-X info, do that. 502*bf21cd93STycho Nightingale * If it's part of the virtio standard stuff, do that. 503*bf21cd93STycho Nightingale * Otherwise dispatch to the actual driver. 504*bf21cd93STycho Nightingale */ 505*bf21cd93STycho Nightingale uint64_t 506*bf21cd93STycho Nightingale vi_pci_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 507*bf21cd93STycho Nightingale int baridx, uint64_t offset, int size) 508*bf21cd93STycho Nightingale { 509*bf21cd93STycho Nightingale struct virtio_softc *vs = pi->pi_arg; 510*bf21cd93STycho Nightingale struct virtio_consts *vc; 511*bf21cd93STycho Nightingale struct config_reg *cr; 512*bf21cd93STycho Nightingale uint64_t virtio_config_size, max; 513*bf21cd93STycho Nightingale const char *name; 514*bf21cd93STycho Nightingale uint32_t newoff; 515*bf21cd93STycho Nightingale uint32_t value; 516*bf21cd93STycho Nightingale int error; 517*bf21cd93STycho Nightingale 518*bf21cd93STycho Nightingale if (vs->vs_flags & VIRTIO_USE_MSIX) { 519*bf21cd93STycho Nightingale if (baridx == pci_msix_table_bar(pi) || 520*bf21cd93STycho Nightingale baridx == pci_msix_pba_bar(pi)) { 521*bf21cd93STycho Nightingale return (pci_emul_msix_tread(pi, offset, size)); 522*bf21cd93STycho Nightingale } 523*bf21cd93STycho Nightingale } 524*bf21cd93STycho Nightingale 525*bf21cd93STycho Nightingale /* XXX probably should do something better than just assert() */ 526*bf21cd93STycho Nightingale assert(baridx == 0); 527*bf21cd93STycho Nightingale 528*bf21cd93STycho Nightingale if (vs->vs_mtx) 529*bf21cd93STycho Nightingale pthread_mutex_lock(vs->vs_mtx); 530*bf21cd93STycho Nightingale 531*bf21cd93STycho Nightingale vc = vs->vs_vc; 532*bf21cd93STycho Nightingale name = vc->vc_name; 533*bf21cd93STycho Nightingale value = size == 1 ? 0xff : size == 2 ? 0xffff : 0xffffffff; 534*bf21cd93STycho Nightingale 535*bf21cd93STycho Nightingale if (size != 1 && size != 2 && size != 4) 536*bf21cd93STycho Nightingale goto bad; 537*bf21cd93STycho Nightingale 538*bf21cd93STycho Nightingale if (pci_msix_enabled(pi)) 539*bf21cd93STycho Nightingale virtio_config_size = VTCFG_R_CFG1; 540*bf21cd93STycho Nightingale else 541*bf21cd93STycho Nightingale virtio_config_size = VTCFG_R_CFG0; 542*bf21cd93STycho Nightingale 543*bf21cd93STycho Nightingale if (offset >= virtio_config_size) { 544*bf21cd93STycho Nightingale /* 545*bf21cd93STycho Nightingale * Subtract off the standard size (including MSI-X 546*bf21cd93STycho Nightingale * registers if enabled) and dispatch to underlying driver. 547*bf21cd93STycho Nightingale * If that fails, fall into general code. 548*bf21cd93STycho Nightingale */ 549*bf21cd93STycho Nightingale newoff = offset - virtio_config_size; 550*bf21cd93STycho Nightingale max = vc->vc_cfgsize ? vc->vc_cfgsize : 0x100000000; 551*bf21cd93STycho Nightingale if (newoff + size > max) 552*bf21cd93STycho Nightingale goto bad; 553*bf21cd93STycho Nightingale error = (*vc->vc_cfgread)(DEV_SOFTC(vs), newoff, size, &value); 554*bf21cd93STycho Nightingale if (!error) 555*bf21cd93STycho Nightingale goto done; 556*bf21cd93STycho Nightingale } 557*bf21cd93STycho Nightingale 558*bf21cd93STycho Nightingale bad: 559*bf21cd93STycho Nightingale cr = vi_find_cr(offset); 560*bf21cd93STycho Nightingale if (cr == NULL || cr->cr_size != size) { 561*bf21cd93STycho Nightingale if (cr != NULL) { 562*bf21cd93STycho Nightingale /* offset must be OK, so size must be bad */ 563*bf21cd93STycho Nightingale fprintf(stderr, 564*bf21cd93STycho Nightingale "%s: read from %s: bad size %d\r\n", 565*bf21cd93STycho Nightingale name, cr->cr_name, size); 566*bf21cd93STycho Nightingale } else { 567*bf21cd93STycho Nightingale fprintf(stderr, 568*bf21cd93STycho Nightingale "%s: read from bad offset/size %jd/%d\r\n", 569*bf21cd93STycho Nightingale name, (uintmax_t)offset, size); 570*bf21cd93STycho Nightingale } 571*bf21cd93STycho Nightingale goto done; 572*bf21cd93STycho Nightingale } 573*bf21cd93STycho Nightingale 574*bf21cd93STycho Nightingale switch (offset) { 575*bf21cd93STycho Nightingale case VTCFG_R_HOSTCAP: 576*bf21cd93STycho Nightingale value = vc->vc_hv_caps; 577*bf21cd93STycho Nightingale break; 578*bf21cd93STycho Nightingale case VTCFG_R_GUESTCAP: 579*bf21cd93STycho Nightingale value = vs->vs_negotiated_caps; 580*bf21cd93STycho Nightingale break; 581*bf21cd93STycho Nightingale case VTCFG_R_PFN: 582*bf21cd93STycho Nightingale if (vs->vs_curq < vc->vc_nvq) 583*bf21cd93STycho Nightingale value = vs->vs_queues[vs->vs_curq].vq_pfn; 584*bf21cd93STycho Nightingale break; 585*bf21cd93STycho Nightingale case VTCFG_R_QNUM: 586*bf21cd93STycho Nightingale value = vs->vs_curq < vc->vc_nvq ? 587*bf21cd93STycho Nightingale vs->vs_queues[vs->vs_curq].vq_qsize : 0; 588*bf21cd93STycho Nightingale break; 589*bf21cd93STycho Nightingale case VTCFG_R_QSEL: 590*bf21cd93STycho Nightingale value = vs->vs_curq; 591*bf21cd93STycho Nightingale break; 592*bf21cd93STycho Nightingale case VTCFG_R_QNOTIFY: 593*bf21cd93STycho Nightingale value = 0; /* XXX */ 594*bf21cd93STycho Nightingale break; 595*bf21cd93STycho Nightingale case VTCFG_R_STATUS: 596*bf21cd93STycho Nightingale value = vs->vs_status; 597*bf21cd93STycho Nightingale break; 598*bf21cd93STycho Nightingale case VTCFG_R_ISR: 599*bf21cd93STycho Nightingale value = vs->vs_isr; 600*bf21cd93STycho Nightingale vs->vs_isr = 0; /* a read clears this flag */ 601*bf21cd93STycho Nightingale if (value) 602*bf21cd93STycho Nightingale pci_lintr_deassert(pi); 603*bf21cd93STycho Nightingale break; 604*bf21cd93STycho Nightingale case VTCFG_R_CFGVEC: 605*bf21cd93STycho Nightingale value = vs->vs_msix_cfg_idx; 606*bf21cd93STycho Nightingale break; 607*bf21cd93STycho Nightingale case VTCFG_R_QVEC: 608*bf21cd93STycho Nightingale value = vs->vs_curq < vc->vc_nvq ? 609*bf21cd93STycho Nightingale vs->vs_queues[vs->vs_curq].vq_msix_idx : 610*bf21cd93STycho Nightingale VIRTIO_MSI_NO_VECTOR; 611*bf21cd93STycho Nightingale break; 612*bf21cd93STycho Nightingale } 613*bf21cd93STycho Nightingale done: 614*bf21cd93STycho Nightingale if (vs->vs_mtx) 615*bf21cd93STycho Nightingale pthread_mutex_unlock(vs->vs_mtx); 616*bf21cd93STycho Nightingale return (value); 617*bf21cd93STycho Nightingale } 618*bf21cd93STycho Nightingale 619*bf21cd93STycho Nightingale /* 620*bf21cd93STycho Nightingale * Handle pci config space writes. 621*bf21cd93STycho Nightingale * If it's to the MSI-X info, do that. 622*bf21cd93STycho Nightingale * If it's part of the virtio standard stuff, do that. 623*bf21cd93STycho Nightingale * Otherwise dispatch to the actual driver. 624*bf21cd93STycho Nightingale */ 625*bf21cd93STycho Nightingale void 626*bf21cd93STycho Nightingale vi_pci_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 627*bf21cd93STycho Nightingale int baridx, uint64_t offset, int size, uint64_t value) 628*bf21cd93STycho Nightingale { 629*bf21cd93STycho Nightingale struct virtio_softc *vs = pi->pi_arg; 630*bf21cd93STycho Nightingale struct vqueue_info *vq; 631*bf21cd93STycho Nightingale struct virtio_consts *vc; 632*bf21cd93STycho Nightingale struct config_reg *cr; 633*bf21cd93STycho Nightingale uint64_t virtio_config_size, max; 634*bf21cd93STycho Nightingale const char *name; 635*bf21cd93STycho Nightingale uint32_t newoff; 636*bf21cd93STycho Nightingale int error; 637*bf21cd93STycho Nightingale 638*bf21cd93STycho Nightingale if (vs->vs_flags & VIRTIO_USE_MSIX) { 639*bf21cd93STycho Nightingale if (baridx == pci_msix_table_bar(pi) || 640*bf21cd93STycho Nightingale baridx == pci_msix_pba_bar(pi)) { 641*bf21cd93STycho Nightingale pci_emul_msix_twrite(pi, offset, size, value); 642*bf21cd93STycho Nightingale return; 643*bf21cd93STycho Nightingale } 644*bf21cd93STycho Nightingale } 645*bf21cd93STycho Nightingale 646*bf21cd93STycho Nightingale /* XXX probably should do something better than just assert() */ 647*bf21cd93STycho Nightingale assert(baridx == 0); 648*bf21cd93STycho Nightingale 649*bf21cd93STycho Nightingale if (vs->vs_mtx) 650*bf21cd93STycho Nightingale pthread_mutex_lock(vs->vs_mtx); 651*bf21cd93STycho Nightingale 652*bf21cd93STycho Nightingale vc = vs->vs_vc; 653*bf21cd93STycho Nightingale name = vc->vc_name; 654*bf21cd93STycho Nightingale 655*bf21cd93STycho Nightingale if (size != 1 && size != 2 && size != 4) 656*bf21cd93STycho Nightingale goto bad; 657*bf21cd93STycho Nightingale 658*bf21cd93STycho Nightingale if (pci_msix_enabled(pi)) 659*bf21cd93STycho Nightingale virtio_config_size = VTCFG_R_CFG1; 660*bf21cd93STycho Nightingale else 661*bf21cd93STycho Nightingale virtio_config_size = VTCFG_R_CFG0; 662*bf21cd93STycho Nightingale 663*bf21cd93STycho Nightingale if (offset >= virtio_config_size) { 664*bf21cd93STycho Nightingale /* 665*bf21cd93STycho Nightingale * Subtract off the standard size (including MSI-X 666*bf21cd93STycho Nightingale * registers if enabled) and dispatch to underlying driver. 667*bf21cd93STycho Nightingale */ 668*bf21cd93STycho Nightingale newoff = offset - virtio_config_size; 669*bf21cd93STycho Nightingale max = vc->vc_cfgsize ? vc->vc_cfgsize : 0x100000000; 670*bf21cd93STycho Nightingale if (newoff + size > max) 671*bf21cd93STycho Nightingale goto bad; 672*bf21cd93STycho Nightingale error = (*vc->vc_cfgwrite)(DEV_SOFTC(vs), newoff, size, value); 673*bf21cd93STycho Nightingale if (!error) 674*bf21cd93STycho Nightingale goto done; 675*bf21cd93STycho Nightingale } 676*bf21cd93STycho Nightingale 677*bf21cd93STycho Nightingale bad: 678*bf21cd93STycho Nightingale cr = vi_find_cr(offset); 679*bf21cd93STycho Nightingale if (cr == NULL || cr->cr_size != size || cr->cr_ro) { 680*bf21cd93STycho Nightingale if (cr != NULL) { 681*bf21cd93STycho Nightingale /* offset must be OK, wrong size and/or reg is R/O */ 682*bf21cd93STycho Nightingale if (cr->cr_size != size) 683*bf21cd93STycho Nightingale fprintf(stderr, 684*bf21cd93STycho Nightingale "%s: write to %s: bad size %d\r\n", 685*bf21cd93STycho Nightingale name, cr->cr_name, size); 686*bf21cd93STycho Nightingale if (cr->cr_ro) 687*bf21cd93STycho Nightingale fprintf(stderr, 688*bf21cd93STycho Nightingale "%s: write to read-only reg %s\r\n", 689*bf21cd93STycho Nightingale name, cr->cr_name); 690*bf21cd93STycho Nightingale } else { 691*bf21cd93STycho Nightingale fprintf(stderr, 692*bf21cd93STycho Nightingale "%s: write to bad offset/size %jd/%d\r\n", 693*bf21cd93STycho Nightingale name, (uintmax_t)offset, size); 694*bf21cd93STycho Nightingale } 695*bf21cd93STycho Nightingale goto done; 696*bf21cd93STycho Nightingale } 697*bf21cd93STycho Nightingale 698*bf21cd93STycho Nightingale switch (offset) { 699*bf21cd93STycho Nightingale case VTCFG_R_GUESTCAP: 700*bf21cd93STycho Nightingale vs->vs_negotiated_caps = value & vc->vc_hv_caps; 701*bf21cd93STycho Nightingale break; 702*bf21cd93STycho Nightingale case VTCFG_R_PFN: 703*bf21cd93STycho Nightingale if (vs->vs_curq >= vc->vc_nvq) 704*bf21cd93STycho Nightingale goto bad_qindex; 705*bf21cd93STycho Nightingale vi_vq_init(vs, value); 706*bf21cd93STycho Nightingale break; 707*bf21cd93STycho Nightingale case VTCFG_R_QSEL: 708*bf21cd93STycho Nightingale /* 709*bf21cd93STycho Nightingale * Note that the guest is allowed to select an 710*bf21cd93STycho Nightingale * invalid queue; we just need to return a QNUM 711*bf21cd93STycho Nightingale * of 0 while the bad queue is selected. 712*bf21cd93STycho Nightingale */ 713*bf21cd93STycho Nightingale vs->vs_curq = value; 714*bf21cd93STycho Nightingale break; 715*bf21cd93STycho Nightingale case VTCFG_R_QNOTIFY: 716*bf21cd93STycho Nightingale if (value >= vc->vc_nvq) { 717*bf21cd93STycho Nightingale fprintf(stderr, "%s: queue %d notify out of range\r\n", 718*bf21cd93STycho Nightingale name, (int)value); 719*bf21cd93STycho Nightingale goto done; 720*bf21cd93STycho Nightingale } 721*bf21cd93STycho Nightingale vq = &vs->vs_queues[value]; 722*bf21cd93STycho Nightingale if (vq->vq_notify) 723*bf21cd93STycho Nightingale (*vq->vq_notify)(DEV_SOFTC(vs), vq); 724*bf21cd93STycho Nightingale else if (vc->vc_qnotify) 725*bf21cd93STycho Nightingale (*vc->vc_qnotify)(DEV_SOFTC(vs), vq); 726*bf21cd93STycho Nightingale else 727*bf21cd93STycho Nightingale fprintf(stderr, 728*bf21cd93STycho Nightingale "%s: qnotify queue %d: missing vq/vc notify\r\n", 729*bf21cd93STycho Nightingale name, (int)value); 730*bf21cd93STycho Nightingale break; 731*bf21cd93STycho Nightingale case VTCFG_R_STATUS: 732*bf21cd93STycho Nightingale vs->vs_status = value; 733*bf21cd93STycho Nightingale if (value == 0) 734*bf21cd93STycho Nightingale (*vc->vc_reset)(DEV_SOFTC(vs)); 735*bf21cd93STycho Nightingale break; 736*bf21cd93STycho Nightingale case VTCFG_R_CFGVEC: 737*bf21cd93STycho Nightingale vs->vs_msix_cfg_idx = value; 738*bf21cd93STycho Nightingale break; 739*bf21cd93STycho Nightingale case VTCFG_R_QVEC: 740*bf21cd93STycho Nightingale if (vs->vs_curq >= vc->vc_nvq) 741*bf21cd93STycho Nightingale goto bad_qindex; 742*bf21cd93STycho Nightingale vq = &vs->vs_queues[vs->vs_curq]; 743*bf21cd93STycho Nightingale vq->vq_msix_idx = value; 744*bf21cd93STycho Nightingale break; 745*bf21cd93STycho Nightingale } 746*bf21cd93STycho Nightingale goto done; 747*bf21cd93STycho Nightingale 748*bf21cd93STycho Nightingale bad_qindex: 749*bf21cd93STycho Nightingale fprintf(stderr, 750*bf21cd93STycho Nightingale "%s: write config reg %s: curq %d >= max %d\r\n", 751*bf21cd93STycho Nightingale name, cr->cr_name, vs->vs_curq, vc->vc_nvq); 752*bf21cd93STycho Nightingale done: 753*bf21cd93STycho Nightingale if (vs->vs_mtx) 754*bf21cd93STycho Nightingale pthread_mutex_unlock(vs->vs_mtx); 755*bf21cd93STycho Nightingale } 756