]> Git Repo - qemu.git/commitdiff
Merge remote-tracking branch 'mst/tags/for_anthony' into staging
authorAnthony Liguori <[email protected]>
Mon, 14 Jan 2013 16:23:50 +0000 (10:23 -0600)
committerAnthony Liguori <[email protected]>
Mon, 14 Jan 2013 16:23:50 +0000 (10:23 -0600)
pci,virtio

This further optimizes MSIX handling in virtio-pci.
Also included is pci cleanup by Paolo, and pci device
assignment fix by Alex.

Signed-off-by: Michael S. Tsirkin <[email protected]>
Signed-off-by: Anthony Liguori <[email protected]>
* mst/tags/for_anthony:
  pci-assign: Enable MSIX on device to match guest
  pci: use constants for devices under the 1B36 device ID, document them
  ivshmem: use symbolic constant for PCI ID, add to pci-ids.txt
  virtio-9p: use symbolic constant, add to pci-ids.txt
  reorganize pci-ids.txt
  docs: move pci-ids.txt to docs/specs/
  vhost: backend masking support
  vhost: set started flag while start is in progress
  virtio-net: set/clear vhost_started in reverse order
  virtio: backend virtqueue notifier masking
  virtio-pci: cache msix messages
  kvm: add stub for update msi route
  msix: add api to access msix message
  virtio: don't waste irqfds on control vqs

1  2 
hw/9pfs/virtio-9p-device.c
hw/ivshmem.c
hw/pci_bridge_dev.c
hw/serial-pci.c
hw/virtio-pci.c

