drm/nouveau/core/memory: add reference counting
authorBen Skeggs <bskeggs@redhat.com>
Tue, 31 Oct 2017 17:56:19 +0000 (03:56 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Thu, 2 Nov 2017 03:32:22 +0000 (13:32 +1000)
We need to be able to prevent memory from being freed while it's still
mapped in a GPU's address-space.

Will be used by upcoming MMU changes.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
19 files changed:
drivers/gpu/drm/nouveau/include/nvkm/core/memory.h
drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c
drivers/gpu/drm/nouveau/nvkm/core/memory.c
drivers/gpu/drm/nouveau/nvkm/engine/falcon.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c
drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c
drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c
drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c
drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c

index a0bfc37b96db09c6a28061dc8816a43c98d0a4e3..9c9c400bea984f338aa8ac54f0eb3573015ecf87 100644 (file)
@@ -20,6 +20,7 @@ enum nvkm_memory_target {
 struct nvkm_memory {
        const struct nvkm_memory_func *func;
        const struct nvkm_memory_ptrs *ptrs;
+       struct kref kref;
        struct nvkm_tags *tags;
 };
 
@@ -44,7 +45,8 @@ struct nvkm_memory_ptrs {
 void nvkm_memory_ctor(const struct nvkm_memory_func *, struct nvkm_memory *);
 int nvkm_memory_new(struct nvkm_device *, enum nvkm_memory_target,
                    u64 size, u32 align, bool zero, struct nvkm_memory **);
-void nvkm_memory_del(struct nvkm_memory **);
+struct nvkm_memory *nvkm_memory_ref(struct nvkm_memory *);
+void nvkm_memory_unref(struct nvkm_memory **);
 int nvkm_memory_tags_get(struct nvkm_memory *, struct nvkm_device *, u32 tags,
                         void (*clear)(struct nvkm_device *, u32, u32),
                         struct nvkm_tags **);
index 1264d5fc632b6371e8e2418888afd1b054e32e1f..d6de2b3ed2c30c7f63f8dd56da5fbcf00511ec5c 100644 (file)
@@ -219,7 +219,7 @@ nvkm_gpuobj_del(struct nvkm_gpuobj **pgpuobj)
                if (gpuobj->parent)
                        nvkm_mm_free(&gpuobj->parent->heap, &gpuobj->node);
                nvkm_mm_fini(&gpuobj->heap);
-               nvkm_memory_del(&gpuobj->memory);
+               nvkm_memory_unref(&gpuobj->memory);
                kfree(*pgpuobj);
                *pgpuobj = NULL;
        }
index 13cfcdde99fdcd561ad09119ece55c630a9e53f3..29f4b4070b5579e6d48b9ab2864a60f25fdec1c6 100644 (file)
@@ -100,20 +100,38 @@ nvkm_memory_ctor(const struct nvkm_memory_func *func,
                 struct nvkm_memory *memory)
 {
        memory->func = func;
+       kref_init(&memory->kref);
+}
+
+static void
+nvkm_memory_del(struct kref *kref)
+{
+       struct nvkm_memory *memory = container_of(kref, typeof(*memory), kref);
+       if (!WARN_ON(!memory->func)) {
+               if (memory->func->dtor)
+                       memory = memory->func->dtor(memory);
+               kfree(memory);
+       }
 }
 
 void
-nvkm_memory_del(struct nvkm_memory **pmemory)
+nvkm_memory_unref(struct nvkm_memory **pmemory)
 {
        struct nvkm_memory *memory = *pmemory;
-       if (memory && !WARN_ON(!memory->func)) {
-               if (memory->func->dtor)
-                       *pmemory = memory->func->dtor(memory);
-               kfree(*pmemory);
+       if (memory) {
+               kref_put(&memory->kref, nvkm_memory_del);
                *pmemory = NULL;
        }
 }
 
+struct nvkm_memory *
+nvkm_memory_ref(struct nvkm_memory *memory)
+{
+       if (memory)
+               kref_get(&memory->kref);
+       return memory;
+}
+
 int
 nvkm_memory_new(struct nvkm_device *device, enum nvkm_memory_target target,
                u64 size, u32 align, bool zero,
index 2e7b4e2105efc4983a63eceb3376aa685fd5cf07..816ccaedfc7326581befc7fb7f2b39607325c903 100644 (file)
@@ -99,7 +99,7 @@ nvkm_falcon_fini(struct nvkm_engine *engine, bool suspend)
        const u32 base = falcon->addr;
 
        if (!suspend) {
-               nvkm_memory_del(&falcon->core);
+               nvkm_memory_unref(&falcon->core);
                if (falcon->external) {
                        vfree(falcon->data.data);
                        vfree(falcon->code.data);
index 14b1a616d26a435852659f3c7450980181503658..24a4c28b32c5cea4708c3a76f2be7ff32129f813 100644 (file)
@@ -642,9 +642,9 @@ gf100_fifo_dtor(struct nvkm_fifo *base)
 {
        struct gf100_fifo *fifo = gf100_fifo(base);
        nvkm_vm_put(&fifo->user.bar);
-       nvkm_memory_del(&fifo->user.mem);
-       nvkm_memory_del(&fifo->runlist.mem[0]);
-       nvkm_memory_del(&fifo->runlist.mem[1]);
+       nvkm_memory_unref(&fifo->user.mem);
+       nvkm_memory_unref(&fifo->runlist.mem[0]);
+       nvkm_memory_unref(&fifo->runlist.mem[1]);
        return fifo;
 }
 
index 9629416f49475114c2c5e0d9a431d7a7787c4bc1..eddf9f12e9ee0a4709796acf1a95a894048d376c 100644 (file)
@@ -880,11 +880,11 @@ gk104_fifo_dtor(struct nvkm_fifo *base)
        int i;
 
        nvkm_vm_put(&fifo->user.bar);
-       nvkm_memory_del(&fifo->user.mem);
+       nvkm_memory_unref(&fifo->user.mem);
 
        for (i = 0; i < fifo->runlist_nr; i++) {
-               nvkm_memory_del(&fifo->runlist[i].mem[1]);
-               nvkm_memory_del(&fifo->runlist[i].mem[0]);
+               nvkm_memory_unref(&fifo->runlist[i].mem[1]);
+               nvkm_memory_unref(&fifo->runlist[i].mem[0]);
        }
 
        return fifo;
index 66eb12c2b5ba75f959ffc7d49c485edd121d2375..fa6e094d8068679b209542c4a0707e7eed643970 100644 (file)
@@ -100,8 +100,8 @@ void *
 nv50_fifo_dtor(struct nvkm_fifo *base)
 {
        struct nv50_fifo *fifo = nv50_fifo(base);
-       nvkm_memory_del(&fifo->runlist[1]);
-       nvkm_memory_del(&fifo->runlist[0]);
+       nvkm_memory_unref(&fifo->runlist[1]);
+       nvkm_memory_unref(&fifo->runlist[0]);
        return fifo;
 }
 
index bc77eea351a5c78351feeadbe244591fa6b6810a..ce69ec8b13add3a2ebecc2371c9ba3d04f9ef409 100644 (file)
@@ -1380,7 +1380,7 @@ gf100_grctx_generate(struct gf100_gr *gr)
        }
 
 done:
-       nvkm_memory_del(&chan);
+       nvkm_memory_unref(&chan);
        return ret;
 }
 
index 0c4ca0fa48cc86fd8cf59fd739b658d064490c41..4fc4deb2db4b5d8292595eefebbf0c662d7cfa1d 100644 (file)
@@ -354,14 +354,14 @@ gf100_gr_chan_dtor(struct nvkm_object *object)
                        nvkm_vm_unmap(&chan->data[i].vma);
                        nvkm_vm_put(&chan->data[i].vma);
                }
-               nvkm_memory_del(&chan->data[i].mem);
+               nvkm_memory_unref(&chan->data[i].mem);
        }
 
        if (chan->mmio_vma.node) {
                nvkm_vm_unmap(&chan->mmio_vma);
                nvkm_vm_put(&chan->mmio_vma);
        }
-       nvkm_memory_del(&chan->mmio);
+       nvkm_memory_unref(&chan->mmio);
        return chan;
 }
 
index d1dc92999dc00f281f5c38507403a3ae0ff8e801..d6840dc81a295a0872d6e02d46ca7d3f8abbab30 100644 (file)
@@ -59,7 +59,7 @@ void *
 nv20_gr_chan_dtor(struct nvkm_object *object)
 {
        struct nv20_gr_chan *chan = nv20_gr_chan(object);
-       nvkm_memory_del(&chan->inst);
+       nvkm_memory_unref(&chan->inst);
        return chan;
 }
 
@@ -323,7 +323,7 @@ void *
 nv20_gr_dtor(struct nvkm_gr *base)
 {
        struct nv20_gr *gr = nv20_gr(base);
-       nvkm_memory_del(&gr->ctxtab);
+       nvkm_memory_unref(&gr->ctxtab);
        return gr;
 }
 
index 06bdb67a020586c45ef2b6c9f2c4f6ece7d8231a..70549381e082833ffcf4489c22d6c778babf5b6e 100644 (file)
@@ -86,7 +86,7 @@ nvkm_xtensa_fini(struct nvkm_engine *engine, bool suspend)
        nvkm_wr32(device, base + 0xd94, 0); /* FIFO_CTRL */
 
        if (!suspend)
-               nvkm_memory_del(&xtensa->gpu_fw);
+               nvkm_memory_unref(&xtensa->gpu_fw);
        return 0;
 }
 
