diff options
author | Thierry Reding <treding@nvidia.com> | 2018-04-23 10:56:29 +0200 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2018-05-02 17:29:40 +0200 |
commit | d9b4cfc82ff2f1c95ebab96ca7d9d26fe078e92a (patch) | |
tree | fb861b0421d6fee768acd903b9d61d9890de11d8 | |
parent | d68e69983555bbb858139ee6e6f1abe5ccc3c31e (diff) |
tegra: Add API to wait for job completion
The API uses fences emitted by the job submission to wait for the
completion of the job.
Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | tegra/fence.c | 105 | ||||
-rw-r--r-- | tegra/job.c | 85 | ||||
-rw-r--r-- | tegra/tegra.h | 8 |
3 files changed, 159 insertions, 39 deletions
diff --git a/tegra/fence.c b/tegra/fence.c index 7e3dc432..8491b01b 100644 --- a/tegra/fence.c +++ b/tegra/fence.c @@ -35,39 +35,26 @@ #include "private.h" -static int drm_tegra_syncobj_destroy(struct drm_tegra *drm, uint32_t handle) +int drm_tegra_wait_fence(struct drm_tegra *drm, struct drm_fence *fence) { - struct drm_syncobj_destroy args; int err; - memset(&args, 0, sizeof(args)); - args.handle = handle; - - err = ioctl(drm->fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args); - if (err < 0) - return -errno; - - return 0; -} - -int drm_tegra_fence_wait(struct drm_tegra *drm, struct drm_tegra_fence *fence) -{ - int err; - - if ((fence->flags & DRM_TEGRA_FENCE_EMIT) == 0) - return 0; + if (fence->type == DRM_FENCE_SYNCOBJ) { + struct drm_syncobj_wait args; - printf("fence: %p\n", fence); - printf(" handle: %u\n", fence->handle); - printf(" flags: %x\n", fence->flags); - printf(" offset: %x\n", fence->offset); - printf(" index: %u\n", fence->index); - printf(" value: %u\n", fence->value); + memset(&args, 0, sizeof(args)); + args.handles = (uintptr_t)&fence->fence.handle; + args.count_handles = 1; + args.timeout_nsec = -1; + args.flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL; - if (fence->flags & DRM_TEGRA_FENCE_FD) { + err = ioctl(drm->fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); + if (err < 0) + err = -errno; + } else { while (true) { struct pollfd fds = { - .fd = fence->handle, + .fd = fence->fence.fd, .events = POLLIN, }; @@ -91,23 +78,65 @@ int drm_tegra_fence_wait(struct drm_tegra *drm, struct drm_tegra_fence *fence) break; } } + } - close(fence->handle); - } else { - struct drm_syncobj_wait args; + return err; +} - memset(&args, 0, sizeof(args)); - args.handles = (uintptr_t)&fence->handle; - args.count_handles = 1; - args.timeout_nsec = -1; - args.flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL; +int drm_tegra_wait_fences(struct drm_tegra *drm, struct drm_fence *fences, + unsigned int num_fences) +{ + unsigned int i; + int err; - err = ioctl(drm->fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); + for (i = 0; i < num_fences; i++) { + err = drm_tegra_wait_fence(drm, &fences[i]); if (err < 0) - err = -errno; + return err; + } + + return 0; +} + +static int drm_syncobj_destroy(int fd, uint32_t handle) +{ + struct drm_syncobj_destroy args; + int err; + + memset(&args, 0, sizeof(args)); + args.handle = handle; + + err = ioctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args); + if (err < 0) + return -errno; - drm_tegra_syncobj_destroy(drm, fence->handle); + return 0; +} + +int drm_tegra_put_fence(struct drm_tegra *drm, struct drm_fence *fence) +{ + if (fence->type == DRM_FENCE_SYNCOBJ) + return drm_syncobj_destroy(drm->fd, fence->fence.handle); + + if (fence->fence.fd < 0) + return -EINVAL; + + close(fence->fence.fd); + + return 0; +} + +int drm_tegra_put_fences(struct drm_tegra *drm, struct drm_fence *fences, + unsigned int num_fences) +{ + unsigned int i; + int err; + + for (i = 0; i < num_fences; i++) { + err = drm_tegra_put_fence(drm, &fences[i]); + if (err < 0) + return err; } - return err; + return 0; } diff --git a/tegra/job.c b/tegra/job.c index 80b6a855..46760a57 100644 --- a/tegra/job.c +++ b/tegra/job.c @@ -29,8 +29,11 @@ #include <errno.h> #include <stdlib.h> #include <string.h> +#include <time.h> +#include <unistd.h> #include <sys/ioctl.h> +#include <sys/poll.h> #include "private.h" @@ -212,6 +215,88 @@ unsigned int drm_tegra_job_get_fences(struct drm_tegra_job *job, return num; } +static int drm_tegra_syncobj_destroy(struct drm_tegra *drm, uint32_t handle) +{ + struct drm_syncobj_destroy args; + int err; + + memset(&args, 0, sizeof(args)); + args.handle = handle; + + err = ioctl(drm->fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args); + if (err < 0) + return -errno; + + return 0; +} + +static uint64_t clock_get_nanoseconds(void) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + return ts.tv_sec * UINT64_C(1000000000) + ts.tv_nsec; +} + +static int drm_tegra_fence_wait(struct drm_tegra *drm, + struct drm_tegra_fence *fence) +{ + unsigned int timeout = 5000; + int err; + + if ((fence->flags & DRM_TEGRA_FENCE_EMIT) == 0) + return 0; + + if (fence->flags & DRM_TEGRA_FENCE_FD) { + while (true) { + struct pollfd fds = { + .fd = fence->handle, + .events = POLLIN, + }; + + err = poll(&fds, 1, timeout); + if (err > 0) { + if (fds.revents & (POLLERR | POLLNVAL)) + err = -EINVAL; + else + err = 0; + + break; + } + + if (err == 0) { + err = -ETIMEDOUT; + break; + } + + if (errno != EINTR && errno != EAGAIN) { + err = -errno; + break; + } + } + + close(fence->handle); + } else { + uint64_t to = clock_get_nanoseconds() + UINT64_C(timeout * 1000000); + struct drm_syncobj_wait args; + + memset(&args, 0, sizeof(args)); + args.handles = (uintptr_t)&fence->handle; + args.count_handles = 1; + args.timeout_nsec = to; + args.flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL; + + err = ioctl(drm->fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); + if (err < 0) + err = -errno; + + drm_tegra_syncobj_destroy(drm, fence->handle); + } + + return err; +} + int drm_tegra_job_wait(struct drm_tegra_job *job) { struct drm_tegra *drm = job->channel->drm; diff --git a/tegra/tegra.h b/tegra/tegra.h index f0b68ddc..ddcf229d 100644 --- a/tegra/tegra.h +++ b/tegra/tegra.h @@ -87,7 +87,13 @@ int drm_tegra_channel_close(struct drm_tegra_channel *channel); unsigned int drm_tegra_channel_get_syncpoints(struct drm_tegra_channel *channel); unsigned int drm_tegra_channel_get_version(struct drm_tegra_channel *channel); -int drm_tegra_fence_wait(struct drm_tegra *drm, struct drm_tegra_fence *fence); +int drm_tegra_wait_fence(struct drm_tegra *drm, struct drm_fence *fence); +int drm_tegra_wait_fences(struct drm_tegra *drm, struct drm_fence *fences, + unsigned int num_fences); + +int drm_tegra_put_fence(struct drm_tegra *drm, struct drm_fence *fence); +int drm_tegra_put_fences(struct drm_tegra *drm, struct drm_fence *fences, + unsigned int num_fences); int drm_tegra_job_new(struct drm_tegra_job **jobp, struct drm_tegra_channel *channel); |