1/* 2 * Copyright © 2012, 2013 Thierry Reding 3 * Copyright © 2013 Erik Faye-Lund 4 * Copyright © 2014 NVIDIA Corporation 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25#ifdef HAVE_CONFIG_H 26# include "config.h" 27#endif 28 29#include <errno.h> 30#include <stdlib.h> 31#include <string.h> 32#include <time.h> 33#include <unistd.h> 34 35#include <sys/ioctl.h> 36#include <sys/poll.h> 37 38#include "private.h" 39 40struct drm_tegra_submit_cmd * 41drm_tegra_job_add_command(struct drm_tegra_job *job, uint32_t type, 42 uint32_t flags) 43{ 44 struct drm_tegra_submit_cmd *commands, *command; 45 size_t size; 46 47 size = (job->num_commands + 1) * sizeof(*commands); 48 49 commands = realloc(job->commands, size); 50 if (!commands) 51 return NULL; 52 53 command = &commands[job->num_commands]; 54 memset(command, 0, sizeof(*command)); 55 command->type = type; 56 command->flags = flags; 57 58 job->commands = commands; 59 job->num_commands++; 60 61 return command; 62} 63 64drm_public int 65drm_tegra_job_new(struct drm_tegra_channel *channel, 66 struct drm_tegra_job **jobp) 67{ 68 struct drm_tegra_job *job; 69 70 job = calloc(1, sizeof(*job)); 71 if (!job) 72 return -ENOMEM; 73 74 job->page_size = sysconf(_SC_PAGESIZE); 75 job->channel = channel; 76 77 *jobp = job; 78 79 return 0; 80} 81 82drm_public int drm_tegra_job_free(struct drm_tegra_job *job) 83{ 84 if (!job) 85 return -EINVAL; 86 87 if (job->pushbuf) 88 drm_tegra_pushbuf_free(job->pushbuf); 89 90 if (job->commands) 91 free(job->commands); 92 93 if (job->buffers) 94 free(job->buffers); 95 96 free(job); 97 98 return 0; 99} 100 101drm_public int 102drm_tegra_job_get_pushbuf(struct drm_tegra_job *job, 103 struct drm_tegra_pushbuf **pushbufp) 104{ 105 struct drm_tegra_pushbuf *pushbuf; 106 107 if (!job->pushbuf) { 108 pushbuf = calloc(1, sizeof(*pushbuf)); 109 if (!pushbuf) 110 return -ENOMEM; 111 112 pushbuf->job = job; 113 114 pushbuf->start = calloc(1, job->page_size); 115 if (!pushbuf->start) { 116 free(pushbuf); 117 return -ENOMEM; 118 } 119 120 pushbuf->end = pushbuf->start + job->page_size / 4; 121 pushbuf->ptr = pushbuf->start; 122 123 job->pushbuf = pushbuf; 124 } 125 126 *pushbufp = job->pushbuf; 127 128 return 0; 129} 130 131drm_public int 132drm_tegra_job_submit(struct drm_tegra_job *job, struct drm_tegra_fence *fence) 133{ 134 struct drm_tegra_channel *channel = job->channel; 135 struct drm_tegra *drm = channel->drm; 136 struct drm_tegra_channel_submit args; 137 int err; 138 139 memset(&args, 0, sizeof(args)); 140 args.context = channel->context; 141 args.num_bufs = job->num_buffers; 142 args.num_cmds = job->num_commands; 143 args.gather_data_words = job->pushbuf->ptr - job->pushbuf->start; 144 args.syncpt.id = job->syncpt.id; 145 args.syncpt.increments = job->syncpt.increments; 146 147 args.bufs_ptr = (uintptr_t)job->buffers; 148 args.cmds_ptr = (uintptr_t)job->commands; 149 args.gather_data_ptr = (uintptr_t)job->pushbuf->start; 150 151 err = ioctl(drm->fd, DRM_IOCTL_TEGRA_CHANNEL_SUBMIT, &args); 152 if (err < 0) 153 return -errno; 154 155 job->syncpt.fence = args.syncpt.value; 156 157 if (fence) { 158 fence->drm = drm; 159 fence->syncpt = job->syncpt.id; 160 fence->value = job->syncpt.fence; 161 } 162 163 return 0; 164} 165 166drm_public int 167drm_tegra_job_wait(struct drm_tegra_job *job, unsigned long timeout) 168{ 169 struct drm_tegra_channel *channel = job->channel; 170 struct drm_tegra *drm = channel->drm; 171 struct drm_tegra_syncpoint_wait args; 172 struct timespec ts; 173 int err; 174 175 clock_gettime(CLOCK_MONOTONIC, &ts); 176 177 memset(&args, 0, sizeof(args)); 178 args.timeout_ns = ts.tv_sec * 1000000000 + ts.tv_nsec + timeout; 179 args.id = job->syncpt.id; 180 args.threshold = job->syncpt.fence; 181 182 err = ioctl(drm->fd, DRM_IOCTL_TEGRA_SYNCPOINT_WAIT, &args); 183 if (err < 0) 184 return -errno; 185 186 return 0; 187} 188