index 2a7c2a3d621315726d8ce61ec27dc082a89f0f06,f16ccfbed148a1b87cadb36f7b4e3e3c21f871fb..6f427dfc5d6c0c54d73708fdeb1cd07abf777e3f
@@@ -170,14 -170,14 +170,14 @@@ static void virtio_9p_class_init(Object
  
      k->init = virtio_9p_init_pci;
      k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
-     k->device_id = 0x1009;
+     k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
      k->revision = VIRTIO_PCI_ABI_VERSION;
      k->class_id = 0x2;
      dc->props = virtio_9p_properties;
      dc->reset = virtio_pci_reset;
  }
  
 -static TypeInfo virtio_9p_info = {
 +static const TypeInfo virtio_9p_info = {
      .name          = "virtio-9p-pci",
      .parent        = TYPE_PCI_DEVICE,
      .instance_size = sizeof(VirtIOPCIProxy),
diff --combined hw/ivshmem.c
index 3adcc98a34c685c0bc9365f8a4addefd90cce454,c86fddd0b39e70ac070e434a176d69d9c300e5e3..afaf9b3bbfcb258d9e861253b37596c611d7f457
@@@ -29,6 -29,9 +29,9 @@@
  #include <sys/mman.h>
  #include <sys/types.h>
  
+ #define PCI_VENDOR_ID_IVSHMEM   PCI_VENDOR_ID_REDHAT_QUMRANET
+ #define PCI_DEVICE_ID_IVSHMEM   0x1110
  #define IVSHMEM_IOEVENTFD   0
  #define IVSHMEM_MSI     1
  
@@@ -800,14 -803,14 +803,14 @@@ static void ivshmem_class_init(ObjectCl
  
      k->init = pci_ivshmem_init;
      k->exit = pci_ivshmem_uninit;
-     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
-     k->device_id = 0x1110;
+     k->vendor_id = PCI_VENDOR_ID_IVSHMEM;
+     k->device_id = PCI_DEVICE_ID_IVSHMEM;
      k->class_id = PCI_CLASS_MEMORY_RAM;
      dc->reset = ivshmem_reset;
      dc->props = ivshmem_properties;
  }
  
 -static TypeInfo ivshmem_info = {
 +static const TypeInfo ivshmem_info = {
      .name          = "ivshmem",
      .parent        = TYPE_PCI_DEVICE,
      .instance_size = sizeof(IVShmemState),
diff --combined hw/pci_bridge_dev.c
index 1a7b2cd89797b1eeea04ecb975a779caf213a0d8,2dd312db351e1878acecba0554404855af42897f..1124c53b8c0dc716fb45feffc1ad36d306540486
  #include "exec/memory.h"
  #include "pci/pci_bus.h"
  
- #define REDHAT_PCI_VENDOR_ID 0x1b36
- #define PCI_BRIDGE_DEV_VENDOR_ID REDHAT_PCI_VENDOR_ID
- #define PCI_BRIDGE_DEV_DEVICE_ID 0x1
  struct PCIBridgeDev {
      PCIBridge bridge;
      MemoryRegion bar;
@@@ -146,8 -142,8 +142,8 @@@ static void pci_bridge_dev_class_init(O
      k->init = pci_bridge_dev_initfn;
      k->exit = pci_bridge_dev_exitfn;
      k->config_write = pci_bridge_dev_write_config;
-     k->vendor_id = PCI_BRIDGE_DEV_VENDOR_ID;
-     k->device_id = PCI_BRIDGE_DEV_DEVICE_ID;
+     k->vendor_id = PCI_VENDOR_ID_REDHAT;
+     k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE;
      k->class_id = PCI_CLASS_BRIDGE_PCI;
      k->is_bridge = 1,
      dc->desc = "Standard PCI Bridge";
      dc->vmsd = &pci_bridge_dev_vmstate;
  }
  
 -static TypeInfo pci_bridge_dev_info = {
 +static const TypeInfo pci_bridge_dev_info = {
      .name = "pci-bridge",
      .parent        = TYPE_PCI_DEVICE,
      .instance_size = sizeof(PCIBridgeDev),
diff --combined hw/serial-pci.c
index c62cc9e3752636749f6ee677fa4f691b093c6242,50e8ab7faff2c47c1f230f0455841b554eff78fb..1c31353f6df5e8d1bf730bed86322590dcc30457
@@@ -185,8 -185,8 +185,8 @@@ static void serial_pci_class_initfn(Obj
      PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
      pc->init = serial_pci_init;
      pc->exit = serial_pci_exit;
-     pc->vendor_id = 0x1b36; /* Red Hat */
-     pc->device_id = 0x0002;
+     pc->vendor_id = PCI_VENDOR_ID_REDHAT;
+     pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL;
      pc->revision = 1;
      pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
      dc->vmsd = &vmstate_pci_serial;
@@@ -199,8 -199,8 +199,8 @@@ static void multi_2x_serial_pci_class_i
      PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
      pc->init = multi_serial_pci_init;
      pc->exit = multi_serial_pci_exit;
-     pc->vendor_id = 0x1b36; /* Red Hat */
-     pc->device_id = 0x0003;
+     pc->vendor_id = PCI_VENDOR_ID_REDHAT;
+     pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL2;
      pc->revision = 1;
      pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
      dc->vmsd = &vmstate_pci_multi_serial;
@@@ -213,29 -213,29 +213,29 @@@ static void multi_4x_serial_pci_class_i
      PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
      pc->init = multi_serial_pci_init;
      pc->exit = multi_serial_pci_exit;
-     pc->vendor_id = 0x1b36; /* Red Hat */
-     pc->device_id = 0x0004;
+     pc->vendor_id = PCI_VENDOR_ID_REDHAT;
+     pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL4;
      pc->revision = 1;
      pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
      dc->vmsd = &vmstate_pci_multi_serial;
      dc->props = multi_4x_serial_pci_properties;
  }
  
 -static TypeInfo serial_pci_info = {
 +static const TypeInfo serial_pci_info = {
      .name          = "pci-serial",
      .parent        = TYPE_PCI_DEVICE,
      .instance_size = sizeof(PCISerialState),
      .class_init    = serial_pci_class_initfn,
  };
  
 -static TypeInfo multi_2x_serial_pci_info = {
 +static const TypeInfo multi_2x_serial_pci_info = {
      .name          = "pci-serial-2x",
      .parent        = TYPE_PCI_DEVICE,
      .instance_size = sizeof(PCIMultiSerialState),
      .class_init    = multi_2x_serial_pci_class_initfn,
  };
  
 -static TypeInfo multi_4x_serial_pci_info = {
 +static const TypeInfo multi_4x_serial_pci_info = {
      .name          = "pci-serial-4x",
      .parent        = TYPE_PCI_DEVICE,
      .instance_size = sizeof(PCIMultiSerialState),
diff --combined hw/virtio-pci.c
index 08d2d1ba8237f431163173a4ab9d202176a34e1a,1f35922f65fc375bbed96a3e6c10aaf1c894df18..0b497399466aae652115a6e5fe228ad6eb38e7b1
@@@ -487,8 -487,6 +487,6 @@@ static int kvm_virtio_pci_vq_vector_use
                                          unsigned int vector,
                                          MSIMessage msg)
  {
-     VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
-     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
      VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
      int ret;
  
          irqfd->virq = ret;
      }
      irqfd->users++;
-     ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq);
-     if (ret < 0) {
-         if (--irqfd->users == 0) {
-             kvm_irqchip_release_virq(kvm_state, irqfd->virq);
-         }
-         return ret;
-     }
      return 0;
  }
  
  static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
-                                              unsigned int queue_no,
                                               unsigned int vector)
+ {
+     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
+     if (--irqfd->users == 0) {
+         kvm_irqchip_release_virq(kvm_state, irqfd->virq);
+     }
+ }
+ static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
+                                  unsigned int queue_no,
+                                  unsigned int vector)
+ {
+     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
+     VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
+     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
+     int ret;
+     ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq);
+     return ret;
+ }
+ static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
+                                       unsigned int queue_no,
+                                       unsigned int vector)
  {
      VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
      EventNotifier *n = virtio_queue_get_guest_notifier(vq);
  
      ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq);
      assert(ret == 0);
+ }
  
-     if (--irqfd->users == 0) {
-         kvm_irqchip_release_virq(kvm_state, irqfd->virq);
+ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
+ {
+     PCIDevice *dev = &proxy->pci_dev;
+     VirtIODevice *vdev = proxy->vdev;
+     unsigned int vector;
+     int ret, queue_no;
+     MSIMessage msg;
+     for (queue_no = 0; queue_no < nvqs; queue_no++) {
+         if (!virtio_queue_get_num(vdev, queue_no)) {
+             break;
+         }
+         vector = virtio_queue_vector(vdev, queue_no);
+         if (vector >= msix_nr_vectors_allocated(dev)) {
+             continue;
+         }
+         msg = msix_get_message(dev, vector);
+         ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg);
+         if (ret < 0) {
+             goto undo;
+         }
+         /* If guest supports masking, set up irqfd now.
+          * Otherwise, delay until unmasked in the frontend.
+          */
+         if (proxy->vdev->guest_notifier_mask) {
+             ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
+             if (ret < 0) {
+                 kvm_virtio_pci_vq_vector_release(proxy, vector);
+                 goto undo;
+             }
+         }
+     }
+     return 0;
+ undo:
+     while (--queue_no >= 0) {
+         vector = virtio_queue_vector(vdev, queue_no);
+         if (vector >= msix_nr_vectors_allocated(dev)) {
+             continue;
+         }
+         if (proxy->vdev->guest_notifier_mask) {
+             kvm_virtio_pci_irqfd_release(proxy, vector, queue_no);
+         }
+         kvm_virtio_pci_vq_vector_release(proxy, vector);
+     }
+     return ret;
+ }
+ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
+ {
+     PCIDevice *dev = &proxy->pci_dev;
+     VirtIODevice *vdev = proxy->vdev;
+     unsigned int vector;
+     int queue_no;
+     for (queue_no = 0; queue_no < nvqs; queue_no++) {
+         if (!virtio_queue_get_num(vdev, queue_no)) {
+             break;
+         }
+         vector = virtio_queue_vector(vdev, queue_no);
+         if (vector >= msix_nr_vectors_allocated(dev)) {
+             continue;
+         }
+         /* If guest supports masking, clean up irqfd now.
+          * Otherwise, it was cleaned when masked in the frontend.
+          */
+         if (proxy->vdev->guest_notifier_mask) {
+             kvm_virtio_pci_irqfd_release(proxy, vector, queue_no);
+         }
+         kvm_virtio_pci_vq_vector_release(proxy, vector);
+     }
+ }
+ static int kvm_virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
+                                         unsigned int queue_no,
+                                         unsigned int vector,
+                                         MSIMessage msg)
+ {
+     VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
+     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
+     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
+     int ret;
+     if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
+         ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg);
+         if (ret < 0) {
+             return ret;
+         }
+     }
+     /* If guest supports masking, irqfd is already setup, unmask it.
+      * Otherwise, set it up now.
+      */
+     if (proxy->vdev->guest_notifier_mask) {
+         proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, false);
+         /* Test after unmasking to avoid losing events. */
+         if (proxy->vdev->guest_notifier_pending &&
+             proxy->vdev->guest_notifier_pending(proxy->vdev, queue_no)) {
+             event_notifier_set(n);
+         }
+     } else {
+         ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
      }
