From 9b44f814ea1a6d2bfc12549670824d8206b015af Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 24 Feb 2014 11:55:13 +0100 Subject: WIP: tegra: Update for de-staged ABI Signed-off-by: Thierry Reding --- include/drm/tegra_drm.h | 465 +++++++++++++++++++++++++++++++++---------- tegra/channel.c | 35 +--- tegra/fence.c | 95 ++++++--- tegra/job.c | 130 ++++++++---- tegra/private.h | 31 +-- tegra/pushbuf.c | 111 +++++++++-- tegra/tegra.c | 97 +-------- tegra/tegra.h | 62 +++--- tests/tegra/drm-test-tegra.c | 6 +- tests/tegra/host1x.h | 34 ++++ 10 files changed, 719 insertions(+), 347 deletions(-) create mode 100644 tests/tegra/host1x.h diff --git a/include/drm/tegra_drm.h b/include/drm/tegra_drm.h index 12f9bf84..f61dc5ae 100644 --- a/include/drm/tegra_drm.h +++ b/include/drm/tegra_drm.h @@ -29,178 +29,431 @@ extern "C" { #endif -#define DRM_TEGRA_GEM_CREATE_TILED (1 << 0) -#define DRM_TEGRA_GEM_CREATE_BOTTOM_UP (1 << 1) +#define DRM_TEGRA_GEM_CONTIGUOUS (1 << 0) +#define DRM_TEGRA_GEM_FLAGS (DRM_TEGRA_GEM_CONTIGUOUS) +/** + * struct drm_tegra_gem_create - parameters for the GEM object creation IOCTL + */ struct drm_tegra_gem_create { + /** + * @size: + * + * The size, in bytes, of the buffer object to be created. + */ __u64 size; + + /** + * @flags: + * + * A bitmask of flags that influence the creation of GEM objects: + * + * DRM_TEGRA_GEM_CONTIGUOUS - The buffer is to be backed by physically + * contiguous memory. + */ __u32 flags; + + /** + * @handle: + * + * Return location for the handle of the created GEM object. + */ __u32 handle; }; +/** + * struct drm_tegra_gem_mmap - parameters for the GEM mmap IOCTL + */ struct drm_tegra_gem_mmap { + /** + * @handle: + * + * Handle of the GEM object to obtain an mmap offset for. + */ __u32 handle; - __u32 pad; - __u64 offset; -}; - -struct drm_tegra_syncpt_read { - __u32 id; - __u32 value; -}; -struct drm_tegra_syncpt_incr { - __u32 id; + /** + * @pad: + * + * Structure padding that may be used in the future. Must be 0. + */ __u32 pad; -}; -struct drm_tegra_syncpt_wait { - __u32 id; - __u32 thresh; - __u32 timeout; - __u32 value; + /** + * @offset: + * + * Return location for the mmap offset for the given GEM object. + */ + __u64 offset; }; -#define DRM_TEGRA_NO_TIMEOUT (0xffffffff) +#define DRM_TEGRA_CHANNEL_FLAGS (0) struct drm_tegra_open_channel { + /** + * @client: + * + * The client ID for this channel. + */ __u32 client; - __u32 pad; + + /** + * @flags: + * + * A bitmask of flags that influence the channel creation. Currently + * no flags are defined, so this must be 0. + */ + __u32 flags; + + /** + * @syncpts: + * + * Return location for the number of syncpoints used by this channel. + */ + __u32 syncpts; + + /** + * @version: + * + * Return location for the implementation version of this channel. + */ + __u32 version; + + /** + * @context: + * + * Return location for the application context of this channel. This + * context needs to be passed to the DRM_TEGRA_CHANNEL_CLOSE or the + * DRM_TEGRA_SUBMIT IOCTLs. + */ __u64 context; + + /** + * @reserved: + * + * This field is reserved for future use. Must be 0. + */ + __u64 reserved; }; struct drm_tegra_close_channel { + /** + * @context: + * + * The application context of this channel. This is obtained from the + * DRM_TEGRA_OPEN_CHANNEL IOCTL. + */ __u64 context; }; -struct drm_tegra_get_syncpt { - __u64 context; - __u32 index; - __u32 id; -}; +#define DRM_TEGRA_BUFFER_FLAGS (0) -struct drm_tegra_get_syncpt_base { - __u64 context; - __u32 syncpt; - __u32 id; +struct drm_tegra_buffer { + /** + * @handle: + * + * Handle of the buffer. + */ + __u32 handle; + + /** + * @flags: + * + * A bitmask of flags specifying the usage of the buffer. Currently no + * flags are defined, so this must be 0. + */ + __u32 flags; }; -struct drm_tegra_syncpt { - __u32 id; - __u32 incrs; +#define DRM_TEGRA_FENCE_WAIT (1 << 0) +#define DRM_TEGRA_FENCE_EMIT (1 << 1) +#define DRM_TEGRA_FENCE_FD (1 << 2) +#define DRM_TEGRA_FENCE_FLAGS (DRM_TEGRA_FENCE_WAIT | \ + DRM_TEGRA_FENCE_EMIT | \ + DRM_TEGRA_FENCE_FD) + +struct drm_tegra_fence { + /** + * @handle: + * + * Handle (syncobj) or file descriptor (sync FD) of the fence. It is + * interpreted based on the DRM_TEGRA_FENCE_FD flag (see below). + */ + __u32 handle; + + /** + * @flags: + * + * A bitmask of flags that specify this fence. + * + * DRM_TEGRA_FENCE_WAIT - Wait for this fence before the new command + * buffer is submitted. + * DRM_TEGRA_FENCE_EMIT - Emit this fence when the command buffer is + * done being processed. + * DRM_TEGRA_FENCE_FD - This fence is a sync FD. If not specified, a + * syncobj will be used. + */ + __u32 flags; + + /** + * @offset: + * + * Offset in the command stream for this fence. This is used to patch + * the command stream with the resolved syncpoint ID. + */ + __u32 offset; + + /** + * @index: + * + * Syncpoint to use for this fence. This is an index into the list of + * syncpoints of the channel. It will be resolved to a real syncpoint + * ID upon job submission. + */ + __u32 index; + + /** + * @value: + * + * Number of times to increment the syncpoint. + */ + __u32 value; + + /** + * @reserved: + * + * This field is reserved for future use. Must be 0. + */ + __u32 reserved[3]; }; +#define DRM_TEGRA_CMDBUF_FLAGS (0) + +/** + * struct drm_tegra_cmdbuf - structure describing a command buffer + */ struct drm_tegra_cmdbuf { - __u32 handle; + /** + * @index: + * + * Index into the job's buffer handle list, pointing to the handle of + * the GEM object that contains this command buffer. + */ + __u32 index; + + /** + * @offset: + * + * Offset, in bytes, into the GEM object at which the command buffer + * starts. Needs to be a multiple of 4. + */ __u32 offset; + + /** + * @words: + * + * Number of 32-bit words in this command buffer. + */ __u32 words; + + /** + * @flags: + * + * A bitmask of flags that influence the processing of this command + * buffer. Currently no flags are defined, so this must be 0. + */ + __u32 flags; + + /** + * @pad: + * + * Structure padding that may be used in the future. Must be 0. + */ __u32 pad; + + /** + * @num_fences: + * + * The number of fences attached to this command buffer. + */ + __u32 num_fences; + + /** + * @fences: + * + * Pointer to an array of @num_fences &struct drm_tegra_fence objects. + */ + __u64 fences; }; +#define DRM_TEGRA_RELOC_FLAGS (0) + +/** + * struct drm_tegra_reloc - GEM object relocation structure + */ struct drm_tegra_reloc { struct { - __u32 handle; + /** + * @cmdbuf.index: + * + * Index into the job's buffer handle list pointing to the + * handle of the GEM object containing the command buffer for + * which to perform this GEM object relocation. + */ + __u32 index; + + /** + * @cmdbuf.offset: + * + * Offset into the command buffer at which to insert the the + * relocated address. + */ __u32 offset; } cmdbuf; + struct { - __u32 handle; + /** + * @target.index: + * + * Index into the job's buffer handle list pointing to the + * handle of the GEM object to be relocated. + */ + __u32 index; + + /** + * @target.offset: + * + * Offset into the target GEM object at which the relocated + * data starts. + */ __u32 offset; } target; + + /** + * @shift: + * + * The number of bits by which to shift relocated addresses. + */ __u32 shift; - __u32 pad; -}; -struct drm_tegra_waitchk { - __u32 handle; - __u32 offset; - __u32 syncpt; - __u32 thresh; + /** + * @flags: + * + * A bitmask of flags that determine how the GEM object should be + * relocated. + */ + __u32 flags; + + /** + * @reserved: + * + * This field is reserved for future use. Must be 0. + */ + __u64 reserved; }; +#define DRM_TEGRA_SUBMIT_FLAGS (0) + +/** + * struct drm_tegra_submit - job submission structure + */ struct drm_tegra_submit { + /** + * @context: + * + * The application context identifying the channel to use for the + * execution of this job. + */ __u64 context; - __u32 num_syncpts; + + /** + * @num_buffers: + * + * The number of GEM objects used during the execution of this job. + */ + __u32 num_buffers; + + /** + * @num_cmdbufs: + * + * The number of command buffers to execute as part of this job. + */ __u32 num_cmdbufs; - __u32 num_relocs; - __u32 num_waitchks; - __u32 waitchk_mask; - __u32 timeout; - __u64 syncpts; - __u64 cmdbufs; - __u64 relocs; - __u64 waitchks; - __u32 fence; /* Return value */ - __u32 reserved[5]; /* future expansion */ -}; + /** + * @num_relocs: + * + * The number of relocations to perform before executing this job. + */ + __u32 num_relocs; -#define DRM_TEGRA_GEM_TILING_MODE_PITCH 0 -#define DRM_TEGRA_GEM_TILING_MODE_TILED 1 -#define DRM_TEGRA_GEM_TILING_MODE_BLOCK 2 + /** + * @timeout: + * + * The maximum amount of time, in milliseconds, to allow for the + * execution of this job. + */ + __u32 timeout; -struct drm_tegra_gem_set_tiling { - /* input */ - __u32 handle; - __u32 mode; - __u32 value; - __u32 pad; -}; + /** + * @buffers: + * + * A pointer to @num_buffers &struct drm_tegra_buffer structures that + * specify the GEM objects used during the execution of this job. + */ + __u64 buffers; -struct drm_tegra_gem_get_tiling { - /* input */ - __u32 handle; - /* output */ - __u32 mode; - __u32 value; - __u32 pad; -}; + /** + * @cmdbufs: + * + * A pointer to @num_cmdbufs &struct drm_tegra_cmdbuf structures that + * define the command buffers to execute as part of this job. + */ + __u64 cmdbufs; -#define DRM_TEGRA_GEM_BOTTOM_UP (1 << 0) -#define DRM_TEGRA_GEM_FLAGS (DRM_TEGRA_GEM_BOTTOM_UP) + /** + * @relocs: + * + * A pointer to @num_relocs &struct drm_tegra_reloc structures that + * specify the relocations that need to be performed before executing + * this job. + */ + __u64 relocs; -struct drm_tegra_gem_set_flags { - /* input */ - __u32 handle; - /* output */ + /** + * @flags: + * + * A bitmask of flags that specify how to execute this job. Currently + * no flags are defined, so this must be 0. + */ __u32 flags; -}; -struct drm_tegra_gem_get_flags { - /* input */ - __u32 handle; - /* output */ - __u32 flags; + /** + * @pad: + * + * Structure padding that may be used in the future. Must be 0. + */ + __u32 pad; + + /** + * @reserved: + * + * This field is reserved for future use. Must be 0. + */ + __u64 reserved[9]; /* future expansion */ }; #define DRM_TEGRA_GEM_CREATE 0x00 #define DRM_TEGRA_GEM_MMAP 0x01 -#define DRM_TEGRA_SYNCPT_READ 0x02 -#define DRM_TEGRA_SYNCPT_INCR 0x03 -#define DRM_TEGRA_SYNCPT_WAIT 0x04 -#define DRM_TEGRA_OPEN_CHANNEL 0x05 -#define DRM_TEGRA_CLOSE_CHANNEL 0x06 -#define DRM_TEGRA_GET_SYNCPT 0x07 -#define DRM_TEGRA_SUBMIT 0x08 -#define DRM_TEGRA_GET_SYNCPT_BASE 0x09 -#define DRM_TEGRA_GEM_SET_TILING 0x0a -#define DRM_TEGRA_GEM_GET_TILING 0x0b -#define DRM_TEGRA_GEM_SET_FLAGS 0x0c -#define DRM_TEGRA_GEM_GET_FLAGS 0x0d +#define DRM_TEGRA_OPEN_CHANNEL 0x02 +#define DRM_TEGRA_CLOSE_CHANNEL 0x03 +#define DRM_TEGRA_SUBMIT 0x04 #define DRM_IOCTL_TEGRA_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_CREATE, struct drm_tegra_gem_create) #define DRM_IOCTL_TEGRA_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_MMAP, struct drm_tegra_gem_mmap) -#define DRM_IOCTL_TEGRA_SYNCPT_READ DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_READ, struct drm_tegra_syncpt_read) -#define DRM_IOCTL_TEGRA_SYNCPT_INCR DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_INCR, struct drm_tegra_syncpt_incr) -#define DRM_IOCTL_TEGRA_SYNCPT_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_WAIT, struct drm_tegra_syncpt_wait) #define DRM_IOCTL_TEGRA_OPEN_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_OPEN_CHANNEL, struct drm_tegra_open_channel) -#define DRM_IOCTL_TEGRA_CLOSE_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_CLOSE_CHANNEL, struct drm_tegra_open_channel) -#define DRM_IOCTL_TEGRA_GET_SYNCPT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GET_SYNCPT, struct drm_tegra_get_syncpt) +#define DRM_IOCTL_TEGRA_CLOSE_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_CLOSE_CHANNEL, struct drm_tegra_close_channel) #define DRM_IOCTL_TEGRA_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SUBMIT, struct drm_tegra_submit) -#define DRM_IOCTL_TEGRA_GET_SYNCPT_BASE DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GET_SYNCPT_BASE, struct drm_tegra_get_syncpt_base) -#define DRM_IOCTL_TEGRA_GEM_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_SET_TILING, struct drm_tegra_gem_set_tiling) -#define DRM_IOCTL_TEGRA_GEM_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_GET_TILING, struct drm_tegra_gem_get_tiling) -#define DRM_IOCTL_TEGRA_GEM_SET_FLAGS DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_SET_FLAGS, struct drm_tegra_gem_set_flags) -#define DRM_IOCTL_TEGRA_GEM_GET_FLAGS DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_GET_FLAGS, struct drm_tegra_gem_get_flags) #if defined(__cplusplus) } diff --git a/tegra/channel.c b/tegra/channel.c index 3818b5e8..4a41daaa 100644 --- a/tegra/channel.c +++ b/tegra/channel.c @@ -33,25 +33,6 @@ #include "private.h" -static int drm_tegra_channel_setup(struct drm_tegra_channel *channel) -{ - struct drm_tegra *drm = channel->drm; - struct drm_tegra_get_syncpt args; - int err; - - memset(&args, 0, sizeof(args)); - args.context = channel->context; - args.index = 0; - - err = ioctl(drm->fd, DRM_IOCTL_TEGRA_GET_SYNCPT, &args); - if (err < 0) - return -errno; - - channel->syncpt = args.id; - - return 0; -} - int drm_tegra_channel_open(struct drm_tegra_channel **channelp, struct drm_tegra *drm, enum drm_tegra_class client) @@ -62,6 +43,10 @@ int drm_tegra_channel_open(struct drm_tegra_channel **channelp, int err; switch (client) { + case DRM_TEGRA_HOST1X: + class = HOST1X_CLASS_HOST1X; + break; + case DRM_TEGRA_GR2D: class = HOST1X_CLASS_GR2D; break; @@ -89,15 +74,10 @@ int drm_tegra_channel_open(struct drm_tegra_channel **channelp, return -errno; } + channel->num_syncpts = args.syncpts; channel->context = args.context; channel->class = class; - err = drm_tegra_channel_setup(channel); - if (err < 0) { - free(channel); - return err; - } - *channelp = channel; return 0; @@ -125,3 +105,8 @@ int drm_tegra_channel_close(struct drm_tegra_channel *channel) return 0; } + +unsigned int drm_tegra_channel_get_syncpoints(struct drm_tegra_channel *channel) +{ + return channel->num_syncpts; +} diff --git a/tegra/fence.c b/tegra/fence.c index a2dd394e..7e3dc432 100644 --- a/tegra/fence.c +++ b/tegra/fence.c @@ -1,7 +1,5 @@ /* - * Copyright © 2012, 2013 Thierry Reding - * Copyright © 2013 Erik Faye-Lund - * Copyright © 2014 NVIDIA Corporation + * Copyright © 2018 NVIDIA Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -27,44 +25,89 @@ #endif #include +#include +#include /* XXX remove */ #include +#include #include +#include #include "private.h" -int drm_tegra_fence_wait_timeout(struct drm_tegra_fence *fence, - unsigned long timeout) +static int drm_tegra_syncobj_destroy(struct drm_tegra *drm, uint32_t handle) { - struct drm_tegra_syncpt_wait args; + struct drm_syncobj_destroy args; int err; memset(&args, 0, sizeof(args)); - args.id = fence->syncpt; - args.thresh = fence->value; - args.timeout = timeout; + args.handle = handle; - while (true) { - err = ioctl(fence->drm->fd, DRM_IOCTL_TEGRA_SYNCPT_WAIT, &args); - if (err < 0) { - if (errno == EINTR) - continue; - - return -errno; - } - - break; - } + err = ioctl(drm->fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args); + if (err < 0) + return -errno; return 0; } -int drm_tegra_fence_wait(struct drm_tegra_fence *fence) +int drm_tegra_fence_wait(struct drm_tegra *drm, struct drm_tegra_fence *fence) { - return drm_tegra_fence_wait_timeout(fence, -1); -} + int err; -void drm_tegra_fence_free(struct drm_tegra_fence *fence) -{ - free(fence); + if ((fence->flags & DRM_TEGRA_FENCE_EMIT) == 0) + return 0; + + 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); + + if (fence->flags & DRM_TEGRA_FENCE_FD) { + while (true) { + struct pollfd fds = { + .fd = fence->handle, + .events = POLLIN, + }; + + err = poll(&fds, 1, -1); + 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 { + struct drm_syncobj_wait args; + + 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; + + err = ioctl(drm->fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); + if (err < 0) + err = -errno; + + drm_tegra_syncobj_destroy(drm, fence->handle); + } + + return err; } diff --git a/tegra/job.c b/tegra/job.c index 370c6939..80b6a855 100644 --- a/tegra/job.c +++ b/tegra/job.c @@ -43,7 +43,7 @@ int drm_tegra_job_add_reloc(struct drm_tegra_job *job, size = (job->num_relocs + 1) * sizeof(*reloc); relocs = realloc(job->relocs, size); - if (!reloc) + if (!relocs) return -ENOMEM; job->relocs = relocs; @@ -53,6 +53,41 @@ int drm_tegra_job_add_reloc(struct drm_tegra_job *job, return 0; } +int drm_tegra_job_add_buffer(struct drm_tegra_job *job, + const struct drm_tegra_buffer *buffer, + unsigned int *index) +{ + struct drm_tegra_buffer *buffers; + unsigned int i; + size_t size; + + /* check if the buffer is already in the job's buffer list */ + for (i = 0; i < job->num_buffers; i++) { + if (job->buffers[i].handle == buffer->handle) { + if (index) + *index = i; + + return 0; + } + } + + size = (job->num_buffers + 1) * sizeof(*buffers); + + buffers = realloc(job->buffers, size); + if (!buffers) + return -ENOMEM; + + buffers[job->num_buffers] = *buffer; + job->buffers = buffers; + + if (index) + *index = job->num_buffers; + + job->num_buffers++; + + return 0; +} + int drm_tegra_job_add_cmdbuf(struct drm_tegra_job *job, const struct drm_tegra_cmdbuf *cmdbuf) { @@ -105,12 +140,9 @@ int drm_tegra_job_free(struct drm_tegra_job *job) return 0; } -int drm_tegra_job_submit(struct drm_tegra_job *job, - struct drm_tegra_fence **fencep) +int drm_tegra_job_submit(struct drm_tegra_job *job, unsigned long timeout) { struct drm_tegra *drm = job->channel->drm; - struct drm_tegra_fence *fence = NULL; - struct drm_tegra_syncpt *syncpts; struct drm_tegra_submit args; int err; @@ -124,50 +156,78 @@ int drm_tegra_job_submit(struct drm_tegra_job *job, job->pushbuf = NULL; - if (fencep) { - fence = calloc(1, sizeof(*fence)); - if (!fence) - return -ENOMEM; - } - - syncpts = calloc(1, sizeof(*syncpts)); - if (!syncpts) { - free(fence); - return -ENOMEM; - } - - syncpts[0].id = job->syncpt; - syncpts[0].incrs = job->increments; - memset(&args, 0, sizeof(args)); args.context = job->channel->context; - args.num_syncpts = 1; + args.num_buffers = job->num_buffers; args.num_cmdbufs = job->num_cmdbufs; args.num_relocs = job->num_relocs; - args.num_waitchks = 0; - args.waitchk_mask = 0; args.timeout = 1000; - args.syncpts = (uintptr_t)syncpts; + args.buffers = (uintptr_t)job->buffers; args.cmdbufs = (uintptr_t)job->cmdbufs; args.relocs = (uintptr_t)job->relocs; - args.waitchks = 0; + args.flags = 0; err = ioctl(drm->fd, DRM_IOCTL_TEGRA_SUBMIT, &args); - if (err < 0) { - free(syncpts); - free(fence); + if (err < 0) return -errno; - } - if (fence) { - fence->syncpt = job->syncpt; - fence->value = args.fence; - fence->drm = drm; - *fencep = fence; + return 0; +} + +static inline void *u64_to_ptr(__u64 address) +{ + return (void *)(uintptr_t)address; +} + +unsigned int drm_tegra_job_get_fences(struct drm_tegra_job *job, + struct drm_fence *out_fences, + unsigned int count) +{ + unsigned int i, j, num = 0; + + for (i = 0; i < job->num_cmdbufs; i++) { + struct drm_tegra_cmdbuf *cmdbuf = &job->cmdbufs[i]; + struct drm_tegra_fence *fences = u64_to_ptr(cmdbuf->fences); + + for (j = 0; j < cmdbuf->num_fences; j++) { + struct drm_tegra_fence *fence = &fences[j]; + + if (fence->flags & DRM_TEGRA_FENCE_EMIT) { + if (num < count) { + if ((fence->flags & DRM_TEGRA_FENCE_FD) == 0) { + out_fences[num].fence.handle = fence->handle; + out_fences[num].type = DRM_FENCE_SYNCOBJ; + } else { + out_fences[num].fence.fd = fence->handle; + out_fences[num].type = DRM_FENCE_FD; + } + } + + num++; + } + } } - free(syncpts); + return num; +} + +int drm_tegra_job_wait(struct drm_tegra_job *job) +{ + struct drm_tegra *drm = job->channel->drm; + unsigned int i, j; + int err; + + for (i = 0; i < job->num_cmdbufs; i++) { + struct drm_tegra_cmdbuf *cmdbuf = &job->cmdbufs[i]; + struct drm_tegra_fence *fences = u64_to_ptr(cmdbuf->fences); + + for (j = 0; j < cmdbuf->num_fences; j++) { + err = drm_tegra_fence_wait(drm, &fences[j]); + if (err < 0) + return err; + } + } return 0; } diff --git a/tegra/private.h b/tegra/private.h index 1c9fca7d..9e9ae86c 100644 --- a/tegra/private.h +++ b/tegra/private.h @@ -60,7 +60,7 @@ struct drm_tegra_bo { struct drm_tegra *drm; drmMMListHead list; uint32_t handle; - uint32_t offset; + uint64_t offset; uint32_t flags; uint32_t size; atomic_t ref; @@ -70,14 +70,8 @@ struct drm_tegra_bo { struct drm_tegra_channel { struct drm_tegra *drm; enum host1x_class class; + unsigned int num_syncpts; uint64_t context; - uint32_t syncpt; -}; - -struct drm_tegra_fence { - struct drm_tegra *drm; - uint32_t syncpt; - uint32_t value; }; struct drm_tegra_pushbuf_private { @@ -87,8 +81,12 @@ struct drm_tegra_pushbuf_private { drmMMListHead bos; struct drm_tegra_bo *bo; + unsigned int index; uint32_t *start; uint32_t *end; + + struct drm_tegra_fence *fences; + unsigned int num_fences; }; static inline struct drm_tegra_pushbuf_private * @@ -102,22 +100,25 @@ int drm_tegra_pushbuf_queue(struct drm_tegra_pushbuf_private *pushbuf); struct drm_tegra_job { struct drm_tegra_channel *channel; - unsigned int increments; - uint32_t syncpt; - - struct drm_tegra_reloc *relocs; - unsigned int num_relocs; + struct drm_tegra_buffer *buffers; + unsigned int num_buffers; struct drm_tegra_cmdbuf *cmdbufs; unsigned int num_cmdbufs; + struct drm_tegra_reloc *relocs; + unsigned int num_relocs; + struct drm_tegra_pushbuf_private *pushbuf; drmMMListHead pushbufs; }; -int drm_tegra_job_add_reloc(struct drm_tegra_job *job, - const struct drm_tegra_reloc *reloc); +int drm_tegra_job_add_buffer(struct drm_tegra_job *job, + const struct drm_tegra_buffer *buffer, + unsigned int *index); int drm_tegra_job_add_cmdbuf(struct drm_tegra_job *job, const struct drm_tegra_cmdbuf *cmdbuf); +int drm_tegra_job_add_reloc(struct drm_tegra_job *job, + const struct drm_tegra_reloc *reloc); #endif /* __DRM_TEGRA_PRIVATE_H__ */ diff --git a/tegra/pushbuf.c b/tegra/pushbuf.c index 7be12a76..54a0f831 100644 --- a/tegra/pushbuf.c +++ b/tegra/pushbuf.c @@ -48,9 +48,14 @@ int drm_tegra_pushbuf_queue(struct drm_tegra_pushbuf_private *pushbuf) /* add buffer object as command buffers for this job */ memset(&cmdbuf, 0, sizeof(cmdbuf)); - cmdbuf.words = pushbuf->base.ptr - pushbuf->start; - cmdbuf.handle = pushbuf->bo->handle; + cmdbuf.index = pushbuf->index; cmdbuf.offset = 0; + cmdbuf.words = pushbuf->base.ptr - pushbuf->start; + + if (pushbuf->num_fences) { + cmdbuf.fences = (uintptr_t)pushbuf->fences; + cmdbuf.num_fences = pushbuf->num_fences; + } err = drm_tegra_job_add_cmdbuf(pushbuf->job, &cmdbuf); if (err < 0) @@ -82,7 +87,7 @@ int drm_tegra_pushbuf_new(struct drm_tegra_pushbuf **pushbufp, *pushbufp = &pushbuf->base; - DRMLISTADD(&pushbuf->list, &job->pushbufs); + DRMLISTADDTAIL(&pushbuf->list, &job->pushbufs); job->pushbuf = pushbuf; return 0; @@ -117,6 +122,7 @@ int drm_tegra_pushbuf_prepare(struct drm_tegra_pushbuf *pushbuf, { struct drm_tegra_pushbuf_private *priv = pushbuf_priv(pushbuf); struct drm_tegra_channel *channel = priv->job->channel; + struct drm_tegra_buffer buffer; struct drm_tegra_bo *bo; void *ptr; int err; @@ -148,12 +154,19 @@ int drm_tegra_pushbuf_prepare(struct drm_tegra_pushbuf *pushbuf, return err; } - DRMLISTADD(&bo->list, &priv->bos); + DRMLISTADDTAIL(&bo->list, &priv->bos); priv->start = priv->base.ptr = ptr; - priv->end = priv->start + bo->size; + priv->end = priv->start + bo->size / 4; priv->bo = bo; + memset(&buffer, 0, sizeof(buffer)); + buffer.handle = bo->handle; + + err = drm_tegra_job_add_buffer(priv->job, &buffer, &priv->index); + if (err < 0) + return err; + return 0; } @@ -163,13 +176,22 @@ int drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf *pushbuf, unsigned long shift) { struct drm_tegra_pushbuf_private *priv = pushbuf_priv(pushbuf); + struct drm_tegra_buffer buffer; struct drm_tegra_reloc reloc; + unsigned int index; int err; + memset(&buffer, 0, sizeof(buffer)); + buffer.handle = target->handle; + + err = drm_tegra_job_add_buffer(priv->job, &buffer, &index); + if (err < 0) + return err; + memset(&reloc, 0, sizeof(reloc)); - reloc.cmdbuf.handle = priv->bo->handle; + reloc.cmdbuf.index = priv->index; reloc.cmdbuf.offset = drm_tegra_pushbuf_get_offset(pushbuf); - reloc.target.handle = target->handle; + reloc.target.index = index; reloc.target.offset = offset; reloc.shift = shift; @@ -182,17 +204,82 @@ int drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf *pushbuf, return 0; } -int drm_tegra_pushbuf_sync(struct drm_tegra_pushbuf *pushbuf, - enum drm_tegra_syncpt_cond cond) +static int drm_tegra_pushbuf_add_fence(struct drm_tegra_pushbuf *pushbuf, + const struct drm_tegra_fence *fence) { struct drm_tegra_pushbuf_private *priv = pushbuf_priv(pushbuf); + struct drm_tegra_fence *fences; + size_t size; + + size = (priv->num_fences + 1) * sizeof(*fence); + + fences = realloc(priv->fences, size); + if (!fences) + return -ENOMEM; + + priv->fences = fences; + + priv->fences[priv->num_fences++] = *fence; + + return 0; +} + +int drm_tegra_pushbuf_wait_fd(struct drm_tegra_pushbuf *pushbuf, + int fd) +{ + struct drm_tegra_fence fence; + int err; + + memset(&fence, 0, sizeof(fence)); + fence.handle = fd; + fence.flags = DRM_TEGRA_FENCE_FD | DRM_TEGRA_FENCE_WAIT; - if (cond >= DRM_TEGRA_SYNCPT_COND_MAX) + err = drm_tegra_pushbuf_add_fence(pushbuf, &fence); + if (err < 0) + return err; + + return 0; +} + +int drm_tegra_pushbuf_wait_syncobj(struct drm_tegra_pushbuf *pushbuf, + uint32_t syncobj) +{ + struct drm_tegra_fence fence; + int err; + + memset(&fence, 0, sizeof(fence)); + fence.handle = syncobj; + fence.flags = DRM_TEGRA_FENCE_WAIT; + + err = drm_tegra_pushbuf_add_fence(pushbuf, &fence); + if (err < 0) + return err; + + return 0; +} + +int drm_tegra_pushbuf_sync(struct drm_tegra_pushbuf *pushbuf, + unsigned int index, unsigned int value, + enum drm_tegra_sync_cond cond) +{ + struct drm_tegra_fence fence; + int err; + + if (cond >= DRM_TEGRA_SYNC_COND_MAX) return -EINVAL; *pushbuf->ptr++ = HOST1X_OPCODE_NONINCR(0x0, 0x1); - *pushbuf->ptr++ = cond << 8 | priv->job->syncpt; - priv->job->increments++; + *pushbuf->ptr++ = cond; + + memset(&fence, 0, sizeof(fence)); + fence.flags = DRM_TEGRA_FENCE_EMIT; + fence.offset = drm_tegra_pushbuf_get_offset(pushbuf) - 4; + fence.index = index; + fence.value = value; + + err = drm_tegra_pushbuf_add_fence(pushbuf, &fence); + if (err < 0) + return err; return 0; } diff --git a/tegra/tegra.c b/tegra/tegra.c index 78f2fcfd..082a17fd 100644 --- a/tegra/tegra.c +++ b/tegra/tegra.c @@ -206,8 +206,8 @@ int drm_tegra_bo_map(struct drm_tegra_bo *bo, void **ptr) bo->offset = args.offset; - bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, - drm->fd, bo->offset); + bo->map = drm_mmap(NULL, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, + drm->fd, bo->offset); if (bo->map == MAP_FAILED) { bo->map = NULL; return -errno; @@ -235,96 +235,3 @@ int drm_tegra_bo_unmap(struct drm_tegra_bo *bo) return 0; } - -int drm_tegra_bo_get_flags(struct drm_tegra_bo *bo, uint32_t *flags) -{ - struct drm_tegra_gem_get_flags args; - struct drm_tegra *drm = bo->drm; - int err; - - if (!bo) - return -EINVAL; - - memset(&args, 0, sizeof(args)); - args.handle = bo->handle; - - err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_FLAGS, &args, - sizeof(args)); - if (err < 0) - return -errno; - - if (flags) - *flags = args.flags; - - return 0; -} - -int drm_tegra_bo_set_flags(struct drm_tegra_bo *bo, uint32_t flags) -{ - struct drm_tegra_gem_get_flags args; - struct drm_tegra *drm = bo->drm; - int err; - - if (!bo) - return -EINVAL; - - memset(&args, 0, sizeof(args)); - args.handle = bo->handle; - args.flags = flags; - - err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_FLAGS, &args, - sizeof(args)); - if (err < 0) - return -errno; - - return 0; -} - -int drm_tegra_bo_get_tiling(struct drm_tegra_bo *bo, - struct drm_tegra_bo_tiling *tiling) -{ - struct drm_tegra_gem_get_tiling args; - struct drm_tegra *drm = bo->drm; - int err; - - if (!bo) - return -EINVAL; - - memset(&args, 0, sizeof(args)); - args.handle = bo->handle; - - err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_TILING, &args, - sizeof(args)); - if (err < 0) - return -errno; - - if (tiling) { - tiling->mode = args.mode; - tiling->value = args.value; - } - - return 0; -} - -int drm_tegra_bo_set_tiling(struct drm_tegra_bo *bo, - const struct drm_tegra_bo_tiling *tiling) -{ - struct drm_tegra_gem_set_tiling args; - struct drm_tegra *drm = bo->drm; - int err; - - if (!bo) - return -EINVAL; - - memset(&args, 0, sizeof(args)); - args.handle = bo->handle; - args.mode = tiling->mode; - args.value = tiling->value; - - err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_TILING, &args, - sizeof(args)); - if (err < 0) - return -errno; - - return 0; -} diff --git a/tegra/tegra.h b/tegra/tegra.h index 01adc5fd..c8576751 100644 --- a/tegra/tegra.h +++ b/tegra/tegra.h @@ -31,10 +31,24 @@ #include enum drm_tegra_class { + DRM_TEGRA_HOST1X, DRM_TEGRA_GR2D, DRM_TEGRA_GR3D, }; +enum drm_fence_type { + DRM_FENCE_SYNCOBJ, + DRM_FENCE_FD, +}; + +struct drm_fence { + enum drm_fence_type type; + union { + uint32_t handle; + int fd; + } fence; +}; + struct drm_tegra_bo; struct drm_tegra; @@ -51,19 +65,6 @@ int drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle); int drm_tegra_bo_map(struct drm_tegra_bo *bo, void **ptr); int drm_tegra_bo_unmap(struct drm_tegra_bo *bo); -int drm_tegra_bo_get_flags(struct drm_tegra_bo *bo, uint32_t *flags); -int drm_tegra_bo_set_flags(struct drm_tegra_bo *bo, uint32_t flags); - -struct drm_tegra_bo_tiling { - uint32_t mode; - uint32_t value; -}; - -int drm_tegra_bo_get_tiling(struct drm_tegra_bo *bo, - struct drm_tegra_bo_tiling *tiling); -int drm_tegra_bo_set_tiling(struct drm_tegra_bo *bo, - const struct drm_tegra_bo_tiling *tiling); - struct drm_tegra_channel; struct drm_tegra_job; @@ -71,26 +72,30 @@ struct drm_tegra_pushbuf { uint32_t *ptr; }; -struct drm_tegra_fence; - -enum drm_tegra_syncpt_cond { - DRM_TEGRA_SYNCPT_COND_IMMEDIATE, - DRM_TEGRA_SYNCPT_COND_OP_DONE, - DRM_TEGRA_SYNCPT_COND_RD_DONE, - DRM_TEGRA_SYNCPT_COND_WR_SAFE, - DRM_TEGRA_SYNCPT_COND_MAX, +enum drm_tegra_sync_cond { + DRM_TEGRA_SYNC_COND_IMMEDIATE, + DRM_TEGRA_SYNC_COND_OP_DONE, + DRM_TEGRA_SYNC_COND_RD_DONE, + DRM_TEGRA_SYNC_COND_WR_SAFE, + DRM_TEGRA_SYNC_COND_MAX, }; int drm_tegra_channel_open(struct drm_tegra_channel **channelp, struct drm_tegra *drm, enum drm_tegra_class client); int drm_tegra_channel_close(struct drm_tegra_channel *channel); +unsigned int drm_tegra_channel_get_syncpoints(struct drm_tegra_channel *channel); + +int drm_tegra_fence_wait(struct drm_tegra *drm, struct drm_tegra_fence *fence); int drm_tegra_job_new(struct drm_tegra_job **jobp, struct drm_tegra_channel *channel); int drm_tegra_job_free(struct drm_tegra_job *job); -int drm_tegra_job_submit(struct drm_tegra_job *job, - struct drm_tegra_fence **fencep); +int drm_tegra_job_submit(struct drm_tegra_job *job, unsigned long timeout); +unsigned int drm_tegra_job_get_fences(struct drm_tegra_job *job, + struct drm_fence *fences, + unsigned int count); +int drm_tegra_job_wait(struct drm_tegra_job *job); int drm_tegra_pushbuf_new(struct drm_tegra_pushbuf **pushbufp, struct drm_tegra_job *job); @@ -101,12 +106,11 @@ int drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf *pushbuf, struct drm_tegra_bo *target, unsigned long offset, unsigned long shift); +int drm_tegra_pushbuf_wait_fd(struct drm_tegra_pushbuf *pushbuf, int fd); +int drm_tegra_pushbuf_wait_syncobj(struct drm_tegra_pushbuf *pushbuf, + uint32_t syncobj); int drm_tegra_pushbuf_sync(struct drm_tegra_pushbuf *pushbuf, - enum drm_tegra_syncpt_cond cond); - -int drm_tegra_fence_wait_timeout(struct drm_tegra_fence *fence, - unsigned long timeout); -int drm_tegra_fence_wait(struct drm_tegra_fence *fence); -void drm_tegra_fence_free(struct drm_tegra_fence *fence); + unsigned int index, unsigned int value, + enum drm_tegra_sync_cond cond); #endif /* __DRM_TEGRA_H__ */ diff --git a/tests/tegra/drm-test-tegra.c b/tests/tegra/drm-test-tegra.c index f5b07de5..0c5a9b80 100644 --- a/tests/tegra/drm-test-tegra.c +++ b/tests/tegra/drm-test-tegra.c @@ -69,7 +69,6 @@ int drm_tegra_gr2d_fill(struct drm_tegra_gr2d *gr2d, struct drm_framebuffer *fb, { struct drm_tegra_bo *fbo = fb->data; struct drm_tegra_pushbuf *pushbuf; - struct drm_tegra_fence *fence; struct drm_tegra_job *job; int err; @@ -117,19 +116,18 @@ int drm_tegra_gr2d_fill(struct drm_tegra_gr2d *gr2d, struct drm_framebuffer *fb, *pushbuf->ptr++ = height << 16 | width; *pushbuf->ptr++ = y << 16 | x; - err = drm_tegra_job_submit(job, &fence); + err = drm_tegra_job_submit(job, 1000); if (err < 0) { fprintf(stderr, "failed to submit job: %d\n", err); return err; } - err = drm_tegra_fence_wait(fence); + err = drm_tegra_job_wait(job); if (err < 0) { fprintf(stderr, "failed to wait for fence: %d\n", err); return err; } - drm_tegra_fence_free(fence); drm_tegra_pushbuf_free(pushbuf); drm_tegra_job_free(job); diff --git a/tests/tegra/host1x.h b/tests/tegra/host1x.h new file mode 100644 index 00000000..902b0c12 --- /dev/null +++ b/tests/tegra/host1x.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef HOST1X_H +#define HOST1X_H + +#define HOST1X_OPCODE_SETCL(offset, classid, mask) \ + ((0x0 << 28) | (((offset) & 0xfff) << 16) | (((classid) & 0x3ff) << 6) | ((mask) & 0x3f)) + +#define HOST1X_OPCODE_INCR(offset, count) \ + ((0x1 << 28) | (((offset) & 0xfff) << 16) | ((count) & 0xffff)) + +#define HOST1X_CLASS_VIC 0x5d + +#endif -- cgit v1.2.3