summaryrefslogtreecommitdiffstats
path: root/hw/virtio/virtio-pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/virtio/virtio-pci.c')
-rw-r--r--hw/virtio/virtio-pci.c87
1 files changed, 43 insertions, 44 deletions
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index f5608140f9..390f8244f3 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -86,6 +86,9 @@
* 12 is historical, and due to x86 page size. */
#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12
+/* Flags track per-device state like workarounds for quirks in older guests. */
+#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG (1 << 0)
+
static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
VirtIOPCIProxy *dev);
@@ -320,6 +323,14 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
proxy->pci_dev.config[PCI_COMMAND] |
PCI_COMMAND_MASTER, 1);
}
+
+ /* Linux before 2.6.34 sets the device as OK without enabling
+ the PCI device bus master bit. In this case we need to disable
+ some safety checks. */
+ if ((val & VIRTIO_CONFIG_S_DRIVER_OK) &&
+ !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
+ proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
+ }
break;
case VIRTIO_MSI_CONFIG_VECTOR:
msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
@@ -469,18 +480,13 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- uint8_t cmd = proxy->pci_dev.config[PCI_COMMAND];
-
pci_default_write_config(pci_dev, address, val, len);
if (range_covers_byte(address, len, PCI_COMMAND) &&
!(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) &&
- (cmd & PCI_COMMAND_MASTER)) {
- /* Bus driver disables bus mastering - make it act
- * as a kind of reset to render the device quiescent. */
+ !(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) {
virtio_pci_stop_ioeventfd(proxy);
- virtio_reset(vdev);
- msix_unuse_all_vectors(&proxy->pci_dev);
+ virtio_set_status(vdev, vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
}
}
@@ -889,19 +895,11 @@ static void virtio_pci_vmstate_change(DeviceState *d, bool running)
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
if (running) {
- /* Linux before 2.6.34 drives the device without enabling
- the PCI device bus master bit. Enable it automatically
- for the guest. This is a PCI spec violation but so is
- initiating DMA with bus master bit clear.
- Note: this only makes a difference when migrating
- across QEMU versions from an old QEMU, as for new QEMU
- bus master and driver bits are always in sync.
- TODO: consider enabling conditionally for compat machine types. */
- if (vdev->status & (VIRTIO_CONFIG_S_ACKNOWLEDGE |
- VIRTIO_CONFIG_S_DRIVER)) {
- pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
- proxy->pci_dev.config[PCI_COMMAND] |
- PCI_COMMAND_MASTER, 1);
+ /* Try to find out if the guest has bus master disabled, but is
+ in ready state. Then we have a buggy guest OS. */
+ if ((vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
+ !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
+ proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
}
virtio_pci_start_ioeventfd(proxy);
} else {
@@ -926,7 +924,6 @@ static Property virtio_9p_pci_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_VIRTIO_9P_PROPERTIES(V9fsPCIState, vdev.fsconf),
DEFINE_PROP_END_OF_LIST(),
};
@@ -948,8 +945,9 @@ static void virtio_9p_pci_class_init(ObjectClass *klass, void *data)
static void virtio_9p_pci_instance_init(Object *obj)
{
V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
- object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_9P);
- object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_9P);
}
static const TypeInfo virtio_9p_pci_info = {
@@ -1042,6 +1040,7 @@ static void virtio_pci_reset(DeviceState *qdev)
virtio_pci_stop_ioeventfd(proxy);
virtio_bus_reset(bus);
msix_unuse_all_vectors(&proxy->pci_dev);
+ proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
}
static Property virtio_pci_properties[] = {
@@ -1111,10 +1110,9 @@ static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
static void virtio_blk_pci_instance_init(Object *obj)
{
VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
- object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK);
- object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
- object_unref(OBJECT(&dev->vdev));
- qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_BLK);
object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
&error_abort);
}
@@ -1135,7 +1133,6 @@ static Property virtio_scsi_pci_properties[] = {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIPCI, vdev.parent_obj.conf),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1185,8 +1182,11 @@ static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
static void virtio_scsi_pci_instance_init(Object *obj)
{
VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
- object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI);
- object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_SCSI);
+ object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
+ &error_abort);
}
static const TypeInfo virtio_scsi_pci_info = {
@@ -1203,7 +1203,6 @@ static const TypeInfo virtio_scsi_pci_info = {
static Property vhost_scsi_pci_properties[] = {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
- DEFINE_VHOST_SCSI_PROPERTIES(VHostSCSIPCI, vdev.parent_obj.conf),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1241,8 +1240,9 @@ static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data)
static void vhost_scsi_pci_instance_init(Object *obj)
{
VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
- object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI);
- object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VHOST_SCSI);
}
static const TypeInfo vhost_scsi_pci_info = {
@@ -1323,7 +1323,7 @@ static void virtio_balloon_pci_instance_init(Object *obj)
VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
-
+ object_unref(OBJECT(&dev->vdev));
object_property_add(obj, "guest-stats", "guest statistics",
balloon_pci_stats_get_all, NULL, NULL, dev,
NULL);
@@ -1385,7 +1385,6 @@ static Property virtio_serial_pci_properties[] = {
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
- DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtIOSerialPCI, vdev.serial),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1406,8 +1405,9 @@ static void virtio_serial_pci_class_init(ObjectClass *klass, void *data)
static void virtio_serial_pci_instance_init(Object *obj)
{
VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
- object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL);
- object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_SERIAL);
}
static const TypeInfo virtio_serial_pci_info = {
@@ -1425,8 +1425,6 @@ static Property virtio_net_properties[] = {
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_NIC_PROPERTIES(VirtIONetPCI, vdev.nic_conf),
- DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetPCI, vdev.net_conf),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1465,8 +1463,9 @@ static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
static void virtio_net_pci_instance_init(Object *obj)
{
VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
- object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET);
- object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_NET);
}
static const TypeInfo virtio_net_pci_info = {
@@ -1480,7 +1479,6 @@ static const TypeInfo virtio_net_pci_info = {
/* virtio-rng-pci */
static Property virtio_rng_pci_properties[] = {
- DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORngPCI, vdev.conf),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1520,8 +1518,9 @@ static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
static void virtio_rng_initfn(Object *obj)
{
VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
- object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
- object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_RNG);
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
(Object **)&dev->vdev.conf.rng,
qdev_prop_allow_set_link_before_realize,