index b155a7f76ca7872219cb4532f55acd782ce1220a..9f7b4e7532b7032d90beb4de5320364868e3c3db 100644 (file)
@@ -166,14 +166,14 @@ gf100_bar_dtor(struct nvkm_bar *base)
 
        nvkm_vm_ref(NULL, &bar->bar[1].vm, bar->bar[1].pgd);
        nvkm_gpuobj_del(&bar->bar[1].pgd);
-       nvkm_memory_del(&bar->bar[1].mem);
+       nvkm_memory_unref(&bar->bar[1].mem);
 
        if (bar->bar[0].vm) {
-               nvkm_memory_del(&bar->bar[0].vm->pgt[0].mem[0]);
+               nvkm_memory_unref(&bar->bar[0].vm->pgt[0].mem[0]);
                nvkm_vm_ref(NULL, &bar->bar[0].vm, bar->bar[0].pgd);
        }
        nvkm_gpuobj_del(&bar->bar[0].pgd);
-       nvkm_memory_del(&bar->bar[0].mem);
+       nvkm_memory_unref(&bar->bar[0].mem);
        return bar;
 }
 
index cf1d0acd2afc8a564e0654a355e70eeb15c23f6c..1aa6b5390d7961feead80045d9f269a4e106db5d 100644 (file)
@@ -201,7 +201,7 @@ nv50_bar_dtor(struct nvkm_bar *base)
        nvkm_vm_ref(NULL, &bar->bar1_vm, bar->pgd);
        nvkm_gpuobj_del(&bar->bar2);
        if (bar->bar2_vm) {
-               nvkm_memory_del(&bar->bar2_vm->pgt[0].mem[0]);
+               nvkm_memory_unref(&bar->bar2_vm->pgt[0].mem[0]);
                nvkm_vm_ref(NULL, &bar->bar2_vm, bar->pgd);
        }
        nvkm_gpuobj_del(&bar->pgd);
