ion_cma_heap.c revision f63958d80c07c04db48812d97ff7450517d80ffa
1/* 2 * drivers/staging/android/ion/ion_cma_heap.c 3 * 4 * Copyright (C) Linaro 2012 5 * Author: <benjamin.gaignard@linaro.org> for ST-Ericsson. 6 * 7 * This software is licensed under the terms of the GNU General Public 8 * License version 2, as published by the Free Software Foundation, and 9 * may be copied, distributed, and modified under those terms. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 */ 17 18#include <linux/device.h> 19#include <linux/slab.h> 20#include <linux/errno.h> 21#include <linux/err.h> 22#include <linux/dma-mapping.h> 23 24#include "ion.h" 25#include "ion_priv.h" 26 27#define ION_CMA_ALLOCATE_FAILED -1 28 29struct ion_cma_heap { 30 struct ion_heap heap; 31 struct device *dev; 32}; 33 34#define to_cma_heap(x) container_of(x, struct ion_cma_heap, heap) 35 36struct ion_cma_buffer_info { 37 void *cpu_addr; 38 dma_addr_t handle; 39 struct sg_table *table; 40}; 41 42/* 43 * Create scatter-list for the already allocated DMA buffer. 44 * This function could be replaced by dma_common_get_sgtable 45 * as soon as it will avalaible. 46 */ 47static int ion_cma_get_sgtable(struct device *dev, struct sg_table *sgt, 48 void *cpu_addr, dma_addr_t handle, size_t size) 49{ 50 struct page *page = virt_to_page(cpu_addr); 51 int ret; 52 53 ret = sg_alloc_table(sgt, 1, GFP_KERNEL); 54 if (unlikely(ret)) 55 return ret; 56 57 sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0); 58 return 0; 59} 60 61/* ION CMA heap operations functions */ 62static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, 63 unsigned long len, unsigned long align, 64 unsigned long flags) 65{ 66 struct ion_cma_heap *cma_heap = to_cma_heap(heap); 67 struct device *dev = cma_heap->dev; 68 struct ion_cma_buffer_info *info; 69 70 dev_dbg(dev, "Request buffer allocation len %ld\n", len); 71 72 info = kzalloc(sizeof(struct ion_cma_buffer_info), GFP_KERNEL); 73 if (!info) { 74 dev_err(dev, "Can't allocate buffer info\n"); 75 return ION_CMA_ALLOCATE_FAILED; 76 } 77 78 info->cpu_addr = dma_alloc_coherent(dev, len, &(info->handle), 0); 79 80 if (!info->cpu_addr) { 81 dev_err(dev, "Fail to allocate buffer\n"); 82 goto err; 83 } 84 85 info->table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); 86 if (!info->table) { 87 dev_err(dev, "Fail to allocate sg table\n"); 88 goto free_mem; 89 } 90 91 if (ion_cma_get_sgtable 92 (dev, info->table, info->cpu_addr, info->handle, len)) 93 goto free_table; 94 /* keep this for memory release */ 95 buffer->priv_virt = info; 96 dev_dbg(dev, "Allocate buffer %p\n", buffer); 97 return 0; 98 99free_table: 100 kfree(info->table); 101free_mem: 102 dma_free_coherent(dev, len, info->cpu_addr, info->handle); 103err: 104 kfree(info); 105 return ION_CMA_ALLOCATE_FAILED; 106} 107 108static void ion_cma_free(struct ion_buffer *buffer) 109{ 110 struct ion_cma_heap *cma_heap = to_cma_heap(buffer->heap); 111 struct device *dev = cma_heap->dev; 112 struct ion_cma_buffer_info *info = buffer->priv_virt; 113 114 dev_dbg(dev, "Release buffer %p\n", buffer); 115 /* release memory */ 116 dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle); 117 /* release sg table */ 118 sg_free_table(info->table); 119 kfree(info->table); 120 kfree(info); 121} 122 123/* return physical address in addr */ 124static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer, 125 ion_phys_addr_t *addr, size_t *len) 126{ 127 struct ion_cma_heap *cma_heap = to_cma_heap(buffer->heap); 128 struct device *dev = cma_heap->dev; 129 struct ion_cma_buffer_info *info = buffer->priv_virt; 130 131 dev_dbg(dev, "Return buffer %p physical address 0x%pa\n", buffer, 132 &info->handle); 133 134 *addr = info->handle; 135 *len = buffer->size; 136 137 return 0; 138} 139 140static struct sg_table *ion_cma_heap_map_dma(struct ion_heap *heap, 141 struct ion_buffer *buffer) 142{ 143 struct ion_cma_buffer_info *info = buffer->priv_virt; 144 145 return info->table; 146} 147 148static void ion_cma_heap_unmap_dma(struct ion_heap *heap, 149 struct ion_buffer *buffer) 150{ 151 return; 152} 153 154static int ion_cma_mmap(struct ion_heap *mapper, struct ion_buffer *buffer, 155 struct vm_area_struct *vma) 156{ 157 struct ion_cma_heap *cma_heap = to_cma_heap(buffer->heap); 158 struct device *dev = cma_heap->dev; 159 struct ion_cma_buffer_info *info = buffer->priv_virt; 160 161 return dma_mmap_coherent(dev, vma, info->cpu_addr, info->handle, 162 buffer->size); 163} 164 165static void *ion_cma_map_kernel(struct ion_heap *heap, 166 struct ion_buffer *buffer) 167{ 168 struct ion_cma_buffer_info *info = buffer->priv_virt; 169 /* kernel memory mapping has been done at allocation time */ 170 return info->cpu_addr; 171} 172 173static struct ion_heap_ops ion_cma_ops = { 174 .allocate = ion_cma_allocate, 175 .free = ion_cma_free, 176 .map_dma = ion_cma_heap_map_dma, 177 .unmap_dma = ion_cma_heap_unmap_dma, 178 .phys = ion_cma_phys, 179 .map_user = ion_cma_mmap, 180 .map_kernel = ion_cma_map_kernel, 181}; 182 183struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data) 184{ 185 struct ion_cma_heap *cma_heap; 186 187 cma_heap = kzalloc(sizeof(struct ion_cma_heap), GFP_KERNEL); 188 189 if (!cma_heap) 190 return ERR_PTR(-ENOMEM); 191 192 cma_heap->heap.ops = &ion_cma_ops; 193 /* get device from private heaps data, later it will be 194 * used to make the link with reserved CMA memory */ 195 cma_heap->dev = data->priv; 196 cma_heap->heap.type = ION_HEAP_TYPE_DMA; 197 return &cma_heap->heap; 198} 199 200void ion_cma_heap_destroy(struct ion_heap *heap) 201{ 202 struct ion_cma_heap *cma_heap = to_cma_heap(heap); 203 204 kfree(cma_heap); 205} 206