From 0793169870f376bc9959b7d81df48ab4a90dcceb Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 9 Feb 2017 16:40:47 +0800 Subject: virtio: Report real progress in VQ aio poll handler In virtio_queue_host_notifier_aio_poll, not all "!virtio_queue_empty()" cases are making true progress. Currently the offending one is virtio-scsi event queue, whose handler does nothing if no event is pending. As a result aio_poll() will spin on the "non-empty" VQ and take 100% host CPU. Fix this by reporting actual progress from virtio queue aio handlers. Reported-by: Ed Swierk Signed-off-by: Fam Zheng Tested-by: Ed Swierk Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/hw/virtio/virtio-blk.h | 2 +- include/hw/virtio/virtio-scsi.h | 6 +++--- include/hw/virtio/virtio.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 9734b4c446..d3c8a6fa8c 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -80,6 +80,6 @@ typedef struct MultiReqBuffer { bool is_write; } MultiReqBuffer; -void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq); +bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq); #endif diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 73751969ba..f536f77e68 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -126,9 +126,9 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, VirtIOHandleOutput cmd); void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); -void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq); -void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq); -void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq); +bool virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq); +bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq); +bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq); void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req); void virtio_scsi_free_req(VirtIOSCSIReq *req); void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 525da24222..0863a254ba 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -154,6 +154,7 @@ void virtio_error(VirtIODevice *vdev, const char *fmt, ...) GCC_FMT_ATTR(2, 3); void virtio_device_set_child_bus_name(VirtIODevice *vdev, char *bus_name); typedef void (*VirtIOHandleOutput)(VirtIODevice *, VirtQueue *); +typedef bool (*VirtIOHandleAIOOutput)(VirtIODevice *, VirtQueue *); VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, VirtIOHandleOutput handle_output); @@ -284,8 +285,7 @@ bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev); EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq); void virtio_queue_host_notifier_read(EventNotifier *n); void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, - void (*fn)(VirtIODevice *, - VirtQueue *)); + VirtIOHandleAIOOutput handle_output); VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector); VirtQueue *virtio_vector_next_queue(VirtQueue *vq); -- cgit v1.2.3-55-g7522 From e6a830d6eba6ed116a0b4ef5577ca0b46edf4c67 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 Jan 2017 16:40:13 +0100 Subject: virtio: add virtio_*_phys_cached Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/hw/virtio/virtio-access.h | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'include') diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h index 91ae14d254..2e92074bd1 100644 --- a/include/hw/virtio/virtio-access.h +++ b/include/hw/virtio/virtio-access.h @@ -156,6 +156,58 @@ static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s) #endif } +static inline uint16_t virtio_lduw_phys_cached(VirtIODevice *vdev, + MemoryRegionCache *cache, + hwaddr pa) +{ + if (virtio_access_is_big_endian(vdev)) { + return lduw_be_phys_cached(cache, pa); + } + return lduw_le_phys_cached(cache, pa); +} + +static inline uint32_t virtio_ldl_phys_cached(VirtIODevice *vdev, + MemoryRegionCache *cache, + hwaddr pa) +{ + if (virtio_access_is_big_endian(vdev)) { + return ldl_be_phys_cached(cache, pa); + } + return ldl_le_phys_cached(cache, pa); +} + +static inline uint64_t virtio_ldq_phys_cached(VirtIODevice *vdev, + MemoryRegionCache *cache, + hwaddr pa) +{ + if (virtio_access_is_big_endian(vdev)) { + return ldq_be_phys_cached(cache, pa); + } + return ldq_le_phys_cached(cache, pa); +} + +static inline void virtio_stw_phys_cached(VirtIODevice *vdev, + MemoryRegionCache *cache, + hwaddr pa, uint16_t value) +{ + if (virtio_access_is_big_endian(vdev)) { + stw_be_phys_cached(cache, pa, value); + } else { + stw_le_phys_cached(cache, pa, value); + } +} + +static inline void virtio_stl_phys_cached(VirtIODevice *vdev, + MemoryRegionCache *cache, + hwaddr pa, uint32_t value) +{ + if (virtio_access_is_big_endian(vdev)) { + stl_be_phys_cached(cache, pa, value); + } else { + stl_le_phys_cached(cache, pa, value); + } +} + static inline void virtio_tswap16s(VirtIODevice *vdev, uint16_t *s) { *s = virtio_tswap16(vdev, *s); -- cgit v1.2.3-55-g7522 From 5eba0404b98294906134c06519c272bfb5f50453 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 Jan 2017 16:40:16 +0100 Subject: virtio: use MemoryRegionCache to access descriptors For now, the cache is created on every virtqueue_pop. Later on, direct descriptors will be able to reuse it. Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 80 +++++++++++++++++++++++++-------------------------- include/exec/memory.h | 2 ++ 2 files changed, 41 insertions(+), 41 deletions(-) (limited to 'include') diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 6ce6a26908..71e41f66b1 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -120,9 +120,10 @@ void virtio_queue_update_rings(VirtIODevice *vdev, int n) } static void vring_desc_read(VirtIODevice *vdev, VRingDesc *desc, - uint8_t *desc_ptr, int i) + MemoryRegionCache *cache, int i) { - memcpy(desc, desc_ptr + i * sizeof(VRingDesc), sizeof(VRingDesc)); + address_space_read_cached(cache, i * sizeof(VRingDesc), + desc, sizeof(VRingDesc)); virtio_tswap64s(vdev, &desc->addr); virtio_tswap32s(vdev, &desc->len); virtio_tswap16s(vdev, &desc->flags); @@ -407,7 +408,7 @@ enum { }; static int virtqueue_read_next_desc(VirtIODevice *vdev, VRingDesc *desc, - void *desc_ptr, unsigned int max, + MemoryRegionCache *desc_cache, unsigned int max, unsigned int *next) { /* If this descriptor says it doesn't chain, we're done. */ @@ -425,7 +426,7 @@ static int virtqueue_read_next_desc(VirtIODevice *vdev, VRingDesc *desc, return VIRTQUEUE_READ_DESC_ERROR; } - vring_desc_read(vdev, desc, desc_ptr, *next); + vring_desc_read(vdev, desc, desc_cache, *next); return VIRTQUEUE_READ_DESC_MORE; } @@ -436,24 +437,25 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, VirtIODevice *vdev = vq->vdev; unsigned int max, idx; unsigned int total_bufs, in_total, out_total; - void *vring_desc_ptr; - void *indirect_desc_ptr = NULL; - hwaddr len = 0; + MemoryRegionCache vring_desc_cache; + MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID; + int64_t len = 0; int rc; idx = vq->last_avail_idx; total_bufs = in_total = out_total = 0; max = vq->vring.num; - len = max * sizeof(VRingDesc); - vring_desc_ptr = address_space_map(vdev->dma_as, vq->vring.desc, &len, false); + len = address_space_cache_init(&vring_desc_cache, vdev->dma_as, + vq->vring.desc, max * sizeof(VRingDesc), + false); if (len < max * sizeof(VRingDesc)) { virtio_error(vdev, "Cannot map descriptor ring"); goto err; } while ((rc = virtqueue_num_heads(vq, idx)) > 0) { - void *desc_ptr = vring_desc_ptr; + MemoryRegionCache *desc_cache = &vring_desc_cache; unsigned int num_bufs; VRingDesc desc; unsigned int i; @@ -464,10 +466,9 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, goto err; } - vring_desc_read(vdev, &desc, desc_ptr, i); + vring_desc_read(vdev, &desc, desc_cache, i); if (desc.flags & VRING_DESC_F_INDIRECT) { - len = desc.len; if (desc.len % sizeof(VRingDesc)) { virtio_error(vdev, "Invalid size for indirect buffer table"); goto err; @@ -480,9 +481,10 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, } /* loop over the indirect descriptor table */ - indirect_desc_ptr = address_space_map(vdev->dma_as, desc.addr, - &len, false); - desc_ptr = indirect_desc_ptr; + len = address_space_cache_init(&indirect_desc_cache, + vdev->dma_as, + desc.addr, desc.len, false); + desc_cache = &indirect_desc_cache; if (len < desc.len) { virtio_error(vdev, "Cannot map indirect buffer"); goto err; @@ -490,7 +492,7 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, max = desc.len / sizeof(VRingDesc); num_bufs = i = 0; - vring_desc_read(vdev, &desc, desc_ptr, i); + vring_desc_read(vdev, &desc, desc_cache, i); } do { @@ -509,16 +511,15 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, goto done; } - rc = virtqueue_read_next_desc(vdev, &desc, desc_ptr, max, &i); + rc = virtqueue_read_next_desc(vdev, &desc, desc_cache, max, &i); } while (rc == VIRTQUEUE_READ_DESC_MORE); if (rc == VIRTQUEUE_READ_DESC_ERROR) { goto err; } - if (desc_ptr == indirect_desc_ptr) { - address_space_unmap(vdev->dma_as, desc_ptr, len, false, 0); - indirect_desc_ptr = NULL; + if (desc_cache == &indirect_desc_cache) { + address_space_cache_destroy(&indirect_desc_cache); total_bufs++; } else { total_bufs = num_bufs; @@ -530,10 +531,8 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, } done: - if (indirect_desc_ptr) { - address_space_unmap(vdev->dma_as, indirect_desc_ptr, len, false, 0); - } - address_space_unmap(vdev->dma_as, vring_desc_ptr, len, false, 0); + address_space_cache_destroy(&indirect_desc_cache); + address_space_cache_destroy(&vring_desc_cache); if (in_bytes) { *in_bytes = in_total; } @@ -673,10 +672,10 @@ static void *virtqueue_alloc_element(size_t sz, unsigned out_num, unsigned in_nu void *virtqueue_pop(VirtQueue *vq, size_t sz) { unsigned int i, head, max; - void *vring_desc_ptr; - void *indirect_desc_ptr = NULL; - void *desc_ptr; - hwaddr len; + MemoryRegionCache vring_desc_cache; + MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID; + MemoryRegionCache *desc_cache; + int64_t len; VirtIODevice *vdev = vq->vdev; VirtQueueElement *elem = NULL; unsigned out_num, in_num; @@ -715,15 +714,16 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) i = head; - len = max * sizeof(VRingDesc); - vring_desc_ptr = address_space_map(vdev->dma_as, vq->vring.desc, &len, false); + len = address_space_cache_init(&vring_desc_cache, vdev->dma_as, + vq->vring.desc, max * sizeof(VRingDesc), + false); if (len < max * sizeof(VRingDesc)) { virtio_error(vdev, "Cannot map descriptor ring"); goto done; } - desc_ptr = vring_desc_ptr; - vring_desc_read(vdev, &desc, desc_ptr, i); + desc_cache = &vring_desc_cache; + vring_desc_read(vdev, &desc, desc_cache, i); if (desc.flags & VRING_DESC_F_INDIRECT) { if (desc.len % sizeof(VRingDesc)) { virtio_error(vdev, "Invalid size for indirect buffer table"); @@ -731,9 +731,9 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) } /* loop over the indirect descriptor table */ - len = desc.len; - indirect_desc_ptr = address_space_map(vdev->dma_as, desc.addr, &len, false); - desc_ptr = indirect_desc_ptr; + len = address_space_cache_init(&indirect_desc_cache, vdev->dma_as, + desc.addr, desc.len, false); + desc_cache = &indirect_desc_cache; if (len < desc.len) { virtio_error(vdev, "Cannot map indirect buffer"); goto done; @@ -741,7 +741,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) max = desc.len / sizeof(VRingDesc); i = 0; - vring_desc_read(vdev, &desc, desc_ptr, i); + vring_desc_read(vdev, &desc, desc_cache, i); } /* Collect all the descriptors */ @@ -772,7 +772,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) goto err_undo_map; } - rc = virtqueue_read_next_desc(vdev, &desc, desc_ptr, max, &i); + rc = virtqueue_read_next_desc(vdev, &desc, desc_cache, max, &i); } while (rc == VIRTQUEUE_READ_DESC_MORE); if (rc == VIRTQUEUE_READ_DESC_ERROR) { @@ -795,10 +795,8 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num); done: - if (indirect_desc_ptr) { - address_space_unmap(vdev->dma_as, indirect_desc_ptr, len, false, 0); - } - address_space_unmap(vdev->dma_as, vring_desc_ptr, len, false, 0); + address_space_cache_destroy(&indirect_desc_cache); + address_space_cache_destroy(&vring_desc_cache); return elem; diff --git a/include/exec/memory.h b/include/exec/memory.h index 987f9251c6..691102317c 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1426,6 +1426,8 @@ struct MemoryRegionCache { bool is_write; }; +#define MEMORY_REGION_CACHE_INVALID ((MemoryRegionCache) { .mr = NULL }) + /* address_space_cache_init: prepare for repeated access to a physical * memory region * -- cgit v1.2.3-55-g7522 From c611c76417f52b335ecaab01c61743e3b705eb7c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 27 Jan 2017 16:40:17 +0100 Subject: virtio: add MemoryListener to cache ring translations The cached translations are RCU-protected to allow efficient use when processing virtqueues. Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 105 +++++++++++++++++++++++++++++++++++++++++++-- include/hw/virtio/virtio.h | 1 + 2 files changed, 103 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 71e41f66b1..b75cb52fcc 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -60,6 +60,13 @@ typedef struct VRingUsed VRingUsedElem ring[0]; } VRingUsed; +typedef struct VRingMemoryRegionCaches { + struct rcu_head rcu; + MemoryRegionCache desc; + MemoryRegionCache avail; + MemoryRegionCache used; +} VRingMemoryRegionCaches; + typedef struct VRing { unsigned int num; @@ -68,6 +75,7 @@ typedef struct VRing hwaddr desc; hwaddr avail; hwaddr used; + VRingMemoryRegionCaches *caches; } VRing; struct VirtQueue @@ -104,6 +112,51 @@ struct VirtQueue QLIST_ENTRY(VirtQueue) node; }; +static void virtio_free_region_cache(VRingMemoryRegionCaches *caches) +{ + if (!caches) { + return; + } + + address_space_cache_destroy(&caches->desc); + address_space_cache_destroy(&caches->avail); + address_space_cache_destroy(&caches->used); + g_free(caches); +} + +static void virtio_init_region_cache(VirtIODevice *vdev, int n) +{ + VirtQueue *vq = &vdev->vq[n]; + VRingMemoryRegionCaches *old = vq->vring.caches; + VRingMemoryRegionCaches *new; + hwaddr addr, size; + int event_size; + + event_size = virtio_vdev_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0; + + addr = vq->vring.desc; + if (!addr) { + return; + } + 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); + + size = virtio_queue_get_used_size(vdev, n) + event_size; + address_space_cache_init(&new->used, vdev->dma_as, + vq->vring.used, size, true); + + size = virtio_queue_get_avail_size(vdev, n) + event_size; + address_space_cache_init(&new->avail, vdev->dma_as, + vq->vring.avail, size, false); + + atomic_rcu_set(&vq->vring.caches, new); + if (old) { + call_rcu(old, virtio_free_region_cache, rcu); + } +} + /* virt queue functions */ void virtio_queue_update_rings(VirtIODevice *vdev, int n) { @@ -117,6 +170,7 @@ void virtio_queue_update_rings(VirtIODevice *vdev, int n) vring->used = vring_align(vring->avail + offsetof(VRingAvail, ring[vring->num]), vring->align); + virtio_init_region_cache(vdev, n); } static void vring_desc_read(VirtIODevice *vdev, VRingDesc *desc, @@ -1264,6 +1318,7 @@ void virtio_queue_set_rings(VirtIODevice *vdev, int n, hwaddr desc, vdev->vq[n].vring.desc = desc; vdev->vq[n].vring.avail = avail; vdev->vq[n].vring.used = used; + virtio_init_region_cache(vdev, n); } void virtio_queue_set_num(VirtIODevice *vdev, int n, int num) @@ -1984,9 +2039,6 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) void virtio_cleanup(VirtIODevice *vdev) { qemu_del_vm_change_state_handler(vdev->vmstate); - g_free(vdev->config); - g_free(vdev->vq); - g_free(vdev->vector_queues); } static void virtio_vmstate_change(void *opaque, int running, RunState state) @@ -2248,6 +2300,19 @@ void GCC_FMT_ATTR(2, 3) virtio_error(VirtIODevice *vdev, const char *fmt, ...) } } +static void virtio_memory_listener_commit(MemoryListener *listener) +{ + VirtIODevice *vdev = container_of(listener, VirtIODevice, listener); + int i; + + for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { + if (vdev->vq[i].vring.num == 0) { + break; + } + virtio_init_region_cache(vdev, i); + } +} + static void virtio_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); @@ -2270,6 +2335,9 @@ static void virtio_device_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } + + vdev->listener.commit = virtio_memory_listener_commit; + memory_listener_register(&vdev->listener, vdev->dma_as); } static void virtio_device_unrealize(DeviceState *dev, Error **errp) @@ -2292,6 +2360,36 @@ static void virtio_device_unrealize(DeviceState *dev, Error **errp) vdev->bus_name = NULL; } +static void virtio_device_free_virtqueues(VirtIODevice *vdev) +{ + int i; + if (!vdev->vq) { + return; + } + + 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); + } + g_free(vdev->vq); +} + +static void virtio_device_instance_finalize(Object *obj) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(obj); + + memory_listener_unregister(&vdev->listener); + virtio_device_free_virtqueues(vdev); + + g_free(vdev->config); + g_free(vdev->vector_queues); +} + static Property virtio_properties[] = { DEFINE_VIRTIO_COMMON_FEATURES(VirtIODevice, host_features), DEFINE_PROP_END_OF_LIST(), @@ -2418,6 +2516,7 @@ static const TypeInfo virtio_device_info = { .parent = TYPE_DEVICE, .instance_size = sizeof(VirtIODevice), .class_init = virtio_device_class_init, + .instance_finalize = virtio_device_instance_finalize, .abstract = true, .class_size = sizeof(VirtioDeviceClass), }; diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 0863a254ba..15efcf2057 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -85,6 +85,7 @@ struct VirtIODevice uint32_t generation; int nvectors; VirtQueue *vq; + MemoryListener listener; uint16_t device_id; bool vm_running; bool broken; /* device in invalid state, needs reset */ -- cgit v1.2.3-55-g7522 From 3b40f0e53c2ebfcec8aabab7e91c11c5bd441ac0 Mon Sep 17 00:00:00 2001 From: Aviv Ben-David Date: Tue, 7 Feb 2017 16:28:06 +0800 Subject: intel_iommu: add "caching-mode" option This capability asks the guest to invalidate cache before each map operation. We can use this invalidation to trap map operations in the hypervisor. Signed-off-by: Aviv Ben-David [peterx: using "caching-mode" instead of "cache-mode" to align with spec] [peterx: re-write the subject to make it short and clear] Reviewed-by: Jason Wang Signed-off-by: Peter Xu Signed-off-by: Aviv Ben-David Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 5 +++++ hw/i386/intel_iommu_internal.h | 1 + include/hw/i386/intel_iommu.h | 2 ++ 3 files changed, 8 insertions(+) (limited to 'include') diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 3270fb9162..50251c3090 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2115,6 +2115,7 @@ static Property vtd_properties[] = { DEFINE_PROP_ON_OFF_AUTO("eim", IntelIOMMUState, intr_eim, ON_OFF_AUTO_AUTO), DEFINE_PROP_BOOL("x-buggy-eim", IntelIOMMUState, buggy_eim, false), + DEFINE_PROP_BOOL("caching-mode", IntelIOMMUState, caching_mode, FALSE), DEFINE_PROP_END_OF_LIST(), }; @@ -2496,6 +2497,10 @@ static void vtd_init(IntelIOMMUState *s) s->ecap |= VTD_ECAP_DT; } + if (s->caching_mode) { + s->cap |= VTD_CAP_CM; + } + vtd_reset_context_cache(s); vtd_reset_iotlb(s); diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 356f188b73..41041219ba 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -202,6 +202,7 @@ #define VTD_CAP_MAMV (VTD_MAMV << 48) #define VTD_CAP_PSI (1ULL << 39) #define VTD_CAP_SLLPS ((1ULL << 34) | (1ULL << 35)) +#define VTD_CAP_CM (1ULL << 7) /* Supported Adjusted Guest Address Widths */ #define VTD_CAP_SAGAW_SHIFT 8 diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 405c9d122e..fe645aa93a 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -257,6 +257,8 @@ struct IntelIOMMUState { uint8_t womask[DMAR_REG_SIZE]; /* WO (write only - read returns 0) */ uint32_t version; + bool caching_mode; /* RO - is cap CM enabled? */ + dma_addr_t root; /* Current root table pointer */ bool root_extended; /* Type of root table (extended or not) */ bool dmar_enabled; /* Set if DMA remapping is enabled */ -- cgit v1.2.3-55-g7522