diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-03-15 18:44:05 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-03-15 18:44:05 +0000 |
commit | 1883ff34b540daacae948f493b0ba525edf5f642 (patch) | |
tree | 457830e286a98b4174e18f27635061f318346333 | |
parent | de71fb96bfcdf6356355f49a886fbf58fe93bf87 (diff) | |
parent | 60a8d8023473dd24957b3a66824f66cd35b80d64 (diff) |
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
virtio, pc: fixes
Some fixes to fallback from using virtio caching,
pls a minor vm gen id fix.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
# gpg: Signature made Wed 15 Mar 2017 17:59:25 GMT
# gpg: using RSA key 0x281F0DB8D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg: aka "Michael S. Tsirkin <mst@redhat.com>"
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17 0970 C350 3912 AFBE 8E67
# Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA 8A0D 281F 0DB8 D28D 5469
* remotes/mst/tags/for_upstream:
virtio-pci: reset modern vq meta data
Revert "virtio: unbreak virtio-pci with IOMMU after caching ring translations"
pci: introduce a bus master container
virtio: validate address space cache during init
virtio: destroy region cache during reset
virtio: guard against NULL pfn
Bugfix: Handle error if VM Generation ID device not present
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hmp.c | 4 | ||||
-rw-r--r-- | hw/acpi/vmgenid.c | 1 | ||||
-rw-r--r-- | hw/pci/pci.c | 9 | ||||
-rw-r--r-- | hw/virtio/virtio-pci.c | 6 | ||||
-rw-r--r-- | hw/virtio/virtio.c | 104 | ||||
-rw-r--r-- | include/hw/pci/pci.h | 1 |
6 files changed, 100 insertions, 25 deletions
@@ -2608,9 +2608,11 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict) void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict) { - GuidInfo *info = qmp_query_vm_generation_id(NULL); + Error *err = NULL; + GuidInfo *info = qmp_query_vm_generation_id(&err); if (info) { monitor_printf(mon, "%s\n", info->guid); } + hmp_handle_error(mon, &err); qapi_free_GuidInfo(info); } diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c index 744f2847da..7a3ad17d66 100644 --- a/hw/acpi/vmgenid.c +++ b/hw/acpi/vmgenid.c @@ -248,6 +248,7 @@ GuidInfo *qmp_query_vm_generation_id(Error **errp) Object *obj = find_vmgenid_dev(); if (!obj) { + error_setg(errp, "VM Generation ID device not found"); return NULL; } vms = VMGENID(obj); diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 273f1e4602..ad46390ec5 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -88,8 +88,8 @@ static void pci_init_bus_master(PCIDevice *pci_dev) OBJECT(pci_dev), "bus master", dma_as->root, 0, memory_region_size(dma_as->root)); memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); - address_space_init(&pci_dev->bus_master_as, - &pci_dev->bus_master_enable_region, pci_dev->name); + memory_region_add_subregion(&pci_dev->bus_master_container_region, 0, + &pci_dev->bus_master_enable_region); } static void pcibus_machine_done(Notifier *notifier, void *data) @@ -995,6 +995,11 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, pci_dev->devfn = devfn; pci_dev->requester_id_cache = pci_req_id_cache_get(pci_dev); + memory_region_init(&pci_dev->bus_master_container_region, OBJECT(pci_dev), + "bus master container", UINT64_MAX); + address_space_init(&pci_dev->bus_master_as, + &pci_dev->bus_master_container_region, pci_dev->name); + if (qdev_hotplug) { pci_init_bus_master(pci_dev); } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index b76f3f62a0..69cc471e56 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1153,7 +1153,7 @@ static AddressSpace *virtio_pci_get_dma_as(DeviceState *d) VirtIOPCIProxy *proxy = VIRTIO_PCI(d); PCIDevice *dev = &proxy->pci_dev; - return pci_device_iommu_address_space(dev); + return pci_get_address_space(dev); } static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy, @@ -1857,6 +1857,10 @@ static void virtio_pci_reset(DeviceState *qdev) for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { proxy->vqs[i].enabled = 0; + proxy->vqs[i].num = 0; + proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0; + proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0; + proxy->vqs[i].used[0] = proxy->vqs[i].used[1] = 0; } } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index efce4b343a..82b6060b2a 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -131,6 +131,7 @@ static void virtio_init_region_cache(VirtIODevice *vdev, int n) VRingMemoryRegionCaches *new; hwaddr addr, size; int event_size; + int64_t len; event_size = virtio_vdev_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0; @@ -140,21 +141,41 @@ static void virtio_init_region_cache(VirtIODevice *vdev, int n) } new = g_new0(VRingMemoryRegionCaches, 1); size = virtio_queue_get_desc_size(vdev, n); - address_space_cache_init(&new->desc, vdev->dma_as, - addr, size, false); + len = address_space_cache_init(&new->desc, vdev->dma_as, + addr, size, false); + if (len < size) { + virtio_error(vdev, "Cannot map desc"); + goto err_desc; + } size = virtio_queue_get_used_size(vdev, n) + event_size; - address_space_cache_init(&new->used, vdev->dma_as, - vq->vring.used, size, true); + len = address_space_cache_init(&new->used, vdev->dma_as, + vq->vring.used, size, true); + if (len < size) { + virtio_error(vdev, "Cannot map used"); + goto err_used; + } size = virtio_queue_get_avail_size(vdev, n) + event_size; - address_space_cache_init(&new->avail, vdev->dma_as, - vq->vring.avail, size, false); + len = address_space_cache_init(&new->avail, vdev->dma_as, + vq->vring.avail, size, false); + if (len < size) { + virtio_error(vdev, "Cannot map avail"); + goto err_avail; + } atomic_rcu_set(&vq->vring.caches, new); if (old) { call_rcu(old, virtio_free_region_cache, rcu); } + return; + +err_avail: + address_space_cache_destroy(&new->used); +err_used: + address_space_cache_destroy(&new->desc); +err_desc: + g_free(new); } /* virt queue functions */ @@ -185,10 +206,16 @@ static void vring_desc_read(VirtIODevice *vdev, VRingDesc *desc, virtio_tswap16s(vdev, &desc->next); } +static VRingMemoryRegionCaches *vring_get_region_caches(struct VirtQueue *vq) +{ + VRingMemoryRegionCaches *caches = atomic_rcu_read(&vq->vring.caches); + assert(caches != NULL); + return caches; +} /* Called within rcu_read_lock(). */ static inline uint16_t vring_avail_flags(VirtQueue *vq) { - VRingMemoryRegionCaches *caches = atomic_rcu_read(&vq->vring.caches); + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); hwaddr pa = offsetof(VRingAvail, flags); return virtio_lduw_phys_cached(vq->vdev, &caches->avail, pa); } @@ -196,7 +223,7 @@ static inline uint16_t vring_avail_flags(VirtQueue *vq) /* Called within rcu_read_lock(). */ static inline uint16_t vring_avail_idx(VirtQueue *vq) { - VRingMemoryRegionCaches *caches = atomic_rcu_read(&vq->vring.caches); + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); hwaddr pa = offsetof(VRingAvail, idx); vq->shadow_avail_idx = virtio_lduw_phys_cached(vq->vdev, &caches->avail, pa); return vq->shadow_avail_idx; @@ -205,7 +232,7 @@ static inline uint16_t vring_avail_idx(VirtQueue *vq) /* Called within rcu_read_lock(). */ static inline uint16_t vring_avail_ring(VirtQueue *vq, int i) { - VRingMemoryRegionCaches *caches = atomic_rcu_read(&vq->vring.caches); + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); hwaddr pa = offsetof(VRingAvail, ring[i]); return virtio_lduw_phys_cached(vq->vdev, &caches->avail, pa); } @@ -220,7 +247,7 @@ static inline uint16_t vring_get_used_event(VirtQueue *vq) static inline void vring_used_write(VirtQueue *vq, VRingUsedElem *uelem, int i) { - VRingMemoryRegionCaches *caches = atomic_rcu_read(&vq->vring.caches); + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); hwaddr pa = offsetof(VRingUsed, ring[i]); virtio_tswap32s(vq->vdev, &uelem->id); virtio_tswap32s(vq->vdev, &uelem->len); @@ -231,7 +258,7 @@ static inline void vring_used_write(VirtQueue *vq, VRingUsedElem *uelem, /* Called within rcu_read_lock(). */ static uint16_t vring_used_idx(VirtQueue *vq) { - VRingMemoryRegionCaches *caches = atomic_rcu_read(&vq->vring.caches); + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); hwaddr pa = offsetof(VRingUsed, idx); return virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); } @@ -239,7 +266,7 @@ static uint16_t vring_used_idx(VirtQueue *vq) /* Called within rcu_read_lock(). */ static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val) { - VRingMemoryRegionCaches *caches = atomic_rcu_read(&vq->vring.caches); + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); hwaddr pa = offsetof(VRingUsed, idx); virtio_stw_phys_cached(vq->vdev, &caches->used, pa, val); address_space_cache_invalidate(&caches->used, pa, sizeof(val)); @@ -249,7 +276,7 @@ static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val) /* Called within rcu_read_lock(). */ static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask) { - VRingMemoryRegionCaches *caches = atomic_rcu_read(&vq->vring.caches); + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); VirtIODevice *vdev = vq->vdev; hwaddr pa = offsetof(VRingUsed, flags); uint16_t flags = virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); @@ -261,7 +288,7 @@ static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask) /* Called within rcu_read_lock(). */ static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask) { - VRingMemoryRegionCaches *caches = atomic_rcu_read(&vq->vring.caches); + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); VirtIODevice *vdev = vq->vdev; hwaddr pa = offsetof(VRingUsed, flags); uint16_t flags = virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); @@ -279,7 +306,7 @@ static inline void vring_set_avail_event(VirtQueue *vq, uint16_t val) return; } - caches = atomic_rcu_read(&vq->vring.caches); + caches = vring_get_region_caches(vq); pa = offsetof(VRingUsed, ring[vq->vring.num]); virtio_stw_phys_cached(vq->vdev, &caches->used, pa, val); address_space_cache_invalidate(&caches->used, pa, sizeof(val)); @@ -318,6 +345,10 @@ int virtio_queue_ready(VirtQueue *vq) * Called within rcu_read_lock(). */ static int virtio_queue_empty_rcu(VirtQueue *vq) { + if (unlikely(!vq->vring.avail)) { + return 1; + } + if (vq->shadow_avail_idx != vq->last_avail_idx) { return 0; } @@ -329,6 +360,10 @@ int virtio_queue_empty(VirtQueue *vq) { bool empty; + if (unlikely(!vq->vring.avail)) { + return 1; + } + if (vq->shadow_avail_idx != vq->last_avail_idx) { return 0; } @@ -431,6 +466,10 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, return; } + if (unlikely(!vq->vring.used)) { + return; + } + idx = (idx + vq->used_idx) % vq->vring.num; uelem.id = elem->index; @@ -448,6 +487,10 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count) return; } + if (unlikely(!vq->vring.used)) { + return; + } + /* Make sure buffer is written before we update index. */ smp_wmb(); trace_virtqueue_flush(vq, count); @@ -546,12 +589,22 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, int64_t len = 0; int rc; + if (unlikely(!vq->vring.desc)) { + if (in_bytes) { + *in_bytes = 0; + } + if (out_bytes) { + *out_bytes = 0; + } + return; + } + rcu_read_lock(); idx = vq->last_avail_idx; total_bufs = in_total = out_total = 0; max = vq->vring.num; - caches = atomic_rcu_read(&vq->vring.caches); + caches = vring_get_region_caches(vq); if (caches->desc.len < max * sizeof(VRingDesc)) { virtio_error(vdev, "Cannot map descriptor ring"); goto err; @@ -818,7 +871,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) i = head; - caches = atomic_rcu_read(&vq->vring.caches); + caches = vring_get_region_caches(vq); if (caches->desc.len < max * sizeof(VRingDesc)) { virtio_error(vdev, "Cannot map descriptor ring"); goto done; @@ -1117,6 +1170,17 @@ static enum virtio_device_endian virtio_current_cpu_endian(void) } } +static void virtio_virtqueue_reset_region_cache(struct VirtQueue *vq) +{ + VRingMemoryRegionCaches *caches; + + caches = atomic_read(&vq->vring.caches); + atomic_rcu_set(&vq->vring.caches, NULL); + if (caches) { + call_rcu(caches, virtio_free_region_cache, rcu); + } +} + void virtio_reset(void *opaque) { VirtIODevice *vdev = opaque; @@ -1157,6 +1221,7 @@ void virtio_reset(void *opaque) vdev->vq[i].notification = true; vdev->vq[i].vring.num = vdev->vq[i].vring.num_default; vdev->vq[i].inuse = 0; + virtio_virtqueue_reset_region_cache(&vdev->vq[i]); } } @@ -2451,13 +2516,10 @@ static void virtio_device_free_virtqueues(VirtIODevice *vdev) } for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { - VRingMemoryRegionCaches *caches; if (vdev->vq[i].vring.num == 0) { break; } - caches = atomic_read(&vdev->vq[i].vring.caches); - atomic_set(&vdev->vq[i].vring.caches, NULL); - virtio_free_region_cache(caches); + virtio_virtqueue_reset_region_cache(&vdev->vq[i]); } g_free(vdev->vq); } diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 9349acbfb2..713ede00bf 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -284,6 +284,7 @@ struct PCIDevice { char name[64]; PCIIORegion io_regions[PCI_NUM_REGIONS]; AddressSpace bus_master_as; + MemoryRegion bus_master_container_region; MemoryRegion bus_master_enable_region; /* do not access the following fields */ |