Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/lima: support heap buffer creation

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

Qiang Yu 6aebc51d dc76cb7a

+147 -11
+5 -1
drivers/gpu/drm/lima/lima_drv.c
··· 15 15 #include "lima_vm.h" 16 16 17 17 int lima_sched_timeout_ms; 18 + uint lima_heap_init_nr_pages = 8; 18 19 19 20 MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms"); 20 21 module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444); 22 + 23 + MODULE_PARM_DESC(heap_init_nr_pages, "heap buffer init number of pages"); 24 + module_param_named(heap_init_nr_pages, lima_heap_init_nr_pages, uint, 0444); 21 25 22 26 static int lima_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file) 23 27 { ··· 72 68 if (args->pad) 73 69 return -EINVAL; 74 70 75 - if (args->flags) 71 + if (args->flags & ~(LIMA_BO_FLAG_HEAP)) 76 72 return -EINVAL; 77 73 78 74 if (args->size == 0)
+1
drivers/gpu/drm/lima/lima_drv.h
··· 9 9 #include "lima_ctx.h" 10 10 11 11 extern int lima_sched_timeout_ms; 12 + extern uint lima_heap_init_nr_pages; 12 13 13 14 struct lima_vm; 14 15 struct lima_bo;
+126 -8
drivers/gpu/drm/lima/lima_gem.c
··· 4 4 #include <linux/mm.h> 5 5 #include <linux/sync_file.h> 6 6 #include <linux/pagemap.h> 7 + #include <linux/shmem_fs.h> 8 + #include <linux/dma-mapping.h> 7 9 8 10 #include <drm/drm_file.h> 9 11 #include <drm/drm_syncobj.h> ··· 17 15 #include "lima_gem.h" 18 16 #include "lima_vm.h" 19 17 18 + int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm) 19 + { 20 + struct page **pages; 21 + struct address_space *mapping = bo->base.base.filp->f_mapping; 22 + struct device *dev = bo->base.base.dev->dev; 23 + size_t old_size = bo->heap_size; 24 + size_t new_size = bo->heap_size ? bo->heap_size * 2 : 25 + (lima_heap_init_nr_pages << PAGE_SHIFT); 26 + struct sg_table sgt; 27 + int i, ret; 28 + 29 + if (bo->heap_size >= bo->base.base.size) 30 + return -ENOSPC; 31 + 32 + new_size = min(new_size, bo->base.base.size); 33 + 34 + mutex_lock(&bo->base.pages_lock); 35 + 36 + if (bo->base.pages) { 37 + pages = bo->base.pages; 38 + } else { 39 + pages = kvmalloc_array(bo->base.base.size >> PAGE_SHIFT, 40 + sizeof(*pages), GFP_KERNEL | __GFP_ZERO); 41 + if (!pages) { 42 + mutex_unlock(&bo->base.pages_lock); 43 + return -ENOMEM; 44 + } 45 + 46 + bo->base.pages = pages; 47 + bo->base.pages_use_count = 1; 48 + 49 + mapping_set_unevictable(mapping); 50 + } 51 + 52 + for (i = old_size >> PAGE_SHIFT; i < new_size >> PAGE_SHIFT; i++) { 53 + struct page *page = shmem_read_mapping_page(mapping, i); 54 + 55 + if (IS_ERR(page)) { 56 + mutex_unlock(&bo->base.pages_lock); 57 + return PTR_ERR(page); 58 + } 59 + pages[i] = page; 60 + } 61 + 62 + mutex_unlock(&bo->base.pages_lock); 63 + 64 + ret = sg_alloc_table_from_pages(&sgt, pages, i, 0, 65 + new_size, GFP_KERNEL); 66 + if (ret) 67 + return ret; 68 + 69 + if (bo->base.sgt) { 70 + dma_unmap_sg(dev, bo->base.sgt->sgl, 71 + bo->base.sgt->nents, DMA_BIDIRECTIONAL); 72 + sg_free_table(bo->base.sgt); 73 + } else { 74 + bo->base.sgt = kmalloc(sizeof(*bo->base.sgt), GFP_KERNEL); 75 + if (!bo->base.sgt) { 76 + sg_free_table(&sgt); 77 + return -ENOMEM; 78 + } 79 + } 80 + 81 + dma_map_sg(dev, sgt.sgl, sgt.nents, DMA_BIDIRECTIONAL); 82 + 83 + *bo->base.sgt = sgt; 84 + 85 + if (vm) { 86 + ret = lima_vm_map_bo(vm, bo, old_size >> PAGE_SHIFT); 87 + if (ret) 88 + return ret; 89 + } 90 + 91 + bo->heap_size = new_size; 92 + return 0; 93 + } 94 + 20 95 int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, 21 96 u32 size, u32 flags, u32 *handle) 22 97 { ··· 101 22 gfp_t mask; 102 23 struct drm_gem_shmem_object *shmem; 103 24 struct drm_gem_object *obj; 104 - struct sg_table *sgt; 25 + struct lima_bo *bo; 26 + bool is_heap = flags & LIMA_BO_FLAG_HEAP; 105 27 106 28 shmem = drm_gem_shmem_create(dev, size); 107 29 if (IS_ERR(shmem)) ··· 116 36 mask |= __GFP_DMA32; 117 37 mapping_set_gfp_mask(obj->filp->f_mapping, mask); 118 38 119 - sgt = drm_gem_shmem_get_pages_sgt(obj); 120 - if (IS_ERR(sgt)) { 121 - err = PTR_ERR(sgt); 122 - goto out; 39 + if (is_heap) { 40 + bo = to_lima_bo(obj); 41 + err = lima_heap_alloc(bo, NULL); 42 + if (err) 43 + goto out; 44 + } else { 45 + struct sg_table *sgt = drm_gem_shmem_get_pages_sgt(obj); 46 + 47 + if (IS_ERR(sgt)) { 48 + err = PTR_ERR(sgt); 49 + goto out; 50 + } 123 51 } 124 52 125 53 err = drm_gem_handle_create(file, obj, handle); ··· 167 79 lima_vm_bo_del(vm, bo); 168 80 } 169 81 82 + static int lima_gem_pin(struct drm_gem_object *obj) 83 + { 84 + struct lima_bo *bo = to_lima_bo(obj); 85 + 86 + if (bo->heap_size) 87 + return -EINVAL; 88 + 89 + return drm_gem_shmem_pin(obj); 90 + } 91 + 92 + static void *lima_gem_vmap(struct drm_gem_object *obj) 93 + { 94 + struct lima_bo *bo = to_lima_bo(obj); 95 + 96 + if (bo->heap_size) 97 + return ERR_PTR(-EINVAL); 98 + 99 + return drm_gem_shmem_vmap(obj); 100 + } 101 + 102 + static int lima_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) 103 + { 104 + struct lima_bo *bo = to_lima_bo(obj); 105 + 106 + if (bo->heap_size) 107 + return -EINVAL; 108 + 109 + return drm_gem_shmem_mmap(obj, vma); 110 + } 111 + 170 112 static const struct drm_gem_object_funcs lima_gem_funcs = { 171 113 .free = lima_gem_free_object, 172 114 .open = lima_gem_object_open, 173 115 .close = lima_gem_object_close, 174 116 .print_info = drm_gem_shmem_print_info, 175 - .pin = drm_gem_shmem_pin, 117 + .pin = lima_gem_pin, 176 118 .unpin = drm_gem_shmem_unpin, 177 119 .get_sg_table = drm_gem_shmem_get_sg_table, 178 - .vmap = drm_gem_shmem_vmap, 120 + .vmap = lima_gem_vmap, 179 121 .vunmap = drm_gem_shmem_vunmap, 180 - .mmap = drm_gem_shmem_mmap, 122 + .mmap = lima_gem_mmap, 181 123 }; 182 124 183 125 struct drm_gem_object *lima_gem_create_object(struct drm_device *dev, size_t size)
+4
drivers/gpu/drm/lima/lima_gem.h
··· 7 7 #include <drm/drm_gem_shmem_helper.h> 8 8 9 9 struct lima_submit; 10 + struct lima_vm; 10 11 11 12 struct lima_bo { 12 13 struct drm_gem_shmem_object base; 13 14 14 15 struct mutex lock; 15 16 struct list_head va; 17 + 18 + size_t heap_size; 16 19 }; 17 20 18 21 static inline struct lima_bo * ··· 34 31 return bo->base.base.resv; 35 32 } 36 33 34 + int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm); 37 35 struct drm_gem_object *lima_gem_create_object(struct drm_device *dev, size_t size); 38 36 int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, 39 37 u32 size, u32 flags, u32 *handle);
+3 -1
drivers/gpu/drm/lima/lima_vm.c
··· 155 155 void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo) 156 156 { 157 157 struct lima_bo_va *bo_va; 158 + u32 size; 158 159 159 160 mutex_lock(&bo->lock); 160 161 ··· 167 166 168 167 mutex_lock(&vm->lock); 169 168 169 + size = bo->heap_size ? bo->heap_size : bo_va->node.size; 170 170 lima_vm_unmap_range(vm, bo_va->node.start, 171 - bo_va->node.start + bo_va->node.size - 1); 171 + bo_va->node.start + size - 1); 172 172 173 173 drm_mm_remove_node(&bo_va->node); 174 174
+8 -1
include/uapi/drm/lima_drm.h
··· 32 32 __u64 value; /* out, parameter value */ 33 33 }; 34 34 35 + /* 36 + * heap buffer dynamically increase backup memory size when GP task fail 37 + * due to lack of heap memory. size field of heap buffer is an up bound of 38 + * the backup memory which can be set to a fairly large value. 39 + */ 40 + #define LIMA_BO_FLAG_HEAP (1 << 0) 41 + 35 42 /** 36 43 * create a buffer for used by GPU 37 44 */ 38 45 struct drm_lima_gem_create { 39 46 __u32 size; /* in, buffer size */ 40 - __u32 flags; /* in, currently no flags, must be zero */ 47 + __u32 flags; /* in, buffer flags */ 41 48 __u32 handle; /* out, GEM buffer handle */ 42 49 __u32 pad; /* pad, must be zero */ 43 50 };