aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/tegra/host/nvhost_cdma.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra/host/nvhost_cdma.c')
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.c508
1 files changed, 508 insertions, 0 deletions
diff --git a/drivers/video/tegra/host/nvhost_cdma.c b/drivers/video/tegra/host/nvhost_cdma.c
new file mode 100644
index 00000000000..775d761e65c
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_cdma.c
@@ -0,0 +1,508 @@
1/*
2 * drivers/video/tegra/host/nvhost_cdma.c
3 *
4 * Tegra Graphics Host Command DMA
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 "nvhost_cdma.h"
22#include "dev.h"
23#include <asm/cacheflush.h>
24
25#include <linux/slab.h>
26#include <linux/kfifo.h>
27#include <trace/events/nvhost.h>
28#include <linux/interrupt.h>
29
30/*
31 * TODO:
32 * stats
33 * - for figuring out what to optimize further
34 * resizable push buffer
35 * - some channels hardly need any, some channels (3d) could use more
36 */
37
38/**
39 * Add an entry to the sync queue.
40 */
41static void add_to_sync_queue(struct nvhost_cdma *cdma,
42 struct nvhost_job *job,
43 u32 nr_slots,
44 u32 first_get)
45{
46 BUG_ON(job->syncpt_id == NVSYNCPT_INVALID);
47
48 job->first_get = first_get;
49 job->num_slots = nr_slots;
50 nvhost_job_get(job);
51 list_add_tail(&job->list, &cdma->sync_queue);
52}
53
54/**
55 * Return the status of the cdma's sync queue or push buffer for the given event
56 * - sq empty: returns 1 for empty, 0 for not empty (as in "1 empty queue" :-)
57 * - pb space: returns the number of free slots in the channel's push buffer
58 * Must be called with the cdma lock held.
59 */
60static unsigned int cdma_status_locked(struct nvhost_cdma *cdma,
61 enum cdma_event event)
62{
63 switch (event) {
64 case CDMA_EVENT_SYNC_QUEUE_EMPTY:
65 return list_empty(&cdma->sync_queue) ? 1 : 0;
66 case CDMA_EVENT_PUSH_BUFFER_SPACE: {
67 struct push_buffer *pb = &cdma->push_buffer;
68 BUG_ON(!cdma_pb_op(cdma).space);
69 return cdma_pb_op(cdma).space(pb);
70 }
71 default:
72 return 0;
73 }
74}
75
76/**
77 * Sleep (if necessary) until the requested event happens
78 * - CDMA_EVENT_SYNC_QUEUE_EMPTY : sync queue is completely empty.
79 * - Returns 1
80 * - CDMA_EVENT_PUSH_BUFFER_SPACE : there is space in the push buffer
81 * - Return the amount of space (> 0)
82 * Must be called with the cdma lock held.
83 */
84unsigned int nvhost_cdma_wait_locked(struct nvhost_cdma *cdma,
85 enum cdma_event event)
86{
87 for (;;) {
88 unsigned int space = cdma_status_locked(cdma, event);
89 if (space)
90 return space;
91
92 trace_nvhost_wait_cdma(cdma_to_channel(cdma)->dev->name,
93 event);
94
95 BUG_ON(cdma->event != CDMA_EVENT_NONE);
96 cdma->event = event;
97
98 mutex_unlock(&cdma->lock);
99 down(&cdma->sem);
100 mutex_lock(&cdma->lock);
101 }
102 return 0;
103}
104
105/**
106 * Start timer for a buffer submition that has completed yet.
107 * Must be called with the cdma lock held.
108 */
109static void cdma_start_timer_locked(struct nvhost_cdma *cdma,
110 struct nvhost_job *job)
111{
112 BUG_ON(!job);
113 if (cdma->timeout.clientid) {
114 /* timer already started */
115 return;
116 }
117
118 cdma->timeout.ctx = job->hwctx;
119 cdma->timeout.clientid = job->clientid;
120 cdma->timeout.syncpt_id = job->syncpt_id;
121 cdma->timeout.syncpt_val = job->syncpt_end;
122 cdma->timeout.start_ktime = ktime_get();
123
124 schedule_delayed_work(&cdma->timeout.wq,
125 msecs_to_jiffies(job->timeout));
126}
127
128/**
129 * Stop timer when a buffer submition completes.
130 * Must be called with the cdma lock held.
131 */
132static void stop_cdma_timer_locked(struct nvhost_cdma *cdma)
133{
134 cancel_delayed_work(&cdma->timeout.wq);
135 cdma->timeout.ctx = NULL;
136 cdma->timeout.clientid = 0;
137}
138
139/**
140 * For all sync queue entries that have already finished according to the
141 * current sync point registers:
142 * - unpin & unref their mems
143 * - pop their push buffer slots
144 * - remove them from the sync queue
145 * This is normally called from the host code's worker thread, but can be
146 * called manually if necessary.
147 * Must be called with the cdma lock held.
148 */
149static void update_cdma_locked(struct nvhost_cdma *cdma)
150{
151 bool signal = false;
152 struct nvhost_master *dev = cdma_to_dev(cdma);
153 struct nvhost_syncpt *sp = &dev->syncpt;
154 struct nvhost_job *job, *n;
155
156 BUG_ON(!cdma->running);
157
158 /*
159 * Walk the sync queue, reading the sync point registers as necessary,
160 * to consume as many sync queue entries as possible without blocking
161 */
162 list_for_each_entry_safe(job, n, &cdma->sync_queue, list) {
163 BUG_ON(job->syncpt_id == NVSYNCPT_INVALID);
164
165 /* Check whether this syncpt has completed, and bail if not */
166 if (!nvhost_syncpt_is_expired(sp,
167 job->syncpt_id, job->syncpt_end)) {
168 /* Start timer on next pending syncpt */
169 if (job->timeout)
170 cdma_start_timer_locked(cdma, job);
171 break;
172 }
173
174 /* Cancel timeout, when a buffer completes */
175 if (cdma->timeout.clientid)
176 stop_cdma_timer_locked(cdma);
177
178 /* Unpin the memory */
179 nvhost_job_unpin(job);
180
181 /* Pop push buffer slots */
182 if (job->num_slots) {
183 struct push_buffer *pb = &cdma->push_buffer;
184 BUG_ON(!cdma_pb_op(cdma).pop_from);
185 cdma_pb_op(cdma).pop_from(pb, job->num_slots);
186 if (cdma->event == CDMA_EVENT_PUSH_BUFFER_SPACE)
187 signal = true;
188 }
189
190 list_del(&job->list);
191 nvhost_job_put(job);
192 }
193
194 if (list_empty(&cdma->sync_queue) &&
195 cdma->event == CDMA_EVENT_SYNC_QUEUE_EMPTY)
196 signal = true;
197
198 /* Wake up CdmaWait() if the requested event happened */
199 if (signal) {
200 cdma->event = CDMA_EVENT_NONE;
201 up(&cdma->sem);
202 }
203}
204
205void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
206 struct nvhost_syncpt *syncpt, struct device *dev)
207{
208 u32 get_restart;
209 u32 syncpt_incrs;
210 bool exec_ctxsave;
211 struct nvhost_job *job = NULL;
212 u32 syncpt_val;
213
214 syncpt_val = nvhost_syncpt_update_min(syncpt, cdma->timeout.syncpt_id);
215
216 dev_dbg(dev,
217 "%s: starting cleanup (thresh %d)\n",
218 __func__, syncpt_val);
219
220 /*
221 * Move the sync_queue read pointer to the first entry that hasn't
222 * completed based on the current HW syncpt value. It's likely there
223 * won't be any (i.e. we're still at the head), but covers the case
224 * where a syncpt incr happens just prior/during the teardown.
225 */
226
227 dev_dbg(dev,
228 "%s: skip completed buffers still in sync_queue\n",
229 __func__);
230
231 list_for_each_entry(job, &cdma->sync_queue, list) {
232 if (syncpt_val < job->syncpt_end)
233 break;
234
235 nvhost_job_dump(dev, job);
236 }
237
238 /*
239 * Walk the sync_queue, first incrementing with the CPU syncpts that
240 * are partially executed (the first buffer) or fully skipped while
241 * still in the current context (slots are also NOP-ed).
242 *
243 * At the point contexts are interleaved, syncpt increments must be
244 * done inline with the pushbuffer from a GATHER buffer to maintain
245 * the order (slots are modified to be a GATHER of syncpt incrs).
246 *
247 * Note: save in get_restart the location where the timed out buffer
248 * started in the PB, so we can start the refetch from there (with the
249 * modified NOP-ed PB slots). This lets things appear to have completed
250 * properly for this buffer and resources are freed.
251 */
252
253 dev_dbg(dev,
254 "%s: perform CPU incr on pending same ctx buffers\n",
255 __func__);
256
257 get_restart = cdma->last_put;
258 if (!list_empty(&cdma->sync_queue))
259 get_restart = job->first_get;
260
261 /* do CPU increments as long as this context continues */
262 list_for_each_entry_from(job, &cdma->sync_queue, list) {
263 /* different context, gets us out of this loop */
264 if (job->clientid != cdma->timeout.clientid)
265 break;
266
267 /* won't need a timeout when replayed */
268 job->timeout = 0;
269
270 syncpt_incrs = job->syncpt_end - syncpt_val;
271 dev_dbg(dev,
272 "%s: CPU incr (%d)\n", __func__, syncpt_incrs);
273
274 nvhost_job_dump(dev, job);
275
276 /* safe to use CPU to incr syncpts */
277 cdma_op(cdma).timeout_cpu_incr(cdma,
278 job->first_get,
279 syncpt_incrs,
280 job->syncpt_end,
281 job->num_slots);
282
283 syncpt_val += syncpt_incrs;
284 }
285
286 dev_dbg(dev,
287 "%s: GPU incr blocked interleaved ctx buffers\n",
288 __func__);
289
290 exec_ctxsave = false;
291
292 /* setup GPU increments */
293 list_for_each_entry_from(job, &cdma->sync_queue, list) {
294 /* same context, increment in the pushbuffer */
295 if (job->clientid == cdma->timeout.clientid) {
296 /* won't need a timeout when replayed */
297 job->timeout = 0;
298
299 /* update buffer's syncpts in the pushbuffer */
300 cdma_op(cdma).timeout_pb_incr(cdma,
301 job->first_get,
302 job->syncpt_incrs,
303 job->num_slots,
304 exec_ctxsave);
305
306 exec_ctxsave = false;
307 } else {
308 dev_dbg(dev,
309 "%s: switch to a different userctx\n",
310 __func__);
311 /*
312 * If previous context was the timed out context
313 * then clear its CTXSAVE in this slot.
314 */
315 exec_ctxsave = true;
316 }
317
318 nvhost_job_dump(dev, job);
319 }
320
321 dev_dbg(dev,
322 "%s: finished sync_queue modification\n", __func__);
323
324 /* roll back DMAGET and start up channel again */
325 cdma_op(cdma).timeout_teardown_end(cdma, get_restart);
326
327 if (cdma->timeout.ctx)
328 cdma->timeout.ctx->has_timedout = true;
329}
330
331/**
332 * Create a cdma
333 */
334int nvhost_cdma_init(struct nvhost_cdma *cdma)
335{
336 int err;
337 struct push_buffer *pb = &cdma->push_buffer;
338 BUG_ON(!cdma_pb_op(cdma).init);
339 mutex_init(&cdma->lock);
340 sema_init(&cdma->sem, 0);
341
342 INIT_LIST_HEAD(&cdma->sync_queue);
343
344 cdma->event = CDMA_EVENT_NONE;
345 cdma->running = false;
346 cdma->torndown = false;
347
348 err = cdma_pb_op(cdma).init(pb);
349 if (err)
350 return err;
351 return 0;
352}
353
354/**
355 * Destroy a cdma
356 */
357void nvhost_cdma_deinit(struct nvhost_cdma *cdma)
358{
359 struct push_buffer *pb = &cdma->push_buffer;
360
361 BUG_ON(!cdma_pb_op(cdma).destroy);
362 BUG_ON(cdma->running);
363 cdma_pb_op(cdma).destroy(pb);
364 cdma_op(cdma).timeout_destroy(cdma);
365}
366
367/**
368 * Begin a cdma submit
369 */
370int nvhost_cdma_begin(struct nvhost_cdma *cdma, struct nvhost_job *job)
371{
372 mutex_lock(&cdma->lock);
373
374 if (job->timeout) {
375 /* init state on first submit with timeout value */
376 if (!cdma->timeout.initialized) {
377 int err;
378 BUG_ON(!cdma_op(cdma).timeout_init);
379 err = cdma_op(cdma).timeout_init(cdma,
380 job->syncpt_id);
381 if (err) {
382 mutex_unlock(&cdma->lock);
383 return err;
384 }
385 }
386 }
387 if (!cdma->running) {
388 BUG_ON(!cdma_op(cdma).start);
389 cdma_op(cdma).start(cdma);
390 }
391 cdma->slots_free = 0;
392 cdma->slots_used = 0;
393 cdma->first_get = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
394 return 0;
395}
396
397/**
398 * Push two words into a push buffer slot
399 * Blocks as necessary if the push buffer is full.
400 */
401void nvhost_cdma_push(struct nvhost_cdma *cdma, u32 op1, u32 op2)
402{
403 nvhost_cdma_push_gather(cdma, NULL, NULL, op1, op2);
404}
405
406/**
407 * Push two words into a push buffer slot
408 * Blocks as necessary if the push buffer is full.
409 */
410void nvhost_cdma_push_gather(struct nvhost_cdma *cdma,
411 struct nvmap_client *client,
412 struct nvmap_handle *handle, u32 op1, u32 op2)
413{
414 u32 slots_free = cdma->slots_free;
415 struct push_buffer *pb = &cdma->push_buffer;
416 BUG_ON(!cdma_pb_op(cdma).push_to);
417 BUG_ON(!cdma_op(cdma).kick);
418 if (slots_free == 0) {
419 cdma_op(cdma).kick(cdma);
420 slots_free = nvhost_cdma_wait_locked(cdma,
421 CDMA_EVENT_PUSH_BUFFER_SPACE);
422 }
423 cdma->slots_free = slots_free - 1;
424 cdma->slots_used++;
425 cdma_pb_op(cdma).push_to(pb, client, handle, op1, op2);
426}
427
428/**
429 * End a cdma submit
430 * Kick off DMA, add job to the sync queue, and a number of slots to be freed
431 * from the pushbuffer. The handles for a submit must all be pinned at the same
432 * time, but they can be unpinned in smaller chunks.
433 */
434void nvhost_cdma_end(struct nvhost_cdma *cdma,
435 struct nvhost_job *job)
436{
437 bool was_idle = list_empty(&cdma->sync_queue);
438
439 BUG_ON(!cdma_op(cdma).kick);
440 cdma_op(cdma).kick(cdma);
441
442 BUG_ON(job->syncpt_id == NVSYNCPT_INVALID);
443
444 add_to_sync_queue(cdma,
445 job,
446 cdma->slots_used,
447 cdma->first_get);
448
449 /* start timer on idle -> active transitions */
450 if (job->timeout && was_idle)
451 cdma_start_timer_locked(cdma, job);
452
453 mutex_unlock(&cdma->lock);
454}
455
456/**
457 * Update cdma state according to current sync point values
458 */
459void nvhost_cdma_update(struct nvhost_cdma *cdma)
460{
461 mutex_lock(&cdma->lock);
462 update_cdma_locked(cdma);
463 mutex_unlock(&cdma->lock);
464}
465
466/**
467 * Wait for push buffer to be empty.
468 * @cdma pointer to channel cdma
469 * @timeout timeout in ms
470 * Returns -ETIME if timeout was reached, zero if push buffer is empty.
471 */
472int nvhost_cdma_flush(struct nvhost_cdma *cdma, int timeout)
473{
474 unsigned int space, err = 0;
475 unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout);
476
477 /*
478 * Wait for at most timeout ms. Recalculate timeout at each iteration
479 * to better keep within given timeout.
480 */
481 while(!err && time_before(jiffies, end_jiffies)) {
482 int timeout_jiffies = end_jiffies - jiffies;
483
484 mutex_lock(&cdma->lock);
485 space = cdma_status_locked(cdma,
486 CDMA_EVENT_SYNC_QUEUE_EMPTY);
487 if (space) {
488 mutex_unlock(&cdma->lock);
489 return 0;
490 }
491
492 /*
493 * Wait for sync queue to become empty. If there is already
494 * an event pending, we need to poll.
495 */
496 if (cdma->event != CDMA_EVENT_NONE) {
497 mutex_unlock(&cdma->lock);
498 schedule();
499 } else {
500 cdma->event = CDMA_EVENT_SYNC_QUEUE_EMPTY;
501
502 mutex_unlock(&cdma->lock);
503 err = down_timeout(&cdma->sem,
504 jiffies_to_msecs(timeout_jiffies));
505 }
506 }
507 return err;
508}