summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@nvidia.com>2010-08-11 10:55:17 +0300
committerVarun Colbert <vcolbert@nvidia.com>2011-01-25 15:26:37 -0800
commitc2aece97469747851ab911591b549721a37c194f (patch)
tree782621673fddd6a66ff7c3def52dc3a4c145abcc /drivers
parentf32916a170d98f56172ab2896b290a4fa955d1ef (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.c14
-rw-r--r--drivers/video/tegra/host/nvhost_channel.c38
-rw-r--r--drivers/video/tegra/host/nvhost_channel.h3
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);