qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] virtio-gpu: handle partial maps properly


From: Auger Eric
Subject: Re: [PATCH] virtio-gpu: handle partial maps properly
Date: Thu, 6 May 2021 13:54:04 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.8.0

Hi Gerd,

On 5/6/21 11:10 AM, Gerd Hoffmann wrote:
> dma_memory_map() may map only a part of the request.  Happens if the
> request can't be mapped in one go, for example due to a iommu creating
> a linear dma mapping for scattered physical pages.  Should that be the
> case virtio-gpu must call dma_memory_map() again with the remaining
> range instead of simply throwing an error.
> 
> Note that this change implies the number of iov entries may differ from
> the number of mapping entries sent by the guest.  Therefore the iov_len
> bookkeeping needs some updates too, we have to explicitly pass around
> the iov length now.
> 
> Reported-by: Auger Eric <eric.auger@redhat.com>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  include/hw/virtio/virtio-gpu.h |  3 +-
>  hw/display/virtio-gpu-3d.c     |  7 ++--
>  hw/display/virtio-gpu.c        | 75 ++++++++++++++++++++--------------
>  3 files changed, 51 insertions(+), 34 deletions(-)
> 
> diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
> index fae149235c58..0d15af41d96d 100644
> --- a/include/hw/virtio/virtio-gpu.h
> +++ b/include/hw/virtio/virtio-gpu.h
> @@ -209,7 +209,8 @@ void virtio_gpu_get_edid(VirtIOGPU *g,
>  int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
>                                    struct virtio_gpu_resource_attach_backing 
> *ab,
>                                    struct virtio_gpu_ctrl_command *cmd,
> -                                  uint64_t **addr, struct iovec **iov);
> +                                  uint64_t **addr, struct iovec **iov,
> +                                  uint32_t *niov);
>  void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g,
>                                      struct iovec *iov, uint32_t count);
>  void virtio_gpu_process_cmdq(VirtIOGPU *g);
> diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c
> index d98964858e13..72c14d91324b 100644
> --- a/hw/display/virtio-gpu-3d.c
> +++ b/hw/display/virtio-gpu-3d.c
> @@ -283,22 +283,23 @@ static void virgl_resource_attach_backing(VirtIOGPU *g,
>  {
>      struct virtio_gpu_resource_attach_backing att_rb;
>      struct iovec *res_iovs;
> +    uint32_t res_niov;
>      int ret;
>  
>      VIRTIO_GPU_FILL_CMD(att_rb);
>      trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
>  
> -    ret = virtio_gpu_create_mapping_iov(g, &att_rb, cmd, NULL, &res_iovs);
> +    ret = virtio_gpu_create_mapping_iov(g, &att_rb, cmd, NULL, &res_iovs, 
> &res_niov);
>      if (ret != 0) {
>          cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
>          return;
>      }
>  
>      ret = virgl_renderer_resource_attach_iov(att_rb.resource_id,
> -                                             res_iovs, att_rb.nr_entries);
> +                                             res_iovs, res_niov);
>  
>      if (ret != 0)
> -        virtio_gpu_cleanup_mapping_iov(g, res_iovs, att_rb.nr_entries);
> +        virtio_gpu_cleanup_mapping_iov(g, res_iovs, res_niov);
>  }
>  
>  static void virgl_resource_detach_backing(VirtIOGPU *g,
> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> index c9f5e36fd076..1dd3648f32a3 100644
> --- a/hw/display/virtio-gpu.c
> +++ b/hw/display/virtio-gpu.c
> @@ -608,11 +608,12 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
>  int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
>                                    struct virtio_gpu_resource_attach_backing 
> *ab,
>                                    struct virtio_gpu_ctrl_command *cmd,
> -                                  uint64_t **addr, struct iovec **iov)
> +                                  uint64_t **addr, struct iovec **iov,
> +                                  uint32_t *niov)
>  {
>      struct virtio_gpu_mem_entry *ents;
>      size_t esize, s;
> -    int i;
> +    int e, v;
>  
>      if (ab->nr_entries > 16384) {
>          qemu_log_mask(LOG_GUEST_ERROR,
> @@ -633,37 +634,53 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
>          return -1;
>      }
>  
> -    *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries);
> +    *iov = NULL;
>      if (addr) {
> -        *addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries);
> +        *addr = NULL;
>      }
> -    for (i = 0; i < ab->nr_entries; i++) {
> -        uint64_t a = le64_to_cpu(ents[i].addr);
> -        uint32_t l = le32_to_cpu(ents[i].length);
> -        hwaddr len = l;
> -        (*iov)[i].iov_base = dma_memory_map(VIRTIO_DEVICE(g)->dma_as,
> -                                            a, &len, 
> DMA_DIRECTION_TO_DEVICE);
> -        (*iov)[i].iov_len = len;
> -        if (addr) {
> -            (*addr)[i] = a;
> -        }
> -        if (!(*iov)[i].iov_base || len != l) {
> -            qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory 
> for"
> -                          " resource %d element %d\n",
> -                          __func__, ab->resource_id, i);
> -            if ((*iov)[i].iov_base) {
> -                i++; /* cleanup the 'i'th map */
> +    for (e = 0, v = 0; e < ab->nr_entries; e++) {
> +        uint64_t a = le64_to_cpu(ents[e].addr);
> +        uint32_t l = le32_to_cpu(ents[e].length);
> +        hwaddr len;
> +        void *map;
> +
> +        do {
> +            len = l;
> +            map = dma_memory_map(VIRTIO_DEVICE(g)->dma_as,
> +                                 a, &len, DMA_DIRECTION_TO_DEVICE);
> +            if (!map) {
> +                qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO 
> memory for"
> +                              " resource %d element %d\n",
> +                              __func__, ab->resource_id, e);
> +                virtio_gpu_cleanup_mapping_iov(g, *iov, v);
> +                g_free(ents);
> +                *iov = NULL;
> +                if (addr) {
> +                    g_free(*addr);
> +                    *addr = NULL;
> +                }
> +                return -1;
>              }
> -            virtio_gpu_cleanup_mapping_iov(g, *iov, i);
> -            g_free(ents);
> -            *iov = NULL;
> +
> +            if (!(v % 16)) {
> +                *iov = g_realloc(*iov, sizeof(struct iovec) * (v + 16));
> +                if (addr) {
> +                    *addr = g_realloc(*addr, sizeof(uint64_t) * (v + 16));
nit: just wondering why you chose to do the alloc by slice of 16 instead
of doing the usual allocation at the beginning and re-allocating the iov
when l != len. Do you think the perf will be better with this
implementation? Looks the guest does concatenation quite often so most
probably your implementation is best.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>

Thanks!

Eric
> +                }
> +            }
> +            (*iov)[v].iov_base = map;
> +            (*iov)[v].iov_len = len;
>              if (addr) {
> -                g_free(*addr);
> -                *addr = NULL;
> +                (*addr)[v] = a;
>              }
> -            return -1;
> -        }
> +
> +            a += len;
> +            l -= len;
> +            v += 1;
> +        } while (l > 0);
>      }
> +    *niov = v;
> +
>      g_free(ents);
>      return 0;
>  }
> @@ -717,13 +734,11 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g,
>          return;
>      }
>  
> -    ret = virtio_gpu_create_mapping_iov(g, &ab, cmd, &res->addrs, &res->iov);
> +    ret = virtio_gpu_create_mapping_iov(g, &ab, cmd, &res->addrs, &res->iov, 
> &res->iov_cnt);
>      if (ret != 0) {
>          cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
>          return;
>      }
> -
> -    res->iov_cnt = ab.nr_entries;
>  }
>  
>  static void
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]