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 | ... | ... |