ion_cma_heap.c revision 349c9e13855109df99c5205a4e8d53d9fa169490
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 */ 47int 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/* 62 * Create scatter-list for each page of the already allocated DMA buffer. 63 */ 64int ion_cma_get_sgtable_per_page(struct device *dev, struct sg_table *sgt, 65 void *cpu_addr, dma_addr_t handle, size_t size) 66{ 67 struct page *page = virt_to_page(cpu_addr); 68 int ret, i; 69 struct scatterlist *sg; 70 71 ret = sg_alloc_table(sgt, PAGE_ALIGN(size) / PAGE_SIZE, GFP_KERNEL); 72 if (unlikely(ret)) 73 return ret; 74 75 sg = sgt->sgl; 76 for (i = 0; i < (PAGE_ALIGN(size) / PAGE_SIZE); i++) { 77 page = virt_to_page(cpu_addr + (i * PAGE_SIZE)); 78 sg_set_page(sg, page, PAGE_SIZE, 0); 79 sg = sg_next(sg); 80 } 81 return 0; 82} 83 84/* ION CMA heap operations functions */ 85static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, 86 unsigned long len, unsigned long align, 87 unsigned long flags) 88{ 89 struct ion_cma_heap *cma_heap = to_cma_heap(heap); 90 struct device *dev = cma_heap->dev; 91 struct ion_cma_buffer_info *info; 92 93 dev_dbg(dev, "Request buffer allocation len %ld\n", len); 94 95 info = kzalloc(sizeof(struct ion_cma_buffer_info), GFP_KERNEL); 96 if (!info) { 97 dev_err(dev, "Can't allocate buffer info\n"); 98 return ION_CMA_ALLOCATE_FAILED; 99 } 100 101 info->cpu_addr = dma_alloc_coherent(dev, len, &(info->handle), 0); 102 103 if (!info->cpu_addr) { 104 dev_err(dev, "Fail to allocate buffer\n"); 105 goto err; 106 } 107 108 info->table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); 109 if (!info->table) { 110 dev_err(dev, "Fail to allocate sg table\n"); 111 goto free_mem; 112 } 113 114 if (ion_buffer_fault_user_mappings(buffer)) { 115 if (ion_cma_get_sgtable_per_page 116 (dev, info->table, info->cpu_addr, info->handle, len)) 117 goto free_table; 118 } else { 119 if (ion_cma_get_sgtable 120 (dev, info->table, info->cpu_addr, info->handle, len)) 121 goto free_table; 122 } 123 /* keep this for memory release */ 124 buffer->priv_virt = info; 125 dev_dbg(dev, "Allocate buffer %p\n", buffer); 126 return 0; 127 128free_table: 129 kfree(info->table); 130free_mem: 131 dma_free_coherent(dev, len, info->cpu_addr, info->handle); 132err: 133 kfree(info); 134 return ION_CMA_ALLOCATE_FAILED; 135} 136 137static void ion_cma_free(struct ion_buffer *buffer) 138{ 139 struct ion_cma_heap *cma_heap = to_cma_heap(buffer->heap); 140 struct device *dev = cma_heap->dev; 141 struct ion_cma_buffer_info *info = buffer->priv_virt; 142 143 dev_dbg(dev, "Release buffer %p\n", buffer); 144 /* release memory */ 145 dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle); 146 /* release sg table */ 147 sg_free_table(info->table); 148 kfree(info->table); 149 kfree(info); 150} 151 152/* return physical address in addr */ 153static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer, 154 ion_phys_addr_t *addr, size_t *len) 155{ 156 struct ion_cma_heap *cma_heap = to_cma_heap(buffer->heap); 157 struct device *dev = cma_heap->dev; 158 struct ion_cma_buffer_info *info = buffer->priv_virt; 159 160 dev_dbg(dev, "Return buffer %p physical address 0x%x\n", buffer, 161 info->handle); 162 163 *addr = info->handle; 164 *len = buffer->size; 165 166 return 0; 167} 168 169struct sg_table *ion_cma_heap_map_dma(struct ion_heap *heap, 170 struct ion_buffer *buffer) 171{ 172 struct ion_cma_buffer_info *info = buffer->priv_virt; 173 174 return info->table; 175} 176 177void ion_cma_heap_unmap_dma(struct ion_heap *heap, 178 struct ion_buffer *buffer) 179{ 180 return; 181} 182 183static int ion_cma_mmap(struct ion_heap *mapper, struct ion_buffer *buffer, 184 struct vm_area_struct *vma) 185{ 186 struct ion_cma_heap *cma_heap = to_cma_heap(buffer->heap); 187 struct device *dev = cma_heap->dev; 188 struct ion_cma_buffer_info *info = buffer->priv_virt; 189 190 return dma_mmap_coherent(dev, vma, info->cpu_addr, info->handle, 191 buffer->size); 192} 193 194void *ion_cma_map_kernel(struct ion_heap *heap, struct ion_buffer *buffer) 195{ 196 struct ion_cma_buffer_info *info = buffer->priv_virt; 197 /* kernel memory mapping has been done at allocation time */ 198 return info->cpu_addr; 199} 200 201static struct ion_heap_ops ion_cma_ops = { 202 .allocate = ion_cma_allocate, 203 .free = ion_cma_free, 204 .map_dma = ion_cma_heap_map_dma, 205 .unmap_dma = ion_cma_heap_unmap_dma, 206 .phys = ion_cma_phys, 207 .map_user = ion_cma_mmap, 208 .map_kernel = ion_cma_map_kernel, 209}; 210 211struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data) 212{ 213 struct ion_cma_heap *cma_heap; 214 215 cma_heap = kzalloc(sizeof(struct ion_cma_heap), GFP_KERNEL); 216 217 if (!cma_heap) 218 return ERR_PTR(-ENOMEM); 219 220 cma_heap->heap.ops = &ion_cma_ops; 221 /* get device from private heaps data, later it will be 222 * used to make the link with reserved CMA memory */ 223 cma_heap->dev = data->priv; 224 cma_heap->heap.type = ION_HEAP_TYPE_DMA; 225 return &cma_heap->heap; 226} 227 228void ion_cma_heap_destroy(struct ion_heap *heap) 229{ 230 struct ion_cma_heap *cma_heap = to_cma_heap(heap); 231 232 kfree(cma_heap); 233} 234