+     return ret;
  }
  
- static int kvm_virtio_pci_vector_use(PCIDevice *dev, unsigned vector,
+ static void kvm_virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
+                                              unsigned int queue_no,
+                                              unsigned int vector)
+ {
+     /* If guest supports masking, keep irqfd but mask it.
+      * Otherwise, clean it up now.
+      */ 
+     if (proxy->vdev->guest_notifier_mask) {
+         proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, true);
+     } else {
+         kvm_virtio_pci_irqfd_release(proxy, vector, queue_no);
+     }
+ }
+ static int kvm_virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
                                       MSIMessage msg)
  {
      VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
      VirtIODevice *vdev = proxy->vdev;
      int ret, queue_no;
  
-     for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) {
+     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
          if (!virtio_queue_get_num(vdev, queue_no)) {
              break;
          }
          if (virtio_queue_vector(vdev, queue_no) != vector) {
              continue;
          }
-         ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg);
+         ret = kvm_virtio_pci_vq_vector_unmask(proxy, queue_no, vector, msg);
          if (ret < 0) {
              goto undo;
          }
@@@ -554,25 -681,25 +681,25 @@@ undo
          if (virtio_queue_vector(vdev, queue_no) != vector) {
              continue;
          }
-         kvm_virtio_pci_vq_vector_release(proxy, queue_no, vector);
+         kvm_virtio_pci_vq_vector_mask(proxy, queue_no, vector);
      }
      return ret;
  }
  
