Module: Mesa Branch: main Commit: 0e3584df44d71636ff4d5b9150a936e9296afb18 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=0e3584df44d71636ff4d5b9150a936e9296afb18
Author: Rob Clark <robdcl...@chromium.org> Date: Wed Aug 9 09:10:25 2023 -0700 freedreno/drm/virtio: Switch to vdrm helper Signed-off-by: Rob Clark <robdcl...@chromium.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24733> --- src/freedreno/drm/freedreno_bo.c | 24 ++- src/freedreno/drm/freedreno_drmif.h | 2 - src/freedreno/drm/freedreno_priv.h | 8 +- src/freedreno/drm/meson.build | 16 +- src/freedreno/drm/msm/msm_device.c | 1 + src/freedreno/drm/virtio/virtio_bo.c | 163 +++++----------- src/freedreno/drm/virtio/virtio_device.c | 269 ++++----------------------- src/freedreno/drm/virtio/virtio_pipe.c | 53 ++---- src/freedreno/drm/virtio/virtio_priv.h | 32 +--- src/freedreno/drm/virtio/virtio_ringbuffer.c | 15 +- 10 files changed, 155 insertions(+), 428 deletions(-) diff --git a/src/freedreno/drm/freedreno_bo.c b/src/freedreno/drm/freedreno_bo.c index 546223d0898..293a9744fd5 100644 --- a/src/freedreno/drm/freedreno_bo.c +++ b/src/freedreno/drm/freedreno_bo.c @@ -218,17 +218,27 @@ out_unlock: return bo; } +uint32_t +fd_handle_from_dmabuf_drm(struct fd_device *dev, int fd) +{ + uint32_t handle; + int ret = drmPrimeFDToHandle(dev->fd, fd, &handle); + if (ret) + return 0; + return handle; +} + struct fd_bo * fd_bo_from_dmabuf_drm(struct fd_device *dev, int fd) { - int ret, size; + int size; uint32_t handle; struct fd_bo *bo; restart: simple_mtx_lock(&table_lock); - ret = drmPrimeFDToHandle(dev->fd, fd, &handle); - if (ret) { + handle = dev->funcs->handle_from_dmabuf(dev, fd); + if (!handle) { simple_mtx_unlock(&table_lock); return NULL; } @@ -437,12 +447,12 @@ fd_bo_fini_fences(struct fd_bo *bo) } void -fd_bo_close_handle_drm(struct fd_device *dev, uint32_t handle) +fd_bo_close_handle_drm(struct fd_bo *bo) { struct drm_gem_close req = { - .handle = handle, + .handle = bo->handle, }; - drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req); + drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req); } /** @@ -468,7 +478,7 @@ fd_bo_fini_common(struct fd_bo *bo) if (handle) { simple_mtx_lock(&table_lock); - dev->funcs->bo_close_handle(dev, handle); + dev->funcs->bo_close_handle(bo); _mesa_hash_table_remove_key(dev->handle_table, &handle); if (bo->name) _mesa_hash_table_remove_key(dev->name_table, &bo->name); diff --git a/src/freedreno/drm/freedreno_drmif.h b/src/freedreno/drm/freedreno_drmif.h index 886d1252568..b86b6c570e8 100644 --- a/src/freedreno/drm/freedreno_drmif.h +++ b/src/freedreno/drm/freedreno_drmif.h @@ -145,7 +145,6 @@ int fd_fence_wait(struct fd_fence *f); #define FD_BO_SCANOUT BITSET_BIT(5) /* internal bo flags: */ -#define _FD_BO_VIRTIO_SHM BITSET_BIT(6) #define _FD_BO_NOSYNC BITSET_BIT(7) /* Avoid userspace fencing on control buffers */ /* @@ -286,7 +285,6 @@ struct fd_bo *fd_bo_from_handle(struct fd_device *dev, uint32_t handle, uint32_t size); struct fd_bo *fd_bo_from_name(struct fd_device *dev, uint32_t name); struct fd_bo *fd_bo_from_dmabuf(struct fd_device *dev, int fd); -struct fd_bo *fd_bo_from_dmabuf_drm(struct fd_device *dev, int fd); void fd_bo_mark_for_dump(struct fd_bo *bo); static inline uint64_t diff --git a/src/freedreno/drm/freedreno_priv.h b/src/freedreno/drm/freedreno_priv.h index e0aac089cb4..9fd12fa22a1 100644 --- a/src/freedreno/drm/freedreno_priv.h +++ b/src/freedreno/drm/freedreno_priv.h @@ -108,8 +108,9 @@ struct fd_device_funcs { */ struct fd_bo *(*bo_from_handle)(struct fd_device *dev, uint32_t size, uint32_t handle); + uint32_t (*handle_from_dmabuf)(struct fd_device *dev, int fd); struct fd_bo *(*bo_from_dmabuf)(struct fd_device *dev, int fd); - void (*bo_close_handle)(struct fd_device *dev, uint32_t handle); + void (*bo_close_handle)(struct fd_bo *bo); struct fd_pipe *(*pipe_new)(struct fd_device *dev, enum fd_pipe_id id, unsigned prio); @@ -471,7 +472,10 @@ void fd_bo_fini_fences(struct fd_bo *bo); void fd_bo_fini_common(struct fd_bo *bo); struct fd_bo *fd_bo_new_ring(struct fd_device *dev, uint32_t size); -void fd_bo_close_handle_drm(struct fd_device *dev, uint32_t handle); + +uint32_t fd_handle_from_dmabuf_drm(struct fd_device *dev, int fd); +struct fd_bo *fd_bo_from_dmabuf_drm(struct fd_device *dev, int fd); +void fd_bo_close_handle_drm(struct fd_bo *bo); #define enable_debug 0 /* TODO make dynamic */ diff --git a/src/freedreno/drm/meson.build b/src/freedreno/drm/meson.build index 4f56e826b0e..72b1137e277 100644 --- a/src/freedreno/drm/meson.build +++ b/src/freedreno/drm/meson.build @@ -38,6 +38,10 @@ libfreedreno_drm_includes = [ inc_include, inc_src, ] +libfreedreno_drm_deps = [ + dep_libdrm, + dep_valgrind, +] libfreedreno_drm_msm_files = files( 'msm/msm_bo.c', @@ -59,7 +63,10 @@ libfreedreno_drm_virtio_files = files( if freedreno_kmds.contains('virtio') libfreedreno_drm_files += libfreedreno_drm_virtio_files libfreedreno_drm_flags += '-DHAVE_FREEDRENO_VIRTIO' - libfreedreno_drm_includes += inc_virtio_gpu + libfreedreno_drm_includes += [ + inc_virtio_gpu, + inc_virtio_vdrm, + ] endif libfreedreno_drm = static_library( @@ -71,10 +78,9 @@ libfreedreno_drm = static_library( include_directories : libfreedreno_drm_includes, c_args : [no_override_init_args, libfreedreno_drm_flags], gnu_symbol_visibility : 'hidden', - dependencies : [ - dep_libdrm, - dep_valgrind, - ], + dependencies : libfreedreno_drm_deps, + # TODO + link_with : [libvdrm], build_by_default : false, ) diff --git a/src/freedreno/drm/msm/msm_device.c b/src/freedreno/drm/msm/msm_device.c index 605808a3d4b..47ebf223cae 100644 --- a/src/freedreno/drm/msm/msm_device.c +++ b/src/freedreno/drm/msm/msm_device.c @@ -38,6 +38,7 @@ msm_device_destroy(struct fd_device *dev) static const struct fd_device_funcs funcs = { .bo_new = msm_bo_new, .bo_from_handle = msm_bo_from_handle, + .handle_from_dmabuf = fd_handle_from_dmabuf_drm, .bo_from_dmabuf = fd_bo_from_dmabuf_drm, .bo_close_handle = fd_bo_close_handle_drm, .pipe_new = msm_pipe_new, diff --git a/src/freedreno/drm/virtio/virtio_bo.c b/src/freedreno/drm/virtio/virtio_bo.c index 66073cee100..a8dcc011110 100644 --- a/src/freedreno/drm/virtio/virtio_bo.c +++ b/src/freedreno/drm/virtio/virtio_bo.c @@ -25,73 +25,33 @@ #include "virtio_priv.h" -static int -bo_allocate(struct virtio_bo *virtio_bo) -{ - struct fd_bo *bo = &virtio_bo->base; - if (!virtio_bo->offset) { - struct drm_virtgpu_map req = { - .handle = bo->handle, - }; - int ret; - - ret = virtio_ioctl(bo->dev->fd, VIRTGPU_MAP, &req); - if (ret) { - ERROR_MSG("alloc failed: %s", strerror(errno)); - return ret; - } - - virtio_bo->offset = req.offset; - } - - return 0; -} - -static int -virtio_bo_offset(struct fd_bo *bo, uint64_t *offset) +static void * +virtio_bo_mmap(struct fd_bo *bo) { + struct vdrm_device *vdrm = to_virtio_device(bo->dev)->vdrm; struct virtio_bo *virtio_bo = to_virtio_bo(bo); - int ret = bo_allocate(virtio_bo); - - if (ret) - return ret; /* If we have uploaded, we need to wait for host to handle that * before we can allow guest-side CPU access: */ if (virtio_bo->has_upload_seqno) { + virtio_bo->has_upload_seqno = false; - virtio_execbuf_flush(bo->dev); - virtio_host_sync(bo->dev, &(struct vdrm_ccmd_req) { + + vdrm_flush(vdrm); + vdrm_host_sync(vdrm, &(struct vdrm_ccmd_req) { .seqno = virtio_bo->upload_seqno, }); } - *offset = virtio_bo->offset; - - return 0; -} - -static int -virtio_bo_cpu_prep_guest(struct fd_bo *bo) -{ - struct drm_virtgpu_3d_wait args = { - .handle = bo->handle, - }; - int ret; - - /* Side note, this ioctl is defined as IO_WR but should be IO_W: */ - ret = virtio_ioctl(bo->dev->fd, VIRTGPU_WAIT, &args); - if (ret && errno == EBUSY) - return -EBUSY; - - return 0; + return vdrm_bo_map(vdrm, bo->handle, bo->size); } static int virtio_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op) { MESA_TRACE_FUNC(); + struct vdrm_device *vdrm = to_virtio_device(bo->dev)->vdrm; int ret; /* @@ -101,7 +61,7 @@ virtio_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op) * know about usage of the bo in the host (or other guests). */ - ret = virtio_bo_cpu_prep_guest(bo); + ret = vdrm_bo_wait(vdrm, bo->handle); if (ret) goto out; @@ -120,9 +80,9 @@ virtio_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op) /* We can't do a blocking wait in the host, so we have to poll: */ do { - rsp = virtio_alloc_rsp(bo->dev, &req.hdr, sizeof(*rsp)); + rsp = vdrm_alloc_rsp(vdrm, &req.hdr, sizeof(*rsp)); - ret = virtio_execbuf(bo->dev, &req.hdr, true); + ret = vdrm_send_req(vdrm, &req.hdr, true); if (ret) goto out; @@ -182,7 +142,15 @@ virtio_bo_set_name(struct fd_bo *bo, const char *fmt, va_list ap) memcpy(req->payload, name, sz); - virtio_execbuf(bo->dev, &req->hdr, false); + vdrm_send_req(to_virtio_device(bo->dev)->vdrm, &req->hdr, false); +} + +static int +virtio_bo_dmabuf(struct fd_bo *bo) +{ + struct virtio_device *virtio_dev = to_virtio_device(bo->dev); + + return vdrm_bo_export_dmabuf(virtio_dev->vdrm, bo->handle); } static void @@ -203,7 +171,7 @@ bo_upload(struct fd_bo *bo, unsigned off, void *src, unsigned len) memcpy(req->payload, src, len); - virtio_execbuf(bo->dev, &req->hdr, false); + vdrm_send_req(to_virtio_device(bo->dev)->vdrm, &req->hdr, false); virtio_bo->upload_seqno = req->hdr.seqno; virtio_bo->has_upload_seqno = true; @@ -257,7 +225,7 @@ set_iova(struct fd_bo *bo, uint64_t iova) .iova = iova, }; - virtio_execbuf(bo->dev, &req.hdr, false); + vdrm_send_req(to_virtio_device(bo->dev)->vdrm, &req.hdr, false); } static void @@ -272,8 +240,7 @@ virtio_bo_finalize(struct fd_bo *bo) } static const struct fd_bo_funcs funcs = { - .offset = virtio_bo_offset, - .map = fd_bo_map_os_mmap, + .map = virtio_bo_mmap, .cpu_prep = virtio_bo_cpu_prep, .madvise = virtio_bo_madvise, .iova = virtio_bo_iova, @@ -288,6 +255,7 @@ static const struct fd_bo_funcs funcs = { static struct fd_bo * bo_from_handle(struct fd_device *dev, uint32_t size, uint32_t handle) { + struct virtio_device *virtio_dev = to_virtio_device(dev); struct virtio_bo *virtio_bo; struct fd_bo *bo; @@ -312,19 +280,7 @@ bo_from_handle(struct fd_device *dev, uint32_t size, uint32_t handle) /* Don't assume we can mmap an imported bo: */ bo->alloc_flags = FD_BO_NOMAP; - struct drm_virtgpu_resource_info args = { - .bo_handle = handle, - }; - int ret; - - ret = virtio_ioctl(dev->fd, VIRTGPU_RESOURCE_INFO, &args); - if (ret) { - INFO_MSG("failed to get resource info: %s", strerror(errno)); - free(virtio_bo); - return NULL; - } - - virtio_bo->res_id = args.res_handle; + virtio_bo->res_id = vdrm_handle_to_res_id(virtio_dev->vdrm, handle); fd_bo_init_common(bo, dev); @@ -359,15 +315,10 @@ struct fd_bo * virtio_bo_new(struct fd_device *dev, uint32_t size, uint32_t flags) { struct virtio_device *virtio_dev = to_virtio_device(dev); - struct drm_virtgpu_resource_create_blob args = { - .blob_mem = VIRTGPU_BLOB_MEM_HOST3D, - .size = size, - }; struct msm_ccmd_gem_new_req req = { .hdr = MSM_CCMD(GEM_NEW, sizeof(req)), .size = size, }; - int ret; if (flags & FD_BO_SCANOUT) req.flags |= MSM_BO_SCANOUT; @@ -381,56 +332,42 @@ virtio_bo_new(struct fd_device *dev, uint32_t size, uint32_t flags) req.flags |= MSM_BO_WC; } - if (flags & _FD_BO_VIRTIO_SHM) { - args.blob_id = 0; - args.blob_flags = VIRTGPU_BLOB_FLAG_USE_MAPPABLE; - } else { - if (flags & (FD_BO_SHARED | FD_BO_SCANOUT)) { - args.blob_flags = VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE | - VIRTGPU_BLOB_FLAG_USE_SHAREABLE; - } - - if (!(flags & FD_BO_NOMAP)) { - args.blob_flags |= VIRTGPU_BLOB_FLAG_USE_MAPPABLE; - } - - args.blob_id = p_atomic_inc_return(&virtio_dev->next_blob_id); - args.cmd = VOID2U64(&req); - args.cmd_size = sizeof(req); - - /* tunneled cmds are processed separately on host side, - * before the renderer->get_blob() callback.. the blob_id - * is used to like the created bo to the get_blob() call - */ - req.blob_id = args.blob_id; - req.iova = virtio_dev_alloc_iova(dev, size); - if (!req.iova) { - ret = -ENOMEM; - goto fail; - } + uint32_t blob_flags = 0; + if (flags & (FD_BO_SHARED | FD_BO_SCANOUT)) { + blob_flags = VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE | + VIRTGPU_BLOB_FLAG_USE_SHAREABLE; } - simple_mtx_lock(&virtio_dev->eb_lock); - if (args.cmd) { - virtio_execbuf_flush_locked(dev); - req.hdr.seqno = ++virtio_dev->next_seqno; + if (!(flags & FD_BO_NOMAP)) { + blob_flags |= VIRTGPU_BLOB_FLAG_USE_MAPPABLE; } - ret = virtio_ioctl(dev->fd, VIRTGPU_RESOURCE_CREATE_BLOB, &args); - simple_mtx_unlock(&virtio_dev->eb_lock); - if (ret) + + uint32_t blob_id = p_atomic_inc_return(&virtio_dev->next_blob_id); + + /* tunneled cmds are processed separately on host side, + * before the renderer->get_blob() callback.. the blob_id + * is used to link the created bo to the get_blob() call + */ + req.blob_id = blob_id; + req.iova = virtio_dev_alloc_iova(dev, size); + if (!req.iova) + goto fail; + + uint32_t handle = + vdrm_bo_create(virtio_dev->vdrm, size, blob_flags, blob_id, &req.hdr); + if (!handle) goto fail; - struct fd_bo *bo = bo_from_handle(dev, size, args.bo_handle); + struct fd_bo *bo = bo_from_handle(dev, size, handle); struct virtio_bo *virtio_bo = to_virtio_bo(bo); - virtio_bo->blob_id = args.blob_id; + virtio_bo->blob_id = blob_id; bo->iova = req.iova; return bo; fail: - if (req.iova) { + if (req.iova) virtio_dev_free_iova(dev, req.iova, size); - } return NULL; } diff --git a/src/freedreno/drm/virtio/virtio_device.c b/src/freedreno/drm/virtio/virtio_device.c index 59781f22553..27f841e5eef 100644 --- a/src/freedreno/drm/virtio/virtio_device.c +++ b/src/freedreno/drm/virtio/virtio_device.c @@ -30,55 +30,44 @@ #include "virtio_priv.h" + +static int virtio_execbuf_flush(struct fd_device *dev); + static void virtio_device_destroy(struct fd_device *dev) { struct virtio_device *virtio_dev = to_virtio_device(dev); - fd_bo_del(virtio_dev->shmem_bo); util_vma_heap_finish(&virtio_dev->address_space); } +static uint32_t +virtio_handle_from_dmabuf(struct fd_device *dev, int fd) +{ + struct virtio_device *virtio_dev = to_virtio_device(dev); + + return vdrm_dmabuf_to_handle(virtio_dev->vdrm, fd); +} + +static void +virtio_close_handle(struct fd_bo *bo) +{ + struct virtio_device *virtio_dev = to_virtio_device(bo->dev); + + vdrm_bo_close(virtio_dev->vdrm, bo->handle); +} + static const struct fd_device_funcs funcs = { .bo_new = virtio_bo_new, .bo_from_handle = virtio_bo_from_handle, + .handle_from_dmabuf = virtio_handle_from_dmabuf, .bo_from_dmabuf = fd_bo_from_dmabuf_drm, - .bo_close_handle = fd_bo_close_handle_drm, + .bo_close_handle = virtio_close_handle, .pipe_new = virtio_pipe_new, .flush = virtio_execbuf_flush, .destroy = virtio_device_destroy, }; -static int -get_capset(int fd, struct virgl_renderer_capset_drm *caps) -{ - struct drm_virtgpu_get_caps args = { - .cap_set_id = VIRGL_RENDERER_CAPSET_DRM, - .cap_set_ver = 0, - .addr = VOID2U64(caps), - .size = sizeof(*caps), - }; - - memset(caps, 0, sizeof(*caps)); - - return virtio_ioctl(fd, VIRTGPU_GET_CAPS, &args); -} - -static int -set_context(int fd) -{ - struct drm_virtgpu_context_set_param params[] = { - { VIRTGPU_CONTEXT_PARAM_CAPSET_ID, VIRGL_RENDERER_CAPSET_DRM }, - { VIRTGPU_CONTEXT_PARAM_NUM_RINGS, 64 }, - }; - struct drm_virtgpu_context_init args = { - .num_params = ARRAY_SIZE(params), - .ctx_set_params = VOID2U64(params), - }; - - return virtio_ioctl(fd, VIRTGPU_CONTEXT_INIT, &args); -} - static void set_debuginfo(struct fd_device *dev) { @@ -117,7 +106,7 @@ set_debuginfo(struct fd_device *dev) memcpy(&req->payload[0], comm, comm_len); memcpy(&req->payload[comm_len], cmdline, cmdline_len); - virtio_execbuf(dev, &req->hdr, false); + vdrm_send_req(to_virtio_device(dev)->vdrm, &req->hdr, false); free(req); } @@ -127,8 +116,8 @@ virtio_device_new(int fd, drmVersionPtr version) { struct virgl_renderer_capset_drm caps; struct virtio_device *virtio_dev; + struct vdrm_device *vdrm; struct fd_device *dev; - int ret; STATIC_ASSERT(FD_BO_PREP_READ == MSM_PREP_READ); STATIC_ASSERT(FD_BO_PREP_WRITE == MSM_PREP_WRITE); @@ -138,16 +127,13 @@ virtio_device_new(int fd, drmVersionPtr version) if (debug_get_bool_option("FD_NO_VIRTIO", false)) return NULL; - ret = get_capset(fd, &caps); - if (ret) { - INFO_MSG("could not get caps: %s", strerror(errno)); + vdrm = vdrm_device_connect(fd, VIRTGPU_DRM_CONTEXT_MSM); + if (!vdrm) { + INFO_MSG("could not connect vdrm"); return NULL; } - if (caps.context_type != VIRTGPU_DRM_CONTEXT_MSM) { - INFO_MSG("wrong context_type: %u", caps.context_type); - return NULL; - } + caps = vdrm->caps; INFO_MSG("wire_format_version: %u", caps.wire_format_version); INFO_MSG("version_major: %u", caps.version_major); @@ -164,29 +150,23 @@ virtio_device_new(int fd, drmVersionPtr version) if (caps.wire_format_version != 2) { ERROR_MSG("Unsupported protocol version: %u", caps.wire_format_version); - return NULL; + goto error; } if ((caps.version_major != 1) || (caps.version_minor < FD_VERSION_SOFTPIN)) { ERROR_MSG("unsupported version: %u.%u.%u", caps.version_major, caps.version_minor, caps.version_patchlevel); - return NULL; + goto error; } if (!caps.u.msm.va_size) { ERROR_MSG("No address space"); - return NULL; - } - - ret = set_context(fd); - if (ret) { - INFO_MSG("Could not set context type: %s", strerror(errno)); - return NULL; + goto error; } virtio_dev = calloc(1, sizeof(*virtio_dev)); if (!virtio_dev) - return NULL; + goto error; dev = &virtio_dev->base; dev->funcs = &funcs; @@ -195,16 +175,13 @@ virtio_device_new(int fd, drmVersionPtr version) dev->has_cached_coherent = caps.u.msm.has_cached_coherent; p_atomic_set(&virtio_dev->next_blob_id, 1); - - virtio_dev->caps = caps; + virtio_dev->shmem = to_msm_shmem(vdrm->shmem); + virtio_dev->vdrm = vdrm; util_queue_init(&dev->submit_queue, "sq", 8, 1, 0, NULL); dev->bo_size = sizeof(struct virtio_bo); - simple_mtx_init(&virtio_dev->rsp_lock, mtx_plain); - simple_mtx_init(&virtio_dev->eb_lock, mtx_plain); - set_debuginfo(dev); util_vma_heap_init(&virtio_dev->address_space, @@ -213,183 +190,16 @@ virtio_device_new(int fd, drmVersionPtr version) simple_mtx_init(&virtio_dev->address_space_lock, mtx_plain); return dev; -} - -void * -virtio_alloc_rsp(struct fd_device *dev, struct vdrm_ccmd_req *req, uint32_t sz) -{ - struct virtio_device *virtio_dev = to_virtio_device(dev); - unsigned off; - - simple_mtx_lock(&virtio_dev->rsp_lock); - - sz = align(sz, 8); - - if ((virtio_dev->next_rsp_off + sz) >= virtio_dev->rsp_mem_len) - virtio_dev->next_rsp_off = 0; - off = virtio_dev->next_rsp_off; - virtio_dev->next_rsp_off += sz; - - simple_mtx_unlock(&virtio_dev->rsp_lock); - - req->rsp_off = off; - - struct vdrm_ccmd_rsp *rsp = (void *)&virtio_dev->rsp_mem[off]; - rsp->len = sz; - - return rsp; +error: + vdrm_device_close(vdrm); + return NULL; } -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 = virtio_ioctl(dev->fd, 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 - * cmdstream execution. - * - * Note that ring_idx 0 is the "CPU ring", ie. for synchronizing btwn - * guest and host CPU. - */ -int -virtio_execbuf_fenced(struct fd_device *dev, struct vdrm_ccmd_req *req, - uint32_t *handles, uint32_t num_handles, - 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; - - ret = execbuf_locked(dev, req, req->len, handles, num_handles, - in_fence_fd, out_fence_fd, ring_idx); - - simple_mtx_unlock(&virtio_dev->eb_lock); - - 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; - - 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_flush_locked(struct fd_device *dev) -{ - struct virtio_device *virtio_dev = to_virtio_device(dev); - simple_mtx_assert_locked(&virtio_dev->eb_lock); - return execbuf_flush_locked(dev, NULL); -} - -int -virtio_execbuf(struct fd_device *dev, struct vdrm_ccmd_req *req, bool sync) -{ - MESA_TRACE_FUNC(); - 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; - - if (sync) { - MESA_TRACE_SCOPE("virtio_execbuf sync"); - sync_wait(fence_fd, -1); - close(fence_fd); - virtio_host_sync(dev, req); - } - - return 0; -} - -/** - * Wait until host as processed the specified request. - */ -void -virtio_host_sync(struct fd_device *dev, const struct vdrm_ccmd_req *req) -{ - struct virtio_device *virtio_dev = to_virtio_device(dev); - - while (fd_fence_before(virtio_dev->shmem->base.seqno, req->seqno)) - sched_yield(); + return vdrm_flush(to_virtio_device(dev)->vdrm); } /** @@ -399,6 +209,7 @@ int virtio_simple_ioctl(struct fd_device *dev, unsigned cmd, void *_req) { MESA_TRACE_FUNC(); + struct vdrm_device *vdrm = to_virtio_device(dev)->vdrm; unsigned req_len = sizeof(struct msm_ccmd_ioctl_simple_req); unsigned rsp_len = sizeof(struct msm_ccmd_ioctl_simple_rsp); @@ -414,9 +225,9 @@ virtio_simple_ioctl(struct fd_device *dev, unsigned cmd, void *_req) req->cmd = cmd; memcpy(req->payload, _req, _IOC_SIZE(cmd)); - rsp = virtio_alloc_rsp(dev, &req->hdr, rsp_len); + rsp = vdrm_alloc_rsp(vdrm, &req->hdr, rsp_len); - int ret = virtio_execbuf(dev, &req->hdr, true); + int ret = vdrm_send_req(vdrm, &req->hdr, true); if (cmd & IOC_OUT) memcpy(_req, rsp->payload, _IOC_SIZE(cmd)); diff --git a/src/freedreno/drm/virtio/virtio_pipe.c b/src/freedreno/drm/virtio/virtio_pipe.c index 9ff2262faaa..8b4644777ac 100644 --- a/src/freedreno/drm/virtio/virtio_pipe.c +++ b/src/freedreno/drm/virtio/virtio_pipe.c @@ -91,12 +91,12 @@ virtio_pipe_get_param(struct fd_pipe *pipe, enum fd_param_id param, *value = virtio_pipe->chip_id; return 0; case FD_MAX_FREQ: - *value = virtio_dev->caps.u.msm.max_freq; + *value = virtio_dev->vdrm->caps.u.msm.max_freq; return 0; case FD_TIMESTAMP: return query_param(pipe, MSM_PARAM_TIMESTAMP, value); case FD_NR_PRIORITIES: - *value = virtio_dev->caps.u.msm.priorities; + *value = virtio_dev->vdrm->caps.u.msm.priorities; return 0; case FD_CTX_FAULTS: case FD_GLOBAL_FAULTS: @@ -104,7 +104,7 @@ virtio_pipe_get_param(struct fd_pipe *pipe, enum fd_param_id param, case FD_SUSPEND_COUNT: return query_param(pipe, MSM_PARAM_SUSPENDS, value); case FD_VA_SIZE: - *value = virtio_dev->caps.u.msm.va_size; + *value = virtio_dev->vdrm->caps.u.msm.va_size; return 0; default: ERROR_MSG("invalid param id: %d", param); @@ -116,7 +116,7 @@ static int virtio_pipe_wait(struct fd_pipe *pipe, const struct fd_fence *fence, uint64_t timeout) { MESA_TRACE_FUNC(); - + struct vdrm_device *vdrm = to_virtio_device(pipe->dev)->vdrm; struct msm_ccmd_wait_fence_req req = { .hdr = MSM_CCMD(WAIT_FENCE, sizeof(req)), .queue_id = to_virtio_pipe(pipe)->queue_id, @@ -129,20 +129,20 @@ virtio_pipe_wait(struct fd_pipe *pipe, const struct fd_fence *fence, uint64_t ti /* Do a non-blocking wait to trigger host-side wait-boost, * if the host kernel is new enough */ - rsp = virtio_alloc_rsp(pipe->dev, &req.hdr, sizeof(*rsp)); - ret = virtio_execbuf(pipe->dev, &req.hdr, false); + rsp = vdrm_alloc_rsp(vdrm, &req.hdr, sizeof(*rsp)); + ret = vdrm_send_req(vdrm, &req.hdr, false); if (ret) goto out; - virtio_execbuf_flush(pipe->dev); + vdrm_flush(vdrm); if (fence->use_fence_fd) return sync_wait(fence->fence_fd, timeout / 1000000); do { - rsp = virtio_alloc_rsp(pipe->dev, &req.hdr, sizeof(*rsp)); + rsp = vdrm_alloc_rsp(vdrm, &req.hdr, sizeof(*rsp)); - ret = virtio_execbuf(pipe->dev, &req.hdr, true); + ret = vdrm_send_req(vdrm, &req.hdr, true); if (ret) goto out; @@ -213,30 +213,6 @@ static const struct fd_pipe_funcs funcs = { .destroy = virtio_pipe_destroy, }; -static void -init_shmem(struct fd_device *dev) -{ - struct virtio_device *virtio_dev = to_virtio_device(dev); - - simple_mtx_lock(&virtio_dev->rsp_lock); - - /* One would like to do this in virtio_device_new(), but we'd - * have to bypass/reinvent fd_bo_new().. - */ - if (unlikely(!virtio_dev->shmem)) { - virtio_dev->shmem_bo = fd_bo_new(dev, 0x4000, - _FD_BO_VIRTIO_SHM, "shmem"); - virtio_dev->shmem = fd_bo_map(virtio_dev->shmem_bo); - virtio_dev->shmem_bo->bo_reuse = NO_CACHE; - - uint32_t offset = virtio_dev->shmem->base.rsp_mem_offset; - virtio_dev->rsp_mem_len = fd_bo_size(virtio_dev->shmem_bo) - offset; - virtio_dev->rsp_mem = &((uint8_t *)virtio_dev->shmem)[offset]; - } - - simple_mtx_unlock(&virtio_dev->rsp_lock); -} - struct fd_pipe * virtio_pipe_new(struct fd_device *dev, enum fd_pipe_id id, uint32_t prio) { @@ -245,11 +221,10 @@ virtio_pipe_new(struct fd_device *dev, enum fd_pipe_id id, uint32_t prio) [FD_PIPE_2D] = MSM_PIPE_2D0, }; struct virtio_device *virtio_dev = to_virtio_device(dev); + struct vdrm_device *vdrm = virtio_dev->vdrm; struct virtio_pipe *virtio_pipe = NULL; struct fd_pipe *pipe = NULL; - init_shmem(dev); - virtio_pipe = calloc(1, sizeof(*virtio_pipe)); if (!virtio_pipe) { ERROR_MSG("allocation failed"); @@ -264,10 +239,10 @@ virtio_pipe_new(struct fd_device *dev, enum fd_pipe_id id, uint32_t prio) pipe->dev = dev; virtio_pipe->pipe = pipe_id[id]; - virtio_pipe->gpu_id = virtio_dev->caps.u.msm.gpu_id; - virtio_pipe->gmem = virtio_dev->caps.u.msm.gmem_size; - virtio_pipe->gmem_base = virtio_dev->caps.u.msm.gmem_base; - virtio_pipe->chip_id = virtio_dev->caps.u.msm.chip_id; + virtio_pipe->gpu_id = vdrm->caps.u.msm.gpu_id; + virtio_pipe->gmem = vdrm->caps.u.msm.gmem_size; + virtio_pipe->gmem_base = vdrm->caps.u.msm.gmem_base; + virtio_pipe->chip_id = vdrm->caps.u.msm.chip_id; if (!(virtio_pipe->gpu_id || virtio_pipe->chip_id)) diff --git a/src/freedreno/drm/virtio/virtio_priv.h b/src/freedreno/drm/virtio/virtio_priv.h index bcf2c34f7c5..4b95ad85006 100644 --- a/src/freedreno/drm/virtio/virtio_priv.h +++ b/src/freedreno/drm/virtio/virtio_priv.h @@ -42,21 +42,15 @@ #include "virglrenderer_hw.h" #include "msm_proto.h" +#include "vdrm.h" + struct virtio_device { struct fd_device base; - struct fd_bo *shmem_bo; - struct msm_shmem *shmem; - uint8_t *rsp_mem; - uint32_t rsp_mem_len; - uint32_t next_rsp_off; - simple_mtx_t rsp_lock; - simple_mtx_t eb_lock; + struct vdrm_device *vdrm; uint32_t next_blob_id; - uint32_t next_seqno; - - struct virgl_renderer_capset_drm caps; + struct msm_shmem *shmem; /* * Notes on address space allocation: @@ -78,19 +72,9 @@ 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); -#define virtio_ioctl(fd, name, args) ({ \ - MESA_TRACE_SCOPE(#name); \ - int ret = drmIoctl((fd), DRM_IOCTL_ ## name, (args)); \ - ret; \ - }) - struct fd_device *virtio_device_new(int fd, drmVersionPtr version); static inline void @@ -177,14 +161,6 @@ struct fd_bo *virtio_bo_from_handle(struct fd_device *dev, uint32_t size, /* * Internal helpers: */ -void *virtio_alloc_rsp(struct fd_device *dev, struct vdrm_ccmd_req *hdr, uint32_t sz); -int virtio_execbuf_fenced(struct fd_device *dev, struct vdrm_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_flush_locked(struct fd_device *dev); -int virtio_execbuf(struct fd_device *dev, struct vdrm_ccmd_req *req, bool sync); -void virtio_host_sync(struct fd_device *dev, const struct vdrm_ccmd_req *req); int virtio_simple_ioctl(struct fd_device *dev, unsigned cmd, void *req); #endif /* VIRTIO_PRIV_H_ */ diff --git a/src/freedreno/drm/virtio/virtio_ringbuffer.c b/src/freedreno/drm/virtio/virtio_ringbuffer.c index b5508f74b6b..38d7e456542 100644 --- a/src/freedreno/drm/virtio/virtio_ringbuffer.c +++ b/src/freedreno/drm/virtio/virtio_ringbuffer.c @@ -190,9 +190,18 @@ flush_submit_list(struct list_head *submit_list) nr_guest_handles = 0; } - virtio_execbuf_fenced(dev, &req->hdr, guest_handles, nr_guest_handles, - fd_submit->in_fence_fd, &out_fence->fence_fd, - virtio_pipe->ring_idx); + struct vdrm_execbuf_params p = { + .req = &req->hdr, + .handles = guest_handles, + .num_handles = nr_guest_handles, + .has_in_fence_fd = !!(fd_submit->in_fence_fd != -1), + .needs_out_fence_fd = true, + .fence_fd = fd_submit->in_fence_fd, + .ring_idx = virtio_pipe->ring_idx, + }; + vdrm_execbuf(to_virtio_device(dev)->vdrm, &p); + + out_fence->fence_fd = p.fence_fd; free(req);