virtio_pci.c (234270) | virtio_pci.c (238360) |
---|---|
1/*- 2 * Copyright (c) 2011, Bryan Venteicher <bryanv@daemoninthecloset.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 13 unchanged lines hidden (view full) --- 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27/* Driver for the VirtIO PCI interface. */ 28 29#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2011, Bryan Venteicher <bryanv@daemoninthecloset.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 13 unchanged lines hidden (view full) --- 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27/* Driver for the VirtIO PCI interface. */ 28 29#include <sys/cdefs.h> |
30__FBSDID("$FreeBSD: head/sys/dev/virtio/pci/virtio_pci.c 234270 2012-04-14 05:48:04Z grehan $"); | 30__FBSDID("$FreeBSD: head/sys/dev/virtio/pci/virtio_pci.c 238360 2012-07-11 02:57:19Z grehan $"); |
31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/bus.h> 35#include <sys/kernel.h> 36#include <sys/module.h> 37#include <sys/malloc.h> 38 --- 13 unchanged lines hidden (view full) --- 52#include "virtio_if.h" 53 54struct vtpci_softc { 55 device_t vtpci_dev; 56 struct resource *vtpci_res; 57 struct resource *vtpci_msix_res; 58 uint64_t vtpci_features; 59 uint32_t vtpci_flags; | 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/bus.h> 35#include <sys/kernel.h> 36#include <sys/module.h> 37#include <sys/malloc.h> 38 --- 13 unchanged lines hidden (view full) --- 52#include "virtio_if.h" 53 54struct vtpci_softc { 55 device_t vtpci_dev; 56 struct resource *vtpci_res; 57 struct resource *vtpci_msix_res; 58 uint64_t vtpci_features; 59 uint32_t vtpci_flags; |
60#define VIRTIO_PCI_FLAG_NO_MSI 0x0001 61#define VIRTIO_PCI_FLAG_MSI 0x0002 62#define VIRTIO_PCI_FLAG_NO_MSIX 0x0010 63#define VIRTIO_PCI_FLAG_MSIX 0x0020 64#define VIRTIO_PCI_FLAG_SHARED_MSIX 0x0040 | 60#define VTPCI_FLAG_NO_MSI 0x0001 61#define VTPCI_FLAG_NO_MSIX 0x0002 62#define VTPCI_FLAG_LEGACY 0x1000 63#define VTPCI_FLAG_MSI 0x2000 64#define VTPCI_FLAG_MSIX 0x4000 65#define VTPCI_FLAG_SHARED_MSIX 0x8000 66#define VTPCI_FLAG_ITYPE_MASK 0xF000 |
65 | 67 |
68 /* This "bus" will only ever have one child. */ |
|
66 device_t vtpci_child_dev; 67 struct virtio_feature_desc *vtpci_child_feat_desc; 68 69 /* 70 * Ideally, each virtqueue that the driver provides a callback for 71 * will receive its own MSIX vector. If there are not sufficient 72 * vectors available, we will then attempt to have all the VQs 73 * share one vector. Note that when using MSIX, the configuration 74 * changed notifications must be on their own vector. 75 * 76 * If MSIX is not available, we will attempt to have the whole 77 * device share one MSI vector, and then, finally, one legacy 78 * interrupt. 79 */ 80 int vtpci_nvqs; 81 struct vtpci_virtqueue { 82 struct virtqueue *vq; | 69 device_t vtpci_child_dev; 70 struct virtio_feature_desc *vtpci_child_feat_desc; 71 72 /* 73 * Ideally, each virtqueue that the driver provides a callback for 74 * will receive its own MSIX vector. If there are not sufficient 75 * vectors available, we will then attempt to have all the VQs 76 * share one vector. Note that when using MSIX, the configuration 77 * changed notifications must be on their own vector. 78 * 79 * If MSIX is not available, we will attempt to have the whole 80 * device share one MSI vector, and then, finally, one legacy 81 * interrupt. 82 */ 83 int vtpci_nvqs; 84 struct vtpci_virtqueue { 85 struct virtqueue *vq; |
83 | 86 /* Device did not provide a callback for this virtqueue. */ 87 int no_intr; |
84 /* Index into vtpci_intr_res[] below. Unused, then -1. */ 85 int ires_idx; 86 } vtpci_vqx[VIRTIO_MAX_VIRTQUEUES]; 87 88 /* 89 * When using MSIX interrupts, the first element of vtpci_intr_res[] 90 * is always the configuration changed notifications. The remaining 91 * element(s) are used for the virtqueues. --- 33 unchanged lines hidden (view full) --- 125static void vtpci_set_status(device_t, uint8_t); 126static void vtpci_read_dev_config(device_t, bus_size_t, void *, int); 127static void vtpci_write_dev_config(device_t, bus_size_t, void *, int); 128 129static void vtpci_describe_features(struct vtpci_softc *, const char *, 130 uint64_t); 131static void vtpci_probe_and_attach_child(struct vtpci_softc *); 132 | 88 /* Index into vtpci_intr_res[] below. Unused, then -1. */ 89 int ires_idx; 90 } vtpci_vqx[VIRTIO_MAX_VIRTQUEUES]; 91 92 /* 93 * When using MSIX interrupts, the first element of vtpci_intr_res[] 94 * is always the configuration changed notifications. The remaining 95 * element(s) are used for the virtqueues. --- 33 unchanged lines hidden (view full) --- 129static void vtpci_set_status(device_t, uint8_t); 130static void vtpci_read_dev_config(device_t, bus_size_t, void *, int); 131static void vtpci_write_dev_config(device_t, bus_size_t, void *, int); 132 133static void vtpci_describe_features(struct vtpci_softc *, const char *, 134 uint64_t); 135static void vtpci_probe_and_attach_child(struct vtpci_softc *); 136 |
133static int vtpci_alloc_interrupts(struct vtpci_softc *, int, int, 134 struct vq_alloc_info *); 135static int vtpci_alloc_intr_resources(struct vtpci_softc *, int, 136 struct vq_alloc_info *); 137static int vtpci_alloc_msi(struct vtpci_softc *); 138static int vtpci_alloc_msix(struct vtpci_softc *, int); | 137static int vtpci_alloc_msix(struct vtpci_softc *, int); 138static int vtpci_alloc_msi(struct vtpci_softc *); 139static int vtpci_alloc_intr_msix_pervq(struct vtpci_softc *); 140static int vtpci_alloc_intr_msix_shared(struct vtpci_softc *); 141static int vtpci_alloc_intr_msi(struct vtpci_softc *); 142static int vtpci_alloc_intr_legacy(struct vtpci_softc *); 143static int vtpci_alloc_intr_resources(struct vtpci_softc *); 144 145static int vtpci_setup_legacy_interrupt(struct vtpci_softc *, 146 enum intr_type); 147static int vtpci_setup_msix_interrupts(struct vtpci_softc *, 148 enum intr_type); 149static int vtpci_setup_interrupts(struct vtpci_softc *, enum intr_type); 150 |
139static int vtpci_register_msix_vector(struct vtpci_softc *, int, int); | 151static int vtpci_register_msix_vector(struct vtpci_softc *, int, int); |
152static int vtpci_set_host_msix_vectors(struct vtpci_softc *); 153static int vtpci_reinit_virtqueue(struct vtpci_softc *, int); |
|
140 141static void vtpci_free_interrupts(struct vtpci_softc *); 142static void vtpci_free_virtqueues(struct vtpci_softc *); | 154 155static void vtpci_free_interrupts(struct vtpci_softc *); 156static void vtpci_free_virtqueues(struct vtpci_softc *); |
157static void vtpci_cleanup_setup_intr_attempt(struct vtpci_softc *); |
|
143static void vtpci_release_child_resources(struct vtpci_softc *); 144static void vtpci_reset(struct vtpci_softc *); 145 | 158static void vtpci_release_child_resources(struct vtpci_softc *); 159static void vtpci_reset(struct vtpci_softc *); 160 |
161static void vtpci_select_virtqueue(struct vtpci_softc *, int); 162 |
|
146static int vtpci_legacy_intr(void *); 147static int vtpci_vq_shared_intr(void *); 148static int vtpci_vq_intr(void *); 149static int vtpci_config_intr(void *); 150 | 163static int vtpci_legacy_intr(void *); 164static int vtpci_vq_shared_intr(void *); 165static int vtpci_vq_intr(void *); 166static int vtpci_config_intr(void *); 167 |
168#define vtpci_setup_msi_interrupt vtpci_setup_legacy_interrupt 169 |
|
151/* 152 * I/O port read/write wrappers. 153 */ 154#define vtpci_read_config_1(sc, o) bus_read_1((sc)->vtpci_res, (o)) 155#define vtpci_read_config_2(sc, o) bus_read_2((sc)->vtpci_res, (o)) 156#define vtpci_read_config_4(sc, o) bus_read_4((sc)->vtpci_res, (o)) 157#define vtpci_write_config_1(sc, o, v) bus_write_1((sc)->vtpci_res, (o), (v)) 158#define vtpci_write_config_2(sc, o, v) bus_write_2((sc)->vtpci_res, (o), (v)) --- 88 unchanged lines hidden (view full) --- 247 sc->vtpci_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 248 RF_ACTIVE); 249 if (sc->vtpci_res == NULL) { 250 device_printf(dev, "cannot map I/O space\n"); 251 return (ENXIO); 252 } 253 254 if (pci_find_cap(dev, PCIY_MSI, NULL) != 0) | 170/* 171 * I/O port read/write wrappers. 172 */ 173#define vtpci_read_config_1(sc, o) bus_read_1((sc)->vtpci_res, (o)) 174#define vtpci_read_config_2(sc, o) bus_read_2((sc)->vtpci_res, (o)) 175#define vtpci_read_config_4(sc, o) bus_read_4((sc)->vtpci_res, (o)) 176#define vtpci_write_config_1(sc, o, v) bus_write_1((sc)->vtpci_res, (o), (v)) 177#define vtpci_write_config_2(sc, o, v) bus_write_2((sc)->vtpci_res, (o), (v)) --- 88 unchanged lines hidden (view full) --- 266 sc->vtpci_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 267 RF_ACTIVE); 268 if (sc->vtpci_res == NULL) { 269 device_printf(dev, "cannot map I/O space\n"); 270 return (ENXIO); 271 } 272 273 if (pci_find_cap(dev, PCIY_MSI, NULL) != 0) |
255 sc->vtpci_flags |= VIRTIO_PCI_FLAG_NO_MSI; | 274 sc->vtpci_flags |= VTPCI_FLAG_NO_MSI; |
256 257 if (pci_find_cap(dev, PCIY_MSIX, NULL) == 0) { 258 rid = PCIR_BAR(1); 259 sc->vtpci_msix_res = bus_alloc_resource_any(dev, 260 SYS_RES_MEMORY, &rid, RF_ACTIVE); 261 } 262 263 if (sc->vtpci_msix_res == NULL) | 275 276 if (pci_find_cap(dev, PCIY_MSIX, NULL) == 0) { 277 rid = PCIR_BAR(1); 278 sc->vtpci_msix_res = bus_alloc_resource_any(dev, 279 SYS_RES_MEMORY, &rid, RF_ACTIVE); 280 } 281 282 if (sc->vtpci_msix_res == NULL) |
264 sc->vtpci_flags |= VIRTIO_PCI_FLAG_NO_MSIX; | 283 sc->vtpci_flags |= VTPCI_FLAG_NO_MSIX; |
265 266 vtpci_reset(sc); 267 268 /* Tell the host we've noticed this device. */ 269 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK); 270 271 if ((child = device_add_child(dev, NULL, -1)) == NULL) { 272 device_printf(dev, "cannot create child device\n"); --- 94 unchanged lines hidden (view full) --- 367 368 sc = device_get_softc(dev); 369 370 if (sc->vtpci_child_dev != child) 371 return (ENOENT); 372 373 switch (index) { 374 case VIRTIO_IVAR_DEVTYPE: | 284 285 vtpci_reset(sc); 286 287 /* Tell the host we've noticed this device. */ 288 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK); 289 290 if ((child = device_add_child(dev, NULL, -1)) == NULL) { 291 device_printf(dev, "cannot create child device\n"); --- 94 unchanged lines hidden (view full) --- 386 387 sc = device_get_softc(dev); 388 389 if (sc->vtpci_child_dev != child) 390 return (ENOENT); 391 392 switch (index) { 393 case VIRTIO_IVAR_DEVTYPE: |
394 case VIRTIO_IVAR_SUBDEVICE: |
|
375 *result = pci_get_subdevice(dev); 376 break; | 395 *result = pci_get_subdevice(dev); 396 break; |
397 case VIRTIO_IVAR_VENDOR: 398 *result = pci_get_vendor(dev); 399 break; 400 case VIRTIO_IVAR_DEVICE: 401 *result = pci_get_device(dev); 402 break; 403 case VIRTIO_IVAR_SUBVENDOR: 404 *result = pci_get_subdevice(dev); 405 break; |
|
377 default: 378 return (ENOENT); 379 } 380 381 return (0); 382} 383 384static int --- 52 unchanged lines hidden (view full) --- 437 return ((sc->vtpci_features & feature) != 0); 438} 439 440static int 441vtpci_alloc_virtqueues(device_t dev, int flags, int nvqs, 442 struct vq_alloc_info *vq_info) 443{ 444 struct vtpci_softc *sc; | 406 default: 407 return (ENOENT); 408 } 409 410 return (0); 411} 412 413static int --- 52 unchanged lines hidden (view full) --- 466 return ((sc->vtpci_features & feature) != 0); 467} 468 469static int 470vtpci_alloc_virtqueues(device_t dev, int flags, int nvqs, 471 struct vq_alloc_info *vq_info) 472{ 473 struct vtpci_softc *sc; |
474 struct virtqueue *vq; |
|
445 struct vtpci_virtqueue *vqx; 446 struct vq_alloc_info *info; | 475 struct vtpci_virtqueue *vqx; 476 struct vq_alloc_info *info; |
447 int queue, error; 448 uint16_t vq_size; | 477 int idx, error; 478 uint16_t size; |
449 450 sc = device_get_softc(dev); | 479 480 sc = device_get_softc(dev); |
481 error = 0; |
|
451 | 482 |
452 if (sc->vtpci_nvqs != 0 || nvqs <= 0 || 453 nvqs > VIRTIO_MAX_VIRTQUEUES) | 483 if (sc->vtpci_nvqs != 0) 484 return (EALREADY); 485 if (nvqs <= 0 || nvqs > VIRTIO_MAX_VIRTQUEUES) |
454 return (EINVAL); 455 | 486 return (EINVAL); 487 |
456 error = vtpci_alloc_interrupts(sc, flags, nvqs, vq_info); 457 if (error) { 458 device_printf(dev, "cannot allocate interrupts\n"); 459 return (error); 460 } | 488 if (flags & VIRTIO_ALLOC_VQS_DISABLE_MSIX) 489 sc->vtpci_flags |= VTPCI_FLAG_NO_MSIX; |
461 | 490 |
462 if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) { 463 error = vtpci_register_msix_vector(sc, 464 VIRTIO_MSI_CONFIG_VECTOR, 0); 465 if (error) 466 return (error); 467 } | 491 for (idx = 0; idx < nvqs; idx++) { 492 vqx = &sc->vtpci_vqx[idx]; 493 info = &vq_info[idx]; |
468 | 494 |
469 for (queue = 0; queue < nvqs; queue++) { 470 vqx = &sc->vtpci_vqx[queue]; 471 info = &vq_info[queue]; | 495 vtpci_select_virtqueue(sc, idx); 496 size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM); |
472 | 497 |
473 vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_SEL, queue); 474 475 vq_size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM); 476 error = virtqueue_alloc(dev, queue, vq_size, 477 VIRTIO_PCI_VRING_ALIGN, 0xFFFFFFFFUL, info, &vqx->vq); 478 if (error) 479 return (error); 480 481 if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) { 482 error = vtpci_register_msix_vector(sc, 483 VIRTIO_MSI_QUEUE_VECTOR, vqx->ires_idx); 484 if (error) 485 return (error); | 498 error = virtqueue_alloc(dev, idx, size, VIRTIO_PCI_VRING_ALIGN, 499 0xFFFFFFFFUL, info, &vq); 500 if (error) { 501 device_printf(dev, 502 "cannot allocate virtqueue %d: %d\n", idx, error); 503 break; |
486 } 487 488 vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN, | 504 } 505 506 vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN, |
489 virtqueue_paddr(vqx->vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); | 507 virtqueue_paddr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); |
490 | 508 |
491 *info->vqai_vq = vqx->vq; | 509 vqx->vq = *info->vqai_vq = vq; 510 vqx->no_intr = info->vqai_intr == NULL; 511 |
492 sc->vtpci_nvqs++; 493 } 494 | 512 sc->vtpci_nvqs++; 513 } 514 |
495 return (0); | 515 return (error); |
496} 497 498static int 499vtpci_setup_intr(device_t dev, enum intr_type type) 500{ 501 struct vtpci_softc *sc; | 516} 517 518static int 519vtpci_setup_intr(device_t dev, enum intr_type type) 520{ 521 struct vtpci_softc *sc; |
502 struct vtpci_intr_resource *ires; 503 struct vtpci_virtqueue *vqx; 504 int i, flags, error; | 522 int attempt, error; |
505 506 sc = device_get_softc(dev); | 523 524 sc = device_get_softc(dev); |
507 flags = type | INTR_MPSAFE; 508 ires = &sc->vtpci_intr_res[0]; | |
509 | 525 |
510 if ((sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) == 0) { 511 error = bus_setup_intr(dev, ires->irq, flags, 512 vtpci_legacy_intr, NULL, sc, &ires->intrhand); | 526 for (attempt = 0; attempt < 5; attempt++) { 527 /* 528 * Start with the most desirable interrupt configuration and 529 * fallback towards less desirable ones. 530 */ 531 switch (attempt) { 532 case 0: 533 error = vtpci_alloc_intr_msix_pervq(sc); 534 break; 535 case 1: 536 error = vtpci_alloc_intr_msix_shared(sc); 537 break; 538 case 2: 539 error = vtpci_alloc_intr_msi(sc); 540 break; 541 case 3: 542 error = vtpci_alloc_intr_legacy(sc); 543 break; 544 default: 545 device_printf(dev, 546 "exhausted all interrupt allocation attempts\n"); 547 return (ENXIO); 548 } |
513 | 549 |
514 return (error); 515 } | 550 if (error == 0 && vtpci_setup_interrupts(sc, type) == 0) 551 break; |
516 | 552 |
517 error = bus_setup_intr(dev, ires->irq, flags, vtpci_config_intr, 518 NULL, sc, &ires->intrhand); 519 if (error) 520 return (error); 521 522 if (sc->vtpci_flags & VIRTIO_PCI_FLAG_SHARED_MSIX) { 523 ires = &sc->vtpci_intr_res[1]; 524 error = bus_setup_intr(dev, ires->irq, flags, 525 vtpci_vq_shared_intr, NULL, sc, &ires->intrhand); 526 527 return (error); | 553 vtpci_cleanup_setup_intr_attempt(sc); |
528 } 529 | 554 } 555 |
530 /* Setup an interrupt handler for each virtqueue. */ 531 for (i = 0; i < sc->vtpci_nvqs; i++) { 532 vqx = &sc->vtpci_vqx[i]; 533 if (vqx->ires_idx < 1) 534 continue; 535 536 ires = &sc->vtpci_intr_res[vqx->ires_idx]; 537 error = bus_setup_intr(dev, ires->irq, flags, 538 vtpci_vq_intr, NULL, vqx->vq, &ires->intrhand); 539 if (error) 540 return (error); | 556 if (bootverbose) { 557 if (sc->vtpci_flags & VTPCI_FLAG_LEGACY) 558 device_printf(dev, "using legacy interrupt\n"); 559 else if (sc->vtpci_flags & VTPCI_FLAG_MSI) 560 device_printf(dev, "using MSI interrupt\n"); 561 else if (sc->vtpci_flags & VTPCI_FLAG_SHARED_MSIX) 562 device_printf(dev, "using shared MSIX interrupts\n"); 563 else 564 device_printf(dev, "using per VQ MSIX interrupts\n"); |
541 } 542 543 return (0); 544} 545 546static void 547vtpci_stop(device_t dev) 548{ 549 550 vtpci_reset(device_get_softc(dev)); 551} 552 553static int 554vtpci_reinit(device_t dev, uint64_t features) 555{ 556 struct vtpci_softc *sc; | 565 } 566 567 return (0); 568} 569 570static void 571vtpci_stop(device_t dev) 572{ 573 574 vtpci_reset(device_get_softc(dev)); 575} 576 577static int 578vtpci_reinit(device_t dev, uint64_t features) 579{ 580 struct vtpci_softc *sc; |
557 struct vtpci_virtqueue *vqx; 558 struct virtqueue *vq; 559 int queue, error; 560 uint16_t vq_size; | 581 int idx, error; |
561 562 sc = device_get_softc(dev); 563 564 /* | 582 583 sc = device_get_softc(dev); 584 585 /* |
565 * Redrive the device initialization. This is a bit of an abuse 566 * of the specification, but both VirtualBox and QEMU/KVM seem 567 * to play nice. We do not allow the host device to change from 568 * what was originally negotiated beyond what the guest driver 569 * changed (MSIX state should not change, number of virtqueues 570 * and their size remain the same, etc). | 586 * Redrive the device initialization. This is a bit of an abuse of 587 * the specification, but VirtualBox, QEMU/KVM, and BHyVe seem to 588 * play nice. 589 * 590 * We do not allow the host device to change from what was originally 591 * negotiated beyond what the guest driver changed. MSIX state should 592 * not change, number of virtqueues and their size remain the same, etc. 593 * This will need to be rethought when we want to support migration. |
571 */ 572 573 if (vtpci_get_status(dev) != VIRTIO_CONFIG_STATUS_RESET) 574 vtpci_stop(dev); 575 576 /* 577 * Quickly drive the status through ACK and DRIVER. The device 578 * does not become usable again until vtpci_reinit_complete(). 579 */ 580 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK); 581 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER); 582 583 vtpci_negotiate_features(dev, features); 584 | 594 */ 595 596 if (vtpci_get_status(dev) != VIRTIO_CONFIG_STATUS_RESET) 597 vtpci_stop(dev); 598 599 /* 600 * Quickly drive the status through ACK and DRIVER. The device 601 * does not become usable again until vtpci_reinit_complete(). 602 */ 603 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK); 604 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER); 605 606 vtpci_negotiate_features(dev, features); 607 |
585 if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) { 586 error = vtpci_register_msix_vector(sc, 587 VIRTIO_MSI_CONFIG_VECTOR, 0); | 608 for (idx = 0; idx < sc->vtpci_nvqs; idx++) { 609 error = vtpci_reinit_virtqueue(sc, idx); |
588 if (error) 589 return (error); 590 } 591 | 610 if (error) 611 return (error); 612 } 613 |
592 for (queue = 0; queue < sc->vtpci_nvqs; queue++) { 593 vqx = &sc->vtpci_vqx[queue]; 594 vq = vqx->vq; 595 596 KASSERT(vq != NULL, ("vq %d not allocated", queue)); 597 vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_SEL, queue); 598 599 vq_size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM); 600 error = virtqueue_reinit(vq, vq_size); | 614 if (sc->vtpci_flags & VTPCI_FLAG_MSIX) { 615 error = vtpci_set_host_msix_vectors(sc); |
601 if (error) 602 return (error); | 616 if (error) 617 return (error); |
603 604 if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) { 605 error = vtpci_register_msix_vector(sc, 606 VIRTIO_MSI_QUEUE_VECTOR, vqx->ires_idx); 607 if (error) 608 return (error); 609 } 610 611 vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN, 612 virtqueue_paddr(vqx->vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); | |
613 } 614 615 return (0); 616} 617 618static void 619vtpci_reinit_complete(device_t dev) 620{ --- 118 unchanged lines hidden (view full) --- 739 if (device_probe(child) != 0) 740 return; 741 742 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER); 743 if (device_attach(child) != 0) { 744 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_FAILED); 745 vtpci_reset(sc); 746 vtpci_release_child_resources(sc); | 618 } 619 620 return (0); 621} 622 623static void 624vtpci_reinit_complete(device_t dev) 625{ --- 118 unchanged lines hidden (view full) --- 744 if (device_probe(child) != 0) 745 return; 746 747 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER); 748 if (device_attach(child) != 0) { 749 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_FAILED); 750 vtpci_reset(sc); 751 vtpci_release_child_resources(sc); |
747 | |
748 /* Reset status for future attempt. */ 749 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK); 750 } else 751 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER_OK); 752} 753 754static int | 752 /* Reset status for future attempt. */ 753 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK); 754 } else 755 vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER_OK); 756} 757 758static int |
755vtpci_alloc_interrupts(struct vtpci_softc *sc, int flags, int nvqs, 756 struct vq_alloc_info *vq_info) | 759vtpci_alloc_msix(struct vtpci_softc *sc, int nvectors) |
757{ | 760{ |
761 device_t dev; 762 int nmsix, cnt, required; 763 764 dev = sc->vtpci_dev; 765 766 /* Allocate an additional vector for the config changes. */ 767 required = nvectors + 1; 768 769 nmsix = pci_msix_count(dev); 770 if (nmsix < required) 771 return (1); 772 773 cnt = required; 774 if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) { 775 sc->vtpci_nintr_res = required; 776 return (0); 777 } 778 779 pci_release_msi(dev); 780 781 return (1); 782} 783 784static int 785vtpci_alloc_msi(struct vtpci_softc *sc) 786{ 787 device_t dev; 788 int nmsi, cnt, required; 789 790 dev = sc->vtpci_dev; 791 required = 1; 792 793 nmsi = pci_msi_count(dev); 794 if (nmsi < required) 795 return (1); 796 797 cnt = required; 798 if (pci_alloc_msi(dev, &cnt) == 0 && cnt >= required) { 799 sc->vtpci_nintr_res = required; 800 return (0); 801 } 802 803 pci_release_msi(dev); 804 805 return (1); 806} 807 808static int 809vtpci_alloc_intr_msix_pervq(struct vtpci_softc *sc) 810{ |
|
758 int i, nvectors, error; 759 | 811 int i, nvectors, error; 812 |
760 /* 761 * Only allocate a vector for virtqueues that are actually 762 * expecting an interrupt. 763 */ 764 for (nvectors = 0, i = 0; i < nvqs; i++) 765 if (vq_info[i].vqai_intr != NULL) | 813 if (vtpci_disable_msix != 0 || 814 sc->vtpci_flags & VTPCI_FLAG_NO_MSIX) 815 return (ENOTSUP); 816 817 for (nvectors = 0, i = 0; i < sc->vtpci_nvqs; i++) { 818 if (sc->vtpci_vqx[i].no_intr == 0) |
766 nvectors++; | 819 nvectors++; |
820 } |
|
767 | 821 |
822 error = vtpci_alloc_msix(sc, nvectors); 823 if (error) 824 return (error); 825 826 sc->vtpci_flags |= VTPCI_FLAG_MSIX; 827 828 return (0); 829} 830 831static int 832vtpci_alloc_intr_msix_shared(struct vtpci_softc *sc) 833{ 834 int error; 835 |
|
768 if (vtpci_disable_msix != 0 || | 836 if (vtpci_disable_msix != 0 || |
769 sc->vtpci_flags & VIRTIO_PCI_FLAG_NO_MSIX || 770 flags & VIRTIO_ALLOC_VQS_DISABLE_MSIX || 771 vtpci_alloc_msix(sc, nvectors) != 0) { 772 /* 773 * Use MSI interrupts if available. Otherwise, we fallback 774 * to legacy interrupts. 775 */ 776 if ((sc->vtpci_flags & VIRTIO_PCI_FLAG_NO_MSI) == 0 && 777 vtpci_alloc_msi(sc) == 0) 778 sc->vtpci_flags |= VIRTIO_PCI_FLAG_MSI; | 837 sc->vtpci_flags & VTPCI_FLAG_NO_MSIX) 838 return (ENOTSUP); |
779 | 839 |
780 sc->vtpci_nintr_res = 1; 781 } | 840 error = vtpci_alloc_msix(sc, 1); 841 if (error) 842 return (error); |
782 | 843 |
783 error = vtpci_alloc_intr_resources(sc, nvqs, vq_info); | 844 sc->vtpci_flags |= VTPCI_FLAG_MSIX | VTPCI_FLAG_SHARED_MSIX; |
784 | 845 |
785 return (error); | 846 return (0); |
786} 787 788static int | 847} 848 849static int |
789vtpci_alloc_intr_resources(struct vtpci_softc *sc, int nvqs, 790 struct vq_alloc_info *vq_info) | 850vtpci_alloc_intr_msi(struct vtpci_softc *sc) |
791{ | 851{ |
852 int error; 853 854 /* Only BHyVe supports MSI. */ 855 if (sc->vtpci_flags & VTPCI_FLAG_NO_MSI) 856 return (ENOTSUP); 857 858 error = vtpci_alloc_msi(sc); 859 if (error) 860 return (error); 861 862 sc->vtpci_flags |= VTPCI_FLAG_MSI; 863 864 return (0); 865} 866 867static int 868vtpci_alloc_intr_legacy(struct vtpci_softc *sc) 869{ 870 871 sc->vtpci_flags |= VTPCI_FLAG_LEGACY; 872 sc->vtpci_nintr_res = 1; 873 874 return (0); 875} 876 877static int 878vtpci_alloc_intr_resources(struct vtpci_softc *sc) 879{ |
|
792 device_t dev; 793 struct resource *irq; 794 struct vtpci_virtqueue *vqx; 795 int i, rid, flags, res_idx; 796 797 dev = sc->vtpci_dev; | 880 device_t dev; 881 struct resource *irq; 882 struct vtpci_virtqueue *vqx; 883 int i, rid, flags, res_idx; 884 885 dev = sc->vtpci_dev; |
798 flags = RF_ACTIVE; | |
799 | 886 |
800 if ((sc->vtpci_flags & 801 (VIRTIO_PCI_FLAG_MSI | VIRTIO_PCI_FLAG_MSIX)) == 0) { | 887 if (sc->vtpci_flags & VTPCI_FLAG_LEGACY) { |
802 rid = 0; | 888 rid = 0; |
803 flags |= RF_SHAREABLE; 804 } else | 889 flags = RF_ACTIVE | RF_SHAREABLE; 890 } else { |
805 rid = 1; | 891 rid = 1; |
892 flags = RF_ACTIVE; 893 } |
|
806 807 for (i = 0; i < sc->vtpci_nintr_res; i++) { 808 irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, flags); 809 if (irq == NULL) 810 return (ENXIO); 811 812 sc->vtpci_intr_res[i].irq = irq; 813 sc->vtpci_intr_res[i].rid = rid++; 814 } 815 816 /* | 894 895 for (i = 0; i < sc->vtpci_nintr_res; i++) { 896 irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, flags); 897 if (irq == NULL) 898 return (ENXIO); 899 900 sc->vtpci_intr_res[i].irq = irq; 901 sc->vtpci_intr_res[i].rid = rid++; 902 } 903 904 /* |
817 * Map the virtqueue into the correct index in vq_intr_res[]. Note the 818 * first index is reserved for configuration changes notifications. | 905 * Map the virtqueue into the correct index in vq_intr_res[]. The 906 * first index is reserved for configuration changed notifications. |
819 */ | 907 */ |
820 for (i = 0, res_idx = 1; i < nvqs; i++) { | 908 for (i = 0, res_idx = 1; i < sc->vtpci_nvqs; i++) { |
821 vqx = &sc->vtpci_vqx[i]; 822 | 909 vqx = &sc->vtpci_vqx[i]; 910 |
823 if (sc->vtpci_flags & VIRTIO_PCI_FLAG_MSIX) { 824 if (vq_info[i].vqai_intr == NULL) | 911 if (sc->vtpci_flags & VTPCI_FLAG_MSIX) { 912 if (vqx->no_intr != 0) |
825 vqx->ires_idx = -1; | 913 vqx->ires_idx = -1; |
826 else if (sc->vtpci_flags & VIRTIO_PCI_FLAG_SHARED_MSIX) | 914 else if (sc->vtpci_flags & VTPCI_FLAG_SHARED_MSIX) |
827 vqx->ires_idx = res_idx; 828 else 829 vqx->ires_idx = res_idx++; 830 } else 831 vqx->ires_idx = -1; 832 } 833 834 return (0); 835} 836 837static int | 915 vqx->ires_idx = res_idx; 916 else 917 vqx->ires_idx = res_idx++; 918 } else 919 vqx->ires_idx = -1; 920 } 921 922 return (0); 923} 924 925static int |
838vtpci_alloc_msi(struct vtpci_softc *sc) | 926vtpci_setup_legacy_interrupt(struct vtpci_softc *sc, enum intr_type type) |
839{ 840 device_t dev; | 927{ 928 device_t dev; |
841 int nmsi, cnt; | 929 struct vtpci_intr_resource *ires; 930 int error; |
842 843 dev = sc->vtpci_dev; | 931 932 dev = sc->vtpci_dev; |
844 nmsi = pci_msi_count(dev); | |
845 | 933 |
846 if (nmsi < 1) 847 return (1); | 934 ires = &sc->vtpci_intr_res[0]; 935 error = bus_setup_intr(dev, ires->irq, type, vtpci_legacy_intr, NULL, 936 sc, &ires->intrhand); |
848 | 937 |
849 cnt = 1; 850 if (pci_alloc_msi(dev, &cnt) == 0 && cnt == 1) 851 return (0); 852 853 return (1); | 938 return (error); |
854} 855 856static int | 939} 940 941static int |
857vtpci_alloc_msix(struct vtpci_softc *sc, int nvectors) | 942vtpci_setup_msix_interrupts(struct vtpci_softc *sc, enum intr_type type) |
858{ 859 device_t dev; | 943{ 944 device_t dev; |
860 int nmsix, cnt, required; | 945 struct vtpci_intr_resource *ires; 946 struct vtpci_virtqueue *vqx; 947 int i, error; |
861 862 dev = sc->vtpci_dev; 863 | 948 949 dev = sc->vtpci_dev; 950 |
864 nmsix = pci_msix_count(dev); 865 if (nmsix < 1) 866 return (1); | 951 /* 952 * The first resource is used for configuration changed interrupts. 953 */ 954 ires = &sc->vtpci_intr_res[0]; 955 error = bus_setup_intr(dev, ires->irq, type, vtpci_config_intr, 956 NULL, sc, &ires->intrhand); 957 if (error) 958 return (error); |
867 | 959 |
868 /* An additional vector is needed for the config changes. */ 869 required = nvectors + 1; 870 if (nmsix >= required) { 871 cnt = required; 872 if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) 873 goto out; | 960 if (sc->vtpci_flags & VTPCI_FLAG_SHARED_MSIX) { 961 ires = &sc->vtpci_intr_res[1]; |
874 | 962 |
875 pci_release_msi(dev); 876 } | 963 error = bus_setup_intr(dev, ires->irq, type, 964 vtpci_vq_shared_intr, NULL, sc, &ires->intrhand); 965 if (error) 966 return (error); 967 } else { 968 /* 969 * Each remaining resource is assigned to a specific virtqueue. 970 */ 971 for (i = 0; i < sc->vtpci_nvqs; i++) { 972 vqx = &sc->vtpci_vqx[i]; 973 if (vqx->ires_idx < 1) 974 continue; |
877 | 975 |
878 /* Attempt shared MSIX configuration. */ 879 required = 2; 880 if (nmsix >= required) { 881 cnt = required; 882 if (pci_alloc_msix(dev, &cnt) == 0 && cnt >= required) { 883 sc->vtpci_flags |= VIRTIO_PCI_FLAG_SHARED_MSIX; 884 goto out; | 976 ires = &sc->vtpci_intr_res[vqx->ires_idx]; 977 error = bus_setup_intr(dev, ires->irq, type, 978 vtpci_vq_intr, NULL, vqx->vq, &ires->intrhand); 979 if (error) 980 return (error); |
885 } | 981 } |
886 887 pci_release_msi(dev); | |
888 } 889 | 982 } 983 |
890 return (1); | 984 error = vtpci_set_host_msix_vectors(sc); 985 if (error) 986 return (error); |
891 | 987 |
892out: 893 sc->vtpci_nintr_res = required; 894 sc->vtpci_flags |= VIRTIO_PCI_FLAG_MSIX; | 988 return (0); 989} |
895 | 990 |
896 if (bootverbose) { 897 if (sc->vtpci_flags & VIRTIO_PCI_FLAG_SHARED_MSIX) 898 device_printf(dev, "using shared virtqueue MSIX\n"); 899 else 900 device_printf(dev, "using per virtqueue MSIX\n"); 901 } | 991static int 992vtpci_setup_interrupts(struct vtpci_softc *sc, enum intr_type type) 993{ 994 int error; |
902 | 995 |
903 return (0); | 996 type |= INTR_MPSAFE; 997 KASSERT(sc->vtpci_flags & VTPCI_FLAG_ITYPE_MASK, 998 ("no interrupt type selected: %#x", sc->vtpci_flags)); 999 1000 error = vtpci_alloc_intr_resources(sc); 1001 if (error) 1002 return (error); 1003 1004 if (sc->vtpci_flags & VTPCI_FLAG_LEGACY) 1005 error = vtpci_setup_legacy_interrupt(sc, type); 1006 else if (sc->vtpci_flags & VTPCI_FLAG_MSI) 1007 error = vtpci_setup_msi_interrupt(sc, type); 1008 else 1009 error = vtpci_setup_msix_interrupts(sc, type); 1010 1011 return (error); |
904} 905 906static int 907vtpci_register_msix_vector(struct vtpci_softc *sc, int offset, int res_idx) 908{ 909 device_t dev; | 1012} 1013 1014static int 1015vtpci_register_msix_vector(struct vtpci_softc *sc, int offset, int res_idx) 1016{ 1017 device_t dev; |
910 uint16_t vector; | 1018 uint16_t vector, rdvector; |
911 912 dev = sc->vtpci_dev; 913 | 1019 1020 dev = sc->vtpci_dev; 1021 |
914 if (offset != VIRTIO_MSI_CONFIG_VECTOR && 915 offset != VIRTIO_MSI_QUEUE_VECTOR) 916 return (EINVAL); 917 | |
918 if (res_idx != -1) { | 1022 if (res_idx != -1) { |
919 /* Map from rid to host vector. */ | 1023 /* Map from guest rid to host vector. */ |
920 vector = sc->vtpci_intr_res[res_idx].rid - 1; 921 } else 922 vector = VIRTIO_MSI_NO_VECTOR; 923 | 1024 vector = sc->vtpci_intr_res[res_idx].rid - 1; 1025 } else 1026 vector = VIRTIO_MSI_NO_VECTOR; 1027 |
924 /* The first resource is special; make sure it is used correctly. */ | 1028 /* 1029 * Assert the first resource is always used for the configuration 1030 * changed interrupts. 1031 */ |
925 if (res_idx == 0) { | 1032 if (res_idx == 0) { |
926 KASSERT(vector == 0, ("unexpected config vector")); 927 KASSERT(offset == VIRTIO_MSI_CONFIG_VECTOR, 928 ("unexpected config offset")); 929 } | 1033 KASSERT(vector == 0 && offset == VIRTIO_MSI_CONFIG_VECTOR, 1034 ("bad first res use vector:%d offset:%d", vector, offset)); 1035 } else 1036 KASSERT(offset == VIRTIO_MSI_QUEUE_VECTOR, ("bad offset")); |
930 931 vtpci_write_config_2(sc, offset, vector); 932 | 1037 1038 vtpci_write_config_2(sc, offset, vector); 1039 |
933 if (vtpci_read_config_2(sc, offset) != vector) { 934 device_printf(dev, "insufficient host resources for " 935 "MSIX interrupts\n"); | 1040 /* Read vector to determine if the host had sufficient resources. */ 1041 rdvector = vtpci_read_config_2(sc, offset); 1042 if (rdvector != vector) { 1043 device_printf(dev, 1044 "insufficient host resources for MSIX interrupts\n"); |
936 return (ENODEV); 937 } 938 939 return (0); 940} 941 | 1045 return (ENODEV); 1046 } 1047 1048 return (0); 1049} 1050 |
1051static int 1052vtpci_set_host_msix_vectors(struct vtpci_softc *sc) 1053{ 1054 struct vtpci_virtqueue *vqx; 1055 int idx, error; 1056 1057 error = vtpci_register_msix_vector(sc, VIRTIO_MSI_CONFIG_VECTOR, 0); 1058 if (error) 1059 return (error); 1060 1061 for (idx = 0; idx < sc->vtpci_nvqs; idx++) { 1062 vqx = &sc->vtpci_vqx[idx]; 1063 1064 vtpci_select_virtqueue(sc, idx); 1065 error = vtpci_register_msix_vector(sc, VIRTIO_MSI_QUEUE_VECTOR, 1066 vqx->ires_idx); 1067 if (error) 1068 return (error); 1069 } 1070 1071 return (0); 1072} 1073 1074static int 1075vtpci_reinit_virtqueue(struct vtpci_softc *sc, int idx) 1076{ 1077 struct vtpci_virtqueue *vqx; 1078 struct virtqueue *vq; 1079 int error; 1080 uint16_t size; 1081 1082 vqx = &sc->vtpci_vqx[idx]; 1083 vq = vqx->vq; 1084 1085 KASSERT(vq != NULL, ("vq %d not allocated", idx)); 1086 1087 vtpci_select_virtqueue(sc, idx); 1088 size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM); 1089 1090 error = virtqueue_reinit(vq, size); 1091 if (error) 1092 return (error); 1093 1094 vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN, 1095 virtqueue_paddr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); 1096 1097 return (0); 1098} 1099 |
|
942static void 943vtpci_free_interrupts(struct vtpci_softc *sc) 944{ 945 device_t dev; 946 struct vtpci_intr_resource *ires; 947 int i; 948 949 dev = sc->vtpci_dev; | 1100static void 1101vtpci_free_interrupts(struct vtpci_softc *sc) 1102{ 1103 device_t dev; 1104 struct vtpci_intr_resource *ires; 1105 int i; 1106 1107 dev = sc->vtpci_dev; |
950 sc->vtpci_nintr_res = 0; | |
951 | 1108 |
952 if (sc->vtpci_flags & (VIRTIO_PCI_FLAG_MSI | VIRTIO_PCI_FLAG_MSIX)) { 953 pci_release_msi(dev); 954 sc->vtpci_flags &= ~(VIRTIO_PCI_FLAG_MSI | 955 VIRTIO_PCI_FLAG_MSIX | VIRTIO_PCI_FLAG_SHARED_MSIX); 956 } 957 958 for (i = 0; i < 1 + VIRTIO_MAX_VIRTQUEUES; i++) { | 1109 for (i = 0; i < sc->vtpci_nintr_res; i++) { |
959 ires = &sc->vtpci_intr_res[i]; 960 961 if (ires->intrhand != NULL) { 962 bus_teardown_intr(dev, ires->irq, ires->intrhand); 963 ires->intrhand = NULL; 964 } 965 966 if (ires->irq != NULL) { 967 bus_release_resource(dev, SYS_RES_IRQ, ires->rid, 968 ires->irq); 969 ires->irq = NULL; 970 } 971 972 ires->rid = -1; 973 } | 1110 ires = &sc->vtpci_intr_res[i]; 1111 1112 if (ires->intrhand != NULL) { 1113 bus_teardown_intr(dev, ires->irq, ires->intrhand); 1114 ires->intrhand = NULL; 1115 } 1116 1117 if (ires->irq != NULL) { 1118 bus_release_resource(dev, SYS_RES_IRQ, ires->rid, 1119 ires->irq); 1120 ires->irq = NULL; 1121 } 1122 1123 ires->rid = -1; 1124 } |
1125 1126 if (sc->vtpci_flags & (VTPCI_FLAG_MSI | VTPCI_FLAG_MSIX)) 1127 pci_release_msi(dev); 1128 1129 sc->vtpci_nintr_res = 0; 1130 sc->vtpci_flags &= ~VTPCI_FLAG_ITYPE_MASK; |
|
974} 975 976static void 977vtpci_free_virtqueues(struct vtpci_softc *sc) 978{ 979 struct vtpci_virtqueue *vqx; 980 int i; 981 | 1131} 1132 1133static void 1134vtpci_free_virtqueues(struct vtpci_softc *sc) 1135{ 1136 struct vtpci_virtqueue *vqx; 1137 int i; 1138 |
1139 for (i = 0; i < sc->vtpci_nvqs; i++) { 1140 vqx = &sc->vtpci_vqx[i]; 1141 1142 virtqueue_free(vqx->vq); 1143 vqx->vq = NULL; 1144 } 1145 |
|
982 sc->vtpci_nvqs = 0; | 1146 sc->vtpci_nvqs = 0; |
1147} |
|
983 | 1148 |
984 for (i = 0; i < VIRTIO_MAX_VIRTQUEUES; i++) { 985 vqx = &sc->vtpci_vqx[i]; | 1149static void 1150vtpci_cleanup_setup_intr_attempt(struct vtpci_softc *sc) 1151{ 1152 int idx; |
986 | 1153 |
987 if (vqx->vq != NULL) { 988 virtqueue_free(vqx->vq); 989 vqx->vq = NULL; | 1154 if (sc->vtpci_flags & VTPCI_FLAG_MSIX) { 1155 vtpci_write_config_2(sc, VIRTIO_MSI_CONFIG_VECTOR, 1156 VIRTIO_MSI_NO_VECTOR); 1157 1158 for (idx = 0; idx < sc->vtpci_nvqs; idx++) { 1159 vtpci_select_virtqueue(sc, idx); 1160 vtpci_write_config_2(sc, VIRTIO_MSI_QUEUE_VECTOR, 1161 VIRTIO_MSI_NO_VECTOR); |
990 } 991 } | 1162 } 1163 } |
1164 1165 vtpci_free_interrupts(sc); |
|
992} 993 994static void 995vtpci_release_child_resources(struct vtpci_softc *sc) 996{ 997 998 vtpci_free_interrupts(sc); 999 vtpci_free_virtqueues(sc); --- 5 unchanged lines hidden (view full) --- 1005 1006 /* 1007 * Setting the status to RESET sets the host device to 1008 * the original, uninitialized state. 1009 */ 1010 vtpci_set_status(sc->vtpci_dev, VIRTIO_CONFIG_STATUS_RESET); 1011} 1012 | 1166} 1167 1168static void 1169vtpci_release_child_resources(struct vtpci_softc *sc) 1170{ 1171 1172 vtpci_free_interrupts(sc); 1173 vtpci_free_virtqueues(sc); --- 5 unchanged lines hidden (view full) --- 1179 1180 /* 1181 * Setting the status to RESET sets the host device to 1182 * the original, uninitialized state. 1183 */ 1184 vtpci_set_status(sc->vtpci_dev, VIRTIO_CONFIG_STATUS_RESET); 1185} 1186 |
1187static void 1188vtpci_select_virtqueue(struct vtpci_softc *sc, int idx) 1189{ 1190 1191 vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_SEL, idx); 1192} 1193 |
|
1013static int 1014vtpci_legacy_intr(void *xsc) 1015{ 1016 struct vtpci_softc *sc; 1017 struct vtpci_virtqueue *vqx; 1018 int i; 1019 uint8_t isr; 1020 --- 61 unchanged lines hidden --- | 1194static int 1195vtpci_legacy_intr(void *xsc) 1196{ 1197 struct vtpci_softc *sc; 1198 struct vtpci_virtqueue *vqx; 1199 int i; 1200 uint8_t isr; 1201 --- 61 unchanged lines hidden --- |