Commit e1341f91 authored by Rob Clark's avatar Rob Clark
Browse files

drm/msm: Extract out syncobj helpers



We'll be re-using these for the VM_BIND ioctl.

Also, rename a few things in the uapi header to reflect that syncobj use
is not specific to the submit ioctl.

Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
Signed-off-by: default avatarRob Clark <robin.clark@oss.qualcomm.com>
Tested-by: default avatarAntonino Maniscalco <antomani103@gmail.com>
Reviewed-by: default avatarAntonino Maniscalco <antomani103@gmail.com>
Patchwork: https://patchwork.freedesktop.org/patch/661512/
parent 06ebb4f0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -127,6 +127,7 @@ msm-y += \
	msm_rd.o \
	msm_ringbuffer.o \
	msm_submitqueue.o \
	msm_syncobj.o \
	msm_gpu_tracepoints.o \

msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
+12 −180
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include "msm_gpu.h"
#include "msm_gem.h"
#include "msm_gpu_trace.h"
#include "msm_syncobj.h"

/* For userspace errors, use DRM_UT_DRIVER.. so that userspace can enable
 * error msgs for debugging, but we don't spam dmesg by default
@@ -491,173 +492,6 @@ void msm_submit_retire(struct msm_gem_submit *submit)
	}
}

struct msm_submit_post_dep {
	struct drm_syncobj *syncobj;
	uint64_t point;
	struct dma_fence_chain *chain;
};

static struct drm_syncobj **msm_parse_deps(struct msm_gem_submit *submit,
                                           struct drm_file *file,
                                           uint64_t in_syncobjs_addr,
                                           uint32_t nr_in_syncobjs,
                                           size_t syncobj_stride)
{
	struct drm_syncobj **syncobjs = NULL;
	struct drm_msm_gem_submit_syncobj syncobj_desc = {0};
	int ret = 0;
	uint32_t i, j;

	syncobjs = kcalloc(nr_in_syncobjs, sizeof(*syncobjs),
	                   GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
	if (!syncobjs)
		return ERR_PTR(-ENOMEM);

	for (i = 0; i < nr_in_syncobjs; ++i) {
		uint64_t address = in_syncobjs_addr + i * syncobj_stride;

		if (copy_from_user(&syncobj_desc,
			           u64_to_user_ptr(address),
			           min(syncobj_stride, sizeof(syncobj_desc)))) {
			ret = -EFAULT;
			break;
		}

		if (syncobj_desc.point &&
		    !drm_core_check_feature(submit->dev, DRIVER_SYNCOBJ_TIMELINE)) {
			ret = SUBMIT_ERROR(EOPNOTSUPP, submit, "syncobj timeline unsupported");
			break;
		}

		if (syncobj_desc.flags & ~MSM_SUBMIT_SYNCOBJ_FLAGS) {
			ret = SUBMIT_ERROR(EINVAL, submit, "invalid syncobj flags: %x", syncobj_desc.flags);
			break;
		}

		ret = drm_sched_job_add_syncobj_dependency(&submit->base, file,
							   syncobj_desc.handle, syncobj_desc.point);
		if (ret)
			break;

		if (syncobj_desc.flags & MSM_SUBMIT_SYNCOBJ_RESET) {
			syncobjs[i] =
				drm_syncobj_find(file, syncobj_desc.handle);
			if (!syncobjs[i]) {
				ret = SUBMIT_ERROR(EINVAL, submit, "invalid syncobj handle: %u", i);
				break;
			}
		}
	}

	if (ret) {
		for (j = 0; j <= i; ++j) {
			if (syncobjs[j])
				drm_syncobj_put(syncobjs[j]);
		}
		kfree(syncobjs);
		return ERR_PTR(ret);
	}
	return syncobjs;
}

static void msm_reset_syncobjs(struct drm_syncobj **syncobjs,
                               uint32_t nr_syncobjs)
{
	uint32_t i;

	for (i = 0; syncobjs && i < nr_syncobjs; ++i) {
		if (syncobjs[i])
			drm_syncobj_replace_fence(syncobjs[i], NULL);
	}
}

static struct msm_submit_post_dep *msm_parse_post_deps(struct drm_device *dev,
                                                       struct drm_file *file,
                                                       uint64_t syncobjs_addr,
                                                       uint32_t nr_syncobjs,
                                                       size_t syncobj_stride)
{
	struct msm_submit_post_dep *post_deps;
	struct drm_msm_gem_submit_syncobj syncobj_desc = {0};
	int ret = 0;
	uint32_t i, j;

	post_deps = kcalloc(nr_syncobjs, sizeof(*post_deps),
			    GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
	if (!post_deps)
		return ERR_PTR(-ENOMEM);

	for (i = 0; i < nr_syncobjs; ++i) {
		uint64_t address = syncobjs_addr + i * syncobj_stride;

		if (copy_from_user(&syncobj_desc,
			           u64_to_user_ptr(address),
			           min(syncobj_stride, sizeof(syncobj_desc)))) {
			ret = -EFAULT;
			break;
		}

		post_deps[i].point = syncobj_desc.point;

		if (syncobj_desc.flags) {
			ret = UERR(EINVAL, dev, "invalid syncobj flags");
			break;
		}

		if (syncobj_desc.point) {
			if (!drm_core_check_feature(dev,
			                            DRIVER_SYNCOBJ_TIMELINE)) {
				ret = UERR(EOPNOTSUPP, dev, "syncobj timeline unsupported");
				break;
			}

			post_deps[i].chain = dma_fence_chain_alloc();
			if (!post_deps[i].chain) {
				ret = -ENOMEM;
				break;
			}
		}

		post_deps[i].syncobj =
			drm_syncobj_find(file, syncobj_desc.handle);
		if (!post_deps[i].syncobj) {
			ret = UERR(EINVAL, dev, "invalid syncobj handle");
			break;
		}
	}

	if (ret) {
		for (j = 0; j <= i; ++j) {
			dma_fence_chain_free(post_deps[j].chain);
			if (post_deps[j].syncobj)
				drm_syncobj_put(post_deps[j].syncobj);
		}

		kfree(post_deps);
		return ERR_PTR(ret);
	}

	return post_deps;
}

static void msm_process_post_deps(struct msm_submit_post_dep *post_deps,
                                  uint32_t count, struct dma_fence *fence)
{
	uint32_t i;

	for (i = 0; post_deps && i < count; ++i) {
		if (post_deps[i].chain) {
			drm_syncobj_add_point(post_deps[i].syncobj,
			                      post_deps[i].chain,
			                      fence, post_deps[i].point);
			post_deps[i].chain = NULL;
		} else {
			drm_syncobj_replace_fence(post_deps[i].syncobj,
			                          fence);
		}
	}
}

int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
		struct drm_file *file)
{
@@ -668,7 +502,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
	struct msm_gpu *gpu = priv->gpu;
	struct msm_gpu_submitqueue *queue;
	struct msm_ringbuffer *ring;
	struct msm_submit_post_dep *post_deps = NULL;
	struct msm_syncobj_post_dep *post_deps = NULL;
	struct drm_syncobj **syncobjs_to_reset = NULL;
	struct sync_file *sync_file = NULL;
	int out_fence_fd = -1;
@@ -746,8 +580,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
	}

	if (args->flags & MSM_SUBMIT_SYNCOBJ_IN) {
		syncobjs_to_reset = msm_parse_deps(submit, file,
		                                   args->in_syncobjs,
		syncobjs_to_reset = msm_syncobj_parse_deps(dev, &submit->base,
							   file, args->in_syncobjs,
							   args->nr_in_syncobjs,
							   args->syncobj_stride);
		if (IS_ERR(syncobjs_to_reset)) {
@@ -757,7 +591,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
	}

	if (args->flags & MSM_SUBMIT_SYNCOBJ_OUT) {
		post_deps = msm_parse_post_deps(dev, file,
		post_deps = msm_syncobj_parse_post_deps(dev, file,
							args->out_syncobjs,
							args->nr_out_syncobjs,
							args->syncobj_stride);
@@ -903,10 +737,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
	args->fence = submit->fence_id;
	queue->last_fence = submit->fence_id;

	msm_reset_syncobjs(syncobjs_to_reset, args->nr_in_syncobjs);
	msm_process_post_deps(post_deps, args->nr_out_syncobjs,
	                      submit->user_fence);

	msm_syncobj_reset(syncobjs_to_reset, args->nr_in_syncobjs);
	msm_syncobj_process_post_deps(post_deps, args->nr_out_syncobjs, submit->user_fence);

out:
	submit_cleanup(submit, !!ret);
+172 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2020 Google, Inc */

