diff options
author | Dan Willemsen <dwillemsen@nvidia.com> | 2010-08-11 10:55:17 +0300 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2011-01-25 15:26:37 -0800 |
commit | c2aece97469747851ab911591b549721a37c194f (patch) | |
tree | 782621673fddd6a66ff7c3def52dc3a4c145abcc /drivers | |
parent | f32916a170d98f56172ab2896b290a4fa955d1ef (diff) |
nvhost: Reimplement null kickoff functionality.
For each channel submit where null kickoff is requested, we don't
place the user's commands in the pushbuffer. All necessary context
switches, syncpoint increments and waitbase increments do happen
though.
Update: Add NULL_KICKOFF ioctl to use instead of FLIP, this prevents
kernel ABI breakage.
Bug 717235
Previous Id: I51c323729ea57993a5b52fb395ab90cb8608ee6b
Previously Reviewed: http://git-master/r/5091
Change-Id: I4f92db457aff6e1c3a8d454255c4b051c4663360
Reviewed-on: http://git-master/r/15882
Reviewed-by: Daniel Willemsen <dwillemsen@nvidia.com>
Tested-by: Daniel Willemsen <dwillemsen@nvidia.com>
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/tegra/host/dev.c | 14 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_channel.c | 38 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_channel.h | 3 |
3 files changed, 44 insertions, 11 deletions
diff --git a/drivers/video/tegra/host/dev.c b/drivers/video/tegra/host/dev.c index c9c88b0171a7..8b577cc9045f 100644 --- a/drivers/video/tegra/host/dev.c +++ b/drivers/video/tegra/host/dev.c @@ -210,7 +210,8 @@ static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf, } static int nvhost_ioctl_channel_flush(struct nvhost_channel_userctx *ctx, - struct nvhost_get_param_args *args) + struct nvhost_get_param_args *args, + int null_kickoff) { struct nvhost_cpuinterrupt ctxsw; int gather_idx = 2; @@ -218,6 +219,7 @@ static int nvhost_ioctl_channel_flush(struct nvhost_channel_userctx *ctx, u32 syncval; int num_unpin; int err; + int nulled_incrs = null_kickoff ? ctx->syncpt_incrs : 0; if (ctx->relocs_pending || ctx->cmdbufs_pending) { reset_submit(ctx); @@ -300,9 +302,10 @@ static int nvhost_ioctl_channel_flush(struct nvhost_channel_userctx *ctx, ctxsw.syncpt_val += syncval - ctx->syncpt_incrs; nvhost_channel_submit(ctx->ch, ctx->nvmap, &ctx->gathers[gather_idx], - ctx->num_gathers - gather_idx, &ctxsw, num_intrs, + (null_kickoff ? 2 : ctx->num_gathers) - gather_idx, &ctxsw, num_intrs, ctx->unpinarray, num_unpin, - ctx->syncpt_id, syncval); + ctx->syncpt_id, syncval, + nulled_incrs); /* schedule a submit complete interrupt */ nvhost_intr_add_action(&ctx->ch->dev->intr, ctx->syncpt_id, syncval, @@ -334,7 +337,10 @@ static long nvhost_channelctl(struct file *filp, switch (cmd) { case NVHOST_IOCTL_CHANNEL_FLUSH: - err = nvhost_ioctl_channel_flush(priv, (void *)buf); + err = nvhost_ioctl_channel_flush(priv, (void *)buf, 0); + break; + case NVHOST_IOCTL_CHANNEL_NULL_KICKOFF: + err = nvhost_ioctl_channel_flush(priv, (void *)buf, 1); break; case NVHOST_IOCTL_CHANNEL_GET_SYNCPOINTS: ((struct nvhost_get_param_args *)buf)->value = diff --git a/drivers/video/tegra/host/nvhost_channel.c b/drivers/video/tegra/host/nvhost_channel.c index 949e67ffb653..70fb173d7f41 100644 --- a/drivers/video/tegra/host/nvhost_channel.c +++ b/drivers/video/tegra/host/nvhost_channel.c @@ -168,11 +168,12 @@ void nvhost_channel_suspend(struct nvhost_channel *ch) } void nvhost_channel_submit(struct nvhost_channel *ch, - struct nvmap_client *user_nvmap, - struct nvhost_op_pair *ops, int num_pairs, - struct nvhost_cpuinterrupt *intrs, int num_intrs, - struct nvmap_handle **unpins, int num_unpins, - u32 syncpt_id, u32 syncpt_val) + struct nvmap_client *user_nvmap, + struct nvhost_op_pair *ops, int num_pairs, + struct nvhost_cpuinterrupt *intrs, int num_intrs, + struct nvmap_handle **unpins, int num_unpins, + u32 syncpt_id, u32 syncpt_val, + int num_nulled_incrs) { int i; struct nvhost_op_pair* p; @@ -190,6 +191,31 @@ void nvhost_channel_submit(struct nvhost_channel *ch, for (i = 0, p = ops; i < num_pairs; i++, p++) nvhost_cdma_push(&ch->cdma, p->op1, p->op2); + /* extra work to do for null kickoff */ + if (num_nulled_incrs) { + u32 incr; + u32 op_incr; + + /* TODO ideally we'd also perform host waits here */ + + /* push increments that correspond to nulled out commands */ + op_incr = nvhost_opcode_imm(0, 0x100 | syncpt_id); + for (incr = 0; incr < (num_nulled_incrs >> 1); incr++) + nvhost_cdma_push(&ch->cdma, op_incr, op_incr); + if (num_nulled_incrs & 1) + nvhost_cdma_push(&ch->cdma, op_incr, NVHOST_OPCODE_NOOP); + + /* for 3d, waitbase needs to be incremented after each submit */ + if (ch->desc->class == NV_GRAPHICS_3D_CLASS_ID) { + u32 op1 = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID, + NV_CLASS_HOST_INCR_SYNCPT_BASE, 1); + u32 op2 = nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D, + num_nulled_incrs); + + nvhost_cdma_push(&ch->cdma, op1, op2); + } + } + /* end CDMA submit & stash pinned hMems into sync queue for later cleanup */ nvhost_cdma_end(user_nvmap, &ch->cdma, syncpt_id, syncpt_val, unpins, num_unpins); @@ -228,7 +254,7 @@ static void power_3d(struct nvhost_module *mod, enum nvhost_power_action action) nvhost_channel_submit(ch, ch->dev->nvmap, &save, 1, &ctxsw, 1, NULL, 0, - NVSYNCPT_3D, syncval); + NVSYNCPT_3D, syncval, 0); nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D, syncval, diff --git a/drivers/video/tegra/host/nvhost_channel.h b/drivers/video/tegra/host/nvhost_channel.h index c62d7397a192..59ba06543a48 100644 --- a/drivers/video/tegra/host/nvhost_channel.h +++ b/drivers/video/tegra/host/nvhost_channel.h @@ -80,7 +80,8 @@ void nvhost_channel_submit(struct nvhost_channel *ch, struct nvhost_op_pair *ops, int num_pairs, struct nvhost_cpuinterrupt *intrs, int num_intrs, struct nvmap_handle **unpins, int num_unpins, - u32 syncpt_id, u32 syncpt_val); + u32 syncpt_id, u32 syncpt_val, + int num_nulled_incrs); struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch); void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx); |