index 94c53454501d3a65ae96f02695296053fe433c13..78248e21a5f0e837f86d312c1007fba269cdd0d3 100644 (file)
@@ -163,8 +163,8 @@ nvkm_fb_dtor(struct nvkm_subdev *subdev)
        struct nvkm_fb *fb = nvkm_fb(subdev);
        int i;
 
-       nvkm_memory_del(&fb->mmu_wr);
-       nvkm_memory_del(&fb->mmu_rd);
+       nvkm_memory_unref(&fb->mmu_wr);
+       nvkm_memory_unref(&fb->mmu_rd);
 
        for (i = 0; i < fb->tile.regions; i++)
                fb->func->tile.fini(fb, i, &fb->tile.region[i]);
index b03940591a3a05df356f79b4a197723b7f55f3d7..364ea4492acc8f0336d3e179a84ec65b1f43184b 100644 (file)
@@ -120,7 +120,7 @@ nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero,
 
 done:
        if (ret)
-               nvkm_memory_del(&memory);
+               nvkm_memory_unref(&memory);
        *pmemory = memory;
        return ret;
 }
index 2e1141319e939335b74eee080c6b11ec82397fc1..6bf0dad469195a65efaa07b7e588922229e2d0d4 100644 (file)
@@ -199,10 +199,10 @@ static void *
 nv04_instmem_dtor(struct nvkm_instmem *base)
 {
        struct nv04_instmem *imem = nv04_instmem(base);
-       nvkm_memory_del(&imem->base.ramfc);
-       nvkm_memory_del(&imem->base.ramro);
+       nvkm_memory_unref(&imem->base.ramfc);
+       nvkm_memory_unref(&imem->base.ramro);
        nvkm_ramht_del(&imem->base.ramht);
-       nvkm_memory_del(&imem->base.vbios);
+       nvkm_memory_unref(&imem->base.vbios);
        nvkm_mm_fini(&imem->heap);
        return imem;
 }
index 7f52a525d2e1ad5598bceac21c4ac8c81f784b58..086c118488ef5fa937b0d7eccf5e023b07349e33 100644 (file)
@@ -215,10 +215,10 @@ static void *
 nv40_instmem_dtor(struct nvkm_instmem *base)
 {
        struct nv40_instmem *imem = nv40_instmem(base);
-       nvkm_memory_del(&imem->base.ramfc);
-       nvkm_memory_del(&imem->base.ramro);
+       nvkm_memory_unref(&imem->base.ramfc);
+       nvkm_memory_unref(&imem->base.ramro);
        nvkm_ramht_del(&imem->base.ramht);
-       nvkm_memory_del(&imem->base.vbios);
+       nvkm_memory_unref(&imem->base.vbios);
        nvkm_mm_fini(&imem->heap);
        if (imem->iomem)
                iounmap(imem->iomem);
index 44c2403e88e6c2b6669b6acc1f89044bd4da76ce..ad11db458fccedcd4199921fc931f516268b0816 100644 (file)
@@ -243,7 +243,7 @@ nvkm_vm_unmap_pgt(struct nvkm_vm *vm, int big, u32 fpde, u32 lpde)
 
                mmu->func->flush(vm);
 
-               nvkm_memory_del(&pgt);
+               nvkm_memory_unref(&pgt);
        }
 }
 
index cd16442f1a918fc892f07e8ec93d0373ded30cd9..43e3b4a77583f3b122cd2be27d20fdff98214440 100644 (file)
@@ -106,7 +106,7 @@ nv04_mmu_dtor(struct nvkm_mmu *base)
        struct nv04_mmu *mmu = nv04_mmu(base);
        struct nvkm_device *device = mmu->base.subdev.device;
        if (mmu->base.vmm) {
-               nvkm_memory_del(&mmu->base.vmm->pgt[0].mem[0]);
+               nvkm_memory_unref(&mmu->base.vmm->pgt[0].mem[0]);
                nvkm_vm_ref(NULL, &mmu->base.vmm, NULL);
        }
        if (mmu->nullp) {