1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * DMABUF System heap exporter 4 * 5 * Copyright (C) 2011 Google, Inc. 6 * Copyright (C) 2019 Linaro Ltd. 7 */ 8 9 #include <linux/dma-buf.h> 10 #include <linux/dma-mapping.h> 11 #include <linux/dma-heap.h> 12 #include <linux/err.h> 13 #include <linux/highmem.h> 14 #include <linux/mm.h> 15 #include <linux/module.h> 16 #include <linux/scatterlist.h> 17 #include <linux/slab.h> 18 #include <linux/sched/signal.h> 19 #include <asm/page.h> 20 21 #include "heap-helpers.h" 22 23 struct dma_heap *sys_heap; 24 25 static void system_heap_free(struct heap_helper_buffer *buffer) 26 { 27 pgoff_t pg; 28 29 for (pg = 0; pg < buffer->pagecount; pg++) 30 __free_page(buffer->pages[pg]); 31 kfree(buffer->pages); 32 kfree(buffer); 33 } 34 35 static int system_heap_allocate(struct dma_heap *heap, 36 unsigned long len, 37 unsigned long fd_flags, 38 unsigned long heap_flags) 39 { 40 struct heap_helper_buffer *helper_buffer; 41 struct dma_buf *dmabuf; 42 int ret = -ENOMEM; 43 pgoff_t pg; 44 45 helper_buffer = kzalloc(sizeof(*helper_buffer), GFP_KERNEL); 46 if (!helper_buffer) 47 return -ENOMEM; 48 49 init_heap_helper_buffer(helper_buffer, system_heap_free); 50 helper_buffer->heap = heap; 51 helper_buffer->size = len; 52 53 helper_buffer->pagecount = len / PAGE_SIZE; 54 helper_buffer->pages = kmalloc_array(helper_buffer->pagecount, 55 sizeof(*helper_buffer->pages), 56 GFP_KERNEL); 57 if (!helper_buffer->pages) { 58 ret = -ENOMEM; 59 goto err0; 60 } 61 62 for (pg = 0; pg < helper_buffer->pagecount; pg++) { 63 /* 64 * Avoid trying to allocate memory if the process 65 * has been killed by by SIGKILL 66 */ 67 if (fatal_signal_pending(current)) 68 goto err1; 69 70 helper_buffer->pages[pg] = alloc_page(GFP_KERNEL | __GFP_ZERO); 71 if (!helper_buffer->pages[pg]) 72 goto err1; 73 } 74 75 /* create the dmabuf */ 76 dmabuf = heap_helper_export_dmabuf(helper_buffer, fd_flags); 77 if (IS_ERR(dmabuf)) { 78 ret = PTR_ERR(dmabuf); 79 goto err1; 80 } 81 82 helper_buffer->dmabuf = dmabuf; 83 84 ret = dma_buf_fd(dmabuf, fd_flags); 85 if (ret < 0) { 86 dma_buf_put(dmabuf); 87 /* just return, as put will call release and that will free */ 88 return ret; 89 } 90 91 return ret; 92 93 err1: 94 while (pg > 0) 95 __free_page(helper_buffer->pages[--pg]); 96 kfree(helper_buffer->pages); 97 err0: 98 kfree(helper_buffer); 99 100 return ret; 101 } 102 103 static const struct dma_heap_ops system_heap_ops = { 104 .allocate = system_heap_allocate, 105 }; 106 107 static int system_heap_create(void) 108 { 109 struct dma_heap_export_info exp_info; 110 int ret = 0; 111 112 exp_info.name = "system_heap"; 113 exp_info.ops = &system_heap_ops; 114 exp_info.priv = NULL; 115 116 sys_heap = dma_heap_add(&exp_info); 117 if (IS_ERR(sys_heap)) 118 ret = PTR_ERR(sys_heap); 119 120 return ret; 121 } 122 module_init(system_heap_create); 123 MODULE_LICENSE("GPL v2"); 124