virtio.c revision 1.17
1/* $NetBSD: virtio.c,v 1.17 2016/08/14 07:47:15 tron Exp $ */ 2 3/* 4 * Copyright (c) 2010 Minoura Makoto. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__KERNEL_RCSID(0, "$NetBSD: virtio.c,v 1.17 2016/08/14 07:47:15 tron Exp $"); 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/kernel.h> 34#include <sys/atomic.h> 35#include <sys/bus.h> 36#include <sys/device.h> 37#include <sys/kmem.h> 38 39#include <dev/pci/pcidevs.h> 40#include <dev/pci/pcireg.h> 41#include <dev/pci/pcivar.h> 42 43#include <dev/pci/virtioreg.h> 44#include <dev/pci/virtiovar.h> 45 46#define MINSEG_INDIRECT 2 /* use indirect if nsegs >= this value */ 47 48static int virtio_match(device_t, cfdata_t, void *); 49static void virtio_attach(device_t, device_t, void *); 50static int virtio_detach(device_t, int); 51static int virtio_intr(void *arg); 52static int virtio_msix_queue_intr(void *); 53static int virtio_msix_config_intr(void *); 54static int virtio_setup_msix_vectors(struct virtio_softc *); 55static int virtio_setup_msix_interrupts(struct virtio_softc *, 56 struct pci_attach_args *); 57static int virtio_setup_intx_interrupt(struct virtio_softc *, 58 struct pci_attach_args *); 59static int virtio_setup_interrupts(struct virtio_softc *, 60 struct pci_attach_args *); 61static void virtio_soft_intr(void *arg); 62static void virtio_init_vq(struct virtio_softc *, 63 struct virtqueue *, const bool); 64 65CFATTACH_DECL3_NEW(virtio, sizeof(struct virtio_softc), 66 virtio_match, virtio_attach, virtio_detach, NULL, NULL, NULL, 67 DVF_DETACH_SHUTDOWN); 68 69static void 70virtio_set_status(struct virtio_softc *sc, int status) 71{ 72 int old = 0; 73 74 if (status != 0) 75 old = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 76 VIRTIO_CONFIG_DEVICE_STATUS); 77 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIRTIO_CONFIG_DEVICE_STATUS, 78 status|old); 79} 80 81#define virtio_device_reset(sc) virtio_set_status((sc), 0) 82 83static int 84virtio_match(device_t parent, cfdata_t match, void *aux) 85{ 86 struct pci_attach_args *pa; 87 88 pa = (struct pci_attach_args *)aux; 89 switch (PCI_VENDOR(pa->pa_id)) { 90 case PCI_VENDOR_QUMRANET: 91 if ((PCI_PRODUCT_QUMRANET_VIRTIO_1000 <= 92 PCI_PRODUCT(pa->pa_id)) && 93 (PCI_PRODUCT(pa->pa_id) <= 94 PCI_PRODUCT_QUMRANET_VIRTIO_103F)) 95 return 1; 96 break; 97 } 98 99 return 0; 100} 101 102static const char *virtio_device_name[] = { 103 "Unknown (0)", /* 0 */ 104 "Network", /* 1 */ 105 "Block", /* 2 */ 106 "Console", /* 3 */ 107 "Entropy", /* 4 */ 108 "Memory Balloon", /* 5 */ 109 "I/O Memory", /* 6 */ 110 "Remote Processor Messaging", /* 7 */ 111 "SCSI", /* 8 */ 112 "9P Transport", /* 9 */ 113 "mac80211 wlan", /* 10 */ 114}; 115#define NDEVNAMES __arraycount(virtio_device_name) 116 117#define VIRTIO_MSIX_CONFIG_VECTOR_INDEX 0 118#define VIRTIO_MSIX_QUEUE_VECTOR_INDEX 1 119 120static int 121virtio_setup_msix_vectors(struct virtio_softc *sc) 122{ 123 int offset, vector, ret, qid; 124 125 offset = VIRTIO_CONFIG_MSI_CONFIG_VECTOR; 126 vector = VIRTIO_MSIX_CONFIG_VECTOR_INDEX; 127 128 bus_space_write_2(sc->sc_iot, sc->sc_ioh, offset, vector); 129 ret = bus_space_read_2(sc->sc_iot, sc->sc_ioh, offset); 130 aprint_debug_dev(sc->sc_dev, "expected=%d, actual=%d\n", 131 vector, ret); 132 if (ret != vector) 133 return -1; 134 135 for (qid = 0; qid < sc->sc_nvqs; qid++) { 136 offset = VIRTIO_CONFIG_QUEUE_SELECT; 137 bus_space_write_2(sc->sc_iot, sc->sc_ioh, offset, qid); 138 139 offset = VIRTIO_CONFIG_MSI_QUEUE_VECTOR; 140 vector = VIRTIO_MSIX_QUEUE_VECTOR_INDEX; 141 142 bus_space_write_2(sc->sc_iot, sc->sc_ioh, offset, vector); 143 ret = bus_space_read_2(sc->sc_iot, sc->sc_ioh, offset); 144 aprint_debug_dev(sc->sc_dev, "expected=%d, actual=%d\n", 145 vector, ret); 146 if (ret != vector) 147 return -1; 148 } 149 150 return 0; 151} 152 153static int 154virtio_setup_msix_interrupts(struct virtio_softc *sc, 155 struct pci_attach_args *pa) 156{ 157 device_t self = sc->sc_dev; 158 pci_chipset_tag_t pc = pa->pa_pc; 159 char intrbuf[PCI_INTRSTR_LEN]; 160 char const *intrstr; 161 int idx; 162 163 idx = VIRTIO_MSIX_CONFIG_VECTOR_INDEX; 164 if (sc->sc_flags & VIRTIO_F_PCI_INTR_MPSAFE) 165 pci_intr_setattr(pc, &sc->sc_ihp[idx], PCI_INTR_MPSAFE, true); 166 167 sc->sc_ihs[idx] = pci_intr_establish_xname(pc, sc->sc_ihp[idx], IPL_NET, 168 virtio_msix_config_intr, sc, device_xname(sc->sc_dev)); 169 if (sc->sc_ihs[idx] == NULL) { 170 aprint_error_dev(self, "couldn't establish MSI-X for config\n"); 171 goto error; 172 } 173 174 idx = VIRTIO_MSIX_QUEUE_VECTOR_INDEX; 175 if (sc->sc_flags & VIRTIO_F_PCI_INTR_MPSAFE) 176 pci_intr_setattr(pc, &sc->sc_ihp[idx], PCI_INTR_MPSAFE, true); 177 178 sc->sc_ihs[idx] = pci_intr_establish_xname(pc, sc->sc_ihp[idx], IPL_NET, 179 virtio_msix_queue_intr, sc, device_xname(sc->sc_dev)); 180 if (sc->sc_ihs[idx] == NULL) { 181 aprint_error_dev(self, "couldn't establish MSI-X for queues\n"); 182 goto error; 183 } 184 185 if (virtio_setup_msix_vectors(sc) != 0) { 186 aprint_error_dev(self, "couldn't setup MSI-X vectors\n"); 187 goto error; 188 } 189 190 idx = VIRTIO_MSIX_CONFIG_VECTOR_INDEX; 191 intrstr = pci_intr_string(pc, sc->sc_ihp[idx], intrbuf, sizeof(intrbuf)); 192 aprint_normal_dev(self, "config interrupting at %s\n", intrstr); 193 idx = VIRTIO_MSIX_QUEUE_VECTOR_INDEX; 194 intrstr = pci_intr_string(pc, sc->sc_ihp[idx], intrbuf, sizeof(intrbuf)); 195 aprint_normal_dev(self, "queues interrupting at %s\n", intrstr); 196 197 return 0; 198 199error: 200 idx = VIRTIO_MSIX_CONFIG_VECTOR_INDEX; 201 if (sc->sc_ihs[idx] != NULL) 202 pci_intr_disestablish(sc->sc_pc, sc->sc_ihs[idx]); 203 idx = VIRTIO_MSIX_QUEUE_VECTOR_INDEX; 204 if (sc->sc_ihs[idx] != NULL) 205 pci_intr_disestablish(sc->sc_pc, sc->sc_ihs[idx]); 206 207 return -1; 208} 209 210static int 211virtio_setup_intx_interrupt(struct virtio_softc *sc, 212 struct pci_attach_args *pa) 213{ 214 device_t self = sc->sc_dev; 215 pci_chipset_tag_t pc = pa->pa_pc; 216 char intrbuf[PCI_INTRSTR_LEN]; 217 char const *intrstr; 218 219 if (sc->sc_flags & VIRTIO_F_PCI_INTR_MPSAFE) 220 pci_intr_setattr(pc, &sc->sc_ihp[0], PCI_INTR_MPSAFE, true); 221 222 sc->sc_ihs[0] = pci_intr_establish_xname(pc, sc->sc_ihp[0], 223 IPL_NET, virtio_intr, sc, device_xname(sc->sc_dev)); 224 if (sc->sc_ihs[0] == NULL) { 225 aprint_error_dev(self, "couldn't establish INTx\n"); 226 return -1; 227 } 228 229 intrstr = pci_intr_string(pc, sc->sc_ihp[0], intrbuf, sizeof(intrbuf)); 230 aprint_normal_dev(self, "interrupting at %s\n", intrstr); 231 232 return 0; 233} 234 235static int 236virtio_setup_interrupts(struct virtio_softc *sc, struct pci_attach_args *pa) 237{ 238 device_t self = sc->sc_dev; 239 pci_chipset_tag_t pc = pa->pa_pc; 240 int error; 241 int nmsix; 242 int counts[PCI_INTR_TYPE_SIZE]; 243 pci_intr_type_t max_type; 244 245 nmsix = pci_msix_count(pa->pa_pc, pa->pa_tag); 246 aprint_debug_dev(self, "pci_msix_count=%d\n", nmsix); 247 248 /* We need at least two: one for config and the other for queues */ 249 if ((sc->sc_flags & VIRTIO_F_PCI_INTR_MSIX) == 0 || nmsix < 2) { 250 /* Try INTx only */ 251 max_type = PCI_INTR_TYPE_INTX; 252 counts[PCI_INTR_TYPE_INTX] = 1; 253 } else { 254 /* Try MSI-X first and INTx second */ 255 max_type = PCI_INTR_TYPE_MSIX; 256 counts[PCI_INTR_TYPE_MSIX] = 2; 257 counts[PCI_INTR_TYPE_MSI] = 0; 258 counts[PCI_INTR_TYPE_INTX] = 1; 259 } 260 261 retry: 262 error = pci_intr_alloc(pa, &sc->sc_ihp, counts, max_type); 263 if (error != 0) { 264 aprint_error_dev(self, "couldn't map interrupt\n"); 265 return -1; 266 } 267 268 if (pci_intr_type(pc, sc->sc_ihp[0]) == PCI_INTR_TYPE_MSIX) { 269 sc->sc_ihs = kmem_alloc(sizeof(*sc->sc_ihs) * 2, 270 KM_SLEEP); 271 if (sc->sc_ihs == NULL) { 272 pci_intr_release(pc, sc->sc_ihp, 2); 273 274 /* Retry INTx */ 275 max_type = PCI_INTR_TYPE_INTX; 276 counts[PCI_INTR_TYPE_INTX] = 1; 277 goto retry; 278 } 279 280 error = virtio_setup_msix_interrupts(sc, pa); 281 if (error != 0) { 282 kmem_free(sc->sc_ihs, sizeof(*sc->sc_ihs) * 2); 283 pci_intr_release(pc, sc->sc_ihp, 2); 284 285 /* Retry INTx */ 286 max_type = PCI_INTR_TYPE_INTX; 287 counts[PCI_INTR_TYPE_INTX] = 1; 288 goto retry; 289 } 290 291 sc->sc_ihs_num = 2; 292 sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_MSI; 293 } else if (pci_intr_type(pc, sc->sc_ihp[0]) == PCI_INTR_TYPE_INTX) { 294 sc->sc_ihs = kmem_alloc(sizeof(*sc->sc_ihs) * 1, 295 KM_SLEEP); 296 if (sc->sc_ihs == NULL) { 297 pci_intr_release(pc, sc->sc_ihp, 1); 298 return -1; 299 } 300 301 error = virtio_setup_intx_interrupt(sc, pa); 302 if (error != 0) { 303 kmem_free(sc->sc_ihs, sizeof(*sc->sc_ihs) * 1); 304 pci_intr_release(pc, sc->sc_ihp, 1); 305 return -1; 306 } 307 308 sc->sc_ihs_num = 1; 309 sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI; 310 } 311 312 return 0; 313} 314 315static void 316virtio_attach(device_t parent, device_t self, void *aux) 317{ 318 struct virtio_softc *sc = device_private(self); 319 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 320 pci_chipset_tag_t pc = pa->pa_pc; 321 pcitag_t tag = pa->pa_tag; 322 int revision; 323 pcireg_t id; 324 int r; 325 326 revision = PCI_REVISION(pa->pa_class); 327 if (revision != 0) { 328 aprint_normal(": unknown revision 0x%02x; giving up\n", 329 revision); 330 return; 331 } 332 aprint_normal("\n"); 333 aprint_naive("\n"); 334 335 /* subsystem ID shows what I am */ 336 id = pci_conf_read(pc, tag, PCI_SUBSYS_ID_REG); 337 aprint_normal_dev(self, "Virtio %s Device (rev. 0x%02x)\n", 338 (PCI_SUBSYS_ID(id) < NDEVNAMES? 339 virtio_device_name[PCI_SUBSYS_ID(id)] : "Unknown"), 340 revision); 341 342 sc->sc_dev = self; 343 sc->sc_pc = pc; 344 sc->sc_tag = tag; 345 sc->sc_iot = pa->pa_iot; 346 if (pci_dma64_available(pa)) 347 sc->sc_dmat = pa->pa_dmat64; 348 else 349 sc->sc_dmat = pa->pa_dmat; 350 sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI; 351 352 if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0, 353 &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_iosize)) { 354 aprint_error_dev(self, "can't map i/o space\n"); 355 return; 356 } 357 358 virtio_device_reset(sc); 359 virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_ACK); 360 virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER); 361 362 /* XXX: use softc as aux... */ 363 sc->sc_childdevid = PCI_SUBSYS_ID(id); 364 sc->sc_child = NULL; 365 config_found(self, sc, NULL); 366 if (sc->sc_child == NULL) { 367 aprint_error_dev(self, 368 "no matching child driver; not configured\n"); 369 return; 370 } 371 if (sc->sc_child == (void*)1) { /* this shows error */ 372 aprint_error_dev(self, 373 "virtio configuration failed\n"); 374 virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED); 375 return; 376 } 377 378 r = virtio_setup_interrupts(sc, pa); 379 if (r != 0) { 380 aprint_error_dev(self, "failed to setup interrupts\n"); 381 virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED); 382 return; 383 } 384 385 sc->sc_soft_ih = NULL; 386 if (sc->sc_flags & VIRTIO_F_PCI_INTR_SOFTINT) { 387 u_int flags = SOFTINT_NET; 388 if (sc->sc_flags & VIRTIO_F_PCI_INTR_MPSAFE) 389 flags |= SOFTINT_MPSAFE; 390 391 sc->sc_soft_ih = softint_establish(flags, virtio_soft_intr, sc); 392 if (sc->sc_soft_ih == NULL) 393 aprint_error(": failed to establish soft interrupt\n"); 394 } 395 396 virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK); 397 398 return; 399} 400 401static int 402virtio_detach(device_t self, int flags) 403{ 404 struct virtio_softc *sc = device_private(self); 405 int r; 406 int i; 407 408 if (sc->sc_child != 0 && sc->sc_child != (void*)1) { 409 r = config_detach(sc->sc_child, flags); 410 if (r) 411 return r; 412 } 413 KASSERT(sc->sc_child == 0 || sc->sc_child == (void*)1); 414 KASSERT(sc->sc_vqs == 0); 415 for (i = 0; i < sc->sc_ihs_num; i++) { 416 if (sc->sc_ihs[i] == NULL) 417 continue; 418 pci_intr_disestablish(sc->sc_pc, sc->sc_ihs[i]); 419 } 420 pci_intr_release(sc->sc_pc, sc->sc_ihp, sc->sc_ihs_num); 421 if (sc->sc_ihs != NULL) 422 kmem_free(sc->sc_ihs, sizeof(*sc->sc_ihs) * sc->sc_ihs_num); 423 sc->sc_ihs_num = 0; 424 if (sc->sc_iosize) 425 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize); 426 sc->sc_iosize = 0; 427 428 return 0; 429} 430 431/* 432 * Reset the device. 433 */ 434/* 435 * To reset the device to a known state, do following: 436 * virtio_reset(sc); // this will stop the device activity 437 * <dequeue finished requests>; // virtio_dequeue() still can be called 438 * <revoke pending requests in the vqs if any>; 439 * virtio_reinit_begin(sc); // dequeue prohibitted 440 * newfeatures = virtio_negotiate_features(sc, requestedfeatures); 441 * <some other initialization>; 442 * virtio_reinit_end(sc); // device activated; enqueue allowed 443 * Once attached, feature negotiation can only be allowed after virtio_reset. 444 */ 445void 446virtio_reset(struct virtio_softc *sc) 447{ 448 virtio_device_reset(sc); 449} 450 451void 452virtio_reinit_start(struct virtio_softc *sc) 453{ 454 int i; 455 456 virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_ACK); 457 virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER); 458 for (i = 0; i < sc->sc_nvqs; i++) { 459 int n; 460 struct virtqueue *vq = &sc->sc_vqs[i]; 461 bus_space_write_2(sc->sc_iot, sc->sc_ioh, 462 VIRTIO_CONFIG_QUEUE_SELECT, 463 vq->vq_index); 464 n = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 465 VIRTIO_CONFIG_QUEUE_SIZE); 466 if (n == 0) /* vq disappeared */ 467 continue; 468 if (n != vq->vq_num) { 469 panic("%s: virtqueue size changed, vq index %d\n", 470 device_xname(sc->sc_dev), 471 vq->vq_index); 472 } 473 virtio_init_vq(sc, vq, true); 474 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 475 VIRTIO_CONFIG_QUEUE_ADDRESS, 476 (vq->vq_dmamap->dm_segs[0].ds_addr 477 / VIRTIO_PAGE_SIZE)); 478 } 479 480 /* MSI-X should have more than one handles where INTx has just one */ 481 if (sc->sc_ihs_num > 1) { 482 if (virtio_setup_msix_vectors(sc) != 0) { 483 aprint_error_dev(sc->sc_dev, 484 "couldn't setup MSI-X vectors\n"); 485 return; 486 } 487 } 488} 489 490void 491virtio_reinit_end(struct virtio_softc *sc) 492{ 493 virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK); 494} 495 496/* 497 * Feature negotiation. 498 */ 499uint32_t 500virtio_negotiate_features(struct virtio_softc *sc, uint32_t guest_features) 501{ 502 uint32_t r; 503 504 if (!(device_cfdata(sc->sc_dev)->cf_flags & 1) && 505 !(device_cfdata(sc->sc_child)->cf_flags & 1)) /* XXX */ 506 guest_features |= VIRTIO_F_RING_INDIRECT_DESC; 507 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 508 VIRTIO_CONFIG_DEVICE_FEATURES); 509 r &= guest_features; 510 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 511 VIRTIO_CONFIG_GUEST_FEATURES, r); 512 sc->sc_features = r; 513 if (r & VIRTIO_F_RING_INDIRECT_DESC) 514 sc->sc_indirect = true; 515 else 516 sc->sc_indirect = false; 517 518 return r; 519} 520 521/* 522 * Device configuration registers. 523 */ 524uint8_t 525virtio_read_device_config_1(struct virtio_softc *sc, int index) 526{ 527 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, 528 sc->sc_config_offset + index); 529} 530 531uint16_t 532virtio_read_device_config_2(struct virtio_softc *sc, int index) 533{ 534 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, 535 sc->sc_config_offset + index); 536} 537 538uint32_t 539virtio_read_device_config_4(struct virtio_softc *sc, int index) 540{ 541 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, 542 sc->sc_config_offset + index); 543} 544 545uint64_t 546virtio_read_device_config_8(struct virtio_softc *sc, int index) 547{ 548 uint64_t r; 549 550 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 551 sc->sc_config_offset + index + sizeof(uint32_t)); 552 r <<= 32; 553 r += bus_space_read_4(sc->sc_iot, sc->sc_ioh, 554 sc->sc_config_offset + index); 555 return r; 556} 557 558void 559virtio_write_device_config_1(struct virtio_softc *sc, 560 int index, uint8_t value) 561{ 562 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 563 sc->sc_config_offset + index, value); 564} 565 566void 567virtio_write_device_config_2(struct virtio_softc *sc, 568 int index, uint16_t value) 569{ 570 bus_space_write_2(sc->sc_iot, sc->sc_ioh, 571 sc->sc_config_offset + index, value); 572} 573 574void 575virtio_write_device_config_4(struct virtio_softc *sc, 576 int index, uint32_t value) 577{ 578 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 579 sc->sc_config_offset + index, value); 580} 581 582void 583virtio_write_device_config_8(struct virtio_softc *sc, 584 int index, uint64_t value) 585{ 586 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 587 sc->sc_config_offset + index, 588 value & 0xffffffff); 589 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 590 sc->sc_config_offset + index + sizeof(uint32_t), 591 value >> 32); 592} 593 594/* 595 * Interrupt handler. 596 */ 597static int 598virtio_intr(void *arg) 599{ 600 struct virtio_softc *sc = arg; 601 int isr, r = 0; 602 603 /* check and ack the interrupt */ 604 isr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 605 VIRTIO_CONFIG_ISR_STATUS); 606 if (isr == 0) 607 return 0; 608 if ((isr & VIRTIO_CONFIG_ISR_CONFIG_CHANGE) && 609 (sc->sc_config_change != NULL)) 610 r = (sc->sc_config_change)(sc); 611 if (sc->sc_intrhand != NULL) { 612 if (sc->sc_soft_ih != NULL) 613 softint_schedule(sc->sc_soft_ih); 614 else 615 r |= (sc->sc_intrhand)(sc); 616 } 617 618 return r; 619} 620 621static int 622virtio_msix_queue_intr(void *arg) 623{ 624 struct virtio_softc *sc = arg; 625 int r = 0; 626 627 if (sc->sc_intrhand != NULL) { 628 if (sc->sc_soft_ih != NULL) 629 softint_schedule(sc->sc_soft_ih); 630 else 631 r |= (sc->sc_intrhand)(sc); 632 } 633 634 return r; 635} 636 637static int 638virtio_msix_config_intr(void *arg) 639{ 640 struct virtio_softc *sc = arg; 641 642 /* TODO: handle events */ 643 aprint_debug_dev(sc->sc_dev, "%s\n", __func__); 644 return 1; 645} 646 647static void 648virtio_soft_intr(void *arg) 649{ 650 struct virtio_softc *sc = arg; 651 652 KASSERT(sc->sc_intrhand != NULL); 653 654 (sc->sc_intrhand)(sc); 655} 656 657/* 658 * dmamap sync operations for a virtqueue. 659 */ 660static inline void 661vq_sync_descs(struct virtio_softc *sc, struct virtqueue *vq, int ops) 662{ 663 /* availoffset == sizeof(vring_desc)*vq_num */ 664 bus_dmamap_sync(sc->sc_dmat, vq->vq_dmamap, 0, vq->vq_availoffset, 665 ops); 666} 667 668static inline void 669vq_sync_aring(struct virtio_softc *sc, struct virtqueue *vq, int ops) 670{ 671 bus_dmamap_sync(sc->sc_dmat, vq->vq_dmamap, 672 vq->vq_availoffset, 673 offsetof(struct vring_avail, ring) 674 + vq->vq_num * sizeof(uint16_t), 675 ops); 676} 677 678static inline void 679vq_sync_uring(struct virtio_softc *sc, struct virtqueue *vq, int ops) 680{ 681 bus_dmamap_sync(sc->sc_dmat, vq->vq_dmamap, 682 vq->vq_usedoffset, 683 offsetof(struct vring_used, ring) 684 + vq->vq_num * sizeof(struct vring_used_elem), 685 ops); 686} 687 688static inline void 689vq_sync_indirect(struct virtio_softc *sc, struct virtqueue *vq, int slot, 690 int ops) 691{ 692 int offset = vq->vq_indirectoffset 693 + sizeof(struct vring_desc) * vq->vq_maxnsegs * slot; 694 695 bus_dmamap_sync(sc->sc_dmat, vq->vq_dmamap, 696 offset, sizeof(struct vring_desc) * vq->vq_maxnsegs, 697 ops); 698} 699 700/* 701 * Can be used as sc_intrhand. 702 */ 703/* 704 * Scan vq, bus_dmamap_sync for the vqs (not for the payload), 705 * and calls (*vq_done)() if some entries are consumed. 706 */ 707int 708virtio_vq_intr(struct virtio_softc *sc) 709{ 710 struct virtqueue *vq; 711 int i, r = 0; 712 713 for (i = 0; i < sc->sc_nvqs; i++) { 714 vq = &sc->sc_vqs[i]; 715 if (vq->vq_queued) { 716 vq->vq_queued = 0; 717 vq_sync_aring(sc, vq, BUS_DMASYNC_POSTWRITE); 718 } 719 vq_sync_uring(sc, vq, BUS_DMASYNC_POSTREAD); 720 membar_consumer(); 721 if (vq->vq_used_idx != vq->vq_used->idx) { 722 if (vq->vq_done) 723 r |= (vq->vq_done)(vq); 724 } 725 } 726 727 return r; 728} 729 730/* 731 * Start/stop vq interrupt. No guarantee. 732 */ 733void 734virtio_stop_vq_intr(struct virtio_softc *sc, struct virtqueue *vq) 735{ 736 vq->vq_avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; 737 vq_sync_aring(sc, vq, BUS_DMASYNC_PREWRITE); 738 vq->vq_queued++; 739} 740 741void 742virtio_start_vq_intr(struct virtio_softc *sc, struct virtqueue *vq) 743{ 744 vq->vq_avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; 745 vq_sync_aring(sc, vq, BUS_DMASYNC_PREWRITE); 746 vq->vq_queued++; 747} 748 749/* 750 * Initialize vq structure. 751 */ 752static void 753virtio_init_vq(struct virtio_softc *sc, struct virtqueue *vq, 754 const bool reinit) 755{ 756 int i, j; 757 int vq_size = vq->vq_num; 758 759 memset(vq->vq_vaddr, 0, vq->vq_bytesize); 760 761 /* build the indirect descriptor chain */ 762 if (vq->vq_indirect != NULL) { 763 struct vring_desc *vd; 764 765 for (i = 0; i < vq_size; i++) { 766 vd = vq->vq_indirect; 767 vd += vq->vq_maxnsegs * i; 768 for (j = 0; j < vq->vq_maxnsegs-1; j++) 769 vd[j].next = j + 1; 770 } 771 } 772 773 /* free slot management */ 774 SIMPLEQ_INIT(&vq->vq_freelist); 775 for (i = 0; i < vq_size; i++) { 776 SIMPLEQ_INSERT_TAIL(&vq->vq_freelist, 777 &vq->vq_entries[i], qe_list); 778 vq->vq_entries[i].qe_index = i; 779 } 780 if (!reinit) 781 mutex_init(&vq->vq_freelist_lock, MUTEX_SPIN, sc->sc_ipl); 782 783 /* enqueue/dequeue status */ 784 vq->vq_avail_idx = 0; 785 vq->vq_used_idx = 0; 786 vq->vq_queued = 0; 787 if (!reinit) { 788 mutex_init(&vq->vq_aring_lock, MUTEX_SPIN, sc->sc_ipl); 789 mutex_init(&vq->vq_uring_lock, MUTEX_SPIN, sc->sc_ipl); 790 } 791 vq_sync_aring(sc, vq, BUS_DMASYNC_PREWRITE); 792 vq_sync_uring(sc, vq, BUS_DMASYNC_PREREAD); 793 vq->vq_queued++; 794} 795 796/* 797 * Allocate/free a vq. 798 */ 799int 800virtio_alloc_vq(struct virtio_softc *sc, struct virtqueue *vq, int index, 801 int maxsegsize, int maxnsegs, const char *name) 802{ 803 int vq_size, allocsize1, allocsize2, allocsize3, allocsize = 0; 804 int rsegs, r; 805#define VIRTQUEUE_ALIGN(n) (((n)+(VIRTIO_PAGE_SIZE-1))& \ 806 ~(VIRTIO_PAGE_SIZE-1)) 807 808 memset(vq, 0, sizeof(*vq)); 809 810 bus_space_write_2(sc->sc_iot, sc->sc_ioh, 811 VIRTIO_CONFIG_QUEUE_SELECT, index); 812 vq_size = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 813 VIRTIO_CONFIG_QUEUE_SIZE); 814 if (vq_size == 0) { 815 aprint_error_dev(sc->sc_dev, 816 "virtqueue not exist, index %d for %s\n", 817 index, name); 818 goto err; 819 } 820 /* allocsize1: descriptor table + avail ring + pad */ 821 allocsize1 = VIRTQUEUE_ALIGN(sizeof(struct vring_desc)*vq_size 822 + sizeof(uint16_t)*(2+vq_size)); 823 /* allocsize2: used ring + pad */ 824 allocsize2 = VIRTQUEUE_ALIGN(sizeof(uint16_t)*2 825 + sizeof(struct vring_used_elem)*vq_size); 826 /* allocsize3: indirect table */ 827 if (sc->sc_indirect && maxnsegs >= MINSEG_INDIRECT) 828 allocsize3 = sizeof(struct vring_desc) * maxnsegs * vq_size; 829 else 830 allocsize3 = 0; 831 allocsize = allocsize1 + allocsize2 + allocsize3; 832 833 /* alloc and map the memory */ 834 r = bus_dmamem_alloc(sc->sc_dmat, allocsize, VIRTIO_PAGE_SIZE, 0, 835 &vq->vq_segs[0], 1, &rsegs, BUS_DMA_NOWAIT); 836 if (r != 0) { 837 aprint_error_dev(sc->sc_dev, 838 "virtqueue %d for %s allocation failed, " 839 "error code %d\n", index, name, r); 840 goto err; 841 } 842 r = bus_dmamem_map(sc->sc_dmat, &vq->vq_segs[0], 1, allocsize, 843 &vq->vq_vaddr, BUS_DMA_NOWAIT); 844 if (r != 0) { 845 aprint_error_dev(sc->sc_dev, 846 "virtqueue %d for %s map failed, " 847 "error code %d\n", index, name, r); 848 goto err; 849 } 850 r = bus_dmamap_create(sc->sc_dmat, allocsize, 1, allocsize, 0, 851 BUS_DMA_NOWAIT, &vq->vq_dmamap); 852 if (r != 0) { 853 aprint_error_dev(sc->sc_dev, 854 "virtqueue %d for %s dmamap creation failed, " 855 "error code %d\n", index, name, r); 856 goto err; 857 } 858 r = bus_dmamap_load(sc->sc_dmat, vq->vq_dmamap, 859 vq->vq_vaddr, allocsize, NULL, BUS_DMA_NOWAIT); 860 if (r != 0) { 861 aprint_error_dev(sc->sc_dev, 862 "virtqueue %d for %s dmamap load failed, " 863 "error code %d\n", index, name, r); 864 goto err; 865 } 866 867 /* set the vq address */ 868 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 869 VIRTIO_CONFIG_QUEUE_ADDRESS, 870 (vq->vq_dmamap->dm_segs[0].ds_addr 871 / VIRTIO_PAGE_SIZE)); 872 873 /* remember addresses and offsets for later use */ 874 vq->vq_owner = sc; 875 vq->vq_num = vq_size; 876 vq->vq_index = index; 877 vq->vq_desc = vq->vq_vaddr; 878 vq->vq_availoffset = sizeof(struct vring_desc)*vq_size; 879 vq->vq_avail = (void*)(((char*)vq->vq_desc) + vq->vq_availoffset); 880 vq->vq_usedoffset = allocsize1; 881 vq->vq_used = (void*)(((char*)vq->vq_desc) + vq->vq_usedoffset); 882 if (allocsize3 > 0) { 883 vq->vq_indirectoffset = allocsize1 + allocsize2; 884 vq->vq_indirect = (void*)(((char*)vq->vq_desc) 885 + vq->vq_indirectoffset); 886 } 887 vq->vq_bytesize = allocsize; 888 vq->vq_maxsegsize = maxsegsize; 889 vq->vq_maxnsegs = maxnsegs; 890 891 /* free slot management */ 892 vq->vq_entries = kmem_zalloc(sizeof(struct vq_entry)*vq_size, 893 KM_NOSLEEP); 894 if (vq->vq_entries == NULL) { 895 r = ENOMEM; 896 goto err; 897 } 898 899 virtio_init_vq(sc, vq, false); 900 901 aprint_verbose_dev(sc->sc_dev, 902 "allocated %u byte for virtqueue %d for %s, " 903 "size %d\n", allocsize, index, name, vq_size); 904 if (allocsize3 > 0) 905 aprint_verbose_dev(sc->sc_dev, 906 "using %d byte (%d entries) " 907 "indirect descriptors\n", 908 allocsize3, maxnsegs * vq_size); 909 return 0; 910 911err: 912 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 913 VIRTIO_CONFIG_QUEUE_ADDRESS, 0); 914 if (vq->vq_dmamap) 915 bus_dmamap_destroy(sc->sc_dmat, vq->vq_dmamap); 916 if (vq->vq_vaddr) 917 bus_dmamem_unmap(sc->sc_dmat, vq->vq_vaddr, allocsize); 918 if (vq->vq_segs[0].ds_addr) 919 bus_dmamem_free(sc->sc_dmat, &vq->vq_segs[0], 1); 920 memset(vq, 0, sizeof(*vq)); 921 922 return -1; 923} 924 925int 926virtio_free_vq(struct virtio_softc *sc, struct virtqueue *vq) 927{ 928 struct vq_entry *qe; 929 int i = 0; 930 931 /* device must be already deactivated */ 932 /* confirm the vq is empty */ 933 SIMPLEQ_FOREACH(qe, &vq->vq_freelist, qe_list) { 934 i++; 935 } 936 if (i != vq->vq_num) { 937 printf("%s: freeing non-empty vq, index %d\n", 938 device_xname(sc->sc_dev), vq->vq_index); 939 return EBUSY; 940 } 941 942 /* tell device that there's no virtqueue any longer */ 943 bus_space_write_2(sc->sc_iot, sc->sc_ioh, 944 VIRTIO_CONFIG_QUEUE_SELECT, vq->vq_index); 945 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 946 VIRTIO_CONFIG_QUEUE_ADDRESS, 0); 947 948 kmem_free(vq->vq_entries, sizeof(*vq->vq_entries) * vq->vq_num); 949 bus_dmamap_unload(sc->sc_dmat, vq->vq_dmamap); 950 bus_dmamap_destroy(sc->sc_dmat, vq->vq_dmamap); 951 bus_dmamem_unmap(sc->sc_dmat, vq->vq_vaddr, vq->vq_bytesize); 952 bus_dmamem_free(sc->sc_dmat, &vq->vq_segs[0], 1); 953 mutex_destroy(&vq->vq_freelist_lock); 954 mutex_destroy(&vq->vq_uring_lock); 955 mutex_destroy(&vq->vq_aring_lock); 956 memset(vq, 0, sizeof(*vq)); 957 958 return 0; 959} 960 961/* 962 * Free descriptor management. 963 */ 964static struct vq_entry * 965vq_alloc_entry(struct virtqueue *vq) 966{ 967 struct vq_entry *qe; 968 969 mutex_enter(&vq->vq_freelist_lock); 970 if (SIMPLEQ_EMPTY(&vq->vq_freelist)) { 971 mutex_exit(&vq->vq_freelist_lock); 972 return NULL; 973 } 974 qe = SIMPLEQ_FIRST(&vq->vq_freelist); 975 SIMPLEQ_REMOVE_HEAD(&vq->vq_freelist, qe_list); 976 mutex_exit(&vq->vq_freelist_lock); 977 978 return qe; 979} 980 981static void 982vq_free_entry(struct virtqueue *vq, struct vq_entry *qe) 983{ 984 mutex_enter(&vq->vq_freelist_lock); 985 SIMPLEQ_INSERT_TAIL(&vq->vq_freelist, qe, qe_list); 986 mutex_exit(&vq->vq_freelist_lock); 987 988 return; 989} 990 991/* 992 * Enqueue several dmamaps as a single request. 993 */ 994/* 995 * Typical usage: 996 * <queue size> number of followings are stored in arrays 997 * - command blocks (in dmamem) should be pre-allocated and mapped 998 * - dmamaps for command blocks should be pre-allocated and loaded 999 * - dmamaps for payload should be pre-allocated 1000 * r = virtio_enqueue_prep(sc, vq, &slot); // allocate a slot 1001 * if (r) // currently 0 or EAGAIN 1002 * return r; 1003 * r = bus_dmamap_load(dmat, dmamap_payload[slot], data, count, ..); 1004 * if (r) { 1005 * virtio_enqueue_abort(sc, vq, slot); 1006 * bus_dmamap_unload(dmat, dmamap_payload[slot]); 1007 * return r; 1008 * } 1009 * r = virtio_enqueue_reserve(sc, vq, slot, 1010 * dmamap_payload[slot]->dm_nsegs+1); 1011 * // ^ +1 for command 1012 * if (r) { // currently 0 or EAGAIN 1013 * bus_dmamap_unload(dmat, dmamap_payload[slot]); 1014 * return r; // do not call abort() 1015 * } 1016 * <setup and prepare commands> 1017 * bus_dmamap_sync(dmat, dmamap_cmd[slot],... BUS_DMASYNC_PREWRITE); 1018 * bus_dmamap_sync(dmat, dmamap_payload[slot],...); 1019 * virtio_enqueue(sc, vq, slot, dmamap_cmd[slot], false); 1020 * virtio_enqueue(sc, vq, slot, dmamap_payload[slot], iswrite); 1021 * virtio_enqueue_commit(sc, vq, slot, true); 1022 */ 1023 1024/* 1025 * enqueue_prep: allocate a slot number 1026 */ 1027int 1028virtio_enqueue_prep(struct virtio_softc *sc, struct virtqueue *vq, int *slotp) 1029{ 1030 struct vq_entry *qe1; 1031 1032 KASSERT(slotp != NULL); 1033 1034 qe1 = vq_alloc_entry(vq); 1035 if (qe1 == NULL) 1036 return EAGAIN; 1037 /* next slot is not allocated yet */ 1038 qe1->qe_next = -1; 1039 *slotp = qe1->qe_index; 1040 1041 return 0; 1042} 1043 1044/* 1045 * enqueue_reserve: allocate remaining slots and build the descriptor chain. 1046 */ 1047int 1048virtio_enqueue_reserve(struct virtio_softc *sc, struct virtqueue *vq, 1049 int slot, int nsegs) 1050{ 1051 int indirect; 1052 struct vq_entry *qe1 = &vq->vq_entries[slot]; 1053 1054 KASSERT(qe1->qe_next == -1); 1055 KASSERT(1 <= nsegs && nsegs <= vq->vq_num); 1056 1057 if ((vq->vq_indirect != NULL) && 1058 (nsegs >= MINSEG_INDIRECT) && 1059 (nsegs <= vq->vq_maxnsegs)) 1060 indirect = 1; 1061 else 1062 indirect = 0; 1063 qe1->qe_indirect = indirect; 1064 1065 if (indirect) { 1066 struct vring_desc *vd; 1067 int i; 1068 1069 vd = &vq->vq_desc[qe1->qe_index]; 1070 vd->addr = vq->vq_dmamap->dm_segs[0].ds_addr 1071 + vq->vq_indirectoffset; 1072 vd->addr += sizeof(struct vring_desc) 1073 * vq->vq_maxnsegs * qe1->qe_index; 1074 vd->len = sizeof(struct vring_desc) * nsegs; 1075 vd->flags = VRING_DESC_F_INDIRECT; 1076 1077 vd = vq->vq_indirect; 1078 vd += vq->vq_maxnsegs * qe1->qe_index; 1079 qe1->qe_desc_base = vd; 1080 1081 for (i = 0; i < nsegs-1; i++) { 1082 vd[i].flags = VRING_DESC_F_NEXT; 1083 } 1084 vd[i].flags = 0; 1085 qe1->qe_next = 0; 1086 1087 return 0; 1088 } else { 1089 struct vring_desc *vd; 1090 struct vq_entry *qe; 1091 int i, s; 1092 1093 vd = &vq->vq_desc[0]; 1094 qe1->qe_desc_base = vd; 1095 qe1->qe_next = qe1->qe_index; 1096 s = slot; 1097 for (i = 0; i < nsegs - 1; i++) { 1098 qe = vq_alloc_entry(vq); 1099 if (qe == NULL) { 1100 vd[s].flags = 0; 1101 virtio_enqueue_abort(sc, vq, slot); 1102 return EAGAIN; 1103 } 1104 vd[s].flags = VRING_DESC_F_NEXT; 1105 vd[s].next = qe->qe_index; 1106 s = qe->qe_index; 1107 } 1108 vd[s].flags = 0; 1109 1110 return 0; 1111 } 1112} 1113 1114/* 1115 * enqueue: enqueue a single dmamap. 1116 */ 1117int 1118virtio_enqueue(struct virtio_softc *sc, struct virtqueue *vq, int slot, 1119 bus_dmamap_t dmamap, bool write) 1120{ 1121 struct vq_entry *qe1 = &vq->vq_entries[slot]; 1122 struct vring_desc *vd = qe1->qe_desc_base; 1123 int i; 1124 int s = qe1->qe_next; 1125 1126 KASSERT(s >= 0); 1127 KASSERT(dmamap->dm_nsegs > 0); 1128 1129 for (i = 0; i < dmamap->dm_nsegs; i++) { 1130 vd[s].addr = dmamap->dm_segs[i].ds_addr; 1131 vd[s].len = dmamap->dm_segs[i].ds_len; 1132 if (!write) 1133 vd[s].flags |= VRING_DESC_F_WRITE; 1134 s = vd[s].next; 1135 } 1136 qe1->qe_next = s; 1137 1138 return 0; 1139} 1140 1141int 1142virtio_enqueue_p(struct virtio_softc *sc, struct virtqueue *vq, int slot, 1143 bus_dmamap_t dmamap, bus_addr_t start, bus_size_t len, 1144 bool write) 1145{ 1146 struct vq_entry *qe1 = &vq->vq_entries[slot]; 1147 struct vring_desc *vd = qe1->qe_desc_base; 1148 int s = qe1->qe_next; 1149 1150 KASSERT(s >= 0); 1151 KASSERT(dmamap->dm_nsegs == 1); /* XXX */ 1152 KASSERT((dmamap->dm_segs[0].ds_len > start) && 1153 (dmamap->dm_segs[0].ds_len >= start + len)); 1154 1155 vd[s].addr = dmamap->dm_segs[0].ds_addr + start; 1156 vd[s].len = len; 1157 if (!write) 1158 vd[s].flags |= VRING_DESC_F_WRITE; 1159 qe1->qe_next = vd[s].next; 1160 1161 return 0; 1162} 1163 1164/* 1165 * enqueue_commit: add it to the aring. 1166 */ 1167int 1168virtio_enqueue_commit(struct virtio_softc *sc, struct virtqueue *vq, int slot, 1169 bool notifynow) 1170{ 1171 struct vq_entry *qe1; 1172 1173 if (slot < 0) { 1174 mutex_enter(&vq->vq_aring_lock); 1175 goto notify; 1176 } 1177 vq_sync_descs(sc, vq, BUS_DMASYNC_PREWRITE); 1178 qe1 = &vq->vq_entries[slot]; 1179 if (qe1->qe_indirect) 1180 vq_sync_indirect(sc, vq, slot, BUS_DMASYNC_PREWRITE); 1181 mutex_enter(&vq->vq_aring_lock); 1182 vq->vq_avail->ring[(vq->vq_avail_idx++) % vq->vq_num] = slot; 1183 1184notify: 1185 if (notifynow) { 1186 vq_sync_aring(sc, vq, BUS_DMASYNC_PREWRITE); 1187 vq_sync_uring(sc, vq, BUS_DMASYNC_PREREAD); 1188 membar_producer(); 1189 vq->vq_avail->idx = vq->vq_avail_idx; 1190 vq_sync_aring(sc, vq, BUS_DMASYNC_PREWRITE); 1191 membar_producer(); 1192 vq->vq_queued++; 1193 vq_sync_uring(sc, vq, BUS_DMASYNC_POSTREAD); 1194 membar_consumer(); 1195 if (!(vq->vq_used->flags & VRING_USED_F_NO_NOTIFY)) 1196 bus_space_write_2(sc->sc_iot, sc->sc_ioh, 1197 VIRTIO_CONFIG_QUEUE_NOTIFY, 1198 vq->vq_index); 1199 } 1200 mutex_exit(&vq->vq_aring_lock); 1201 1202 return 0; 1203} 1204 1205/* 1206 * enqueue_abort: rollback. 1207 */ 1208int 1209virtio_enqueue_abort(struct virtio_softc *sc, struct virtqueue *vq, int slot) 1210{ 1211 struct vq_entry *qe = &vq->vq_entries[slot]; 1212 struct vring_desc *vd; 1213 int s; 1214 1215 if (qe->qe_next < 0) { 1216 vq_free_entry(vq, qe); 1217 return 0; 1218 } 1219 1220 s = slot; 1221 vd = &vq->vq_desc[0]; 1222 while (vd[s].flags & VRING_DESC_F_NEXT) { 1223 s = vd[s].next; 1224 vq_free_entry(vq, qe); 1225 qe = &vq->vq_entries[s]; 1226 } 1227 vq_free_entry(vq, qe); 1228 return 0; 1229} 1230 1231/* 1232 * Dequeue a request. 1233 */ 1234/* 1235 * dequeue: dequeue a request from uring; dmamap_sync for uring is 1236 * already done in the interrupt handler. 1237 */ 1238int 1239virtio_dequeue(struct virtio_softc *sc, struct virtqueue *vq, 1240 int *slotp, int *lenp) 1241{ 1242 uint16_t slot, usedidx; 1243 struct vq_entry *qe; 1244 1245 if (vq->vq_used_idx == vq->vq_used->idx) 1246 return ENOENT; 1247 mutex_enter(&vq->vq_uring_lock); 1248 usedidx = vq->vq_used_idx++; 1249 mutex_exit(&vq->vq_uring_lock); 1250 usedidx %= vq->vq_num; 1251 slot = vq->vq_used->ring[usedidx].id; 1252 qe = &vq->vq_entries[slot]; 1253 1254 if (qe->qe_indirect) 1255 vq_sync_indirect(sc, vq, slot, BUS_DMASYNC_POSTWRITE); 1256 1257 if (slotp) 1258 *slotp = slot; 1259 if (lenp) 1260 *lenp = vq->vq_used->ring[usedidx].len; 1261 1262 return 0; 1263} 1264 1265/* 1266 * dequeue_commit: complete dequeue; the slot is recycled for future use. 1267 * if you forget to call this the slot will be leaked. 1268 */ 1269int 1270virtio_dequeue_commit(struct virtio_softc *sc, struct virtqueue *vq, int slot) 1271{ 1272 struct vq_entry *qe = &vq->vq_entries[slot]; 1273 struct vring_desc *vd = &vq->vq_desc[0]; 1274 int s = slot; 1275 1276 while (vd[s].flags & VRING_DESC_F_NEXT) { 1277 s = vd[s].next; 1278 vq_free_entry(vq, qe); 1279 qe = &vq->vq_entries[s]; 1280 } 1281 vq_free_entry(vq, qe); 1282 1283 return 0; 1284} 1285