Commit 7f53d6dc authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/core/memory: comptag allocation

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: default avatarBen Skeggs <bskeggs@redhat.com>
parent 6cd7670c
......@@ -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)
......
......@@ -22,8 +22,79 @@
* 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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment