diff options
Diffstat (limited to 'hw/virtio/virtio-pci.c')
-rw-r--r-- | hw/virtio/virtio-pci.c | 139 |
1 files changed, 117 insertions, 22 deletions
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 755f9218b7..06831de5ff 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -294,6 +294,12 @@ static void virtio_pci_ioeventfd_set_disabled(DeviceState *d, bool disabled) #define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x1000 +static inline int virtio_pci_queue_mem_mult(struct VirtIOPCIProxy *proxy) +{ + return (proxy->flags & VIRTIO_PCI_FLAG_PAGE_PER_VQ) ? + QEMU_VIRTIO_PCI_QUEUE_MEM_MULT : 4; +} + static int virtio_pci_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, int n, bool assign) { @@ -307,7 +313,7 @@ static int virtio_pci_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, MemoryRegion *modern_mr = &proxy->notify.mr; MemoryRegion *modern_notify_mr = &proxy->notify_pio.mr; MemoryRegion *legacy_mr = &proxy->bar; - hwaddr modern_addr = QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * + hwaddr modern_addr = virtio_pci_queue_mem_mult(proxy) * virtio_get_queue_index(vq); hwaddr legacy_addr = VIRTIO_PCI_QUEUE_NOTIFY; @@ -1370,7 +1376,8 @@ static void virtio_pci_notify_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { VirtIODevice *vdev = opaque; - unsigned queue = addr / QEMU_VIRTIO_PCI_QUEUE_MEM_MULT; + VirtIOPCIProxy *proxy = VIRTIO_PCI(DEVICE(vdev)->parent_bus->parent); + unsigned queue = addr / virtio_pci_queue_mem_mult(proxy); if (queue < VIRTIO_QUEUE_MAX) { virtio_queue_notify(vdev, queue); @@ -1520,7 +1527,7 @@ static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy) ¬ify_pio_ops, virtio_bus_get_device(&proxy->bus), "virtio-pci-notify-pio", - proxy->notify.size); + proxy->notify_pio.size); } static void virtio_pci_modern_region_map(VirtIOPCIProxy *proxy, @@ -1544,7 +1551,7 @@ static void virtio_pci_modern_mem_region_map(VirtIOPCIProxy *proxy, struct virtio_pci_cap *cap) { virtio_pci_modern_region_map(proxy, region, cap, - &proxy->modern_bar, proxy->modern_mem_bar); + &proxy->modern_bar, proxy->modern_mem_bar_idx); } static void virtio_pci_modern_io_region_map(VirtIOPCIProxy *proxy, @@ -1552,7 +1559,7 @@ static void virtio_pci_modern_io_region_map(VirtIOPCIProxy *proxy, struct virtio_pci_cap *cap) { virtio_pci_modern_region_map(proxy, region, cap, - &proxy->io_bar, proxy->modern_io_bar); + &proxy->io_bar, proxy->modern_io_bar_idx); } static void virtio_pci_modern_mem_region_unmap(VirtIOPCIProxy *proxy, @@ -1569,18 +1576,48 @@ static void virtio_pci_modern_io_region_unmap(VirtIOPCIProxy *proxy, ®ion->mr); } +static void virtio_pci_pre_plugged(DeviceState *d, Error **errp) +{ + VirtIOPCIProxy *proxy = VIRTIO_PCI(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + + if (virtio_pci_modern(proxy)) { + virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1); + } + + virtio_add_feature(&vdev->host_features, VIRTIO_F_BAD_FEATURE); +} + /* This is called by virtio-bus just after the device is plugged. */ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) { VirtIOPCIProxy *proxy = VIRTIO_PCI(d); VirtioBusState *bus = &proxy->bus; bool legacy = virtio_pci_legacy(proxy); - bool modern = virtio_pci_modern(proxy); + bool modern; bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; uint8_t *config; uint32_t size; VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + /* + * Virtio capabilities present without + * VIRTIO_F_VERSION_1 confuses guests + */ + if (!virtio_has_feature(vdev->host_features, VIRTIO_F_VERSION_1)) { + virtio_pci_disable_modern(proxy); + + if (!legacy) { + error_setg(errp, "Device doesn't support modern mode, and legacy" + " mode is disabled"); + error_append_hint(errp, "Set disable-legacy to off\n"); + + return; + } + } + + modern = virtio_pci_modern(proxy); + config = proxy->pci_dev.config; if (proxy->class_code) { pci_config_set_class(config, proxy->class_code); @@ -1609,7 +1646,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) struct virtio_pci_notify_cap notify = { .cap.cap_len = sizeof notify, .notify_off_multiplier = - cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT), + cpu_to_le32(virtio_pci_queue_mem_mult(proxy)), }; struct virtio_pci_cfg_cap cfg = { .cap.cap_len = sizeof cfg, @@ -1622,7 +1659,6 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) struct virtio_pci_cfg_cap *cfg_mask; - virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1); virtio_pci_modern_regions_init(proxy); virtio_pci_modern_mem_region_map(proxy, &proxy->common, &cap); @@ -1634,14 +1670,14 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) memory_region_init(&proxy->io_bar, OBJECT(proxy), "virtio-pci-io", 0x4); - pci_register_bar(&proxy->pci_dev, proxy->modern_io_bar, + pci_register_bar(&proxy->pci_dev, proxy->modern_io_bar_idx, PCI_BASE_ADDRESS_SPACE_IO, &proxy->io_bar); virtio_pci_modern_io_region_map(proxy, &proxy->notify_pio, ¬ify_pio.cap); } - pci_register_bar(&proxy->pci_dev, proxy->modern_mem_bar, + pci_register_bar(&proxy->pci_dev, proxy->modern_mem_bar_idx, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH | PCI_BASE_ADDRESS_MEM_TYPE_64, @@ -1657,7 +1693,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) if (proxy->nvectors) { int err = msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, - proxy->msix_bar); + proxy->msix_bar_idx); if (err) { /* Notice when a system that supports MSIx can't initialize it. */ if (err != -ENOTSUP) { @@ -1680,15 +1716,13 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) &virtio_pci_config_ops, proxy, "virtio-pci", size); - pci_register_bar(&proxy->pci_dev, proxy->legacy_io_bar, + pci_register_bar(&proxy->pci_dev, proxy->legacy_io_bar_idx, PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar); } if (!kvm_has_many_ioeventfds()) { proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD; } - - virtio_add_feature(&vdev->host_features, VIRTIO_F_BAD_FEATURE); } static void virtio_pci_device_unplugged(DeviceState *d) @@ -1726,10 +1760,10 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) * region 4+5 -- virtio modern memory (64bit) bar * */ - proxy->legacy_io_bar = 0; - proxy->msix_bar = 1; - proxy->modern_io_bar = 2; - proxy->modern_mem_bar = 4; + proxy->legacy_io_bar_idx = 0; + proxy->msix_bar_idx = 1; + proxy->modern_io_bar_idx = 2; + proxy->modern_mem_bar_idx = 4; proxy->common.offset = 0x0; proxy->common.size = 0x1000; @@ -1744,8 +1778,7 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) proxy->device.type = VIRTIO_PCI_CAP_DEVICE_CFG; proxy->notify.offset = 0x3000; - proxy->notify.size = - QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * VIRTIO_QUEUE_MAX; + proxy->notify.size = virtio_pci_queue_mem_mult(proxy) * VIRTIO_QUEUE_MAX; proxy->notify.type = VIRTIO_PCI_CAP_NOTIFY_CFG; proxy->notify_pio.offset = 0x0; @@ -1754,8 +1787,8 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) /* subclasses can enforce modern, so do this unconditionally */ memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci", - 2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * - VIRTIO_QUEUE_MAX); + /* PCI BAR regions must be powers of 2 */ + pow2ceil(proxy->notify.offset + proxy->notify.size)); memory_region_init_alias(&proxy->modern_cfg, OBJECT(proxy), @@ -1770,6 +1803,14 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; } + if (!virtio_pci_modern(proxy) && !virtio_pci_legacy(proxy)) { + error_setg(errp, "device cannot work as neither modern nor legacy mode" + " is enabled"); + error_append_hint(errp, "Set either disable-modern or disable-legacy" + " to off\n"); + return; + } + if (pcie_port && pci_is_express(pci_dev)) { int pos; @@ -1833,6 +1874,8 @@ static Property virtio_pci_properties[] = { VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, false), DEFINE_PROP_BIT("x-disable-pcie", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, false), + DEFINE_PROP_BIT("page-per-vq", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, false), DEFINE_PROP_END_OF_LIST(), }; @@ -2055,6 +2098,54 @@ static const TypeInfo vhost_scsi_pci_info = { }; #endif +/* vhost-vsock-pci */ + +#ifdef CONFIG_VHOST_VSOCK +static Property vhost_vsock_pci_properties[] = { + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vhost_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VHostVSockPCI *dev = VHOST_VSOCK_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void vhost_vsock_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + k->realize = vhost_vsock_pci_realize; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->props = vhost_vsock_pci_properties; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_VSOCK; + pcidev_k->revision = 0x00; + pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER; +} + +static void vhost_vsock_pci_instance_init(Object *obj) +{ + VHostVSockPCI *dev = VHOST_VSOCK_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_VSOCK); +} + +static const TypeInfo vhost_vsock_pci_info = { + .name = TYPE_VHOST_VSOCK_PCI, + .parent = TYPE_VIRTIO_PCI, + .instance_size = sizeof(VHostVSockPCI), + .instance_init = vhost_vsock_pci_instance_init, + .class_init = vhost_vsock_pci_class_init, +}; +#endif + /* virtio-balloon-pci */ static Property virtio_balloon_pci_properties[] = { @@ -2444,6 +2535,7 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) k->query_guest_notifiers = virtio_pci_query_guest_notifiers; k->set_guest_notifiers = virtio_pci_set_guest_notifiers; k->vmstate_change = virtio_pci_vmstate_change; + k->pre_plugged = virtio_pci_pre_plugged; k->device_plugged = virtio_pci_device_plugged; k->device_unplugged = virtio_pci_device_unplugged; k->query_nvectors = virtio_pci_query_nvectors; @@ -2485,6 +2577,9 @@ static void virtio_pci_register_types(void) #ifdef CONFIG_VHOST_SCSI type_register_static(&vhost_scsi_pci_info); #endif +#ifdef CONFIG_VHOST_VSOCK + type_register_static(&vhost_vsock_pci_info); +#endif } type_init(virtio_pci_register_types) |