|
|
a83cc2 |
From cdc537ada9528e09f8c70219f5a9a1ce8a4efa7e Mon Sep 17 00:00:00 2001
|
|
|
a83cc2 |
From: Gerd Hoffmann <kraxel@redhat.com>
|
|
|
a83cc2 |
Date: Thu, 6 May 2021 11:10:01 +0200
|
|
|
a83cc2 |
Subject: [PATCH 02/12] virtio-gpu: handle partial maps properly
|
|
|
a83cc2 |
|
|
|
a83cc2 |
RH-Author: Eric Auger <eric.auger@redhat.com>
|
|
|
a83cc2 |
RH-MergeRequest: 15: virtio-gpu: handle partial maps properly
|
|
|
a83cc2 |
RH-Commit: [1/1] f2b0fd9758251d1f3a5ff9563911c8bdb4b191f0 (eauger1/centos-qemu-kvm)
|
|
|
a83cc2 |
RH-Bugzilla: 1974795
|
|
|
a83cc2 |
RH-Acked-by: Gavin Shan <gshan@redhat.com>
|
|
|
a83cc2 |
RH-Acked-by: Andrew Jones <drjones@redhat.com>
|
|
|
a83cc2 |
RH-Acked-by: Peter Xu <Peter Xu <peterx@redhat.com>
|
|
|
a83cc2 |
|
|
|
a83cc2 |
dma_memory_map() may map only a part of the request. Happens if the
|
|
|
a83cc2 |
request can't be mapped in one go, for example due to a iommu creating
|
|
|
a83cc2 |
a linear dma mapping for scattered physical pages. Should that be the
|
|
|
a83cc2 |
case virtio-gpu must call dma_memory_map() again with the remaining
|
|
|
a83cc2 |
range instead of simply throwing an error.
|
|
|
a83cc2 |
|
|
|
a83cc2 |
Note that this change implies the number of iov entries may differ from
|
|
|
a83cc2 |
the number of mapping entries sent by the guest. Therefore the iov_len
|
|
|
a83cc2 |
bookkeeping needs some updates too, we have to explicitly pass around
|
|
|
a83cc2 |
the iov length now.
|
|
|
a83cc2 |
|
|
|
a83cc2 |
Reported-by: Auger Eric <eric.auger@redhat.com>
|
|
|
a83cc2 |
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
|
|
a83cc2 |
Message-id: 20210506091001.1301250-1-kraxel@redhat.com
|
|
|
a83cc2 |
Reviewed-by: Eric Auger <eric.auger@redhat.com>
|
|
|
a83cc2 |
Tested-by: Eric Auger <eric.auger@redhat.com>
|
|
|
a83cc2 |
Message-Id: <20210506091001.1301250-1-kraxel@redhat.com>
|
|
|
a83cc2 |
(cherry picked from commit 9049f8bc445d50c0b5fe5500c0ec51fcc821c2ef)
|
|
|
a83cc2 |
Signed-off-by: Eric Auger <eric.auger@redhat.com>
|
|
|
a83cc2 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
a83cc2 |
---
|
|
|
a83cc2 |
hw/display/virtio-gpu-3d.c | 7 ++--
|
|
|
a83cc2 |
hw/display/virtio-gpu.c | 76 ++++++++++++++++++++--------------
|
|
|
a83cc2 |
include/hw/virtio/virtio-gpu.h | 3 +-
|
|
|
a83cc2 |
3 files changed, 52 insertions(+), 34 deletions(-)
|
|
|
a83cc2 |
|
|
|
a83cc2 |
diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c
|
|
|
a83cc2 |
index d98964858e..72c14d9132 100644
|
|
|
a83cc2 |
--- a/hw/display/virtio-gpu-3d.c
|
|
|
a83cc2 |
+++ b/hw/display/virtio-gpu-3d.c
|
|
|
a83cc2 |
@@ -283,22 +283,23 @@ static void virgl_resource_attach_backing(VirtIOGPU *g,
|
|
|
a83cc2 |
{
|
|
|
a83cc2 |
struct virtio_gpu_resource_attach_backing att_rb;
|
|
|
a83cc2 |
struct iovec *res_iovs;
|
|
|
a83cc2 |
+ uint32_t res_niov;
|
|
|
a83cc2 |
int ret;
|
|
|
a83cc2 |
|
|
|
a83cc2 |
VIRTIO_GPU_FILL_CMD(att_rb);
|
|
|
a83cc2 |
trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
|
|
|
a83cc2 |
|
|
|
a83cc2 |
- ret = virtio_gpu_create_mapping_iov(g, &att_rb, cmd, NULL, &res_iovs);
|
|
|
a83cc2 |
+ ret = virtio_gpu_create_mapping_iov(g, &att_rb, cmd, NULL, &res_iovs, &res_niov);
|
|
|
a83cc2 |
if (ret != 0) {
|
|
|
a83cc2 |
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
|
|
a83cc2 |
return;
|
|
|
a83cc2 |
}
|
|
|
a83cc2 |
|
|
|
a83cc2 |
ret = virgl_renderer_resource_attach_iov(att_rb.resource_id,
|
|
|
a83cc2 |
- res_iovs, att_rb.nr_entries);
|
|
|
a83cc2 |
+ res_iovs, res_niov);
|
|
|
a83cc2 |
|
|
|
a83cc2 |
if (ret != 0)
|
|
|
a83cc2 |
- virtio_gpu_cleanup_mapping_iov(g, res_iovs, att_rb.nr_entries);
|
|
|
a83cc2 |
+ virtio_gpu_cleanup_mapping_iov(g, res_iovs, res_niov);
|
|
|
a83cc2 |
}
|
|
|
a83cc2 |
|
|
|
a83cc2 |
static void virgl_resource_detach_backing(VirtIOGPU *g,
|
|
|
a83cc2 |
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
|
|
|
a83cc2 |
index c9f5e36fd0..6f3791deb3 100644
|
|
|
a83cc2 |
--- a/hw/display/virtio-gpu.c
|
|
|
a83cc2 |
+++ b/hw/display/virtio-gpu.c
|
|
|
a83cc2 |
@@ -608,11 +608,12 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
|
|
|
a83cc2 |
int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
|
|
|
a83cc2 |
struct virtio_gpu_resource_attach_backing *ab,
|
|
|
a83cc2 |
struct virtio_gpu_ctrl_command *cmd,
|
|
|
a83cc2 |
- uint64_t **addr, struct iovec **iov)
|
|
|
a83cc2 |
+ uint64_t **addr, struct iovec **iov,
|
|
|
a83cc2 |
+ uint32_t *niov)
|
|
|
a83cc2 |
{
|
|
|
a83cc2 |
struct virtio_gpu_mem_entry *ents;
|
|
|
a83cc2 |
size_t esize, s;
|
|
|
a83cc2 |
- int i;
|
|
|
a83cc2 |
+ int e, v;
|
|
|
a83cc2 |
|
|
|
a83cc2 |
if (ab->nr_entries > 16384) {
|
|
|
a83cc2 |
qemu_log_mask(LOG_GUEST_ERROR,
|
|
|
a83cc2 |
@@ -633,37 +634,53 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
|
|
|
a83cc2 |
return -1;
|
|
|
a83cc2 |
}
|
|
|
a83cc2 |
|
|
|
a83cc2 |
- *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries);
|
|
|
a83cc2 |
+ *iov = NULL;
|
|
|
a83cc2 |
if (addr) {
|
|
|
a83cc2 |
- *addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries);
|
|
|
a83cc2 |
+ *addr = NULL;
|
|
|
a83cc2 |
}
|
|
|
a83cc2 |
- for (i = 0; i < ab->nr_entries; i++) {
|
|
|
a83cc2 |
- uint64_t a = le64_to_cpu(ents[i].addr);
|
|
|
a83cc2 |
- uint32_t l = le32_to_cpu(ents[i].length);
|
|
|
a83cc2 |
- hwaddr len = l;
|
|
|
a83cc2 |
- (*iov)[i].iov_base = dma_memory_map(VIRTIO_DEVICE(g)->dma_as,
|
|
|
a83cc2 |
- a, &len, DMA_DIRECTION_TO_DEVICE);
|
|
|
a83cc2 |
- (*iov)[i].iov_len = len;
|
|
|
a83cc2 |
- if (addr) {
|
|
|
a83cc2 |
- (*addr)[i] = a;
|
|
|
a83cc2 |
- }
|
|
|
a83cc2 |
- if (!(*iov)[i].iov_base || len != l) {
|
|
|
a83cc2 |
- qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
|
|
|
a83cc2 |
- " resource %d element %d\n",
|
|
|
a83cc2 |
- __func__, ab->resource_id, i);
|
|
|
a83cc2 |
- if ((*iov)[i].iov_base) {
|
|
|
a83cc2 |
- i++; /* cleanup the 'i'th map */
|
|
|
a83cc2 |
+ for (e = 0, v = 0; e < ab->nr_entries; e++) {
|
|
|
a83cc2 |
+ uint64_t a = le64_to_cpu(ents[e].addr);
|
|
|
a83cc2 |
+ uint32_t l = le32_to_cpu(ents[e].length);
|
|
|
a83cc2 |
+ hwaddr len;
|
|
|
a83cc2 |
+ void *map;
|
|
|
a83cc2 |
+
|
|
|
a83cc2 |
+ do {
|
|
|
a83cc2 |
+ len = l;
|
|
|
a83cc2 |
+ map = dma_memory_map(VIRTIO_DEVICE(g)->dma_as,
|
|
|
a83cc2 |
+ a, &len, DMA_DIRECTION_TO_DEVICE);
|
|
|
a83cc2 |
+ if (!map) {
|
|
|
a83cc2 |
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
|
|
|
a83cc2 |
+ " resource %d element %d\n",
|
|
|
a83cc2 |
+ __func__, ab->resource_id, e);
|
|
|
a83cc2 |
+ virtio_gpu_cleanup_mapping_iov(g, *iov, v);
|
|
|
a83cc2 |
+ g_free(ents);
|
|
|
a83cc2 |
+ *iov = NULL;
|
|
|
a83cc2 |
+ if (addr) {
|
|
|
a83cc2 |
+ g_free(*addr);
|
|
|
a83cc2 |
+ *addr = NULL;
|
|
|
a83cc2 |
+ }
|
|
|
a83cc2 |
+ return -1;
|
|
|
a83cc2 |
+ }
|
|
|
a83cc2 |
+
|
|
|
a83cc2 |
+ if (!(v % 16)) {
|
|
|
a83cc2 |
+ *iov = g_realloc(*iov, sizeof(struct iovec) * (v + 16));
|
|
|
a83cc2 |
+ if (addr) {
|
|
|
a83cc2 |
+ *addr = g_realloc(*addr, sizeof(uint64_t) * (v + 16));
|
|
|
a83cc2 |
+ }
|
|
|
a83cc2 |
}
|
|
|
a83cc2 |
- virtio_gpu_cleanup_mapping_iov(g, *iov, i);
|
|
|
a83cc2 |
- g_free(ents);
|
|
|
a83cc2 |
- *iov = NULL;
|
|
|
a83cc2 |
+ (*iov)[v].iov_base = map;
|
|
|
a83cc2 |
+ (*iov)[v].iov_len = len;
|
|
|
a83cc2 |
if (addr) {
|
|
|
a83cc2 |
- g_free(*addr);
|
|
|
a83cc2 |
- *addr = NULL;
|
|
|
a83cc2 |
+ (*addr)[v] = a;
|
|
|
a83cc2 |
}
|
|
|
a83cc2 |
- return -1;
|
|
|
a83cc2 |
- }
|
|
|
a83cc2 |
+
|
|
|
a83cc2 |
+ a += len;
|
|
|
a83cc2 |
+ l -= len;
|
|
|
a83cc2 |
+ v += 1;
|
|
|
a83cc2 |
+ } while (l > 0);
|
|
|
a83cc2 |
}
|
|
|
a83cc2 |
+ *niov = v;
|
|
|
a83cc2 |
+
|
|
|
a83cc2 |
g_free(ents);
|
|
|
a83cc2 |
return 0;
|
|
|
a83cc2 |
}
|
|
|
a83cc2 |
@@ -717,13 +734,12 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g,
|
|
|
a83cc2 |
return;
|
|
|
a83cc2 |
}
|
|
|
a83cc2 |
|
|
|
a83cc2 |
- ret = virtio_gpu_create_mapping_iov(g, &ab, cmd, &res->addrs, &res->iov);
|
|
|
a83cc2 |
+ ret = virtio_gpu_create_mapping_iov(g, &ab, cmd, &res->addrs,
|
|
|
a83cc2 |
+ &res->iov, &res->iov_cnt);
|
|
|
a83cc2 |
if (ret != 0) {
|
|
|
a83cc2 |
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
|
|
a83cc2 |
return;
|
|
|
a83cc2 |
}
|
|
|
a83cc2 |
-
|
|
|
a83cc2 |
- res->iov_cnt = ab.nr_entries;
|
|
|
a83cc2 |
}
|
|
|
a83cc2 |
|
|
|
a83cc2 |
static void
|
|
|
a83cc2 |
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
|
|
|
a83cc2 |
index fae149235c..0d15af41d9 100644
|
|
|
a83cc2 |
--- a/include/hw/virtio/virtio-gpu.h
|
|
|
a83cc2 |
+++ b/include/hw/virtio/virtio-gpu.h
|
|
|
a83cc2 |
@@ -209,7 +209,8 @@ void virtio_gpu_get_edid(VirtIOGPU *g,
|
|
|
a83cc2 |
int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
|
|
|
a83cc2 |
struct virtio_gpu_resource_attach_backing *ab,
|
|
|
a83cc2 |
struct virtio_gpu_ctrl_command *cmd,
|
|
|
a83cc2 |
- uint64_t **addr, struct iovec **iov);
|
|
|
a83cc2 |
+ uint64_t **addr, struct iovec **iov,
|
|
|
a83cc2 |
+ uint32_t *niov);
|
|
|
a83cc2 |
void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g,
|
|
|
a83cc2 |
struct iovec *iov, uint32_t count);
|
|
|
a83cc2 |
void virtio_gpu_process_cmdq(VirtIOGPU *g);
|
|
|
a83cc2 |
--
|
|
|
a83cc2 |
2.27.0
|
|
|
a83cc2 |
|