Merge remote-tracking branch 'airlied/drm-next' into drm-misc-next

Required for Daniel's drm_vblank_cleanup cleanup
This commit is contained in:
Sean Paul
2017-06-27 09:18:17 -04:00
melakukan b740e76936
2139 mengubah file dengan 367233 tambahan dan 31165 penghapusan

Melihat File

@@ -26,6 +26,7 @@
#define DRIVER_PATCHLEVEL 0
#define CARVEOUT_SZ SZ_64M
#define CDMA_GATHER_FETCHES_MAX_NB 16383
struct tegra_drm_file {
struct idr contexts;
@@ -345,6 +346,36 @@ static int host1x_reloc_copy_from_user(struct host1x_reloc *dest,
return 0;
}
static int host1x_waitchk_copy_from_user(struct host1x_waitchk *dest,
struct drm_tegra_waitchk __user *src,
struct drm_file *file)
{
u32 cmdbuf;
int err;
err = get_user(cmdbuf, &src->handle);
if (err < 0)
return err;
err = get_user(dest->offset, &src->offset);
if (err < 0)
return err;
err = get_user(dest->syncpt_id, &src->syncpt);
if (err < 0)
return err;
err = get_user(dest->thresh, &src->thresh);
if (err < 0)
return err;
dest->bo = host1x_bo_lookup(file, cmdbuf);
if (!dest->bo)
return -ENOENT;
return 0;
}
int tegra_drm_submit(struct tegra_drm_context *context,
struct drm_tegra_submit *args, struct drm_device *drm,
struct drm_file *file)
@@ -359,6 +390,8 @@ int tegra_drm_submit(struct tegra_drm_context *context,
struct drm_tegra_waitchk __user *waitchks =
(void __user *)(uintptr_t)args->waitchks;
struct drm_tegra_syncpt syncpt;
struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
struct host1x_syncpt *sp;
struct host1x_job *job;
int err;
@@ -366,6 +399,10 @@ int tegra_drm_submit(struct tegra_drm_context *context,
if (args->num_syncpts != 1)
return -EINVAL;
/* We don't yet support waitchks */
if (args->num_waitchks != 0)
return -EINVAL;
job = host1x_job_alloc(context->channel, args->num_cmdbufs,
args->num_relocs, args->num_waitchks);
if (!job)
@@ -380,18 +417,42 @@ int tegra_drm_submit(struct tegra_drm_context *context,
while (num_cmdbufs) {
struct drm_tegra_cmdbuf cmdbuf;
struct host1x_bo *bo;
struct tegra_bo *obj;
u64 offset;
if (copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf))) {
err = -EFAULT;
goto fail;
}
/*
* The maximum number of CDMA gather fetches is 16383, a higher
* value means the words count is malformed.
*/
if (cmdbuf.words > CDMA_GATHER_FETCHES_MAX_NB) {
err = -EINVAL;
goto fail;
}
bo = host1x_bo_lookup(file, cmdbuf.handle);
if (!bo) {
err = -ENOENT;
goto fail;
}
offset = (u64)cmdbuf.offset + (u64)cmdbuf.words * sizeof(u32);
obj = host1x_to_tegra_bo(bo);
/*
* Gather buffer base address must be 4-bytes aligned,
* unaligned offset is malformed and cause commands stream
* corruption on the buffer address relocation.
*/
if (offset & 3 || offset >= obj->gem.size) {
err = -EINVAL;
goto fail;
}
host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset);
num_cmdbufs--;
cmdbufs++;
@@ -399,17 +460,59 @@ int tegra_drm_submit(struct tegra_drm_context *context,
/* copy and resolve relocations from submit */
while (num_relocs--) {
struct host1x_reloc *reloc;
struct tegra_bo *obj;
err = host1x_reloc_copy_from_user(&job->relocarray[num_relocs],
&relocs[num_relocs], drm,
file);
if (err < 0)
goto fail;
reloc = &job->relocarray[num_relocs];
obj = host1x_to_tegra_bo(reloc->cmdbuf.bo);
/*
* The unaligned cmdbuf offset will cause an unaligned write
* during of the relocations patching, corrupting the commands
* stream.
*/
if (reloc->cmdbuf.offset & 3 ||
reloc->cmdbuf.offset >= obj->gem.size) {
err = -EINVAL;
goto fail;
}
obj = host1x_to_tegra_bo(reloc->target.bo);
if (reloc->target.offset >= obj->gem.size) {
err = -EINVAL;
goto fail;
}
}
if (copy_from_user(job->waitchk, waitchks,
sizeof(*waitchks) * num_waitchks)) {
err = -EFAULT;
goto fail;
/* copy and resolve waitchks from submit */
while (num_waitchks--) {
struct host1x_waitchk *wait = &job->waitchk[num_waitchks];
struct tegra_bo *obj;
err = host1x_waitchk_copy_from_user(wait,
&waitchks[num_waitchks],
file);
if (err < 0)
goto fail;
obj = host1x_to_tegra_bo(wait->bo);
/*
* The unaligned offset will cause an unaligned write during
* of the waitchks patching, corrupting the commands stream.
*/
if (wait->offset & 3 ||
wait->offset >= obj->gem.size) {
err = -EINVAL;
goto fail;
}
}
if (copy_from_user(&syncpt, (void __user *)(uintptr_t)args->syncpts,
@@ -418,7 +521,15 @@ int tegra_drm_submit(struct tegra_drm_context *context,
goto fail;
}
/* check whether syncpoint ID is valid */
sp = host1x_syncpt_get(host1x, syncpt.id);
if (!sp) {
err = -ENOENT;
goto fail;
}
job->is_addr_reg = context->client->ops->is_addr_reg;
job->is_valid_class = context->client->ops->is_valid_class;
job->syncpt_incrs = syncpt.incrs;
job->syncpt_id = syncpt.id;
job->timeout = 10000;
@@ -448,18 +559,6 @@ fail:
#ifdef CONFIG_DRM_TEGRA_STAGING
static struct tegra_drm_context *
tegra_drm_file_get_context(struct tegra_drm_file *file, u32 id)
{
struct tegra_drm_context *context;
mutex_lock(&file->lock);
context = idr_find(&file->contexts, id);
mutex_unlock(&file->lock);
return context;
}
static int tegra_gem_create(struct drm_device *drm, void *data,
struct drm_file *file)
{
@@ -548,7 +647,7 @@ static int tegra_client_open(struct tegra_drm_file *fpriv,
if (err < 0)
return err;
err = idr_alloc(&fpriv->contexts, context, 0, 0, GFP_KERNEL);
err = idr_alloc(&fpriv->contexts, context, 1, 0, GFP_KERNEL);
if (err < 0) {
client->ops->close_channel(context);
return err;
@@ -603,7 +702,7 @@ static int tegra_close_channel(struct drm_device *drm, void *data,
mutex_lock(&fpriv->lock);
context = tegra_drm_file_get_context(fpriv, args->context);
context = idr_find(&fpriv->contexts, args->context);
if (!context) {
err = -EINVAL;
goto unlock;
@@ -628,7 +727,7 @@ static int tegra_get_syncpt(struct drm_device *drm, void *data,
mutex_lock(&fpriv->lock);
context = tegra_drm_file_get_context(fpriv, args->context);
context = idr_find(&fpriv->contexts, args->context);
if (!context) {
err = -ENODEV;
goto unlock;
@@ -657,7 +756,7 @@ static int tegra_submit(struct drm_device *drm, void *data,
mutex_lock(&fpriv->lock);
context = tegra_drm_file_get_context(fpriv, args->context);
context = idr_find(&fpriv->contexts, args->context);
if (!context) {
err = -ENODEV;
goto unlock;
@@ -682,7 +781,7 @@ static int tegra_get_syncpt_base(struct drm_device *drm, void *data,
mutex_lock(&fpriv->lock);
context = tegra_drm_file_get_context(fpriv, args->context);
context = idr_find(&fpriv->contexts, args->context);
if (!context) {
err = -ENODEV;
goto unlock;