summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2018-04-23 10:56:29 +0200
committerThierry Reding <treding@nvidia.com>2018-05-02 17:29:40 +0200
commitd9b4cfc82ff2f1c95ebab96ca7d9d26fe078e92a (patch)
treefb861b0421d6fee768acd903b9d61d9890de11d8
parentd68e69983555bbb858139ee6e6f1abe5ccc3c31e (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.c105
-rw-r--r--tegra/job.c85
-rw-r--r--tegra/tegra.h8
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);