gpu: nvgpu: Simplify ref-counting on VMs
Alex Waterman [Wed, 30 Nov 2016 00:01:41 +0000 (16:01 -0800)]
Simplify ref-counting on VMs: take a ref when a VM is bound to a
channel and drop a ref when a channel is freed.

Previously ref-counts were scattered over the driver. Also the CE
and CDE code would bind channels with custom rolled code. This was
because the gk20a_vm_bind_channel() function took an as_share as
the VM argument (the VM was then inferred from that as_share).
However, it is trivial to abtract that bit out and allow a central
bind channel function that just takes a VM and a channel.

Bug 1846718
Bug 200288656
Bug 1887273

Change-Id: I156aab259f6c7a2fa338408c6c4a3a464cd44a0c
Reviewed-on: http://git-master/r/1261886
(cherry picked from commit 7e403974d3584ab8880e42d422ee3afb7f49d6f3)
Reviewed-on: http://git-master/r/1312293
(cherry picked from commit 1b73a6e97bf66f6bd67ffacf49a4cec1e4c14790)
Reviewed-on: http://git-master/r/1320258
(cherry picked from commit c8b139cfb4835735cb1302c69e37a8793de286d3)
Signed-off-by: Gagan Grover <ggrover@nvidia.com>
Reviewed-on: http://git-master/r/1458139
Reviewed-by: Manish Tuteja <mtuteja@nvidia.com>
Tested-by: Manish Tuteja <mtuteja@nvidia.com>

drivers/gpu/nvgpu/gk20a/cde_gk20a.c
drivers/gpu/nvgpu/gk20a/channel_gk20a.c
drivers/gpu/nvgpu/gk20a/mm_gk20a.c
drivers/gpu/nvgpu/gk20a/mm_gk20a.h
drivers/gpu/nvgpu/gk20a/semaphore_gk20a.c
drivers/gpu/nvgpu/vgpu/mm_vgpu.c

index 68cabce..1b33645 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Color decompression engine support
  *
- * Copyright (c) 2014-2016, NVIDIA Corporation.  All rights reserved.
+ * Copyright (c) 2014-2017, NVIDIA Corporation.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -1109,9 +1109,7 @@ static int gk20a_cde_load(struct gk20a_cde_ctx *cde_ctx)
        }
 
        /* bind the channel to the vm */
-       gk20a_vm_get(&g->mm.pmu.vm);
-       ch->vm = &g->mm.pmu.vm;
-       err = channel_gk20a_commit_va(ch);
+       err = __gk20a_vm_bind_channel(&g->mm.pmu.vm, ch);
        if (err) {
                gk20a_warn(&cde_ctx->pdev->dev, "cde: could not bind vm");
                goto err_commit_va;
index 2da69ef..1f88314 100644 (file)
@@ -855,11 +855,10 @@ static void gk20a_free_channel(struct channel_gk20a *ch)
        }
        mutex_unlock(&ch->sync_lock);
 
-       /* release channel binding to the as_share */
-       if (ch_vm->as_share)
-               gk20a_as_release_share(ch_vm->as_share);
-       else
-               gk20a_vm_put(ch_vm);
+       /*
+        * When releasing the channel we unbind the VM - so release the ref.
+        */
+       gk20a_vm_put(ch_vm);
 
        spin_lock(&ch->update_fn_lock);
        ch->update_fn = NULL;
