Commit 7055e687cd4cea5befefb2d8012e4e2574cfa9b3
Committed by
Anthony Liguori
1 parent
54c96da7
qemu/virtio: virtio support for many interrupt vectors
Extend virtio to support many interrupt vectors, and rearrange code in preparation for multi-vector support (mostly move reset out to bindings, because we will have to reset the vectors in transport-specific code). Actual bindings in pci, and use in net, to follow. Load and save are not connected to bindings yet, so they are left stubbed out for now. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Showing
4 changed files
with
81 additions
and
25 deletions
hw/syborg_virtio.c
| ... | ... | @@ -134,7 +134,10 @@ static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset, |
| 134 | 134 | vdev->features = value; |
| 135 | 135 | break; |
| 136 | 136 | case SYBORG_VIRTIO_QUEUE_BASE: |
| 137 | - virtio_queue_set_addr(vdev, vdev->queue_sel, value); | |
| 137 | + if (value == 0) | |
| 138 | + virtio_reset(vdev); | |
| 139 | + else | |
| 140 | + virtio_queue_set_addr(vdev, vdev->queue_sel, value); | |
| 138 | 141 | break; |
| 139 | 142 | case SYBORG_VIRTIO_QUEUE_SEL: |
| 140 | 143 | if (value < VIRTIO_PCI_QUEUE_MAX) |
| ... | ... | @@ -228,7 +231,7 @@ static CPUWriteMemoryFunc *syborg_virtio_writefn[] = { |
| 228 | 231 | syborg_virtio_writel |
| 229 | 232 | }; |
| 230 | 233 | |
| 231 | -static void syborg_virtio_update_irq(void *opaque) | |
| 234 | +static void syborg_virtio_update_irq(void *opaque, uint16_t vector) | |
| 232 | 235 | { |
| 233 | 236 | SyborgVirtIOProxy *proxy = opaque; |
| 234 | 237 | int level; |
| ... | ... | @@ -239,7 +242,7 @@ static void syborg_virtio_update_irq(void *opaque) |
| 239 | 242 | } |
| 240 | 243 | |
| 241 | 244 | static VirtIOBindings syborg_virtio_bindings = { |
| 242 | - .update_irq = syborg_virtio_update_irq | |
| 245 | + .notify = syborg_virtio_update_irq | |
| 243 | 246 | }; |
| 244 | 247 | |
| 245 | 248 | static void syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev) |
| ... | ... | @@ -248,6 +251,8 @@ static void syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev) |
| 248 | 251 | |
| 249 | 252 | proxy->vdev = vdev; |
| 250 | 253 | |
| 254 | + /* Don't support multiple vectors */ | |
| 255 | + proxy->vdev->nvectors = 0; | |
| 251 | 256 | sysbus_init_irq(&proxy->busdev, &proxy->irq); |
| 252 | 257 | iomemtype = cpu_register_io_memory(syborg_virtio_readfn, |
| 253 | 258 | syborg_virtio_writefn, proxy); |
| ... | ... | @@ -255,6 +260,8 @@ static void syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev) |
| 255 | 260 | |
| 256 | 261 | proxy->id = ((uint32_t)0x1af4 << 16) | vdev->device_id; |
| 257 | 262 | |
| 263 | + qemu_register_reset(virtio_reset, 0, vdev); | |
| 264 | + | |
| 258 | 265 | virtio_bind_device(vdev, &syborg_virtio_bindings, proxy); |
| 259 | 266 | } |
| 260 | 267 | ... | ... |
hw/virtio-pci.c
| ... | ... | @@ -78,13 +78,19 @@ typedef struct { |
| 78 | 78 | |
| 79 | 79 | /* virtio device */ |
| 80 | 80 | |
| 81 | -static void virtio_pci_update_irq(void *opaque) | |
| 81 | +static void virtio_pci_notify(void *opaque, uint16_t vector) | |
| 82 | 82 | { |
| 83 | 83 | VirtIOPCIProxy *proxy = opaque; |
| 84 | 84 | |
| 85 | 85 | qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1); |
| 86 | 86 | } |
| 87 | 87 | |
| 88 | +static void virtio_pci_reset(void *opaque) | |
| 89 | +{ | |
| 90 | + VirtIOPCIProxy *proxy = opaque; | |
| 91 | + virtio_reset(proxy->vdev); | |
| 92 | +} | |
| 93 | + | |
| 88 | 94 | static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 89 | 95 | { |
| 90 | 96 | VirtIOPCIProxy *proxy = opaque; |
| ... | ... | @@ -108,7 +114,10 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 108 | 114 | break; |
| 109 | 115 | case VIRTIO_PCI_QUEUE_PFN: |
| 110 | 116 | pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; |
| 111 | - virtio_queue_set_addr(vdev, vdev->queue_sel, pa); | |
| 117 | + if (pa == 0) | |
| 118 | + virtio_pci_reset(proxy); | |
| 119 | + else | |
| 120 | + virtio_queue_set_addr(vdev, vdev->queue_sel, pa); | |
| 112 | 121 | break; |
| 113 | 122 | case VIRTIO_PCI_QUEUE_SEL: |
| 114 | 123 | if (val < VIRTIO_PCI_QUEUE_MAX) |
| ... | ... | @@ -120,7 +129,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 120 | 129 | case VIRTIO_PCI_STATUS: |
| 121 | 130 | vdev->status = val & 0xFF; |
| 122 | 131 | if (vdev->status == 0) |
| 123 | - virtio_reset(vdev); | |
| 132 | + virtio_pci_reset(proxy); | |
| 124 | 133 | break; |
| 125 | 134 | } |
| 126 | 135 | } |
| ... | ... | @@ -160,7 +169,7 @@ static uint32_t virtio_ioport_read(void *opaque, uint32_t addr) |
| 160 | 169 | /* reading from the ISR also clears it. */ |
| 161 | 170 | ret = vdev->isr; |
| 162 | 171 | vdev->isr = 0; |
| 163 | - virtio_update_irq(vdev); | |
| 172 | + qemu_set_irq(proxy->pci_dev.irq[0], 0); | |
| 164 | 173 | break; |
| 165 | 174 | default: |
| 166 | 175 | break; |
| ... | ... | @@ -245,7 +254,7 @@ static void virtio_map(PCIDevice *pci_dev, int region_num, |
| 245 | 254 | } |
| 246 | 255 | |
| 247 | 256 | static const VirtIOBindings virtio_pci_bindings = { |
| 248 | - .update_irq = virtio_pci_update_irq | |
| 257 | + .notify = virtio_pci_notify | |
| 249 | 258 | }; |
| 250 | 259 | |
| 251 | 260 | static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev, |
| ... | ... | @@ -257,6 +266,9 @@ static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev, |
| 257 | 266 | |
| 258 | 267 | proxy->vdev = vdev; |
| 259 | 268 | |
| 269 | + /* No support for multiple vectors yet. */ | |
| 270 | + proxy->vdev->nvectors = 0; | |
| 271 | + | |
| 260 | 272 | config = proxy->pci_dev.config; |
| 261 | 273 | pci_config_set_vendor_id(config, vendor); |
| 262 | 274 | pci_config_set_device_id(config, device); |
| ... | ... | @@ -281,6 +293,8 @@ static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev, |
| 281 | 293 | pci_register_bar(&proxy->pci_dev, 0, size, PCI_ADDRESS_SPACE_IO, |
| 282 | 294 | virtio_map); |
| 283 | 295 | |
| 296 | + qemu_register_reset(virtio_pci_reset, 0, proxy); | |
| 297 | + | |
| 284 | 298 | virtio_bind_device(vdev, &virtio_pci_bindings, proxy); |
| 285 | 299 | } |
| 286 | 300 | ... | ... |
hw/virtio.c
| ... | ... | @@ -68,6 +68,7 @@ struct VirtQueue |
| 68 | 68 | target_phys_addr_t pa; |
| 69 | 69 | uint16_t last_avail_idx; |
| 70 | 70 | int inuse; |
| 71 | + uint16_t vector; | |
| 71 | 72 | void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq); |
| 72 | 73 | }; |
| 73 | 74 | |
| ... | ... | @@ -421,12 +422,16 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) |
| 421 | 422 | } |
| 422 | 423 | |
| 423 | 424 | /* virtio device */ |
| 425 | +static void virtio_notify_vector(VirtIODevice *vdev, uint16_t vector) | |
| 426 | +{ | |
| 427 | + if (vdev->binding->notify) { | |
| 428 | + vdev->binding->notify(vdev->binding_opaque, vector); | |
| 429 | + } | |
| 430 | +} | |
| 424 | 431 | |
| 425 | 432 | void virtio_update_irq(VirtIODevice *vdev) |
| 426 | 433 | { |
| 427 | - if (vdev->binding->update_irq) { | |
| 428 | - vdev->binding->update_irq(vdev->binding_opaque); | |
| 429 | - } | |
| 434 | + virtio_notify_vector(vdev, VIRTIO_NO_VECTOR); | |
| 430 | 435 | } |
| 431 | 436 | |
| 432 | 437 | void virtio_reset(void *opaque) |
| ... | ... | @@ -441,7 +446,8 @@ void virtio_reset(void *opaque) |
| 441 | 446 | vdev->queue_sel = 0; |
| 442 | 447 | vdev->status = 0; |
| 443 | 448 | vdev->isr = 0; |
| 444 | - virtio_update_irq(vdev); | |
| 449 | + vdev->config_vector = VIRTIO_NO_VECTOR; | |
| 450 | + virtio_notify_vector(vdev, vdev->config_vector); | |
| 445 | 451 | |
| 446 | 452 | for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) { |
| 447 | 453 | vdev->vq[i].vring.desc = 0; |
| ... | ... | @@ -449,6 +455,7 @@ void virtio_reset(void *opaque) |
| 449 | 455 | vdev->vq[i].vring.used = 0; |
| 450 | 456 | vdev->vq[i].last_avail_idx = 0; |
| 451 | 457 | vdev->vq[i].pa = 0; |
| 458 | + vdev->vq[i].vector = VIRTIO_NO_VECTOR; | |
| 452 | 459 | } |
| 453 | 460 | } |
| 454 | 461 | |
| ... | ... | @@ -532,12 +539,8 @@ void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data) |
| 532 | 539 | |
| 533 | 540 | void virtio_queue_set_addr(VirtIODevice *vdev, int n, target_phys_addr_t addr) |
| 534 | 541 | { |
| 535 | - if (addr == 0) { | |
| 536 | - virtio_reset(vdev); | |
| 537 | - } else { | |
| 538 | - vdev->vq[n].pa = addr; | |
| 539 | - virtqueue_init(&vdev->vq[n]); | |
| 540 | - } | |
| 542 | + vdev->vq[n].pa = addr; | |
| 543 | + virtqueue_init(&vdev->vq[n]); | |
| 541 | 544 | } |
| 542 | 545 | |
| 543 | 546 | target_phys_addr_t virtio_queue_get_addr(VirtIODevice *vdev, int n) |
| ... | ... | @@ -557,6 +560,18 @@ void virtio_queue_notify(VirtIODevice *vdev, int n) |
| 557 | 560 | } |
| 558 | 561 | } |
| 559 | 562 | |
| 563 | +uint16_t virtio_queue_vector(VirtIODevice *vdev, int n) | |
| 564 | +{ | |
| 565 | + return n < VIRTIO_PCI_QUEUE_MAX ? vdev->vq[n].vector : | |
| 566 | + VIRTIO_NO_VECTOR; | |
| 567 | +} | |
| 568 | + | |
| 569 | +void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector) | |
| 570 | +{ | |
| 571 | + if (n < VIRTIO_PCI_QUEUE_MAX) | |
| 572 | + vdev->vq[n].vector = vector; | |
| 573 | +} | |
| 574 | + | |
| 560 | 575 | VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, |
| 561 | 576 | void (*handle_output)(VirtIODevice *, VirtQueue *)) |
| 562 | 577 | { |
| ... | ... | @@ -585,7 +600,7 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq) |
| 585 | 600 | return; |
| 586 | 601 | |
| 587 | 602 | vdev->isr |= 0x01; |
| 588 | - virtio_update_irq(vdev); | |
| 603 | + virtio_notify_vector(vdev, vq->vector); | |
| 589 | 604 | } |
| 590 | 605 | |
| 591 | 606 | void virtio_notify_config(VirtIODevice *vdev) |
| ... | ... | @@ -594,7 +609,7 @@ void virtio_notify_config(VirtIODevice *vdev) |
| 594 | 609 | return; |
| 595 | 610 | |
| 596 | 611 | vdev->isr |= 0x03; |
| 597 | - virtio_update_irq(vdev); | |
| 612 | + virtio_notify_vector(vdev, vdev->config_vector); | |
| 598 | 613 | } |
| 599 | 614 | |
| 600 | 615 | void virtio_save(VirtIODevice *vdev, QEMUFile *f) |
| ... | ... | @@ -603,6 +618,7 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) |
| 603 | 618 | |
| 604 | 619 | /* FIXME: load/save binding. */ |
| 605 | 620 | //pci_device_save(&vdev->pci_dev, f); |
| 621 | + //msix_save(&vdev->pci_dev, f); | |
| 606 | 622 | |
| 607 | 623 | qemu_put_8s(f, &vdev->status); |
| 608 | 624 | qemu_put_8s(f, &vdev->isr); |
| ... | ... | @@ -611,6 +627,9 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) |
| 611 | 627 | qemu_put_be32(f, vdev->config_len); |
| 612 | 628 | qemu_put_buffer(f, vdev->config, vdev->config_len); |
| 613 | 629 | |
| 630 | + if (vdev->nvectors) | |
| 631 | + qemu_put_be16s(f, &vdev->config_vector); | |
| 632 | + | |
| 614 | 633 | for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) { |
| 615 | 634 | if (vdev->vq[i].vring.num == 0) |
| 616 | 635 | break; |
| ... | ... | @@ -625,6 +644,8 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) |
| 625 | 644 | qemu_put_be32(f, vdev->vq[i].vring.num); |
| 626 | 645 | qemu_put_be64(f, vdev->vq[i].pa); |
| 627 | 646 | qemu_put_be16s(f, &vdev->vq[i].last_avail_idx); |
| 647 | + if (vdev->nvectors) | |
| 648 | + qemu_put_be16s(f, &vdev->vq[i].vector); | |
| 628 | 649 | } |
| 629 | 650 | } |
| 630 | 651 | |
| ... | ... | @@ -634,6 +655,7 @@ void virtio_load(VirtIODevice *vdev, QEMUFile *f) |
| 634 | 655 | |
| 635 | 656 | /* FIXME: load/save binding. */ |
| 636 | 657 | //pci_device_load(&vdev->pci_dev, f); |
| 658 | + //r = msix_load(&vdev->pci_dev, f); | |
| 637 | 659 | |
| 638 | 660 | qemu_get_8s(f, &vdev->status); |
| 639 | 661 | qemu_get_8s(f, &vdev->isr); |
| ... | ... | @@ -642,6 +664,10 @@ void virtio_load(VirtIODevice *vdev, QEMUFile *f) |
| 642 | 664 | vdev->config_len = qemu_get_be32(f); |
| 643 | 665 | qemu_get_buffer(f, vdev->config, vdev->config_len); |
| 644 | 666 | |
| 667 | + if (vdev->nvectors) { | |
| 668 | + qemu_get_be16s(f, &vdev->config_vector); | |
| 669 | + //msix_vector_use(&vdev->pci_dev, vdev->config_vector); | |
| 670 | + } | |
| 645 | 671 | num = qemu_get_be32(f); |
| 646 | 672 | |
| 647 | 673 | for (i = 0; i < num; i++) { |
| ... | ... | @@ -652,9 +678,13 @@ void virtio_load(VirtIODevice *vdev, QEMUFile *f) |
| 652 | 678 | if (vdev->vq[i].pa) { |
| 653 | 679 | virtqueue_init(&vdev->vq[i]); |
| 654 | 680 | } |
| 681 | + if (vdev->nvectors) { | |
| 682 | + qemu_get_be16s(f, &vdev->vq[i].vector); | |
| 683 | + //msix_vector_use(&vdev->pci_dev, vdev->config_vector); | |
| 684 | + } | |
| 655 | 685 | } |
| 656 | 686 | |
| 657 | - virtio_update_irq(vdev); | |
| 687 | + virtio_notify_vector(vdev, VIRTIO_NO_VECTOR); | |
| 658 | 688 | } |
| 659 | 689 | |
| 660 | 690 | void virtio_cleanup(VirtIODevice *vdev) |
| ... | ... | @@ -675,6 +705,7 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, |
| 675 | 705 | vdev->status = 0; |
| 676 | 706 | vdev->isr = 0; |
| 677 | 707 | vdev->queue_sel = 0; |
| 708 | + vdev->config_vector = VIRTIO_NO_VECTOR; | |
| 678 | 709 | vdev->vq = qemu_mallocz(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX); |
| 679 | 710 | |
| 680 | 711 | vdev->name = name; |
| ... | ... | @@ -684,8 +715,6 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, |
| 684 | 715 | else |
| 685 | 716 | vdev->config = NULL; |
| 686 | 717 | |
| 687 | - qemu_register_reset(virtio_reset, 0, vdev); | |
| 688 | - | |
| 689 | 718 | return vdev; |
| 690 | 719 | } |
| 691 | 720 | ... | ... |
hw/virtio.h
| ... | ... | @@ -75,11 +75,13 @@ typedef struct VirtQueueElement |
| 75 | 75 | } VirtQueueElement; |
| 76 | 76 | |
| 77 | 77 | typedef struct { |
| 78 | - void (*update_irq)(void * opaque); | |
| 78 | + void (*notify)(void * opaque, uint16_t vector); | |
| 79 | 79 | } VirtIOBindings; |
| 80 | 80 | |
| 81 | 81 | #define VIRTIO_PCI_QUEUE_MAX 16 |
| 82 | 82 | |
| 83 | +#define VIRTIO_NO_VECTOR 0xffff | |
| 84 | + | |
| 83 | 85 | struct VirtIODevice |
| 84 | 86 | { |
| 85 | 87 | const char *name; |
| ... | ... | @@ -89,6 +91,8 @@ struct VirtIODevice |
| 89 | 91 | uint32_t features; |
| 90 | 92 | size_t config_len; |
| 91 | 93 | void *config; |
| 94 | + uint16_t config_vector; | |
| 95 | + int nvectors; | |
| 92 | 96 | uint32_t (*get_features)(VirtIODevice *vdev); |
| 93 | 97 | uint32_t (*bad_features)(VirtIODevice *vdev); |
| 94 | 98 | void (*set_features)(VirtIODevice *vdev, uint32_t val); |
| ... | ... | @@ -118,7 +122,7 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq); |
| 118 | 122 | |
| 119 | 123 | void virtio_save(VirtIODevice *vdev, QEMUFile *f); |
| 120 | 124 | |
| 121 | -void virtio_load(VirtIODevice *vdev, QEMUFile *f); | |
| 125 | +int virtio_load(VirtIODevice *vdev, QEMUFile *f); | |
| 122 | 126 | |
| 123 | 127 | void virtio_cleanup(VirtIODevice *vdev); |
| 124 | 128 | |
| ... | ... | @@ -144,6 +148,8 @@ void virtio_queue_set_addr(VirtIODevice *vdev, int n, target_phys_addr_t addr); |
| 144 | 148 | target_phys_addr_t virtio_queue_get_addr(VirtIODevice *vdev, int n); |
| 145 | 149 | int virtio_queue_get_num(VirtIODevice *vdev, int n); |
| 146 | 150 | void virtio_queue_notify(VirtIODevice *vdev, int n); |
| 151 | +uint16_t virtio_queue_vector(VirtIODevice *vdev, int n); | |
| 152 | +void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector); | |
| 147 | 153 | void virtio_reset(void *opaque); |
| 148 | 154 | void virtio_update_irq(VirtIODevice *vdev); |
| 149 | 155 | ... | ... |