diff options
author | Thierry Reding <treding@nvidia.com> | 2013-10-10 11:00:33 +0200 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2013-10-31 09:55:45 +0100 |
commit | c40f0f1afcb1dcce7f9fd978fbbc8d8d68cf5e84 (patch) | |
tree | e038523b47f8e4980e121fa7c337018ee90b910c | |
parent | 497c56a5817f1610ca189e1dc546934c7ce8eb7d (diff) |
drm/tegra: Introduce tegra_drm_submit()
Command stream submissions are the same across all devices that expose
a channel to userspace, so move the code into a generic function.
Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 129 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gr2d.c | 132 |
3 files changed, 136 insertions, 130 deletions
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 2d8f925899d..6f42f1692f2 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -109,6 +109,135 @@ static void tegra_drm_lastclose(struct drm_device *drm) tegra_fbdev_restore_mode(tegra->fbdev); } +static struct host1x_bo * +host1x_bo_lookup(struct drm_device *drm, struct drm_file *file, u32 handle) +{ + struct drm_gem_object *gem; + struct tegra_bo *bo; + + gem = drm_gem_object_lookup(drm, file, handle); + if (!gem) + return NULL; + + mutex_lock(&drm->struct_mutex); + drm_gem_object_unreference(gem); + mutex_unlock(&drm->struct_mutex); + + bo = to_tegra_bo(gem); + return &bo->base; +} + +int tegra_drm_submit(struct tegra_drm_context *context, + struct drm_tegra_submit *args, struct drm_device *drm, + struct drm_file *file) +{ + unsigned int num_cmdbufs = args->num_cmdbufs; + unsigned int num_relocs = args->num_relocs; + unsigned int num_waitchks = args->num_waitchks; + struct drm_tegra_cmdbuf __user *cmdbufs = + (void * __user)(uintptr_t)args->cmdbufs; + struct drm_tegra_reloc __user *relocs = + (void * __user)(uintptr_t)args->relocs; + struct drm_tegra_waitchk __user *waitchks = + (void * __user)(uintptr_t)args->waitchks; + struct drm_tegra_syncpt syncpt; + struct host1x_job *job; + int err; + + /* We don't yet support other than one syncpt_incr struct per submit */ + if (args->num_syncpts != 1) + return -EINVAL; + + job = host1x_job_alloc(context->channel, args->num_cmdbufs, + args->num_relocs, args->num_waitchks); + if (!job) + return -ENOMEM; + + job->num_relocs = args->num_relocs; + job->num_waitchk = args->num_waitchks; + job->client = (u32)args->context; + job->class = context->client->base.class; + job->serialize = true; + + while (num_cmdbufs) { + struct drm_tegra_cmdbuf cmdbuf; + struct host1x_bo *bo; + + err = copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf)); + if (err) + goto fail; + + bo = host1x_bo_lookup(drm, file, cmdbuf.handle); + if (!bo) { + err = -ENOENT; + goto fail; + } + + host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset); + num_cmdbufs--; + cmdbufs++; + } + + err = copy_from_user(job->relocarray, relocs, + sizeof(*relocs) * num_relocs); + if (err) + goto fail; + + while (num_relocs--) { + struct host1x_reloc *reloc = &job->relocarray[num_relocs]; + struct host1x_bo *cmdbuf, *target; + + cmdbuf = host1x_bo_lookup(drm, file, (u32)reloc->cmdbuf); + target = host1x_bo_lookup(drm, file, (u32)reloc->target); + + reloc->cmdbuf = cmdbuf; + reloc->target = target; + + if (!reloc->target || !reloc->cmdbuf) { + err = -ENOENT; + goto fail; + } + } + + err = copy_from_user(job->waitchk, waitchks, + sizeof(*waitchks) * num_waitchks); + if (err) + goto fail; + + err = copy_from_user(&syncpt, (void * __user)(uintptr_t)args->syncpts, + sizeof(syncpt)); + if (err) + goto fail; + + job->is_addr_reg = context->client->ops->is_addr_reg; + job->syncpt_incrs = syncpt.incrs; + job->syncpt_id = syncpt.id; + job->timeout = 10000; + + if (args->timeout && args->timeout < 10000) + job->timeout = args->timeout; + + err = host1x_job_pin(job, context->client->base.dev); + if (err) + goto fail; + + err = host1x_job_submit(job); + if (err) + goto fail_submit; + + args->fence = job->syncpt_end; + + host1x_job_put(job); + return 0; + +fail_submit: + host1x_job_unpin(job); +fail: + host1x_job_put(job); + return err; +} + + #ifdef CONFIG_DRM_TEGRA_STAGING static struct tegra_drm_context *tegra_drm_get_context(__u64 context) { diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index dc4b994fe61..e3cd3ed438d 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -51,11 +51,16 @@ struct tegra_drm_client_ops { int (*open_channel)(struct tegra_drm_client *client, struct tegra_drm_context *context); void (*close_channel)(struct tegra_drm_context *context); + int (*is_addr_reg)(struct device *dev, u32 class, u32 offset); int (*submit)(struct tegra_drm_context *context, struct drm_tegra_submit *args, struct drm_device *drm, struct drm_file *file); }; +int tegra_drm_submit(struct tegra_drm_context *context, + struct drm_tegra_submit *args, struct drm_device *drm, + struct drm_file *file); + struct tegra_drm_client { struct host1x_client base; struct list_head list; diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index bbeedc24d00..73b79bad613 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -91,25 +91,6 @@ static void gr2d_close_channel(struct tegra_drm_context *context) host1x_channel_put(context->channel); } -static struct host1x_bo *host1x_bo_lookup(struct drm_device *drm, - struct drm_file *file, - u32 handle) -{ - struct drm_gem_object *gem; - struct tegra_bo *bo; - - gem = drm_gem_object_lookup(drm, file, handle); - if (!gem) - return NULL; - - mutex_lock(&drm->struct_mutex); - drm_gem_object_unreference(gem); - mutex_unlock(&drm->struct_mutex); - - bo = to_tegra_bo(gem); - return &bo->base; -} - static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 offset) { struct gr2d *gr2d = dev_get_drvdata(dev); @@ -135,120 +116,11 @@ static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 offset) return 0; } -static int gr2d_submit(struct tegra_drm_context *context, - struct drm_tegra_submit *args, struct drm_device *drm, - struct drm_file *file) -{ - unsigned int num_cmdbufs = args->num_cmdbufs; - unsigned int num_relocs = args->num_relocs; - unsigned int num_waitchks = args->num_waitchks; - struct drm_tegra_cmdbuf __user *cmdbufs = - (void * __user)(uintptr_t)args->cmdbufs; - struct drm_tegra_reloc __user *relocs = - (void * __user)(uintptr_t)args->relocs; - struct drm_tegra_waitchk __user *waitchks = - (void * __user)(uintptr_t)args->waitchks; - struct drm_tegra_syncpt syncpt; - struct host1x_job *job; - int err; - - /* We don't yet support other than one syncpt_incr struct per submit */ - if (args->num_syncpts != 1) - return -EINVAL; - - job = host1x_job_alloc(context->channel, args->num_cmdbufs, - args->num_relocs, args->num_waitchks); - if (!job) - return -ENOMEM; - - job->num_relocs = args->num_relocs; - job->num_waitchk = args->num_waitchks; - job->client = (u32)args->context; - job->class = context->client->base.class; - job->serialize = true; - - while (num_cmdbufs) { - struct drm_tegra_cmdbuf cmdbuf; - struct host1x_bo *bo; - - err = copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf)); - if (err) - goto fail; - - bo = host1x_bo_lookup(drm, file, cmdbuf.handle); - if (!bo) { - err = -ENOENT; - goto fail; - } - - host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset); - num_cmdbufs--; - cmdbufs++; - } - - err = copy_from_user(job->relocarray, relocs, - sizeof(*relocs) * num_relocs); - if (err) - goto fail; - - while (num_relocs--) { - struct host1x_reloc *reloc = &job->relocarray[num_relocs]; - struct host1x_bo *cmdbuf, *target; - - cmdbuf = host1x_bo_lookup(drm, file, (u32)reloc->cmdbuf); - target = host1x_bo_lookup(drm, file, (u32)reloc->target); - - reloc->cmdbuf = cmdbuf; - reloc->target = target; - - if (!reloc->target || !reloc->cmdbuf) { - err = -ENOENT; - goto fail; - } - } - - err = copy_from_user(job->waitchk, waitchks, - sizeof(*waitchks) * num_waitchks); - if (err) - goto fail; - - err = copy_from_user(&syncpt, (void * __user)(uintptr_t)args->syncpts, - sizeof(syncpt)); - if (err) - goto fail; - - job->syncpt_id = syncpt.id; - job->syncpt_incrs = syncpt.incrs; - job->timeout = 10000; - job->is_addr_reg = gr2d_is_addr_reg; - - if (args->timeout && args->timeout < 10000) - job->timeout = args->timeout; - - err = host1x_job_pin(job, context->client->base.dev); - if (err) - goto fail; - - err = host1x_job_submit(job); - if (err) - goto fail_submit; - - args->fence = job->syncpt_end; - - host1x_job_put(job); - return 0; - -fail_submit: - host1x_job_unpin(job); -fail: - host1x_job_put(job); - return err; -} - static const struct tegra_drm_client_ops gr2d_ops = { .open_channel = gr2d_open_channel, .close_channel = gr2d_close_channel, - .submit = gr2d_submit, + .is_addr_reg = gr2d_is_addr_reg, + .submit = tegra_drm_submit, }; static const struct of_device_id gr2d_match[] = { |