Skip to content

Commit

Permalink
drm/lima: support heap buffer creation
Browse files Browse the repository at this point in the history
heap buffer is used as output of GP and input of PP for
Mali Utgard GPU. Size of heap buffer depends on the task
so is a runtime variable.

Previously we just create a large enough buffer as heap
buffer. Now we add a heap buffer type to be able to
increase the backup memory dynamically when GP fail due
to lack of heap memory.

Reviewed-by: Vasily Khoruzhick <anarsoul@gmail.com>
Tested-by: Andreas Baierl <ichgeh@imkreisrum.de>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200116131157.13346-4-yuq825@gmail.com
  • Loading branch information
Qiang Yu committed Jan 27, 2020
1 parent dc76cb7 commit 6aebc51
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 11 deletions.
6 changes: 5 additions & 1 deletion drivers/gpu/drm/lima/lima_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@
#include "lima_vm.h"

int lima_sched_timeout_ms;
uint lima_heap_init_nr_pages = 8;

MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms");
module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444);

MODULE_PARM_DESC(heap_init_nr_pages, "heap buffer init number of pages");
module_param_named(heap_init_nr_pages, lima_heap_init_nr_pages, uint, 0444);

static int lima_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file)
{
struct drm_lima_get_param *args = data;
Expand Down Expand Up @@ -68,7 +72,7 @@ static int lima_ioctl_gem_create(struct drm_device *dev, void *data, struct drm_
if (args->pad)
return -EINVAL;

if (args->flags)
if (args->flags & ~(LIMA_BO_FLAG_HEAP))
return -EINVAL;

if (args->size == 0)
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/lima/lima_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "lima_ctx.h"

extern int lima_sched_timeout_ms;
extern uint lima_heap_init_nr_pages;

struct lima_vm;
struct lima_bo;
Expand Down
134 changes: 126 additions & 8 deletions drivers/gpu/drm/lima/lima_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <linux/mm.h>
#include <linux/sync_file.h>
#include <linux/pagemap.h>
#include <linux/shmem_fs.h>
#include <linux/dma-mapping.h>

#include <drm/drm_file.h>
#include <drm/drm_syncobj.h>
Expand All @@ -15,14 +17,92 @@
#include "lima_gem.h"
#include "lima_vm.h"

int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm)
{
struct page **pages;
struct address_space *mapping = bo->base.base.filp->f_mapping;
struct device *dev = bo->base.base.dev->dev;
size_t old_size = bo->heap_size;
size_t new_size = bo->heap_size ? bo->heap_size * 2 :
(lima_heap_init_nr_pages << PAGE_SHIFT);
struct sg_table sgt;
int i, ret;

if (bo->heap_size >= bo->base.base.size)
return -ENOSPC;

new_size = min(new_size, bo->base.base.size);

mutex_lock(&bo->base.pages_lock);

if (bo->base.pages) {
pages = bo->base.pages;
} else {
pages = kvmalloc_array(bo->base.base.size >> PAGE_SHIFT,
sizeof(*pages), GFP_KERNEL | __GFP_ZERO);
if (!pages) {
mutex_unlock(&bo->base.pages_lock);
return -ENOMEM;
}

bo->base.pages = pages;
bo->base.pages_use_count = 1;

mapping_set_unevictable(mapping);
}

for (i = old_size >> PAGE_SHIFT; i < new_size >> PAGE_SHIFT; i++) {
struct page *page = shmem_read_mapping_page(mapping, i);

if (IS_ERR(page)) {
mutex_unlock(&bo->base.pages_lock);
return PTR_ERR(page);
}
pages[i] = page;
}

mutex_unlock(&bo->base.pages_lock);

ret = sg_alloc_table_from_pages(&sgt, pages, i, 0,
new_size, GFP_KERNEL);
if (ret)
return ret;

if (bo->base.sgt) {
dma_unmap_sg(dev, bo->base.sgt->sgl,
bo->base.sgt->nents, DMA_BIDIRECTIONAL);
sg_free_table(bo->base.sgt);
} else {
bo->base.sgt = kmalloc(sizeof(*bo->base.sgt), GFP_KERNEL);
if (!bo->base.sgt) {
sg_free_table(&sgt);
return -ENOMEM;
}
}

dma_map_sg(dev, sgt.sgl, sgt.nents, DMA_BIDIRECTIONAL);

*bo->base.sgt = sgt;

if (vm) {
ret = lima_vm_map_bo(vm, bo, old_size >> PAGE_SHIFT);
if (ret)
return ret;
}

bo->heap_size = new_size;
return 0;
}

int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
u32 size, u32 flags, u32 *handle)
{
int err;
gfp_t mask;
struct drm_gem_shmem_object *shmem;
struct drm_gem_object *obj;
struct sg_table *sgt;
struct lima_bo *bo;
bool is_heap = flags & LIMA_BO_FLAG_HEAP;

shmem = drm_gem_shmem_create(dev, size);
if (IS_ERR(shmem))
Expand All @@ -36,10 +116,18 @@ int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
mask |= __GFP_DMA32;
mapping_set_gfp_mask(obj->filp->f_mapping, mask);

sgt = drm_gem_shmem_get_pages_sgt(obj);
if (IS_ERR(sgt)) {
err = PTR_ERR(sgt);
goto out;
if (is_heap) {
bo = to_lima_bo(obj);
err = lima_heap_alloc(bo, NULL);
if (err)
goto out;
} else {
struct sg_table *sgt = drm_gem_shmem_get_pages_sgt(obj);

if (IS_ERR(sgt)) {
err = PTR_ERR(sgt);
goto out;
}
}

err = drm_gem_handle_create(file, obj, handle);
Expand Down Expand Up @@ -79,17 +167,47 @@ static void lima_gem_object_close(struct drm_gem_object *obj, struct drm_file *f
lima_vm_bo_del(vm, bo);
}

static int lima_gem_pin(struct drm_gem_object *obj)
{
struct lima_bo *bo = to_lima_bo(obj);

if (bo->heap_size)
return -EINVAL;

return drm_gem_shmem_pin(obj);
}

static void *lima_gem_vmap(struct drm_gem_object *obj)
{
struct lima_bo *bo = to_lima_bo(obj);

if (bo->heap_size)
return ERR_PTR(-EINVAL);

return drm_gem_shmem_vmap(obj);
}

static int lima_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
{
struct lima_bo *bo = to_lima_bo(obj);

if (bo->heap_size)
return -EINVAL;

return drm_gem_shmem_mmap(obj, vma);
}

static const struct drm_gem_object_funcs lima_gem_funcs = {
.free = lima_gem_free_object,
.open = lima_gem_object_open,
.close = lima_gem_object_close,
.print_info = drm_gem_shmem_print_info,
.pin = drm_gem_shmem_pin,
.pin = lima_gem_pin,
.unpin = drm_gem_shmem_unpin,
.get_sg_table = drm_gem_shmem_get_sg_table,
.vmap = drm_gem_shmem_vmap,
.vmap = lima_gem_vmap,
.vunmap = drm_gem_shmem_vunmap,
.mmap = drm_gem_shmem_mmap,
.mmap = lima_gem_mmap,
};

struct drm_gem_object *lima_gem_create_object(struct drm_device *dev, size_t size)
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/lima/lima_gem.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
#include <drm/drm_gem_shmem_helper.h>

struct lima_submit;
struct lima_vm;

struct lima_bo {
struct drm_gem_shmem_object base;

struct mutex lock;
struct list_head va;

size_t heap_size;
};

static inline struct lima_bo *
Expand All @@ -31,6 +34,7 @@ static inline struct dma_resv *lima_bo_resv(struct lima_bo *bo)
return bo->base.base.resv;
}

int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm);
struct drm_gem_object *lima_gem_create_object(struct drm_device *dev, size_t size);
int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
u32 size, u32 flags, u32 *handle);
Expand Down
4 changes: 3 additions & 1 deletion drivers/gpu/drm/lima/lima_vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create)
void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo)
{
struct lima_bo_va *bo_va;
u32 size;

mutex_lock(&bo->lock);

Expand All @@ -166,8 +167,9 @@ void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo)

mutex_lock(&vm->lock);

size = bo->heap_size ? bo->heap_size : bo_va->node.size;
lima_vm_unmap_range(vm, bo_va->node.start,
bo_va->node.start + bo_va->node.size - 1);
bo_va->node.start + size - 1);

drm_mm_remove_node(&bo_va->node);

Expand Down
9 changes: 8 additions & 1 deletion include/uapi/drm/lima_drm.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,19 @@ struct drm_lima_get_param {
__u64 value; /* out, parameter value */
};

/*
* heap buffer dynamically increase backup memory size when GP task fail
* due to lack of heap memory. size field of heap buffer is an up bound of
* the backup memory which can be set to a fairly large value.
*/
#define LIMA_BO_FLAG_HEAP (1 << 0)

/**
* create a buffer for used by GPU
*/
struct drm_lima_gem_create {
__u32 size; /* in, buffer size */
__u32 flags; /* in, currently no flags, must be zero */
__u32 flags; /* in, buffer flags */
__u32 handle; /* out, GEM buffer handle */
__u32 pad; /* pad, must be zero */
};
Expand Down

0 comments on commit 6aebc51

Please sign in to comment.