2 * drivers/video/tegra/host/host1x/channel_host1x.c
4 * Tegra Graphics Host Channel
6 * Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved.
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.
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
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/>.
21 #include "nvhost_channel.h"
23 #include "class_ids.h"
24 #include "nvhost_acm.h"
25 #include "nvhost_job.h"
26 #include "nvhost_hwctx.h"
27 #include <trace/events/nvhost.h>
28 #include <linux/slab.h>
29 #include "nvhost_sync.h"
31 #include "nvhost_hwctx.h"
32 #include "nvhost_intr.h"
33 #include "class_ids.h"
35 static void sync_waitbases(struct nvhost_channel *ch, u32 syncpt_val)
37 unsigned long waitbase;
38 struct nvhost_device_data *pdata = platform_get_drvdata(ch->dev);
39 if (pdata->waitbasesync) {
40 waitbase = pdata->waitbases[0];
41 nvhost_cdma_push(&ch->cdma,
42 nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
43 host1x_uclass_load_syncpt_base_r(),
45 nvhost_class_host_load_syncpt_base(waitbase,
50 static void serialize(struct nvhost_job *job)
52 struct nvhost_channel *ch = job->ch;
53 struct nvhost_syncpt *sp = &nvhost_get_host(ch->dev)->syncpt;
54 struct nvhost_device_data *pdata = platform_get_drvdata(ch->dev);
57 if (!job->serialize && !pdata->serialize)
61 * Force serialization by inserting a host wait for the
62 * previous job to finish before this one can commence.
64 * NOTE! This cannot be packed because otherwise we might
65 * overwrite the RESTART opcode at the end of the push
69 for (i = 0; i < job->num_syncpts; ++i) {
70 u32 id = job->sp[i].id;
71 u32 max = nvhost_syncpt_read_max(sp, id);
73 nvhost_cdma_push(&ch->cdma,
74 nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
75 host1x_uclass_wait_syncpt_r(), 1),
76 nvhost_class_host_wait_syncpt(id, max));
80 static bool ctxsave_needed(struct nvhost_job *job, struct nvhost_hwctx *cur_ctx)
82 struct nvhost_channel *ch = job->ch;
84 if (!cur_ctx || ch->cur_ctx == job->hwctx ||
85 ch->cur_ctx->has_timedout ||
86 !ch->cur_ctx->h->save_push)
92 static void submit_ctxsave(struct nvhost_job *job, struct nvhost_hwctx *cur_ctx)
94 struct nvhost_master *host = nvhost_get_host(job->ch->dev);
95 struct nvhost_channel *ch = job->ch;
98 /* Is a save needed? */
99 if (!ctxsave_needed(job, cur_ctx))
102 /* Adjust the syncpoint max */
103 job->sp[job->hwctx_syncpt_idx].incrs +=
105 syncval = nvhost_syncpt_incr_max(&host->syncpt,
106 job->sp[job->hwctx_syncpt_idx].id,
107 cur_ctx->save_incrs);
109 /* Send the save to channel */
110 cur_ctx->valid = true;
111 cur_ctx->h->save_push(cur_ctx, &ch->cdma);
112 nvhost_job_get_hwctx(job, cur_ctx);
114 trace_nvhost_channel_context_save(ch->dev->name, cur_ctx);
117 static void add_sync_waits(struct nvhost_channel *ch, int fd)
119 struct nvhost_master *host = nvhost_get_host(ch->dev);
120 struct nvhost_syncpt *sp = &host->syncpt;
121 struct sync_fence *fence;
123 struct nvhost_sync_pt *pt;
124 struct list_head *pos;
129 fence = nvhost_sync_fdget(fd);
134 * Force serialization by inserting a host wait for the
135 * previous job to finish before this one can commence.
137 * NOTE! This cannot be packed because otherwise we might
138 * overwrite the RESTART opcode at the end of the push
142 list_for_each(pos, &fence->pt_list_head) {
146 _pt = container_of(pos, struct sync_pt, pt_list);
147 pt = to_nvhost_sync_pt(_pt);
148 id = nvhost_sync_pt_id(pt);
149 thresh = nvhost_sync_pt_thresh(pt);
151 if (nvhost_syncpt_is_expired(sp, id, thresh))
154 nvhost_cdma_push(&ch->cdma,
155 nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
156 host1x_uclass_wait_syncpt_r(), 1),
157 nvhost_class_host_wait_syncpt(id, thresh));
159 sync_fence_put(fence);
162 static void submit_ctxrestore(struct nvhost_job *job)
164 struct nvhost_master *host = nvhost_get_host(job->ch->dev);
165 struct nvhost_channel *ch = job->ch;
167 struct nvhost_hwctx *ctx = job->hwctx;
169 /* First check if we have a valid context to restore */
170 if (ch->cur_ctx == job->hwctx || !job->hwctx ||
171 !job->hwctx->valid ||
172 !ctx->h->restore_push)
175 /* Increment syncpt max */
176 job->sp[job->hwctx_syncpt_idx].incrs += ctx->restore_incrs;
177 syncval = nvhost_syncpt_incr_max(&host->syncpt,
178 job->sp[job->hwctx_syncpt_idx].id,
181 /* Send restore buffer to channel */
182 ctx->h->restore_push(ctx, &ch->cdma);
184 trace_nvhost_channel_context_restore(ch->dev->name, ctx);
187 static void submit_nullkickoff(struct nvhost_job *job, u32 user_syncpt_incrs)
189 struct nvhost_channel *ch = job->ch;
192 struct nvhost_device_data *pdata = platform_get_drvdata(ch->dev);
194 /* push increments that correspond to nulled out commands */
195 for (i = 0; i < job->num_syncpts; ++i) {
196 u32 incrs = (i == job->hwctx_syncpt_idx) ?
197 user_syncpt_incrs : job->sp[i].incrs;
198 op_incr = nvhost_opcode_imm_incr_syncpt(
199 host1x_uclass_incr_syncpt_cond_op_done_v(),
201 for (incr = 0; incr < (incrs >> 1); incr++)
202 nvhost_cdma_push(&ch->cdma, op_incr, op_incr);
204 nvhost_cdma_push(&ch->cdma, op_incr,
208 /* for 3d, waitbase needs to be incremented after each submit */
209 if (pdata->class == NV_GRAPHICS_3D_CLASS_ID) {
210 u32 waitbase = job->hwctx->h->waitbase;
211 nvhost_cdma_push(&ch->cdma,
212 nvhost_opcode_setclass(
214 host1x_uclass_incr_syncpt_base_r(),
216 nvhost_class_host_incr_syncpt_base(
218 job->sp[job->hwctx_syncpt_idx].incrs));
222 static inline u32 gather_regnum(u32 word)
224 return (word >> 16) & 0xfff;
227 static inline u32 gather_type(u32 word)
229 return (word >> 28) & 1;
232 static inline u32 gather_count(u32 word)
234 return word & 0x3fff;
237 static void submit_gathers(struct nvhost_job *job)
243 /* push user gathers */
244 for (i = 0 ; i < job->num_gathers; i++) {
245 struct nvhost_job_gather *g = &job->gathers[i];
249 add_sync_waits(job->ch, g->pre_fence);
251 if (g->class_id != class_id) {
252 nvhost_cdma_push(&job->ch->cdma,
253 nvhost_opcode_setclass(g->class_id, 0, 0),
255 class_id = g->class_id;
258 /* If register is specified, add a gather with incr/nonincr.
259 * This allows writing large amounts of data directly from
260 * memory to a register. */
261 if (gather_regnum(g->words))
262 op1 = nvhost_opcode_gather_insert(
263 gather_regnum(g->words),
264 gather_type(g->words),
265 gather_count(g->words));
267 op1 = nvhost_opcode_gather(g->words);
268 op2 = job->gathers[i].mem_base + g->offset;
270 cpuva = dma_buf_vmap(g->buf);
271 nvhost_cdma_push_gather(&job->ch->cdma,
273 job->gathers[i].mem_base,
276 dma_buf_vunmap(g->buf, cpuva);
280 static int host1x_channel_submit(struct nvhost_job *job)
282 struct nvhost_channel *ch = job->ch;
283 struct nvhost_syncpt *sp = &nvhost_get_host(job->ch->dev)->syncpt;
284 u32 user_syncpt_incrs;
287 void *completed_waiters[job->num_syncpts];
288 struct nvhost_job_syncpt *hwctx_sp = job->sp + job->hwctx_syncpt_idx;
290 memset(completed_waiters, 0, sizeof(void *) * job->num_syncpts);
292 /* Bail out on timed out contexts */
293 if (job->hwctx && job->hwctx->has_timedout)
296 /* Turn on the client module and host1x */
297 for (i = 0; i < job->num_syncpts; ++i)
298 nvhost_module_busy(ch->dev);
300 /* before error checks, return current max */
301 prev_max = hwctx_sp->fence = nvhost_syncpt_read_max(sp, hwctx_sp->id);
303 /* get submit lock */
304 err = mutex_lock_interruptible(&ch->submitlock);
306 nvhost_module_idle_mult(ch->dev, job->num_syncpts);
310 for (i = 0; i < job->num_syncpts; ++i) {
311 completed_waiters[i] = nvhost_intr_alloc_waiter();
312 if (!completed_waiters[i]) {
313 nvhost_module_idle_mult(ch->dev, job->num_syncpts);
314 mutex_unlock(&ch->submitlock);
318 if (nvhost_intr_has_pending_jobs(
319 &nvhost_get_host(ch->dev)->intr, job->sp[i].id, ch))
320 dev_warn(&ch->dev->dev,
321 "%s: cross-channel dependencies on syncpt %d\n",
322 __func__, job->sp[i].id);
325 /* begin a CDMA submit */
326 err = nvhost_cdma_begin(&ch->cdma, job);
328 mutex_unlock(&ch->submitlock);
329 nvhost_module_idle_mult(ch->dev, job->num_syncpts);
335 /* submit_ctxsave() and submit_ctxrestore() use the channel syncpt */
336 user_syncpt_incrs = hwctx_sp->incrs;
338 submit_ctxsave(job, ch->cur_ctx);
339 submit_ctxrestore(job);
340 ch->cur_ctx = job->hwctx;
342 /* determine fences for all syncpoints */
343 for (i = 0; i < job->num_syncpts; ++i) {
344 u32 incrs = (i == job->hwctx_syncpt_idx) ?
348 /* create a valid max for client managed syncpoints */
349 if (nvhost_syncpt_client_managed(sp, job->sp[i].id)) {
350 u32 min = nvhost_syncpt_read(sp, job->sp[i].id);
352 dev_warn(&job->ch->dev->dev,
353 "converting an active unmanaged syncpoint %d to managed\n",
355 nvhost_syncpt_set_max(sp, job->sp[i].id, min);
356 nvhost_syncpt_set_manager(sp, job->sp[i].id, false);
360 nvhost_syncpt_incr_max(sp, job->sp[i].id, incrs);
363 if (job->null_kickoff)
364 submit_nullkickoff(job, user_syncpt_incrs);
368 sync_waitbases(ch, hwctx_sp->fence);
370 /* end CDMA submit & stash pinned hMems into sync queue */
371 nvhost_cdma_end(&ch->cdma, job);
373 trace_nvhost_channel_submitted(ch->dev->name, prev_max,
376 for (i = 0; i < job->num_syncpts; ++i) {
377 /* schedule a submit complete interrupt */
378 err = nvhost_intr_add_action(&nvhost_get_host(ch->dev)->intr,
379 job->sp[i].id, job->sp[i].fence,
380 NVHOST_INTR_ACTION_SUBMIT_COMPLETE, ch,
381 completed_waiters[i],
383 WARN(err, "Failed to set submit complete interrupt");
386 mutex_unlock(&ch->submitlock);
391 for (i = 0; i < job->num_syncpts; ++i)
392 kfree(completed_waiters[i]);
397 static int host1x_save_context(struct nvhost_channel *ch)
399 struct nvhost_hwctx *hwctx_to_save;
400 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
401 u32 syncpt_incrs, syncpt_val;
404 void *wakeup_waiter = NULL;
405 struct nvhost_job *job;
406 u32 syncpt_id, waitbase;
408 wakeup_waiter = nvhost_intr_alloc_waiter();
409 if (!wakeup_waiter) {
414 nvhost_module_busy(nvhost_get_parent(ch->dev));
416 mutex_lock(&ch->submitlock);
417 hwctx_to_save = ch->cur_ctx;
418 if (!hwctx_to_save) {
419 mutex_unlock(&ch->submitlock);
423 job = nvhost_job_alloc(ch, hwctx_to_save, 0, 0, 0, 1);
426 mutex_unlock(&ch->submitlock);
430 hwctx_to_save->valid = true;
432 syncpt_id = hwctx_to_save->h->syncpt;
433 waitbase = hwctx_to_save->h->waitbase;
435 syncpt_incrs = hwctx_to_save->save_incrs;
436 syncpt_val = nvhost_syncpt_incr_max(&nvhost_get_host(ch->dev)->syncpt,
437 syncpt_id, syncpt_incrs);
439 job->hwctx_syncpt_idx = 0;
440 job->sp->id = syncpt_id;
441 job->sp->waitbase = waitbase;
442 job->sp->incrs = syncpt_incrs;
443 job->sp->fence = syncpt_val;
444 job->num_syncpts = 1;
446 err = nvhost_cdma_begin(&ch->cdma, job);
448 mutex_unlock(&ch->submitlock);
452 hwctx_to_save->h->save_push(hwctx_to_save, &ch->cdma);
453 nvhost_cdma_end(&ch->cdma, job);
457 err = nvhost_intr_add_action(&nvhost_get_host(ch->dev)->intr,
458 syncpt_id, syncpt_val,
459 NVHOST_INTR_ACTION_WAKEUP, &wq,
462 wakeup_waiter = NULL;
463 WARN(err, "Failed to set wakeup interrupt");
465 nvhost_syncpt_is_expired(&nvhost_get_host(ch->dev)->syncpt,
466 syncpt_id, syncpt_val));
468 nvhost_intr_put_ref(&nvhost_get_host(ch->dev)->intr, syncpt_id, ref);
470 nvhost_cdma_update(&ch->cdma);
472 mutex_unlock(&ch->submitlock);
473 nvhost_module_idle(nvhost_get_parent(ch->dev));
476 kfree(wakeup_waiter);
480 static inline void __iomem *host1x_channel_aperture(void __iomem *p, int ndx)
482 p += ndx * NV_HOST1X_CHANNEL_MAP_SIZE_BYTES;
486 static inline int hwctx_handler_init(struct nvhost_channel *ch)
490 struct nvhost_device_data *pdata = platform_get_drvdata(ch->dev);
491 u32 syncpt = pdata->syncpts[0];
492 u32 waitbase = pdata->waitbases[0];
494 if (pdata->alloc_hwctx_handler) {
495 ch->ctxhandler = pdata->alloc_hwctx_handler(syncpt,
504 static int host1x_channel_init(struct nvhost_channel *ch,
505 struct nvhost_master *dev)
507 mutex_init(&ch->reflock);
508 mutex_init(&ch->submitlock);
510 ch->aperture = host1x_channel_aperture(dev->aperture, ch->chid);
512 return hwctx_handler_init(ch);
515 static const struct nvhost_channel_ops host1x_channel_ops = {
516 .init = host1x_channel_init,
517 .submit = host1x_channel_submit,
518 .save_context = host1x_save_context,