From 8607f5c3072caeebbe0217df28651fffd3a79fd9 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 30 Dec 2016 18:09:10 +0800 Subject: virtio: convert to use DMA api Currently, all virtio devices bypass IOMMU completely. This is because address_space_memory is assumed and used during DMA emulation. This patch converts the virtio core API to use DMA API. This idea is - introducing a new transport specific helper to query the dma address space. (only pci version is implemented). - query and use this address space during virtio device guest memory accessing when iommu platform (VIRTIO_F_IOMMU_PLATFORM) was enabled for this device. Cc: Michael S. Tsirkin Cc: Stefan Hajnoczi Cc: Kevin Wolf Cc: Amit Shah Cc: Paolo Bonzini Cc: qemu-block@nongnu.org Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/hw/virtio/virtio-access.h | 31 +++++++++++++++++++++---------- include/hw/virtio/virtio-bus.h | 1 + include/hw/virtio/virtio.h | 9 ++++++--- 3 files changed, 28 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h index 440b4555ea..91ae14d254 100644 --- a/include/hw/virtio/virtio-access.h +++ b/include/hw/virtio/virtio-access.h @@ -17,6 +17,7 @@ #define QEMU_VIRTIO_ACCESS_H #include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-bus.h" #include "exec/address-spaces.h" #if defined(TARGET_PPC64) || defined(TARGET_ARM) @@ -40,45 +41,55 @@ static inline bool virtio_access_is_big_endian(VirtIODevice *vdev) static inline uint16_t virtio_lduw_phys(VirtIODevice *vdev, hwaddr pa) { + AddressSpace *dma_as = vdev->dma_as; + if (virtio_access_is_big_endian(vdev)) { - return lduw_be_phys(&address_space_memory, pa); + return lduw_be_phys(dma_as, pa); } - return lduw_le_phys(&address_space_memory, pa); + return lduw_le_phys(dma_as, pa); } static inline uint32_t virtio_ldl_phys(VirtIODevice *vdev, hwaddr pa) { + AddressSpace *dma_as = vdev->dma_as; + if (virtio_access_is_big_endian(vdev)) { - return ldl_be_phys(&address_space_memory, pa); + return ldl_be_phys(dma_as, pa); } - return ldl_le_phys(&address_space_memory, pa); + return ldl_le_phys(dma_as, pa); } static inline uint64_t virtio_ldq_phys(VirtIODevice *vdev, hwaddr pa) { + AddressSpace *dma_as = vdev->dma_as; + if (virtio_access_is_big_endian(vdev)) { - return ldq_be_phys(&address_space_memory, pa); + return ldq_be_phys(dma_as, pa); } - return ldq_le_phys(&address_space_memory, pa); + return ldq_le_phys(dma_as, pa); } static inline void virtio_stw_phys(VirtIODevice *vdev, hwaddr pa, uint16_t value) { + AddressSpace *dma_as = vdev->dma_as; + if (virtio_access_is_big_endian(vdev)) { - stw_be_phys(&address_space_memory, pa, value); + stw_be_phys(dma_as, pa, value); } else { - stw_le_phys(&address_space_memory, pa, value); + stw_le_phys(dma_as, pa, value); } } static inline void virtio_stl_phys(VirtIODevice *vdev, hwaddr pa, uint32_t value) { + AddressSpace *dma_as = vdev->dma_as; + if (virtio_access_is_big_endian(vdev)) { - stl_be_phys(&address_space_memory, pa, value); + stl_be_phys(dma_as, pa, value); } else { - stl_le_phys(&address_space_memory, pa, value); + stl_le_phys(dma_as, pa, value); } } diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h index 8a51e2c564..a63c1d216d 100644 --- a/include/hw/virtio/virtio-bus.h +++ b/include/hw/virtio/virtio-bus.h @@ -88,6 +88,7 @@ typedef struct VirtioBusClass { * Note that changing this will break migration for this transport. */ bool has_variable_vring_alignment; + AddressSpace *(*get_dma_as)(DeviceState *d); } VirtioBusClass; struct VirtioBusState { diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index ab0e030cc4..5e4176f94c 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -92,6 +92,7 @@ struct VirtIODevice char *bus_name; uint8_t device_endian; bool use_guest_notifier_mask; + AddressSpace *dma_as; QLIST_HEAD(, VirtQueue) *vector_queues; }; @@ -170,9 +171,9 @@ bool virtqueue_rewind(VirtQueue *vq, unsigned int num); void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len, unsigned int idx); -void virtqueue_map(VirtQueueElement *elem); +void virtqueue_map(VirtIODevice *vdev, VirtQueueElement *elem); void *virtqueue_pop(VirtQueue *vq, size_t sz); -void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz); +void *qemu_get_virtqueue_element(VirtIODevice *vdev, QEMUFile *f, size_t sz); void qemu_put_virtqueue_element(QEMUFile *f, VirtQueueElement *elem); int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, unsigned int out_bytes); @@ -255,7 +256,9 @@ typedef struct VirtIORNGConf VirtIORNGConf; DEFINE_PROP_BIT64("notify_on_empty", _state, _field, \ VIRTIO_F_NOTIFY_ON_EMPTY, true), \ DEFINE_PROP_BIT64("any_layout", _state, _field, \ - VIRTIO_F_ANY_LAYOUT, true) + VIRTIO_F_ANY_LAYOUT, true), \ + DEFINE_PROP_BIT64("iommu_platform", _state, _field, \ + VIRTIO_F_IOMMU_PLATFORM, false) hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n); hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n); -- cgit v1.2.3-55-g7522