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>
 -----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJYyYD9AAoJECgfDbjSjVRpVC0IAL50O94eD711A1LhbHYaf01j
 0d++IQM0FeyY+Vg3YfIhpil/sjJ9xVt4GiX3sr2yE7Et4f57N4nXKqemsjyNAeno
 RgfTrO/s3VOFSjmy0RpwJYdbLs5bIMd3fWh7Yc1auSfpWtxkGVZFDDGuXYmmQnJP
 4FgJSMmJGzSSlSxCl7R9AKnR9xfPuPkpLUlq1hcSZe/gjG/jNPkGa0ZxuiCWgKzB
 kQIrOl8q1lWAQ2AqdWKL+XPzicARrk5thFD2uhOPqHJo5i2oEB8P1vtxOSG3Qtw1
 X0P/B5WooCi9cjJHujNSQiG5mUCrGWrlftpKxBdO0BIz29WnXpcjTl7zZauKdsA=
 =RXnk
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Peter Maydell 2017-03-15 18:44:05 +00:00
commit 1883ff34b5
6 changed files with 100 additions and 25 deletions

4
hmp.c
View File

@ -2608,9 +2608,11 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict)
void hmp_info_vm_generation_id(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) { if (info) {
monitor_printf(mon, "%s\n", info->guid); monitor_printf(mon, "%s\n", info->guid);
} }
hmp_handle_error(mon, &err);
qapi_free_GuidInfo(info); qapi_free_GuidInfo(info);
} }

View File

@ -248,6 +248,7 @@ GuidInfo *qmp_query_vm_generation_id(Error **errp)
Object *obj = find_vmgenid_dev(); Object *obj = find_vmgenid_dev();
if (!obj) { if (!obj) {
error_setg(errp, "VM Generation ID device not found");
return NULL; return NULL;
} }
vms = VMGENID(obj); vms = VMGENID(obj);

View File

@ -88,8 +88,8 @@ static void pci_init_bus_master(PCIDevice *pci_dev)
OBJECT(pci_dev), "bus master", OBJECT(pci_dev), "bus master",
dma_as->root, 0, memory_region_size(dma_as->root)); dma_as->root, 0, memory_region_size(dma_as->root));
memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); memory_region_set_enabled(&pci_dev->bus_master_enable_region, false);
address_space_init(&pci_dev->bus_master_as, memory_region_add_subregion(&pci_dev->bus_master_container_region, 0,
&pci_dev->bus_master_enable_region, pci_dev->name); &pci_dev->bus_master_enable_region);
} }
static void pcibus_machine_done(Notifier *notifier, void *data) 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->devfn = devfn;
pci_dev->requester_id_cache = pci_req_id_cache_get(pci_dev); 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) { if (qdev_hotplug) {
pci_init_bus_master(pci_dev); pci_init_bus_master(pci_dev);
} }

View File

@ -1153,7 +1153,7 @@ static AddressSpace *virtio_pci_get_dma_as(DeviceState *d)
VirtIOPCIProxy *proxy = VIRTIO_PCI(d); VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
PCIDevice *dev = &proxy->pci_dev; 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, 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++) { for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
proxy->vqs[i].enabled = 0; 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;
} }
} }

View File