@@ -1550,22 +1549,16 @@ static int gk20a_channel_add_job(struct channel_gk20a *c,
        struct mapped_buffer_node **mapped_buffers = NULL;
        int err = 0, num_mapped_buffers = 0;
 
-       /* job needs reference to this vm (released in channel_update) */
-       gk20a_vm_get(vm);
-
        if (!skip_buffer_refcounting) {
                err = gk20a_vm_get_buffers(vm, &mapped_buffers,
                                        &num_mapped_buffers);
-               if (err) {
-                       gk20a_vm_put(vm);
+               if (err)
                        return err;
-               }
        }
 
        job = kzalloc(sizeof(*job), GFP_KERNEL);
        if (!job) {
                gk20a_vm_put_buffers(vm, mapped_buffers, num_mapped_buffers);
-               gk20a_vm_put(vm);
                return -ENOMEM;
        }
 
@@ -1657,8 +1650,6 @@ static void gk20a_channel_clean_up_jobs(struct work_struct *work)
                gk20a_free_priv_cmdbuf(c, job->wait_cmd);
                gk20a_free_priv_cmdbuf(c, job->incr_cmd);
 
-               /* job is done. release its vm reference (taken in add_job) */
-               gk20a_vm_put(vm);
                /* another bookkeeping taken in add_job. caller must hold a ref
                 * so this wouldn't get freed here. */
                gk20a_channel_put(c);
index e0347ae..155af4e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * GK20A memory management
  *
- * Copyright (c) 2011-2016, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2011-2017, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -320,7 +320,7 @@ static int gk20a_alloc_comptags(struct gk20a *g,
        if (err)
                return err;
 
-       /* 
+       /*
         * offset needs to be at the start of a page/cacheline boundary;
         * prune the preceding ctaglines that were allocated for alignment.
         */
@@ -2968,12 +2968,10 @@ int gk20a_vm_release_share(struct gk20a_as_share *as_share)
        gk20a_dbg_fn("");
 
        vm->as_share = NULL;
+       as_share->vm = NULL;
 
-       /* put as reference to vm */
        gk20a_vm_put(vm);
 
-       as_share->vm = NULL;
-
        return 0;
 }
 
@@ -3126,14 +3124,13 @@ int gk20a_vm_free_space(struct gk20a_as_share *as_share,
        return err;
 }
 
-int gk20a_vm_bind_channel(struct gk20a_as_share *as_share,
-                         struct channel_gk20a *ch)
+int __gk20a_vm_bind_channel(struct vm_gk20a *vm, struct channel_gk20a *ch)
 {
        int err = 0;
-       struct vm_gk20a *vm = as_share->vm;
 
        gk20a_dbg_fn("");
 
+       gk20a_vm_get(vm);
        ch->vm = vm;
        err = channel_gk20a_commit_va(ch);
        if (err)
@@ -3142,6 +3139,12 @@ int gk20a_vm_bind_channel(struct gk20a_as_share *as_share,
        return err;
 }
 
+int gk20a_vm_bind_channel(struct gk20a_as_share *as_share,
+                         struct channel_gk20a *ch)
+{
+       return __gk20a_vm_bind_channel(as_share->vm, ch);
+}
+
 int gk20a_dmabuf_alloc_drvdata(struct dma_buf *dmabuf, struct device *dev)
 {
        struct gk20a_dmabuf_priv *priv;
@@ -3718,4 +3721,3 @@ void gk20a_init_mm(struct gpu_ops *gops)
        gops->mm.init_pdb = gk20a_mm_init_pdb;
        gops->mm.init_mm_setup_hw = gk20a_init_mm_setup_hw;
 }
-
index 18fa415..d70d5c8 100644 (file)
@@ -588,6 +588,7 @@ int gk20a_vm_free_space(struct gk20a_as_share *as_share,
                        struct nvgpu_as_free_space_args *args);
 int gk20a_vm_bind_channel(struct gk20a_as_share *as_share,
                          struct channel_gk20a *ch);
+int __gk20a_vm_bind_channel(struct vm_gk20a *vm, struct channel_gk20a *ch);
 
 /* batching eliminates redundant cache flushes and invalidates */
 void gk20a_vm_mapping_batch_start(struct vm_gk20a_mapping_batch *batch);
index cf85546..39f1a68 100644 (file)
@@ -3,7 +3,7 @@
  *
  * GK20A Semaphores
  *
- * Copyright (c) 2014-2015, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -117,7 +117,6 @@ int gk20a_semaphore_pool_map(struct gk20a_semaphore_pool *p,
                kfree(map);
                return -ENOMEM;
        }
-       gk20a_vm_get(vm);
 
        mutex_lock(&p->maps_mutex);
        WARN_ON(gk20a_semaphore_pool_find_map_locked(p, vm));
@@ -136,7 +135,6 @@ void gk20a_semaphore_pool_unmap(struct gk20a_semaphore_pool *p,
        map = gk20a_semaphore_pool_find_map_locked(p, vm);
        if (map) {
                gk20a_gmmu_unmap(vm, map->gpu_va, p->size, map->rw_flag);
-               gk20a_vm_put(vm);
                list_del(&map->list);
                kfree(map);
        }
index 69e9f47..52e65d1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Virtualized GPU Memory Management
  *
- * Copyright (c) 2014-2015, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -377,6 +377,9 @@ static int vgpu_vm_bind_channel(struct gk20a_as_share *as_share,
                err = -ENOMEM;
        }
 
+       if (ch->vm)
+               gk20a_vm_get(ch->vm);
+
        return err;
 }