]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
drm/nouveau/core/memory: comptag allocation
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)
nvkm_memory is going to be used by the upcoming mmu rework for the basic
representation of a memory allocation, as such, this commit adds support
for comptag allocation to nvkm_memory.

This is very simple for now, in that it requires comptags for the entire
memory allocation even if only certain ranges are compressed.

Support for tracking ranges will be added at a later date.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/include/nvkm/core/memory.h
drivers/gpu/drm/nouveau/nvkm/core/memory.c

index 14ce7df9864e64a4b6d3d27ef2465c5220cc8a05..ce04e0f74f0c718e35e3bf773ad14052795b3f21 100644 (file)
@@ -5,6 +5,11 @@ struct nvkm_device;
 struct nvkm_vma;
 struct nvkm_vm;
 
+struct nvkm_tags {
+       struct nvkm_mm_node *mn;
+       refcount_t refcount;
+};
+
 enum nvkm_memory_target {
        NVKM_MEM_TARGET_INST, /* instance memory */
        NVKM_MEM_TARGET_VRAM, /* video memory */
@@ -15,6 +20,7 @@ enum nvkm_memory_target {
 struct nvkm_memory {
        const struct nvkm_memory_func *func;
        const struct nvkm_memory_ptrs *ptrs;
+       struct nvkm_tags *tags;
 };
 
 struct nvkm_memory_func {
@@ -37,6 +43,12 @@ 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 **);
+int nvkm_memory_tags_get(struct nvkm_memory *, struct nvkm_device *, u32 tags,
+                        void (*clear)(struct nvkm_device *, u32, u32),
+                        struct nvkm_tags **);
+void nvkm_memory_tags_put(struct nvkm_memory *, struct nvkm_device *,
+                         struct nvkm_tags **);
+
 #define nvkm_memory_target(p) (p)->func->target(p)
 #define nvkm_memory_addr(p) (p)->func->addr(p)
 #define nvkm_memory_size(p) (p)->func->size(p)
index 8903c04c977e8d6a169da5d92ecb7f876d5a2441..13cfcdde99fdcd561ad09119ece55c630a9e53f3 100644 (file)
  * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 #include <core/memory.h>
+#include <core/mm.h>
+#include <subdev/fb.h>
 #include <subdev/instmem.h>
 
+void
+nvkm_memory_tags_put(struct nvkm_memory *memory, struct nvkm_device *device,
+                    struct nvkm_tags **ptags)
+{
+       struct nvkm_fb *fb = device->fb;
+       struct nvkm_tags *tags = *ptags;
+       if (tags) {
+               mutex_lock(&fb->subdev.mutex);
+               if (refcount_dec_and_test(&tags->refcount)) {
+                       nvkm_mm_free(&fb->tags, &tags->mn);
+                       kfree(memory->tags);
+                       memory->tags = NULL;
+               }
+               mutex_unlock(&fb->subdev.mutex);
+               *ptags = NULL;
+       }
+}
+
+int
+nvkm_memory_tags_get(struct nvkm_memory *memory, struct nvkm_device *device,
+                    u32 nr, void (*clr)(struct nvkm_device *, u32, u32),
+                    struct nvkm_tags **ptags)
+{
+       struct nvkm_fb *fb = device->fb;
+       struct nvkm_tags *tags;
+
+       mutex_lock(&fb->subdev.mutex);
+       if ((tags = memory->tags)) {
+               /* If comptags exist for the memory, but a different amount
+                * than requested, the buffer is being mapped with settings
+                * that are incompatible with existing mappings.
+                */
+               if (tags->mn && tags->mn->length != nr) {
+                       mutex_unlock(&fb->subdev.mutex);
+                       return -EINVAL;
+               }
+
+               refcount_inc(&tags->refcount);
+               *ptags = tags;
+               return 0;
+       }
+
+       if (!(tags = kmalloc(sizeof(*tags), GFP_KERNEL))) {
+               mutex_unlock(&fb->subdev.mutex);
+               return -ENOMEM;
+       }
+
+       if (!nvkm_mm_head(&fb->tags, 0, 1, nr, nr, 1, &tags->mn)) {
+               if (clr)
+                       clr(device, tags->mn->offset, tags->mn->length);
+       } else {
+               /* Failure to allocate HW comptags is not an error, the
+                * caller should fall back to an uncompressed map.
+                *
+                * As memory can be mapped in multiple places, we still
+                * need to track the allocation failure and ensure that
+                * any additional mappings remain uncompressed.
+                *
+                * This is handled by returning an empty nvkm_tags.
+                */
+               tags->mn = NULL;
+       }
+
+       refcount_set(&tags->refcount, 1);
+       mutex_unlock(&fb->subdev.mutex);
+       *ptags = tags;
+       return 0;
+}
+
 void
 nvkm_memory_ctor(const struct nvkm_memory_func *func,
                 struct nvkm_memory *memory)