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)
{
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);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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 */