|
@@ -306,8 +306,6 @@ host1x_bo_lookup(struct drm_file *file, u32 handle)
|
|
|
if (!gem)
|
|
|
return NULL;
|
|
|
|
|
|
- drm_gem_object_unreference_unlocked(gem);
|
|
|
-
|
|
|
bo = to_tegra_bo(gem);
|
|
|
return &bo->base;
|
|
|
}
|
|
@@ -396,8 +394,10 @@ int tegra_drm_submit(struct tegra_drm_context *context,
|
|
|
(void __user *)(uintptr_t)args->waitchks;
|
|
|
struct drm_tegra_syncpt syncpt;
|
|
|
struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
|
|
|
+ struct drm_gem_object **refs;
|
|
|
struct host1x_syncpt *sp;
|
|
|
struct host1x_job *job;
|
|
|
+ unsigned int num_refs;
|
|
|
int err;
|
|
|
|
|
|
/* We don't yet support other than one syncpt_incr struct per submit */
|
|
@@ -419,6 +419,21 @@ int tegra_drm_submit(struct tegra_drm_context *context,
|
|
|
job->class = context->client->base.class;
|
|
|
job->serialize = true;
|
|
|
|
|
|
+ /*
|
|
|
+ * Track referenced BOs so that they can be unreferenced after the
|
|
|
+ * submission is complete.
|
|
|
+ */
|
|
|
+ num_refs = num_cmdbufs + num_relocs * 2 + num_waitchks;
|
|
|
+
|
|
|
+ refs = kmalloc_array(num_refs, sizeof(*refs), GFP_KERNEL);
|
|
|
+ if (!refs) {
|
|
|
+ err = -ENOMEM;
|
|
|
+ goto put;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* reuse as an iterator later */
|
|
|
+ num_refs = 0;
|
|
|
+
|
|
|
while (num_cmdbufs) {
|
|
|
struct drm_tegra_cmdbuf cmdbuf;
|
|
|
struct host1x_bo *bo;
|
|
@@ -447,6 +462,7 @@ int tegra_drm_submit(struct tegra_drm_context *context,
|
|
|
|
|
|
offset = (u64)cmdbuf.offset + (u64)cmdbuf.words * sizeof(u32);
|
|
|
obj = host1x_to_tegra_bo(bo);
|
|
|
+ refs[num_refs++] = &obj->gem;
|
|
|
|
|
|
/*
|
|
|
* Gather buffer base address must be 4-bytes aligned,
|
|
@@ -476,6 +492,7 @@ int tegra_drm_submit(struct tegra_drm_context *context,
|
|
|
|
|
|
reloc = &job->relocarray[num_relocs];
|
|
|
obj = host1x_to_tegra_bo(reloc->cmdbuf.bo);
|
|
|
+ refs[num_refs++] = &obj->gem;
|
|
|
|
|
|
/*
|
|
|
* The unaligned cmdbuf offset will cause an unaligned write
|
|
@@ -489,6 +506,7 @@ int tegra_drm_submit(struct tegra_drm_context *context,
|
|
|
}
|
|
|
|
|
|
obj = host1x_to_tegra_bo(reloc->target.bo);
|
|
|
+ refs[num_refs++] = &obj->gem;
|
|
|
|
|
|
if (reloc->target.offset >= obj->gem.size) {
|
|
|
err = -EINVAL;
|
|
@@ -508,6 +526,7 @@ int tegra_drm_submit(struct tegra_drm_context *context,
|
|
|
goto fail;
|
|
|
|
|
|
obj = host1x_to_tegra_bo(wait->bo);
|
|
|
+ refs[num_refs++] = &obj->gem;
|
|
|
|
|
|
/*
|
|
|
* The unaligned offset will cause an unaligned write during
|
|
@@ -547,17 +566,20 @@ int tegra_drm_submit(struct tegra_drm_context *context,
|
|
|
goto fail;
|
|
|
|
|
|
err = host1x_job_submit(job);
|
|
|
- if (err)
|
|
|
- goto fail_submit;
|
|
|
+ if (err) {
|
|
|
+ host1x_job_unpin(job);
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
|
|
|
args->fence = job->syncpt_end;
|
|
|
|
|
|
- host1x_job_put(job);
|
|
|
- return 0;
|
|
|
-
|
|
|
-fail_submit:
|
|
|
- host1x_job_unpin(job);
|
|
|
fail:
|
|
|
+ while (num_refs--)
|
|
|
+ drm_gem_object_put_unlocked(refs[num_refs]);
|
|
|
+
|
|
|
+ kfree(refs);
|
|
|
+
|
|
|
+put:
|
|
|
host1x_job_put(job);
|
|
|
return err;
|
|
|
}
|
|
@@ -593,7 +615,7 @@ static int tegra_gem_mmap(struct drm_device *drm, void *data,
|
|
|
|
|
|
args->offset = drm_vma_node_offset_addr(&bo->gem.vma_node);
|
|
|
|
|
|
- drm_gem_object_unreference_unlocked(gem);
|
|
|
+ drm_gem_object_put_unlocked(gem);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -860,7 +882,7 @@ static int tegra_gem_set_tiling(struct drm_device *drm, void *data,
|
|
|
bo->tiling.mode = mode;
|
|
|
bo->tiling.value = value;
|
|
|
|
|
|
- drm_gem_object_unreference_unlocked(gem);
|
|
|
+ drm_gem_object_put_unlocked(gem);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -900,7 +922,7 @@ static int tegra_gem_get_tiling(struct drm_device *drm, void *data,
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- drm_gem_object_unreference_unlocked(gem);
|
|
|
+ drm_gem_object_put_unlocked(gem);
|
|
|
|
|
|
return err;
|
|
|
}
|
|
@@ -925,7 +947,7 @@ static int tegra_gem_set_flags(struct drm_device *drm, void *data,
|
|
|
if (args->flags & DRM_TEGRA_GEM_BOTTOM_UP)
|
|
|
bo->flags |= TEGRA_BO_BOTTOM_UP;
|
|
|
|
|
|
- drm_gem_object_unreference_unlocked(gem);
|
|
|
+ drm_gem_object_put_unlocked(gem);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -947,7 +969,7 @@ static int tegra_gem_get_flags(struct drm_device *drm, void *data,
|
|
|
if (bo->flags & TEGRA_BO_BOTTOM_UP)
|
|
|
args->flags |= DRM_TEGRA_GEM_BOTTOM_UP;
|
|
|
|
|
|
- drm_gem_object_unreference_unlocked(gem);
|
|
|
+ drm_gem_object_put_unlocked(gem);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -955,20 +977,34 @@ static int tegra_gem_get_flags(struct drm_device *drm, void *data,
|
|
|
|
|
|
static const struct drm_ioctl_desc tegra_drm_ioctls[] = {
|
|
|
#ifdef CONFIG_DRM_TEGRA_STAGING
|
|
|
- DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, 0),
|
|
|
- DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, 0),
|
|
|
- DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, 0),
|
|
|
- DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, 0),
|
|
|
- DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT, tegra_syncpt_wait, 0),
|
|
|
- DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL, tegra_open_channel, 0),
|
|
|
- DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel, 0),
|
|
|
- DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, 0),
|
|
|
- DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, 0),
|
|
|
- DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT_BASE, tegra_get_syncpt_base, 0),
|
|
|
- DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_TILING, tegra_gem_set_tiling, 0),
|
|
|
- DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_TILING, tegra_gem_get_tiling, 0),
|
|
|
- DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_FLAGS, tegra_gem_set_flags, 0),
|
|
|
- DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_FLAGS, tegra_gem_get_flags, 0),
|
|
|
+ DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create,
|
|
|
+ DRM_UNLOCKED | DRM_RENDER_ALLOW),
|
|
|
+ DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap,
|
|
|
+ DRM_UNLOCKED | DRM_RENDER_ALLOW),
|
|
|
+ DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read,
|
|
|
+ DRM_UNLOCKED | DRM_RENDER_ALLOW),
|
|
|
+ DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr,
|
|
|
+ DRM_UNLOCKED | DRM_RENDER_ALLOW),
|
|
|
+ DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT, tegra_syncpt_wait,
|
|
|
+ DRM_UNLOCKED | DRM_RENDER_ALLOW),
|
|
|
+ DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL, tegra_open_channel,
|
|
|
+ DRM_UNLOCKED | DRM_RENDER_ALLOW),
|
|
|
+ DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel,
|
|
|
+ DRM_UNLOCKED | DRM_RENDER_ALLOW),
|
|
|
+ DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt,
|
|
|
+ DRM_UNLOCKED | DRM_RENDER_ALLOW),
|
|
|
+ DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit,
|
|
|
+ DRM_UNLOCKED | DRM_RENDER_ALLOW),
|
|
|
+ DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT_BASE, tegra_get_syncpt_base,
|
|
|
+ DRM_UNLOCKED | DRM_RENDER_ALLOW),
|
|
|
+ DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_TILING, tegra_gem_set_tiling,
|
|
|
+ DRM_UNLOCKED | DRM_RENDER_ALLOW),
|
|
|
+ DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_TILING, tegra_gem_get_tiling,
|
|
|
+ DRM_UNLOCKED | DRM_RENDER_ALLOW),
|
|
|
+ DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_FLAGS, tegra_gem_set_flags,
|
|
|
+ DRM_UNLOCKED | DRM_RENDER_ALLOW),
|
|
|
+ DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_FLAGS, tegra_gem_get_flags,
|
|
|
+ DRM_UNLOCKED | DRM_RENDER_ALLOW),
|
|
|
#endif
|
|
|
};
|
|
|
|
|
@@ -1035,9 +1071,11 @@ static int tegra_debugfs_iova(struct seq_file *s, void *data)
|
|
|
struct tegra_drm *tegra = drm->dev_private;
|
|
|
struct drm_printer p = drm_seq_file_printer(s);
|
|
|
|
|
|
- mutex_lock(&tegra->mm_lock);
|
|
|
- drm_mm_print(&tegra->mm, &p);
|
|
|
- mutex_unlock(&tegra->mm_lock);
|
|
|
+ if (tegra->domain) {
|
|
|
+ mutex_lock(&tegra->mm_lock);
|
|
|
+ drm_mm_print(&tegra->mm, &p);
|
|
|
+ mutex_unlock(&tegra->mm_lock);
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -1057,7 +1095,7 @@ static int tegra_debugfs_init(struct drm_minor *minor)
|
|
|
|
|
|
static struct drm_driver tegra_drm_driver = {
|
|
|
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
|
|
|
- DRIVER_ATOMIC,
|
|
|
+ DRIVER_ATOMIC | DRIVER_RENDER,
|
|
|
.load = tegra_drm_load,
|
|
|
.unload = tegra_drm_unload,
|
|
|
.open = tegra_drm_open,
|