summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nouveau_gem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_gem.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c84
1 files changed, 65 insertions, 19 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index b4b4d0c1f4af..e72d09c068a8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -50,7 +50,8 @@ nouveau_gem_object_del(struct drm_gem_object *gem)
return;
nvbo->gem = NULL;
- if (unlikely(nvbo->pin_refcnt)) {
+ /* Lockdep hates you for doing reserve with gem object lock held */
+ if (WARN_ON_ONCE(nvbo->pin_refcnt)) {
nvbo->pin_refcnt = 1;
nouveau_bo_unpin(nvbo);
}
@@ -101,6 +102,41 @@ out:
return ret;
}
+static void
+nouveau_gem_object_delete(void *data)
+{
+ struct nouveau_vma *vma = data;
+ nouveau_vm_unmap(vma);
+ nouveau_vm_put(vma);
+ kfree(vma);
+}
+
+static void
+nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
+{
+ const bool mapped = nvbo->bo.mem.mem_type != TTM_PL_SYSTEM;
+ struct nouveau_fence *fence = NULL;
+
+ list_del(&vma->head);
+
+ if (mapped) {
+ spin_lock(&nvbo->bo.bdev->fence_lock);
+ if (nvbo->bo.sync_obj)
+ fence = nouveau_fence_ref(nvbo->bo.sync_obj);
+ spin_unlock(&nvbo->bo.bdev->fence_lock);
+ }
+
+ if (fence) {
+ nouveau_fence_work(fence, nouveau_gem_object_delete, vma);
+ } else {
+ if (mapped)
+ nouveau_vm_unmap(vma);
+ nouveau_vm_put(vma);
+ kfree(vma);
+ }
+ nouveau_fence_unref(&fence);
+}
+
void
nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
{
@@ -118,10 +154,8 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
vma = nouveau_bo_vma_find(nvbo, cli->base.vm);
if (vma) {
- if (--vma->refcount == 0) {
- nouveau_bo_vma_del(nvbo, vma);
- kfree(vma);
- }
+ if (--vma->refcount == 0)
+ nouveau_gem_object_unmap(nvbo, vma);
}
ttm_bo_unreserve(&nvbo->bo);
}
@@ -276,10 +310,12 @@ struct validate_op {
struct list_head vram_list;
struct list_head gart_list;
struct list_head both_list;
+ struct ww_acquire_ctx ticket;
};
static void
-validate_fini_list(struct list_head *list, struct nouveau_fence *fence)
+validate_fini_list(struct list_head *list, struct nouveau_fence *fence,
+ struct ww_acquire_ctx *ticket)
{
struct list_head *entry, *tmp;
struct nouveau_bo *nvbo;
@@ -296,17 +332,24 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence)
list_del(&nvbo->entry);
nvbo->reserved_by = NULL;
- ttm_bo_unreserve(&nvbo->bo);
+ ttm_bo_unreserve_ticket(&nvbo->bo, ticket);
drm_gem_object_unreference_unlocked(nvbo->gem);
}
}
static void
-validate_fini(struct validate_op *op, struct nouveau_fence* fence)
+validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence)
{
- validate_fini_list(&op->vram_list, fence);
- validate_fini_list(&op->gart_list, fence);
- validate_fini_list(&op->both_list, fence);
+ validate_fini_list(&op->vram_list, fence, &op->ticket);
+ validate_fini_list(&op->gart_list, fence, &op->ticket);
+ validate_fini_list(&op->both_list, fence, &op->ticket);
+}
+
+static void
+validate_fini(struct validate_op *op, struct nouveau_fence *fence)
+{
+ validate_fini_no_ticket(op, fence);
+ ww_acquire_fini(&op->ticket);
}
static int
@@ -316,13 +359,11 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv,
{
struct nouveau_cli *cli = nouveau_cli(file_priv);
struct drm_device *dev = chan->drm->dev;
- struct nouveau_drm *drm = nouveau_drm(dev);
- uint32_t sequence;
int trycnt = 0;
int ret, i;
struct nouveau_bo *res_bo = NULL;
- sequence = atomic_add_return(1, &drm->ttm.validate_sequence);
+ ww_acquire_init(&op->ticket, &reservation_ww_class);
retry:
if (++trycnt > 100000) {
NV_ERROR(cli, "%s failed and gave up.\n", __func__);
@@ -337,6 +378,7 @@ retry:
gem = drm_gem_object_lookup(dev, file_priv, b->handle);
if (!gem) {
NV_ERROR(cli, "Unknown handle 0x%08x\n", b->handle);
+ ww_acquire_done(&op->ticket);
validate_fini(op, NULL);
return -ENOENT;
}
@@ -351,21 +393,23 @@ retry:
NV_ERROR(cli, "multiple instances of buffer %d on "
"validation list\n", b->handle);
drm_gem_object_unreference_unlocked(gem);
+ ww_acquire_done(&op->ticket);
validate_fini(op, NULL);
return -EINVAL;
}
- ret = ttm_bo_reserve(&nvbo->bo, true, false, true, sequence);
+ ret = ttm_bo_reserve(&nvbo->bo, true, false, true, &op->ticket);
if (ret) {
- validate_fini(op, NULL);
- if (unlikely(ret == -EAGAIN)) {
- sequence = atomic_add_return(1, &drm->ttm.validate_sequence);
+ validate_fini_no_ticket(op, NULL);
+ if (unlikely(ret == -EDEADLK)) {
ret = ttm_bo_reserve_slowpath(&nvbo->bo, true,
- sequence);
+ &op->ticket);
if (!ret)
res_bo = nvbo;
}
if (unlikely(ret)) {
+ ww_acquire_done(&op->ticket);
+ ww_acquire_fini(&op->ticket);
drm_gem_object_unreference_unlocked(gem);
if (ret != -ERESTARTSYS)
NV_ERROR(cli, "fail reserve\n");
@@ -389,6 +433,7 @@ retry:
NV_ERROR(cli, "invalid valid domains: 0x%08x\n",
b->valid_domains);
list_add_tail(&nvbo->entry, &op->both_list);
+ ww_acquire_done(&op->ticket);
validate_fini(op, NULL);
return -EINVAL;
}
@@ -396,6 +441,7 @@ retry:
goto retry;
}
+ ww_acquire_done(&op->ticket);
return 0;
}