diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-09-30 13:09:39 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-09-30 13:09:40 +0100 |
commit | 2e456b2b606aef488de27f8212e22382141fa022 (patch) | |
tree | 39184cd190bedef458e5d9c698e9915ea49932b0 /hw/virtio | |
parent | 45c270b1ea7987ab93e41ab095dd77370523e6b3 (diff) | |
parent | 28d16f38d0d5881f95b074cc802dae8cacc1bf58 (diff) |
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pci, pc, virtio, misc bugfixes
A bunch of bugfixes.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
# gpg: Signature made Mon 29 Sep 2014 17:59:57 BST using RSA key ID D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg: aka "Michael S. Tsirkin <mst@redhat.com>"
* remotes/mst/tags/for_upstream:
vl: Adjust the place of calling mlockall to speedup VM's startup
pc-dimm: Don't check dimm->node when there is non-NUMA config
pci-hotplug-old: avoid losing error message
Revert "virtio-pci: fix migration for pci bus master"
loader: g_realloc(p, 0) frees and returns NULL, simplify
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/virtio')
-rw-r--r-- | hw/virtio/virtio-pci.c | 39 |
1 files changed, 19 insertions, 20 deletions
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index f5608140f9..a827cd41bf 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 { @@ -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[] = { |