@ -131,6 +131,7 @@ static void virtio_init_region_cache(VirtIODevice *vdev, int n)
VRingMemoryRegionCaches *new; VRingMemoryRegionCaches *new;
hwaddr addr, size; hwaddr addr, size;
int event_size; int event_size;
int64_t len;
event_size = virtio_vdev_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0; 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); new = g_new0(VRingMemoryRegionCaches, 1);
size = virtio_queue_get_desc_size(vdev, n); size = virtio_queue_get_desc_size(vdev, n);
address_space_cache_init(&new->desc, vdev->dma_as, len = address_space_cache_init(&new->desc, vdev->dma_as,
addr, size, false); 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; size = virtio_queue_get_used_size(vdev, n) + event_size;
address_space_cache_init(&new->used, vdev->dma_as, len = address_space_cache_init(&new->used, vdev->dma_as,
vq->vring.used, size, true); 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; size = virtio_queue_get_avail_size(vdev, n) + event_size;
address_space_cache_init(&new->avail, vdev->dma_as, len = address_space_cache_init(&new->avail, vdev->dma_as,
vq->vring.avail, size, false); vq->vring.avail, size, false);
if (len < size) {
virtio_error(vdev, "Cannot map avail");
goto err_avail;
}
atomic_rcu_set(&vq->vring.caches, new); atomic_rcu_set(&vq->vring.caches, new);
if (old) { if (old) {
call_rcu(old, virtio_free_region_cache, rcu); 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 */ /* virt queue functions */
@ -185,10 +206,16 @@ static void vring_desc_read(VirtIODevice *vdev, VRingDesc *desc,
virtio_tswap16s(vdev, &desc->next); 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(). */ /* Called within rcu_read_lock(). */
static inline uint16_t vring_avail_flags(VirtQueue *vq) 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); hwaddr pa = offsetof(VRingAvail, flags);
return virtio_lduw_phys_cached(vq->vdev, &caches->avail, pa); 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(). */ /* Called within rcu_read_lock(). */
static inline uint16_t vring_avail_idx(VirtQueue *vq) 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); hwaddr pa = offsetof(VRingAvail, idx);
vq->shadow_avail_idx = virtio_lduw_phys_cached(vq->vdev, &caches->avail, pa); vq->shadow_avail_idx = virtio_lduw_phys_cached(vq->vdev, &caches->avail, pa);
return vq->shadow_avail_idx; return vq->shadow_avail_idx;
@ -205,7 +232,7 @@ static inline uint16_t vring_avail_idx(VirtQueue *vq)
/* Called within rcu_read_lock(). */ /* Called within rcu_read_lock(). */
static inline uint16_t vring_avail_ring(VirtQueue *vq, int i) 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]); hwaddr pa = offsetof(VRingAvail, ring[i]);
return virtio_lduw_phys_cached(vq->vdev, &caches->avail, pa); 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, static inline void vring_used_write(VirtQueue *vq, VRingUsedElem *uelem,
int i) int i)
{ {
VRingMemoryRegionCaches *caches = atomic_rcu_read(&vq->vring.caches); VRingMemoryRegionCaches *caches = vring_get_region_caches(vq);
hwaddr pa = offsetof(VRingUsed, ring[i]); hwaddr pa = offsetof(VRingUsed, ring[i]);
virtio_tswap32s(vq->vdev, &uelem->id); virtio_tswap32s(vq->vdev, &uelem->id);
virtio_tswap32s(vq->vdev, &uelem->len); 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(). */ /* Called within rcu_read_lock(). */
static uint16_t vring_used_idx(VirtQueue *vq) 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); hwaddr pa = offsetof(VRingUsed, idx);
return virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); 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(). */ /* Called within rcu_read_lock(). */
static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val) 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); hwaddr pa = offsetof(VRingUsed, idx);
virtio_stw_phys_cached(vq->vdev, &caches->used, pa, val); virtio_stw_phys_cached(vq->vdev, &caches->used, pa, val);
address_space_cache_invalidate(&caches->used, pa, sizeof(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(). */ /* Called within rcu_read_lock(). */
static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask) 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; VirtIODevice *vdev = vq->vdev;
hwaddr pa = offsetof(VRingUsed, flags); hwaddr pa = offsetof(VRingUsed, flags);
uint16_t flags = virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); 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(). */ /* Called within rcu_read_lock(). */
static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask) 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; VirtIODevice *vdev = vq->vdev;
hwaddr pa = offsetof(VRingUsed, flags); hwaddr pa = offsetof(VRingUsed, flags);
uint16_t flags = virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); 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; return;
} }
caches = atomic_rcu_read(&vq->vring.caches); caches = vring_get_region_caches(vq);
pa = offsetof(VRingUsed, ring[vq->vring.num]); pa = offsetof(VRingUsed, ring[vq->vring.num]);
virtio_stw_phys_cached(vq->vdev, &caches->used, pa, val); virtio_stw_phys_cached(vq->vdev, &caches->used, pa, val);
address_space_cache_invalidate(&caches->used, pa, sizeof(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(). */ * Called within rcu_read_lock(). */
static int virtio_queue_empty_rcu(VirtQueue *vq) static int virtio_queue_empty_rcu(VirtQueue *vq)
{ {
if (unlikely(!vq->vring.avail)) {
return 1;
}
if (vq->shadow_avail_idx != vq->last_avail_idx) { if (vq->shadow_avail_idx != vq->last_avail_idx) {
return 0; return 0;
} }
@ -329,6 +360,10 @@ int virtio_queue_empty(VirtQueue *vq)
{ {
bool empty; bool empty;
if (unlikely(!vq->vring.avail)) {
return 1;
}
if (vq->shadow_avail_idx != vq->last_avail_idx) { if (vq->shadow_avail_idx != vq->last_avail_idx) {
return 0; return 0;
} }
@ -431,6 +466,10 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
return; return;
} }
if (unlikely(!vq->vring.used)) {
return;
}
idx = (idx + vq->used_idx) % vq->vring.num; idx = (idx + vq->used_idx) % vq->vring.num;
uelem.id = elem->index; uelem.id = elem->index;
@ -448,6 +487,10 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count)
return; return;
} }
if (unlikely(!vq->vring.used)) {
return;
}
/* Make sure buffer is written before we update index. */ /* Make sure buffer is written before we update index. */
smp_wmb(); smp_wmb();
trace_virtqueue_flush(vq, count); trace_virtqueue_flush(vq, count);
@ -546,12 +589,22 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
int64_t len = 0; int64_t len = 0;
int rc; int rc;
if (unlikely(!vq->vring.desc)) {
if (in_bytes) {
*in_bytes = 0;
}
if (out_bytes) {
*out_bytes = 0;
}
return;
}
rcu_read_lock(); rcu_read_lock();
idx = vq->last_avail_idx; idx = vq->last_avail_idx;
total_bufs = in_total = out_total = 0; total_bufs = in_total = out_total = 0;
max = vq->vring.num; max = vq->vring.num;
caches = atomic_rcu_read(&vq->vring.caches); caches = vring_get_region_caches(vq);
if (caches->desc.len < max * sizeof(VRingDesc)) { if (caches->desc.len < max * sizeof(VRingDesc)) {
virtio_error(vdev, "Cannot map descriptor ring"); virtio_error(vdev, "Cannot map descriptor ring");
goto err; goto err;
@ -818,7 +871,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
i = head; i = head;
caches = atomic_rcu_read(&vq->vring.caches); caches = vring_get_region_caches(vq);
if (caches->desc.len < max * sizeof(VRingDesc)) { if (caches->desc.len < max * sizeof(VRingDesc)) {
virtio_error(vdev, "Cannot map descriptor ring"); virtio_error(vdev, "Cannot map descriptor ring");
goto done; 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) void virtio_reset(void *opaque)
{ {
VirtIODevice *vdev = opaque; VirtIODevice *vdev = opaque;
@ -1157,6 +1221,7 @@ void virtio_reset(void *opaque)
vdev->vq[i].notification = true; vdev->vq[i].notification = true;
vdev->vq[i].vring.num = vdev->vq[i].vring.num_default; vdev->vq[i].vring.num = vdev->vq[i].vring.num_default;
vdev->vq[i].inuse = 0; 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++) { for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
VRingMemoryRegionCaches *caches;
if (vdev->vq[i].vring.num == 0) { if (vdev->vq[i].vring.num == 0) {
break; break;
} }
caches = atomic_read(&vdev->vq[i].vring.caches); virtio_virtqueue_reset_region_cache(&vdev->vq[i]);
atomic_set(&vdev->vq[i].vring.caches, NULL);
virtio_free_region_cache(caches);
} }
g_free(vdev->vq); g_free(vdev->vq);
} }

View File

@ -284,6 +284,7 @@ struct PCIDevice {
char name[64]; char name[64];
PCIIORegion io_regions[PCI_NUM_REGIONS]; PCIIORegion io_regions[PCI_NUM_REGIONS];
AddressSpace bus_master_as; AddressSpace bus_master_as;
MemoryRegion bus_master_container_region;
MemoryRegion bus_master_enable_region; MemoryRegion bus_master_enable_region;
/* do not access the following fields */ /* do not access the following fields */