summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Clark <robdclark@chromium.org>2022-04-18 14:23:13 -0700
committerMarge Bot <emma+marge@anholt.net>2022-04-27 23:10:00 +0000
commit0aab31043979bc478f2d2a2a35bbe882154f457e (patch)
tree5d015f2535306295527bbaa9a61550bd17301e01
parent528fa581c1f74a0abbb63a11faed8dea7a3d7af7 (diff)
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 <robdclark@chromium.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16086>
-rw-r--r--src/freedreno/drm/virtio/virtio_bo.c8
-rw-r--r--src/freedreno/drm/virtio/virtio_device.c108
-rw-r--r--src/freedreno/drm/virtio/virtio_priv.h5
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);