- static void kvm_virtio_pci_vector_release(PCIDevice *dev, unsigned vector)
+ static void kvm_virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
  {
      VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
      VirtIODevice *vdev = proxy->vdev;
      int queue_no;
  
-     for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) {
+     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
          if (!virtio_queue_get_num(vdev, queue_no)) {
              break;
          }
          if (virtio_queue_vector(vdev, queue_no) != vector) {
              continue;
          }
-         kvm_virtio_pci_vq_vector_release(proxy, queue_no, vector);
+         kvm_virtio_pci_vq_vector_mask(proxy, queue_no, vector);
      }
  }
  
@@@ -587,7 -714,7 +714,7 @@@ static void kvm_virtio_pci_vector_poll(
      EventNotifier *notifier;
      VirtQueue *vq;
  
-     for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) {
+     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
          if (!virtio_queue_get_num(vdev, queue_no)) {
              break;
          }
          }
          vq = virtio_get_queue(vdev, queue_no);
          notifier = virtio_queue_get_guest_notifier(vq);
-         if (event_notifier_test_and_clear(notifier)) {
+         if (vdev->guest_notifier_pending) {
+             if (vdev->guest_notifier_pending(vdev, queue_no)) {
+                 msix_set_pending(dev, vector);
+             }
+         } else if (event_notifier_test_and_clear(notifier)) {
              msix_set_pending(dev, vector);
          }
      }
@@@ -631,7 -762,7 +762,7 @@@ static bool virtio_pci_query_guest_noti
      return msix_enabled(&proxy->pci_dev);
  }
  
