From 0aab31043979bc478f2d2a2a35bbe882154f457e Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 18 Apr 2022 14:23:13 -0700 Subject: freedreno/drm/virtio: Async ccmd batching This could be a bit more clever an avoid extra memcpy.. but that seems to be in the noise at this point. Signed-off-by: Rob Clark Part-of: --- src/freedreno/drm/virtio/virtio_bo.c | 8 +++ src/freedreno/drm/virtio/virtio_device.c | 108 +++++++++++++++++++++++++------ src/freedreno/drm/virtio/virtio_priv.h | 5 ++ 3 files changed, 100 insertions(+), 21 deletions(-) diff --git a/src/freedreno/drm/virtio/virtio_bo.c b/src/freedreno/drm/virtio/virtio_bo.c index 36cf8c9e364..2fc7cb079bc 100644 --- a/src/freedreno/drm/virtio/virtio_bo.c +++ b/src/freedreno/drm/virtio/virtio_bo.c @@ -221,8 +221,16 @@ virtio_bo_destroy(struct fd_bo *bo) /* Release iova by setting to zero: */ if (bo->iova) { set_iova(bo, 0); + virtio_dev_free_iova(bo->dev, bo->iova, bo->size); + + /* Need to flush batched ccmds to ensure the host sees the iova + * release before the GEM handle is closed (ie. detach_resource() + * on the host side) + */ + virtio_execbuf_flush(bo->dev); } + free(virtio_bo); } diff --git a/src/freedreno/drm/virtio/virtio_device.c b/src/freedreno/drm/virtio/virtio_device.c index dddabe76a49..4c395b8b6d5 100644 --- a/src/freedreno/drm/virtio/virtio_device.c +++ b/src/freedreno/drm/virtio/virtio_device.c @@ -238,6 +238,38 @@ virtio_alloc_rsp(struct fd_device *dev, struct msm_ccmd_req *req, uint32_t sz) return rsp; } +static int execbuf_flush_locked(struct fd_device *dev, int *out_fence_fd); + +static int +execbuf_locked(struct fd_device *dev, void *cmd, uint32_t cmd_size, + uint32_t *handles, uint32_t num_handles, + int in_fence_fd, int *out_fence_fd, int ring_idx) +{ +#define COND(bool, val) ((bool) ? (val) : 0) + struct drm_virtgpu_execbuffer eb = { + .flags = COND(out_fence_fd, VIRTGPU_EXECBUF_FENCE_FD_OUT) | + COND(in_fence_fd != -1, VIRTGPU_EXECBUF_FENCE_FD_IN) | + VIRTGPU_EXECBUF_RING_IDX, + .fence_fd = in_fence_fd, + .size = cmd_size, + .command = VOID2U64(cmd), + .ring_idx = ring_idx, + .bo_handles = VOID2U64(handles), + .num_bo_handles = num_handles, + }; + + int ret = drmIoctl(dev->fd, DRM_IOCTL_VIRTGPU_EXECBUFFER, &eb); + if (ret) { + ERROR_MSG("EXECBUFFER failed: %s", strerror(errno)); + return ret; + } + + if (out_fence_fd) + *out_fence_fd = eb.fence_fd; + + return 0; +} + /** * Helper for "execbuf" ioctl.. note that in virtgpu execbuf is just * a generic "send commands to host", not necessarily specific to @@ -252,42 +284,76 @@ virtio_execbuf_fenced(struct fd_device *dev, struct msm_ccmd_req *req, int in_fence_fd, int *out_fence_fd, int ring_idx) { struct virtio_device *virtio_dev = to_virtio_device(dev); + int ret; simple_mtx_lock(&virtio_dev->eb_lock); + execbuf_flush_locked(dev, NULL); req->seqno = ++virtio_dev->next_seqno; -#define COND(bool, val) ((bool) ? (val) : 0) - struct drm_virtgpu_execbuffer eb = { - .flags = COND(out_fence_fd, VIRTGPU_EXECBUF_FENCE_FD_OUT) | - COND(in_fence_fd != -1, VIRTGPU_EXECBUF_FENCE_FD_IN) | - VIRTGPU_EXECBUF_RING_IDX, - .fence_fd = in_fence_fd, - .size = req->len, - .command = VOID2U64(req), - .ring_idx = ring_idx, - .bo_handles = VOID2U64(handles), - .num_bo_handles = num_handles, - }; + ret = execbuf_locked(dev, req, req->len, handles, num_handles, + in_fence_fd, out_fence_fd, ring_idx); - int ret = drmIoctl(dev->fd, DRM_IOCTL_VIRTGPU_EXECBUFFER, &eb); simple_mtx_unlock(&virtio_dev->eb_lock); - if (ret) { - ERROR_MSG("EXECBUFFER failed: %s", strerror(errno)); + + return ret; +} + +static int +execbuf_flush_locked(struct fd_device *dev, int *out_fence_fd) +{ + struct virtio_device *virtio_dev = to_virtio_device(dev); + int ret; + + if (!virtio_dev->reqbuf_len) + return 0; + + ret = execbuf_locked(dev, virtio_dev->reqbuf, virtio_dev->reqbuf_len, + NULL, 0, -1, out_fence_fd, 0); + if (ret) return ret; - } - if (out_fence_fd) - *out_fence_fd = eb.fence_fd; + virtio_dev->reqbuf_len = 0; + virtio_dev->reqbuf_cnt = 0; return 0; } +int +virtio_execbuf_flush(struct fd_device *dev) +{ + struct virtio_device *virtio_dev = to_virtio_device(dev); + simple_mtx_lock(&virtio_dev->eb_lock); + int ret = execbuf_flush_locked(dev, NULL); + simple_mtx_unlock(&virtio_dev->eb_lock); + return ret; +} + int virtio_execbuf(struct fd_device *dev, struct msm_ccmd_req *req, bool sync) { - int fence_fd; - int ret = virtio_execbuf_fenced(dev, req, NULL, 0, -1, - sync ? &fence_fd : NULL, 0); + struct virtio_device *virtio_dev = to_virtio_device(dev); + int fence_fd, ret = 0; + + simple_mtx_lock(&virtio_dev->eb_lock); + req->seqno = ++virtio_dev->next_seqno; + + if ((virtio_dev->reqbuf_len + req->len) > sizeof(virtio_dev->reqbuf)) { + ret = execbuf_flush_locked(dev, NULL); + if (ret) + goto out_unlock; + } + + memcpy(&virtio_dev->reqbuf[virtio_dev->reqbuf_len], req, req->len); + virtio_dev->reqbuf_len += req->len; + virtio_dev->reqbuf_cnt++; + + if (!sync) + goto out_unlock; + + ret = execbuf_flush_locked(dev, &fence_fd); + +out_unlock: + simple_mtx_unlock(&virtio_dev->eb_lock); if (ret) return ret; diff --git a/src/freedreno/drm/virtio/virtio_priv.h b/src/freedreno/drm/virtio/virtio_priv.h index 0effae6744c..2387ab516ff 100644 --- a/src/freedreno/drm/virtio/virtio_priv.h +++ b/src/freedreno/drm/virtio/virtio_priv.h @@ -79,6 +79,10 @@ struct virtio_device { */ struct util_vma_heap address_space; simple_mtx_t address_space_lock; + + uint32_t reqbuf_len; + uint32_t reqbuf_cnt; + uint8_t reqbuf[0x4000]; }; FD_DEFINE_CAST(fd_device, virtio_device); @@ -175,6 +179,7 @@ void *virtio_alloc_rsp(struct fd_device *dev, struct msm_ccmd_req *hdr, uint32_t int virtio_execbuf_fenced(struct fd_device *dev, struct msm_ccmd_req *req, uint32_t *handles, uint32_t num_handles, int in_fence_fd, int *out_fence_fd, int ring_idx); +int virtio_execbuf_flush(struct fd_device *dev); int virtio_execbuf(struct fd_device *dev, struct msm_ccmd_req *req, bool sync); void virtio_host_sync(struct fd_device *dev, const struct msm_ccmd_req *req); int virtio_simple_ioctl(struct fd_device *dev, unsigned cmd, void *req); -- cgit v1.2.3