Branch data Line data Source code
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 : 0 : static void system_heap_free(struct heap_helper_buffer *buffer) 26 : : { 27 : : pgoff_t pg; 28 : : 29 : 0 : for (pg = 0; pg < buffer->pagecount; pg++) 30 : 0 : __free_page(buffer->pages[pg]); 31 : 0 : kfree(buffer->pages); 32 : 0 : kfree(buffer); 33 : 0 : } 34 : : 35 : 0 : 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 : 0 : helper_buffer = kzalloc(sizeof(*helper_buffer), GFP_KERNEL); 46 : 0 : if (!helper_buffer) 47 : : return -ENOMEM; 48 : : 49 : 0 : init_heap_helper_buffer(helper_buffer, system_heap_free); 50 : 0 : helper_buffer->heap = heap; 51 : 0 : helper_buffer->size = len; 52 : : 53 : 0 : helper_buffer->pagecount = len / PAGE_SIZE; 54 : 0 : helper_buffer->pages = kmalloc_array(helper_buffer->pagecount, 55 : : sizeof(*helper_buffer->pages), 56 : : GFP_KERNEL); 57 : 0 : if (!helper_buffer->pages) { 58 : : ret = -ENOMEM; 59 : : goto err0; 60 : : } 61 : : 62 : 0 : 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 : 0 : if (fatal_signal_pending(current)) 68 : : goto err1; 69 : : 70 : 0 : helper_buffer->pages[pg] = alloc_page(GFP_KERNEL | __GFP_ZERO); 71 : 0 : if (!helper_buffer->pages[pg]) 72 : : goto err1; 73 : : } 74 : : 75 : : /* create the dmabuf */ 76 : 0 : dmabuf = heap_helper_export_dmabuf(helper_buffer, fd_flags); 77 : 0 : if (IS_ERR(dmabuf)) { 78 : : ret = PTR_ERR(dmabuf); 79 : 0 : goto err1; 80 : : } 81 : : 82 : 0 : helper_buffer->dmabuf = dmabuf; 83 : : 84 : 0 : ret = dma_buf_fd(dmabuf, fd_flags); 85 : 0 : if (ret < 0) { 86 : 0 : dma_buf_put(dmabuf); 87 : : /* just return, as put will call release and that will free */ 88 : 0 : return ret; 89 : : } 90 : : 91 : : return ret; 92 : : 93 : : err1: 94 : 0 : while (pg > 0) 95 : 0 : __free_page(helper_buffer->pages[--pg]); 96 : 0 : kfree(helper_buffer->pages); 97 : : err0: 98 : 0 : kfree(helper_buffer); 99 : : 100 : 0 : return ret; 101 : : } 102 : : 103 : : static const struct dma_heap_ops system_heap_ops = { 104 : : .allocate = system_heap_allocate, 105 : : }; 106 : : 107 : 3 : static int system_heap_create(void) 108 : : { 109 : : struct dma_heap_export_info exp_info; 110 : : int ret = 0; 111 : : 112 : 3 : exp_info.name = "system"; 113 : 3 : exp_info.ops = &system_heap_ops; 114 : 3 : exp_info.priv = NULL; 115 : : 116 : 3 : sys_heap = dma_heap_add(&exp_info); 117 : 3 : if (IS_ERR(sys_heap)) 118 : : ret = PTR_ERR(sys_heap); 119 : : 120 : 3 : return ret; 121 : : } 122 : : module_init(system_heap_create); 123 : : MODULE_LICENSE("GPL v2");