/** * Increment syncpoint value from cpu, updating cache */ void nvhost_syncpt_incr(struct nvhost_syncpt *sp, u32 id) { nvhost_syncpt_incr_max(sp, id, 1); nvhost_module_busy(&syncpt_to_dev(sp)->mod); nvhost_syncpt_cpu_incr(sp, id); nvhost_module_idle(&syncpt_to_dev(sp)->mod); }
/** * Increment syncpoint value from cpu, updating cache */ void nvhost_syncpt_incr(struct nvhost_syncpt *sp, u32 id) { if (nvhost_syncpt_client_managed(sp, id)) nvhost_syncpt_incr_max(sp, id, 1); nvhost_module_busy(syncpt_to_dev(sp)->dev); nvhost_syncpt_cpu_incr(sp, id); nvhost_module_idle(syncpt_to_dev(sp)->dev); }
/** * Increment syncpoint value from cpu, updating cache */ void nvhost_syncpt_incr(struct nvhost_syncpt *sp, u32 id) { #ifdef CONFIG_MACH_N1 u32 min, max; max = nvhost_syncpt_incr_max(sp, id, 1); min = nvhost_syncpt_incr_min(sp, id, 1); if (sp->restore_needed) { /* XXX restore_needed used only for logging (to be removed in final checkin) */ dev_warn(&syncpt_to_dev(sp)->pdev->dev, "syncpoint id %d (%s) incremented min = %d, max = %d while nvhost suspended\n", id, nvhost_syncpt_name(id), min, max); } #else nvhost_syncpt_incr_max(sp, id, 1); #endif nvhost_module_busy(&syncpt_to_dev(sp)->mod); nvhost_syncpt_cpu_incr(sp, id); nvhost_module_idle(&syncpt_to_dev(sp)->mod); }
u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc, int i) { u32 max; mutex_lock(&dc->lock); max = nvhost_syncpt_incr_max(&dc->ndev->host->syncpt, dc->syncpt[i].id, 1); dc->syncpt[i].max = max; mutex_unlock(&dc->lock); return max; }
/* public sync point API */ u32 nvhost_syncpt_incr_max_ext(struct platform_device *dev, u32 id, u32 incrs) { struct platform_device *pdev; struct nvhost_syncpt *sp; BUG_ON(!nvhost_get_parent(dev)); /* get the parent */ pdev = to_platform_device(dev->dev.parent); sp = &(nvhost_get_host(pdev)->syncpt); return nvhost_syncpt_incr_max(sp, id, incrs); }
/** * Increment syncpoint value from cpu, updating cache */ int nvhost_syncpt_incr(struct nvhost_syncpt *sp, u32 id) { int err; err = nvhost_module_busy(syncpt_to_dev(sp)->dev); if (err) return err; if (nvhost_syncpt_client_managed(sp, id)) nvhost_syncpt_incr_max(sp, id, 1); nvhost_syncpt_cpu_incr(sp, id); nvhost_module_idle(syncpt_to_dev(sp)->dev); return 0; }
/* public sync point API */ u32 nvhost_syncpt_incr_max_ext(struct platform_device *dev, u32 id, u32 incrs) { struct platform_device *pdev; struct nvhost_syncpt *sp; if (!nvhost_get_parent(dev)) { dev_err(&dev->dev, "Incr max called with wrong dev\n"); return 0; } /* get the parent */ pdev = to_platform_device(dev->dev.parent); sp = &(nvhost_get_host(pdev)->syncpt); return nvhost_syncpt_incr_max(sp, id, incrs); }
/* public sync point API */ u32 nvhost_syncpt_incr_max_ext(struct nvhost_device *dev, u32 id, u32 incrs) { struct nvhost_syncpt *sp = &(nvhost_get_host(dev)->syncpt); return nvhost_syncpt_incr_max(sp, id, incrs); }
int nvhost_3dctx_prepare_power_off(struct nvhost_module *mod) { struct nvhost_channel *ch = container_of(mod, struct nvhost_channel, mod); struct nvhost_hwctx *hwctx_to_save; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); u32 syncpt_incrs, syncpt_val; int err = 0; void *ref; void *ctx_waiter = NULL, *wakeup_waiter = NULL; ctx_waiter = nvhost_intr_alloc_waiter(); wakeup_waiter = nvhost_intr_alloc_waiter(); if (!ctx_waiter || !wakeup_waiter) { err = -ENOMEM; goto done; } if (mod->desc->busy) mod->desc->busy(mod); mutex_lock(&ch->submitlock); hwctx_to_save = ch->cur_ctx; if (!hwctx_to_save) { mutex_unlock(&ch->submitlock); goto done; } err = nvhost_cdma_begin(&ch->cdma, hwctx_to_save->timeout); if (err) { mutex_unlock(&ch->submitlock); goto done; } hwctx_to_save->valid = true; ch->ctxhandler.get(hwctx_to_save); ch->cur_ctx = NULL; syncpt_incrs = hwctx_to_save->save_incrs; syncpt_val = nvhost_syncpt_incr_max(&ch->dev->syncpt, NVSYNCPT_3D, syncpt_incrs); ch->ctxhandler.save_push(&ch->cdma, hwctx_to_save); nvhost_cdma_end(&ch->cdma, ch->dev->nvmap, NVSYNCPT_3D, syncpt_val, NULL, 0, hwctx_to_save->timeout); err = nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D, syncpt_val - syncpt_incrs + hwctx_to_save->save_thresh, NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save, ctx_waiter, NULL); ctx_waiter = NULL; WARN(err, "Failed to set context save interrupt"); err = nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D, syncpt_val, NVHOST_INTR_ACTION_WAKEUP, &wq, wakeup_waiter, &ref); wakeup_waiter = NULL; WARN(err, "Failed to set wakeup interrupt"); wait_event(wq, nvhost_syncpt_min_cmp(&ch->dev->syncpt, NVSYNCPT_3D, syncpt_val)); nvhost_intr_put_ref(&ch->dev->intr, ref); nvhost_cdma_update(&ch->cdma); mutex_unlock(&ch->submitlock); done: kfree(ctx_waiter); kfree(wakeup_waiter); return err; }
int nvhost_gr3d_t20_read_reg( struct nvhost_device *dev, struct nvhost_channel *channel, struct nvhost_hwctx *hwctx, u32 offset, u32 *value) { struct host1x_hwctx *hwctx_to_save = NULL; struct nvhost_hwctx_handler *h = hwctx->h; struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h); bool need_restore = false; u32 syncpt_incrs = 4; unsigned int pending = 0; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); void *ref; void *ctx_waiter, *read_waiter, *completed_waiter; struct nvhost_job *job; u32 syncval; int err; if (hwctx->has_timedout) return -ETIMEDOUT; ctx_waiter = nvhost_intr_alloc_waiter(); read_waiter = nvhost_intr_alloc_waiter(); completed_waiter = nvhost_intr_alloc_waiter(); if (!ctx_waiter || !read_waiter || !completed_waiter) { err = -ENOMEM; goto done; } job = nvhost_job_alloc(channel, hwctx, NULL, nvhost_get_host(dev)->memmgr, 0, 0); if (!job) { err = -ENOMEM; goto done; } /* keep module powered */ nvhost_module_busy(dev); /* get submit lock */ err = mutex_lock_interruptible(&channel->submitlock); if (err) { nvhost_module_idle(dev); return err; } /* context switch */ if (channel->cur_ctx != hwctx) { hwctx_to_save = channel->cur_ctx ? to_host1x_hwctx(channel->cur_ctx) : NULL; if (hwctx_to_save) { syncpt_incrs += hwctx_to_save->save_incrs; hwctx_to_save->hwctx.valid = true; nvhost_job_get_hwctx(job, &hwctx_to_save->hwctx); } channel->cur_ctx = hwctx; if (channel->cur_ctx && channel->cur_ctx->valid) { need_restore = true; syncpt_incrs += to_host1x_hwctx(channel->cur_ctx) ->restore_incrs; } } syncval = nvhost_syncpt_incr_max(&nvhost_get_host(dev)->syncpt, p->syncpt, syncpt_incrs); job->syncpt_id = p->syncpt; job->syncpt_incrs = syncpt_incrs; job->syncpt_end = syncval; /* begin a CDMA submit */ nvhost_cdma_begin(&channel->cdma, job); /* push save buffer (pre-gather setup depends on unit) */ if (hwctx_to_save) h->save_push(&hwctx_to_save->hwctx, &channel->cdma); /* gather restore buffer */ if (need_restore) nvhost_cdma_push(&channel->cdma, nvhost_opcode_gather(to_host1x_hwctx(channel->cur_ctx) ->restore_size), to_host1x_hwctx(channel->cur_ctx)->restore_phys); /* Switch to 3D - wait for it to complete what it was doing */ nvhost_cdma_push(&channel->cdma, nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0), nvhost_opcode_imm_incr_syncpt( host1x_uclass_incr_syncpt_cond_op_done_v(), p->syncpt)); nvhost_cdma_push(&channel->cdma, nvhost_opcode_setclass(NV_HOST1X_CLASS_ID, host1x_uclass_wait_syncpt_base_r(), 1), nvhost_class_host_wait_syncpt_base(p->syncpt, p->waitbase, 1)); /* Tell 3D to send register value to FIFO */ nvhost_cdma_push(&channel->cdma, nvhost_opcode_nonincr(host1x_uclass_indoff_r(), 1), nvhost_class_host_indoff_reg_read( host1x_uclass_indoff_indmodid_gr3d_v(), offset, false)); nvhost_cdma_push(&channel->cdma, nvhost_opcode_imm(host1x_uclass_inddata_r(), 0), NVHOST_OPCODE_NOOP); /* Increment syncpt to indicate that FIFO can be read */ nvhost_cdma_push(&channel->cdma, nvhost_opcode_imm_incr_syncpt( host1x_uclass_incr_syncpt_cond_immediate_v(), p->syncpt), NVHOST_OPCODE_NOOP); /* Wait for value to be read from FIFO */ nvhost_cdma_push(&channel->cdma, nvhost_opcode_nonincr(host1x_uclass_wait_syncpt_base_r(), 1), nvhost_class_host_wait_syncpt_base(p->syncpt, p->waitbase, 3)); /* Indicate submit complete */ nvhost_cdma_push(&channel->cdma, nvhost_opcode_nonincr(host1x_uclass_incr_syncpt_base_r(), 1), nvhost_class_host_incr_syncpt_base(p->waitbase, 4)); nvhost_cdma_push(&channel->cdma, NVHOST_OPCODE_NOOP, nvhost_opcode_imm_incr_syncpt( host1x_uclass_incr_syncpt_cond_immediate_v(), p->syncpt)); /* end CDMA submit */ nvhost_cdma_end(&channel->cdma, job); nvhost_job_put(job); job = NULL; /* * schedule a context save interrupt (to drain the host FIFO * if necessary, and to release the restore buffer) */ if (hwctx_to_save) { err = nvhost_intr_add_action( &nvhost_get_host(dev)->intr, p->syncpt, syncval - syncpt_incrs + hwctx_to_save->save_incrs - 1, NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save, ctx_waiter, NULL); ctx_waiter = NULL; WARN(err, "Failed to set context save interrupt"); } /* Wait for FIFO to be ready */ err = nvhost_intr_add_action(&nvhost_get_host(dev)->intr, p->syncpt, syncval - 2, NVHOST_INTR_ACTION_WAKEUP, &wq, read_waiter, &ref); read_waiter = NULL; WARN(err, "Failed to set wakeup interrupt"); wait_event(wq, nvhost_syncpt_is_expired(&nvhost_get_host(dev)->syncpt, p->syncpt, syncval - 2)); nvhost_intr_put_ref(&nvhost_get_host(dev)->intr, p->syncpt, ref); /* Read the register value from FIFO */ err = nvhost_channel_drain_read_fifo(channel, value, 1, &pending); /* Indicate we've read the value */ nvhost_syncpt_cpu_incr(&nvhost_get_host(dev)->syncpt, p->syncpt); /* Schedule a submit complete interrupt */ err = nvhost_intr_add_action(&nvhost_get_host(dev)->intr, p->syncpt, syncval, NVHOST_INTR_ACTION_SUBMIT_COMPLETE, channel, completed_waiter, NULL); completed_waiter = NULL; WARN(err, "Failed to set submit complete interrupt"); mutex_unlock(&channel->submitlock); done: kfree(ctx_waiter); kfree(read_waiter); kfree(completed_waiter); return err; }
/* public sync point API */ u32 nvhost_syncpt_incr_max_ext(struct platform_device *dev, u32 id, u32 incrs) { struct nvhost_master *master = nvhost_get_host(dev); struct nvhost_syncpt *sp = &master->syncpt; return nvhost_syncpt_incr_max(sp, id, incrs); }