summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/host/dev.c
diff options
context:
space:
mode:
authorChris Johnson <cwj@nvidia.com>2011-04-30 14:24:44 -0700
committerNiket Sirsi <nsirsi@nvidia.com>2011-05-16 15:15:20 -0700
commit6d8d2c454e835f7cfe34371e07dac173f3153452 (patch)
treec80564468037653f45c29d607e52e8c472ae8367 /drivers/video/tegra/host/dev.c
parent0edac603fc410d7b6686b27e545586b42feb7a80 (diff)
nvrm: move stale wait checking into the kerneltegra-11.2.6
The kernel now receives wait tracking data (similar to gathers and relocs) and compares the current syncpt with the threshold value. If it's old, it gets a kernel mapping and rewrites the method data to use a kernel reserved syncpt that is always 0 (so trivially pops when seen by the HW). Bug 519650 Bug 785525 Bug 803452 Note: reset the author in this commit to fix a email addr problem and since from the latest/last cherry pick there was a reworking of the code to be compatible with different user space versions it also seemed reasonable. (cherry picked from commit 4069d8e67665624ad3dceb628e572980dd57acd0) (cherry picked from commit 6e4336408588e348804a62e53386acc9abc06823) (cherry picked from commit 87a9efe751716ca741caac72b9061fdfdcec540a) Change-Id: I9c6076da2384f373d5f402bee4406b09b4ebc4ff Reviewed-on: http://git-master/r/23159 Reviewed-on: http://git-master/r/30281 Tested-by: Chris Johnson <cwj@nvidia.com> Reviewed-by: Ken Adams <kadams@nvidia.com> Reviewed-by: Prajakta Gudadhe <pgudadhe@nvidia.com>
Diffstat (limited to 'drivers/video/tegra/host/dev.c')
-rw-r--r--drivers/video/tegra/host/dev.c119
1 files changed, 90 insertions, 29 deletions
diff --git a/drivers/video/tegra/host/dev.c b/drivers/video/tegra/host/dev.c
index 8b577cc9045f..fdbf5cc8efc1 100644
--- a/drivers/video/tegra/host/dev.c
+++ b/drivers/video/tegra/host/dev.c
@@ -46,10 +46,7 @@ static int nvhost_minor = NVHOST_CHANNEL_BASE;
struct nvhost_channel_userctx {
struct nvhost_channel *ch;
struct nvhost_hwctx *hwctx;
- u32 syncpt_id;
- u32 syncpt_incrs;
- u32 cmdbufs_pending;
- u32 relocs_pending;
+ struct nvhost_submit_hdr_ext hdr;
struct nvmap_handle_ref *gather_mem;
struct nvhost_op_pair *gathers;
int num_gathers;
@@ -57,6 +54,8 @@ struct nvhost_channel_userctx {
struct nvmap_pinarray_elem pinarray[NVHOST_MAX_HANDLES];
struct nvmap_handle *unpinarray[NVHOST_MAX_HANDLES];
struct nvmap_client *nvmap;
+ struct nvhost_waitchk waitchks[NVHOST_MAX_WAIT_CHECKS];
+ u32 num_waitchks;
};
struct nvhost_ctrl_userctx {
@@ -137,10 +136,25 @@ static void add_gather(struct nvhost_channel_userctx *ctx, int idx,
ctx->gathers[idx].op1 = nvhost_opcode_gather(0, words);
}
+static int set_submit(struct nvhost_channel_userctx *ctx)
+{
+ int err = 0;
+
+ /* submit should have at least 1 cmdbuf */
+ if (!ctx->hdr.num_cmdbufs)
+ return -EFAULT;
+
+ /* leave room for ctx switch */
+ ctx->num_gathers = 2;
+ ctx->pinarray_size = 0;
+ return err;
+}
+
static void reset_submit(struct nvhost_channel_userctx *ctx)
{
- ctx->cmdbufs_pending = 0;
- ctx->relocs_pending = 0;
+ ctx->hdr.num_cmdbufs = 0;
+ ctx->hdr.num_relocs = 0;
+ ctx->hdr.num_waitchks = 0;
}
static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf,
@@ -152,22 +166,19 @@ static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf,
while (remaining) {
size_t consumed;
- if (!priv->relocs_pending && !priv->cmdbufs_pending) {
+ if (!priv->hdr.num_relocs && !priv->hdr.num_cmdbufs && !priv->hdr.num_waitchks) {
consumed = sizeof(struct nvhost_submit_hdr);
if (remaining < consumed)
break;
- if (copy_from_user(&priv->syncpt_id, buf, consumed)) {
+ if (copy_from_user(&priv->hdr, buf, consumed)) {
err = -EFAULT;
break;
}
- if (!priv->cmdbufs_pending) {
- err = -EFAULT;
+ BUG_ON(priv->hdr.submit_version != NVHOST_SUBMIT_VERSION_V0);
+ err = set_submit(priv);
+ if (err)
break;
- }
- /* leave room for ctx switch */
- priv->num_gathers = 2;
- priv->pinarray_size = 0;
- } else if (priv->cmdbufs_pending) {
+ } else if (priv->hdr.num_cmdbufs) {
struct nvhost_cmdbuf cmdbuf;
consumed = sizeof(cmdbuf);
if (remaining < consumed)
@@ -178,12 +189,12 @@ static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf,
}
add_gather(priv, priv->num_gathers++,
cmdbuf.mem, cmdbuf.words, cmdbuf.offset);
- priv->cmdbufs_pending--;
- } else if (priv->relocs_pending) {
+ priv->hdr.num_cmdbufs--;
+ } else if (priv->hdr.num_relocs) {
int numrelocs = remaining / sizeof(struct nvhost_reloc);
if (!numrelocs)
break;
- numrelocs = min_t(int, numrelocs, priv->relocs_pending);
+ numrelocs = min_t(int, numrelocs, priv->hdr.num_relocs);
consumed = numrelocs * sizeof(struct nvhost_reloc);
if (copy_from_user(&priv->pinarray[priv->pinarray_size],
buf, consumed)) {
@@ -191,7 +202,19 @@ static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf,
break;
}
priv->pinarray_size += numrelocs;
- priv->relocs_pending -= numrelocs;
+ priv->hdr.num_relocs -= numrelocs;
+ } else if (priv->hdr.num_waitchks) {
+ struct nvhost_waitchk *waitp;
+ consumed = sizeof(struct nvhost_waitchk);
+ if (remaining < consumed)
+ break;
+ waitp = &priv->waitchks[priv->num_waitchks];
+ if (copy_from_user(waitp, buf, consumed)) {
+ err = -EFAULT;
+ break;
+ }
+ priv->num_waitchks++;
+ priv->hdr.num_waitchks--;
} else {
err = -EFAULT;
break;
@@ -219,9 +242,9 @@ 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;
+ int nulled_incrs = null_kickoff ? ctx->hdr.syncpt_incrs : 0;
- if (ctx->relocs_pending || ctx->cmdbufs_pending) {
+ if (ctx->hdr.num_relocs || ctx->hdr.num_cmdbufs || ctx->hdr.num_waitchks) {
reset_submit(ctx);
dev_err(&ctx->ch->dev->pdev->dev, "channel submit out of sync\n");
return -EFAULT;
@@ -256,6 +279,22 @@ static int nvhost_ioctl_channel_flush(struct nvhost_channel_userctx *ctx,
return err;
}
+ /* remove stale waits */
+ if (ctx->num_waitchks) {
+ err = nvhost_syncpt_wait_check(ctx->nvmap,
+ &ctx->ch->dev->syncpt, ctx->hdr.waitchk_mask,
+ ctx->waitchks, ctx->num_waitchks);
+ if (err) {
+ dev_warn(&ctx->ch->dev->pdev->dev,
+ "nvhost_syncpt_wait_check failed: %d\n", err);
+ mutex_unlock(&ctx->ch->submitlock);
+ nvmap_unpin_handles(ctx->nvmap, ctx->unpinarray, num_unpin);
+ nvhost_module_idle(&ctx->ch->mod);
+ return err;
+ }
+ ctx->num_waitchks = 0;
+ }
+
/* context switch */
if (ctx->ch->cur_ctx != ctx->hwctx) {
struct nvhost_hwctx *hw = ctx->hwctx;
@@ -264,7 +303,7 @@ static int nvhost_ioctl_channel_flush(struct nvhost_channel_userctx *ctx,
ctx->gathers[gather_idx].op1 =
nvhost_opcode_gather(0, hw->restore_size);
ctx->gathers[gather_idx].op2 = hw->restore_phys;
- ctx->syncpt_incrs += hw->restore_incrs;
+ ctx->hdr.syncpt_incrs += hw->restore_incrs;
}
hw = ctx->ch->cur_ctx;
if (hw) {
@@ -272,7 +311,7 @@ static int nvhost_ioctl_channel_flush(struct nvhost_channel_userctx *ctx,
ctx->gathers[gather_idx].op1 =
nvhost_opcode_gather(0, hw->save_size);
ctx->gathers[gather_idx].op2 = hw->save_phys;
- ctx->syncpt_incrs += hw->save_incrs;
+ ctx->hdr.syncpt_incrs += hw->save_incrs;
num_intrs = 1;
ctxsw.syncpt_val = hw->save_incrs - 1;
ctxsw.intr_data = hw;
@@ -291,24 +330,24 @@ static int nvhost_ioctl_channel_flush(struct nvhost_channel_userctx *ctx,
}
/* get absolute sync value */
- if (BIT(ctx->syncpt_id) & NVSYNCPTS_CLIENT_MANAGED)
+ if (BIT(ctx->hdr.syncpt_id) & NVSYNCPTS_CLIENT_MANAGED)
syncval = nvhost_syncpt_set_max(&ctx->ch->dev->syncpt,
- ctx->syncpt_id, ctx->syncpt_incrs);
+ ctx->hdr.syncpt_id, ctx->hdr.syncpt_incrs);
else
syncval = nvhost_syncpt_incr_max(&ctx->ch->dev->syncpt,
- ctx->syncpt_id, ctx->syncpt_incrs);
+ ctx->hdr.syncpt_id, ctx->hdr.syncpt_incrs);
/* patch absolute syncpt value into interrupt triggers */
- ctxsw.syncpt_val += syncval - ctx->syncpt_incrs;
+ ctxsw.syncpt_val += syncval - ctx->hdr.syncpt_incrs;
nvhost_channel_submit(ctx->ch, ctx->nvmap, &ctx->gathers[gather_idx],
(null_kickoff ? 2 : ctx->num_gathers) - gather_idx, &ctxsw, num_intrs,
ctx->unpinarray, num_unpin,
- ctx->syncpt_id, syncval,
+ ctx->hdr.syncpt_id, syncval,
nulled_incrs);
/* schedule a submit complete interrupt */
- nvhost_intr_add_action(&ctx->ch->dev->intr, ctx->syncpt_id, syncval,
+ nvhost_intr_add_action(&ctx->ch->dev->intr, ctx->hdr.syncpt_id, syncval,
NVHOST_INTR_ACTION_SUBMIT_COMPLETE, ctx->ch, NULL);
mutex_unlock(&ctx->ch->submitlock);
@@ -342,7 +381,29 @@ static long nvhost_channelctl(struct file *filp,
case NVHOST_IOCTL_CHANNEL_NULL_KICKOFF:
err = nvhost_ioctl_channel_flush(priv, (void *)buf, 1);
break;
+ case NVHOST_IOCTL_CHANNEL_SUBMIT_EXT:
+ {
+ struct nvhost_submit_hdr_ext *hdr = (struct nvhost_submit_hdr_ext *)buf;
+
+ if (priv->hdr.num_relocs || priv->hdr.num_cmdbufs || priv->hdr.num_waitchks) {
+ reset_submit(priv);
+ dev_err(&priv->ch->dev->pdev->dev, "channel submit out of sync\n");
+ err = -EFAULT;
+ break;
+ }
+ if (hdr->submit_version > NVHOST_SUBMIT_VERSION_MAX_SUPPORTED) {
+ dev_err(&priv->ch->dev->pdev->dev, "submit version %d > max supported %d\n",
+ hdr->submit_version, NVHOST_SUBMIT_VERSION_MAX_SUPPORTED);
+ err = -EINVAL;
+ break;
+ }
+ memcpy(&priv->hdr, hdr, sizeof(struct nvhost_submit_hdr_ext));
+ err = set_submit(priv);
+ break;
+ }
case NVHOST_IOCTL_CHANNEL_GET_SYNCPOINTS:
+ /* host syncpt ID is used by the RM (and never be given out) */
+ BUG_ON(priv->ch->desc->syncpts & (1 << NVSYNCPT_GRAPHICS_HOST));
((struct nvhost_get_param_args *)buf)->value =
priv->ch->desc->syncpts;
break;