Commit 7055e687cd4cea5befefb2d8012e4e2574cfa9b3

Authored by Michael S. Tsirkin
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>
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  
... ...