diff options
Diffstat (limited to 'drivers/video/tegra/host/dev.c')
-rw-r--r-- | drivers/video/tegra/host/dev.c | 42 |
1 files changed, 40 insertions, 2 deletions
diff --git a/drivers/video/tegra/host/dev.c b/drivers/video/tegra/host/dev.c index 8b577cc9045f..fccb46da83c0 100644 --- a/drivers/video/tegra/host/dev.c +++ b/drivers/video/tegra/host/dev.c @@ -50,6 +50,8 @@ struct nvhost_channel_userctx { u32 syncpt_incrs; u32 cmdbufs_pending; u32 relocs_pending; + u32 waitchk_pending; + u32 waitchk_ref; struct nvmap_handle_ref *gather_mem; struct nvhost_op_pair *gathers; int num_gathers; @@ -57,6 +59,9 @@ 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; + u32 waitchk_mask; }; struct nvhost_ctrl_userctx { @@ -141,6 +146,7 @@ static void reset_submit(struct nvhost_channel_userctx *ctx) { ctx->cmdbufs_pending = 0; ctx->relocs_pending = 0; + ctx->waitchk_pending = 0; } static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf, @@ -152,7 +158,7 @@ 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->relocs_pending && !priv->cmdbufs_pending && !priv->waitchk_pending) { consumed = sizeof(struct nvhost_submit_hdr); if (remaining < consumed) break; @@ -167,6 +173,7 @@ static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf, /* leave room for ctx switch */ priv->num_gathers = 2; priv->pinarray_size = 0; + priv->waitchk_mask |= priv->waitchk_ref; } else if (priv->cmdbufs_pending) { struct nvhost_cmdbuf cmdbuf; consumed = sizeof(cmdbuf); @@ -192,6 +199,18 @@ static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf, } priv->pinarray_size += numrelocs; priv->relocs_pending -= numrelocs; + } else if (priv->waitchk_pending) { + 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->waitchk_pending--; } else { err = -EFAULT; break; @@ -221,7 +240,7 @@ static int nvhost_ioctl_channel_flush(struct nvhost_channel_userctx *ctx, int err; int nulled_incrs = null_kickoff ? ctx->syncpt_incrs : 0; - if (ctx->relocs_pending || ctx->cmdbufs_pending) { + if (ctx->relocs_pending || ctx->cmdbufs_pending || ctx->waitchk_pending) { reset_submit(ctx); dev_err(&ctx->ch->dev->pdev->dev, "channel submit out of sync\n"); return -EFAULT; @@ -256,6 +275,23 @@ 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->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; + ctx->waitchk_mask = 0; + } + /* context switch */ if (ctx->ch->cur_ctx != ctx->hwctx) { struct nvhost_hwctx *hw = ctx->hwctx; @@ -343,6 +379,8 @@ static long nvhost_channelctl(struct file *filp, err = nvhost_ioctl_channel_flush(priv, (void *)buf, 1); 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; |