- static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign)
+ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
  {
      VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
      VirtIODevice *vdev = proxy->vdev;
      bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
          kvm_msi_via_irqfd_enabled();
  
+     nvqs = MIN(nvqs, VIRTIO_PCI_QUEUE_MAX);
+     /* When deassigning, pass a consistent nvqs value
+      * to avoid leaking notifiers.
+      */
+     assert(assign || nvqs == proxy->nvqs_with_notifiers);
+     proxy->nvqs_with_notifiers = nvqs;
      /* Must unset vector notifier while guest notifier is still assigned */
      if (proxy->vector_irqfd && !assign) {
          msix_unset_vector_notifiers(&proxy->pci_dev);
+         kvm_virtio_pci_vector_release(proxy, nvqs);
          g_free(proxy->vector_irqfd);
          proxy->vector_irqfd = NULL;
      }
  
-     for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+     for (n = 0; n < nvqs; n++) {
          if (!virtio_queue_get_num(vdev, n)) {
              break;
          }
          proxy->vector_irqfd =
              g_malloc0(sizeof(*proxy->vector_irqfd) *
                        msix_nr_vectors_allocated(&proxy->pci_dev));
+         r = kvm_virtio_pci_vector_use(proxy, nvqs);
+         if (r < 0) {
+             goto assign_error;
+         }
          r = msix_set_vector_notifiers(&proxy->pci_dev,
-                                       kvm_virtio_pci_vector_use,
-                                       kvm_virtio_pci_vector_release,
+                                       kvm_virtio_pci_vector_unmask,
+                                       kvm_virtio_pci_vector_mask,
                                        kvm_virtio_pci_vector_poll);
          if (r < 0) {
-             goto assign_error;
+             goto notifiers_error;
          }
      }
  
      return 0;
  
+ notifiers_error:
+     assert(assign);
+     kvm_virtio_pci_vector_release(proxy, nvqs);
  assign_error:
      /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
      assert(assign);
@@@ -961,7 -1110,7 +1110,7 @@@ static void virtio_blk_class_init(Objec
      dc->props = virtio_blk_properties;
  }
  
 -static TypeInfo virtio_blk_info = {
 +static const TypeInfo virtio_blk_info = {
      .name          = "virtio-blk-pci",
      .parent        = TYPE_PCI_DEVICE,
      .instance_size = sizeof(VirtIOPCIProxy),
@@@ -995,7 -1144,7 +1144,7 @@@ static void virtio_net_class_init(Objec
      dc->props = virtio_net_properties;
  }
  
 -static TypeInfo virtio_net_info = {
 +static const TypeInfo virtio_net_info = {
      .name          = "virtio-net-pci",
      .parent        = TYPE_PCI_DEVICE,
      .instance_size = sizeof(VirtIOPCIProxy),
@@@ -1026,7 -1175,7 +1175,7 @@@ static void virtio_serial_class_init(Ob
      dc->props = virtio_serial_properties;
  }
  
 -static TypeInfo virtio_serial_info = {
 +static const TypeInfo virtio_serial_info = {
      .name          = "virtio-serial-pci",
      .parent        = TYPE_PCI_DEVICE,
      .instance_size = sizeof(VirtIOPCIProxy),
@@@ -1054,7 -1203,7 +1203,7 @@@ static void virtio_balloon_class_init(O
      dc->props = virtio_balloon_properties;
  }
  
 -static TypeInfo virtio_balloon_info = {
 +static const TypeInfo virtio_balloon_info = {
      .name          = "virtio-balloon-pci",
      .parent        = TYPE_PCI_DEVICE,
      .instance_size = sizeof(VirtIOPCIProxy),
@@@ -1097,7 -1246,7 +1246,7 @@@ static void virtio_rng_class_init(Objec
      dc->props = virtio_rng_properties;
  }
  
 -static TypeInfo virtio_rng_info = {
 +static const TypeInfo virtio_rng_info = {
      .name          = "virtio-rng-pci",
      .parent        = TYPE_PCI_DEVICE,
      .instance_size = sizeof(VirtIOPCIProxy),
@@@ -1155,7 -1304,7 +1304,7 @@@ static void virtio_scsi_class_init(Obje
      dc->props = virtio_scsi_properties;
  }
  
 -static TypeInfo virtio_scsi_info = {
 +static const TypeInfo virtio_scsi_info = {
      .name          = "virtio-scsi-pci",
      .parent        = TYPE_PCI_DEVICE,
      .instance_size = sizeof(VirtIOPCIProxy),
This page took 0.087848 seconds and 4 git commands to generate.