#include "drm/drm_drv.h"

#include "msm_drv.h"
#include "msm_syncobj.h"

struct drm_syncobj **
msm_syncobj_parse_deps(struct drm_device *dev,
		       struct drm_sched_job *job,
		       struct drm_file *file,
		       uint64_t in_syncobjs_addr,
		       uint32_t nr_in_syncobjs,
		       size_t syncobj_stride)
{
	struct drm_syncobj **syncobjs = NULL;
	struct drm_msm_syncobj syncobj_desc = {0};
	int ret = 0;
	uint32_t i, j;

	syncobjs = kcalloc(nr_in_syncobjs, sizeof(*syncobjs),
	                   GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
	if (!syncobjs)
		return ERR_PTR(-ENOMEM);

	for (i = 0; i < nr_in_syncobjs; ++i) {
		uint64_t address = in_syncobjs_addr + i * syncobj_stride;

		if (copy_from_user(&syncobj_desc,
			           u64_to_user_ptr(address),
			           min(syncobj_stride, sizeof(syncobj_desc)))) {
			ret = -EFAULT;
			break;
		}

		if (syncobj_desc.point &&
		    !drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) {
			ret = UERR(EOPNOTSUPP, dev, "syncobj timeline unsupported");
			break;
		}

		if (syncobj_desc.flags & ~MSM_SYNCOBJ_FLAGS) {
			ret = UERR(EINVAL, dev, "invalid syncobj flags: %x", syncobj_desc.flags);
			break;
		}

		ret = drm_sched_job_add_syncobj_dependency(job, file,
						   syncobj_desc.handle,
						   syncobj_desc.point);
		if (ret)
			break;

		if (syncobj_desc.flags & MSM_SYNCOBJ_RESET) {
			syncobjs[i] = drm_syncobj_find(file, syncobj_desc.handle);
			if (!syncobjs[i]) {
				ret = UERR(EINVAL, dev, "invalid syncobj handle: %u", i);
				break;
			}
		}
	}

	if (ret) {
		for (j = 0; j <= i; ++j) {
			if (syncobjs[j])
				drm_syncobj_put(syncobjs[j]);
		}
		kfree(syncobjs);
		return ERR_PTR(ret);
	}
	return syncobjs;
}

void
msm_syncobj_reset(struct drm_syncobj **syncobjs, uint32_t nr_syncobjs)
{
	uint32_t i;

	for (i = 0; syncobjs && i < nr_syncobjs; ++i) {
		if (syncobjs[i])
			drm_syncobj_replace_fence(syncobjs[i], NULL);
	}
}

struct msm_syncobj_post_dep *
msm_syncobj_parse_post_deps(struct drm_device *dev,
			    struct drm_file *file,
			    uint64_t syncobjs_addr,
			    uint32_t nr_syncobjs,
			    size_t syncobj_stride)
{
	struct msm_syncobj_post_dep *post_deps;
	struct drm_msm_syncobj syncobj_desc = {0};
	int ret = 0;
	uint32_t i, j;

	post_deps = kcalloc(nr_syncobjs, sizeof(*post_deps),
			    GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
	if (!post_deps)
		return ERR_PTR(-ENOMEM);

	for (i = 0; i < nr_syncobjs; ++i) {
		uint64_t address = syncobjs_addr + i * syncobj_stride;

		if (copy_from_user(&syncobj_desc,
			           u64_to_user_ptr(address),
			           min(syncobj_stride, sizeof(syncobj_desc)))) {
			ret = -EFAULT;
			break;
		}

		post_deps[i].point = syncobj_desc.point;

		if (syncobj_desc.flags) {
			ret = UERR(EINVAL, dev, "invalid syncobj flags");
			break;
		}

		if (syncobj_desc.point) {
			if (!drm_core_check_feature(dev,
			                            DRIVER_SYNCOBJ_TIMELINE)) {
				ret = UERR(EOPNOTSUPP, dev, "syncobj timeline unsupported");
				break;
			}

			post_deps[i].chain = dma_fence_chain_alloc();
			if (!post_deps[i].chain) {
				ret = -ENOMEM;
				break;
			}
		}

		post_deps[i].syncobj =
			drm_syncobj_find(file, syncobj_desc.handle);
		if (!post_deps[i].syncobj) {
			ret = UERR(EINVAL, dev, "invalid syncobj handle");
			break;
		}
	}

	if (ret) {
		for (j = 0; j <= i; ++j) {
			dma_fence_chain_free(post_deps[j].chain);
			if (post_deps[j].syncobj)
				drm_syncobj_put(post_deps[j].syncobj);
		}

		kfree(post_deps);
		return ERR_PTR(ret);
	}

	return post_deps;
}

void
msm_syncobj_process_post_deps(struct msm_syncobj_post_dep *post_deps,
			      uint32_t count, struct dma_fence *fence)
{
	uint32_t i;

	for (i = 0; post_deps && i < count; ++i) {
		if (post_deps[i].chain) {
			drm_syncobj_add_point(post_deps[i].syncobj,
			                      post_deps[i].chain,
			                      fence, post_deps[i].point);
			post_deps[i].chain = NULL;
		} else {
			drm_syncobj_replace_fence(post_deps[i].syncobj,
			                          fence);
		}
	}
}
+37 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2020 Google, Inc */

#ifndef __MSM_GEM_SYNCOBJ_H__
#define __MSM_GEM_SYNCOBJ_H__

#include "drm/drm_device.h"
#include "drm/drm_syncobj.h"
#include "drm/gpu_scheduler.h"

struct msm_syncobj_post_dep {
	struct drm_syncobj *syncobj;
	uint64_t point;
	struct dma_fence_chain *chain;
};

struct drm_syncobj **
msm_syncobj_parse_deps(struct drm_device *dev,
		       struct drm_sched_job *job,
		       struct drm_file *file,
		       uint64_t in_syncobjs_addr,
		       uint32_t nr_in_syncobjs,
		       size_t syncobj_stride);

void msm_syncobj_reset(struct drm_syncobj **syncobjs, uint32_t nr_syncobjs);

struct msm_syncobj_post_dep *
msm_syncobj_parse_post_deps(struct drm_device *dev,
			    struct drm_file *file,
			    uint64_t syncobjs_addr,
			    uint32_t nr_syncobjs,
			    size_t syncobj_stride);

void msm_syncobj_process_post_deps(struct msm_syncobj_post_dep *post_deps,
				   uint32_t count, struct dma_fence *fence);

#endif /* __MSM_GEM_SYNCOBJ_H__ */
+13 −13
Original line number Diff line number Diff line
@@ -220,6 +220,17 @@ struct drm_msm_gem_cpu_fini {
 * Cmdstream Submission:
 */

#define MSM_SYNCOBJ_RESET 0x00000001 /* Reset syncobj after wait. */
#define MSM_SYNCOBJ_FLAGS ( \
		MSM_SYNCOBJ_RESET | \
		0)

struct drm_msm_syncobj {
	__u32 handle;     /* in, syncobj handle. */
	__u32 flags;      /* in, from MSM_SUBMIT_SYNCOBJ_FLAGS */
	__u64 point;      /* in, timepoint for timeline syncobjs. */
};

/* The value written into the cmdstream is logically:
 *
 *   ((relocbuf->gpuaddr + reloc_offset) << shift) | or
@@ -309,17 +320,6 @@ struct drm_msm_gem_submit_bo {
		MSM_SUBMIT_FENCE_SN_IN   | \
		0)

#define MSM_SUBMIT_SYNCOBJ_RESET 0x00000001 /* Reset syncobj after wait. */
#define MSM_SUBMIT_SYNCOBJ_FLAGS        ( \
		MSM_SUBMIT_SYNCOBJ_RESET | \
		0)

struct drm_msm_gem_submit_syncobj {
	__u32 handle;     /* in, syncobj handle. */
	__u32 flags;      /* in, from MSM_SUBMIT_SYNCOBJ_FLAGS */
	__u64 point;      /* in, timepoint for timeline syncobjs. */
};

/* Each cmdstream submit consists of a table of buffers involved, and
 * one or more cmdstream buffers.  This allows for conditional execution
 * (context-restore), and IB buffers needed for per tile/bin draw cmds.
@@ -333,8 +333,8 @@ struct drm_msm_gem_submit {
	__u64 cmds;           /* in, ptr to array of submit_cmd's */
	__s32 fence_fd;       /* in/out fence fd (see MSM_SUBMIT_FENCE_FD_IN/OUT) */
	__u32 queueid;        /* in, submitqueue id */
	__u64 in_syncobjs;    /* in, ptr to array of drm_msm_gem_submit_syncobj */
	__u64 out_syncobjs;   /* in, ptr to array of drm_msm_gem_submit_syncobj */
	__u64 in_syncobjs;    /* in, ptr to array of drm_msm_syncobj */
	__u64 out_syncobjs;   /* in, ptr to array of drm_msm_syncobj */
	__u32 nr_in_syncobjs; /* in, number of entries in in_syncobj */
	__u32 nr_out_syncobjs; /* in, number of entries in out_syncobj. */
	__u32 syncobj_stride; /* in, stride of syncobj arrays. */