aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/tegra/host/nvhost_job.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra/host/nvhost_job.c')
-rw-r--r--drivers/video/tegra/host/nvhost_job.c339
1 files changed, 339 insertions, 0 deletions
diff --git a/drivers/video/tegra/host/nvhost_job.c b/drivers/video/tegra/host/nvhost_job.c
new file mode 100644
index 00000000000..df7a62d689b
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_job.c
@@ -0,0 +1,339 @@
1/*
2 * drivers/video/tegra/host/nvhost_job.c
3 *
4 * Tegra Graphics Host Job
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/slab.h>
22#include <linux/kref.h>
23#include <linux/err.h>
24#include <linux/vmalloc.h>
25#include <mach/nvmap.h>
26#include "nvhost_channel.h"
27#include "nvhost_job.h"
28#include "dev.h"
29
30/* Magic to use to fill freed handle slots */
31#define BAD_MAGIC 0xdeadbeef
32
33static int job_size(struct nvhost_submit_hdr_ext *hdr)
34{
35 int num_pins = hdr ? (hdr->num_relocs + hdr->num_cmdbufs)*2 : 0;
36 int num_waitchks = hdr ? hdr->num_waitchks : 0;
37
38 return sizeof(struct nvhost_job)
39 + num_pins * sizeof(struct nvmap_pinarray_elem)
40 + num_pins * sizeof(struct nvmap_handle *)
41 + num_waitchks * sizeof(struct nvhost_waitchk);
42}
43
44static int gather_size(int num_cmdbufs)
45{
46 return num_cmdbufs * sizeof(struct nvhost_channel_gather);
47}
48
49static void free_gathers(struct nvhost_job *job)
50{
51 if (job->gathers) {
52 nvmap_munmap(job->gather_mem, job->gathers);
53 job->gathers = NULL;
54 }
55 if (job->gather_mem) {
56 nvmap_free(job->nvmap, job->gather_mem);
57 job->gather_mem = NULL;
58 }
59}
60
61static int alloc_gathers(struct nvhost_job *job,
62 int num_cmdbufs)
63{
64 int err = 0;
65
66 job->gather_mem = NULL;
67 job->gathers = NULL;
68 job->gather_mem_size = 0;
69
70 if (num_cmdbufs) {
71 /* Allocate memory */
72 job->gather_mem = nvmap_alloc(job->nvmap,
73 gather_size(num_cmdbufs),
74 32, NVMAP_HANDLE_CACHEABLE, 0);
75 if (IS_ERR_OR_NULL(job->gather_mem)) {
76 err = PTR_ERR(job->gather_mem);
77 job->gather_mem = NULL;
78 goto error;
79 }
80 job->gather_mem_size = gather_size(num_cmdbufs);
81
82 /* Map memory to kernel */
83 job->gathers = nvmap_mmap(job->gather_mem);
84 if (IS_ERR_OR_NULL(job->gathers)) {
85 err = PTR_ERR(job->gathers);
86 job->gathers = NULL;
87 goto error;
88 }
89 }
90
91 return 0;
92
93error:
94 free_gathers(job);
95 return err;
96}
97
98static int realloc_gathers(struct nvhost_job *oldjob,
99 struct nvhost_job *newjob,
100 int num_cmdbufs)
101{
102 int err = 0;
103
104 /* Check if we can reuse gather buffer */
105 if (oldjob->gather_mem_size < gather_size(num_cmdbufs)
106 || oldjob->nvmap != newjob->nvmap) {
107 free_gathers(oldjob);
108 err = alloc_gathers(newjob, num_cmdbufs);
109 } else {
110 newjob->gather_mem = oldjob->gather_mem;
111 newjob->gathers = oldjob->gathers;
112 newjob->gather_mem_size = oldjob->gather_mem_size;
113
114 oldjob->gather_mem = NULL;
115 oldjob->gathers = NULL;
116 oldjob->gather_mem_size = 0;
117 }
118 return err;
119}
120
121static void init_fields(struct nvhost_job *job,
122 struct nvhost_submit_hdr_ext *hdr,
123 int priority, int clientid)
124{
125 int num_pins = hdr ? (hdr->num_relocs + hdr->num_cmdbufs)*2 : 0;
126 int num_waitchks = hdr ? hdr->num_waitchks : 0;
127 void *mem = job;
128
129 /* First init state to zero */
130 job->num_gathers = 0;
131 job->num_pins = 0;
132 job->num_unpins = 0;
133 job->num_waitchk = 0;
134 job->waitchk_mask = 0;
135 job->syncpt_id = 0;
136 job->syncpt_incrs = 0;
137 job->syncpt_end = 0;
138 job->priority = priority;
139 job->clientid = clientid;
140 job->null_kickoff = false;
141 job->first_get = 0;
142 job->num_slots = 0;
143
144 /* Redistribute memory to the structs */
145 mem += sizeof(struct nvhost_job);
146 if (num_pins) {
147 job->pinarray = mem;
148 mem += num_pins * sizeof(struct nvmap_pinarray_elem);
149 job->unpins = mem;
150 mem += num_pins * sizeof(struct nvmap_handle *);
151 } else {
152 job->pinarray = NULL;
153 job->unpins = NULL;
154 }
155
156 job->waitchk = num_waitchks ? mem : NULL;
157
158 /* Copy information from header */
159 if (hdr) {
160 job->waitchk_mask = hdr->waitchk_mask;
161 job->syncpt_id = hdr->syncpt_id;
162 job->syncpt_incrs = hdr->syncpt_incrs;
163 }
164}
165
166struct nvhost_job *nvhost_job_alloc(struct nvhost_channel *ch,
167 struct nvhost_hwctx *hwctx,
168 struct nvhost_submit_hdr_ext *hdr,
169 struct nvmap_client *nvmap,
170 int priority,
171 int clientid)
172{
173 struct nvhost_job *job = NULL;
174 int num_cmdbufs = hdr ? hdr->num_cmdbufs : 0;
175 int err = 0;
176
177 job = vzalloc(job_size(hdr));
178 if (!job)
179 goto error;
180
181 kref_init(&job->ref);
182 job->ch = ch;
183 job->hwctx = hwctx;
184 if (hwctx)
185 hwctx->h->get(hwctx);
186 job->nvmap = nvmap ? nvmap_client_get(nvmap) : NULL;
187
188 err = alloc_gathers(job, num_cmdbufs);
189 if (err)
190 goto error;
191
192 init_fields(job, hdr, priority, clientid);
193
194 return job;
195
196error:
197 if (job)
198 nvhost_job_put(job);
199 return NULL;
200}
201
202struct nvhost_job *nvhost_job_realloc(
203 struct nvhost_job *oldjob,
204 struct nvhost_hwctx *hwctx,
205 struct nvhost_submit_hdr_ext *hdr,
206 struct nvmap_client *nvmap,
207 int priority, int clientid)
208{
209 struct nvhost_job *newjob = NULL;
210 int num_cmdbufs = hdr ? hdr->num_cmdbufs : 0;
211 int err = 0;
212
213 newjob = vzalloc(job_size(hdr));
214 if (!newjob)
215 goto error;
216 kref_init(&newjob->ref);
217 newjob->ch = oldjob->ch;
218 newjob->hwctx = hwctx;
219 if (hwctx)
220 newjob->hwctx->h->get(newjob->hwctx);
221 newjob->timeout = oldjob->timeout;
222 newjob->nvmap = nvmap ? nvmap_client_get(nvmap) : NULL;
223
224 err = realloc_gathers(oldjob, newjob, num_cmdbufs);
225 if (err)
226 goto error;
227
228 nvhost_job_put(oldjob);
229
230 init_fields(newjob, hdr, priority, clientid);
231
232 return newjob;
233
234error:
235 if (newjob)
236 nvhost_job_put(newjob);
237 if (oldjob)
238 nvhost_job_put(oldjob);
239 return NULL;
240}
241
242void nvhost_job_get(struct nvhost_job *job)
243{
244 kref_get(&job->ref);
245}
246
247static void job_free(struct kref *ref)
248{
249 struct nvhost_job *job = container_of(ref, struct nvhost_job, ref);
250
251 if (job->hwctxref)
252 job->hwctxref->h->put(job->hwctxref);
253 if (job->hwctx)
254 job->hwctx->h->put(job->hwctx);
255 if (job->gathers)
256 nvmap_munmap(job->gather_mem, job->gathers);
257 if (job->gather_mem)
258 nvmap_free(job->nvmap, job->gather_mem);
259 if (job->nvmap)
260 nvmap_client_put(job->nvmap);
261 vfree(job);
262}
263
264/* Acquire reference to a hardware context. Used for keeping saved contexts in
265 * memory. */
266void nvhost_job_get_hwctx(struct nvhost_job *job, struct nvhost_hwctx *hwctx)
267{
268 BUG_ON(job->hwctxref);
269
270 job->hwctxref = hwctx;
271 hwctx->h->get(hwctx);
272}
273
274void nvhost_job_put(struct nvhost_job *job)
275{
276 kref_put(&job->ref, job_free);
277}
278
279void nvhost_job_add_gather(struct nvhost_job *job,
280 u32 mem_id, u32 words, u32 offset)
281{
282 struct nvmap_pinarray_elem *pin;
283 struct nvhost_channel_gather *cur_gather =
284 &job->gathers[job->num_gathers];
285
286 pin = &job->pinarray[job->num_pins++];
287 pin->patch_mem = (u32)nvmap_ref_to_handle(job->gather_mem);
288 pin->patch_offset = (void *)&(cur_gather->mem) - (void *)job->gathers;
289 pin->pin_mem = nvmap_convert_handle_u2k(mem_id);
290 pin->pin_offset = offset;
291 cur_gather->words = words;
292 cur_gather->mem_id = mem_id;
293 cur_gather->offset = offset;
294 job->num_gathers += 1;
295}
296
297int nvhost_job_pin(struct nvhost_job *job)
298{
299 int err = 0;
300
301 /* pin mem handles and patch physical addresses */
302 job->num_unpins = nvmap_pin_array(job->nvmap,
303 nvmap_ref_to_handle(job->gather_mem),
304 job->pinarray, job->num_pins,
305 job->unpins);
306 if (job->num_unpins < 0)
307 err = job->num_unpins;
308
309 return err;
310}
311
312void nvhost_job_unpin(struct nvhost_job *job)
313{
314 nvmap_unpin_handles(job->nvmap, job->unpins,
315 job->num_unpins);
316 memset(job->unpins, BAD_MAGIC,
317 job->num_unpins * sizeof(struct nvmap_handle *));
318}
319
320/**
321 * Debug routine used to dump job entries
322 */
323void nvhost_job_dump(struct device *dev, struct nvhost_job *job)
324{
325 dev_dbg(dev, " SYNCPT_ID %d\n",
326 job->syncpt_id);
327 dev_dbg(dev, " SYNCPT_VAL %d\n",
328 job->syncpt_end);
329 dev_dbg(dev, " FIRST_GET 0x%x\n",
330 job->first_get);
331 dev_dbg(dev, " TIMEOUT %d\n",
332 job->timeout);
333 dev_dbg(dev, " CTX 0x%p\n",
334 job->hwctx);
335 dev_dbg(dev, " NUM_SLOTS %d\n",
336 job->num_slots);
337 dev_dbg(dev, " NUM_HANDLES %d\n",
338 job->num_unpins);
339}