ion_cma_heap.c revision f0ca3e87cc132b67c40ba1161cd02c8a2985ac4c
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 if (buffer->flags & ION_FLAG_CACHED) 73 return -EINVAL; 74 75 if (align > PAGE_SIZE) 76 return -EINVAL; 77 78 info = kzalloc(sizeof(struct ion_cma_buffer_info), GFP_KERNEL); 79 if (!info) 80 return ION_CMA_ALLOCATE_FAILED; 81 82 info->cpu_addr = dma_alloc_coherent(dev, len, &(info->handle), 83 GFP_HIGHUSER | __GFP_ZERO); 84 85 if (!info->cpu_addr) { 86 dev_err(dev, "Fail to allocate buffer\n"); 87 goto err; 88 } 89 90 info->table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); 91 if (!info->table) 92 goto free_mem; 93 94 if (ion_cma_get_sgtable 95 (dev, info->table, info->cpu_addr, info->handle, len)) 96 goto free_table; 97 /* keep this for memory release */ 98 buffer->priv_virt = info; 99 dev_dbg(dev, "Allocate buffer %p\n", buffer); 100 return 0; 101 102free_table: 103 kfree(info->table); 104free_mem: 105 dma_free_coherent(dev, len, info->cpu_addr, info->handle); 106err: 107 kfree(info); 108 return ION_CMA_ALLOCATE_FAILED; 109} 110 111static void ion_cma_free(struct ion_buffer *buffer) 112{ 113 struct ion_cma_heap *cma_heap = to_cma_heap(buffer->heap); 114 struct device *dev = cma_heap->dev; 115 struct ion_cma_buffer_info *info = buffer->priv_virt; 116 117 dev_dbg(dev, "Release buffer %p\n", buffer); 118 /* release memory */ 119 dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle); 120 /* release sg table */ 121 sg_free_table(info->table); 122 kfree(info->table); 123 kfree(info); 124} 125 126/* return physical address in addr */ 127static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer, 128 ion_phys_addr_t *addr, size_t *len) 129{ 130 struct ion_cma_heap *cma_heap = to_cma_heap(buffer->heap); 131 struct device *dev = cma_heap->dev; 132 struct ion_cma_buffer_info *info = buffer->priv_virt; 133 134 dev_dbg(dev, "Return buffer %p physical address %pa\n", buffer, 135 &info->handle); 136 137 *addr = info->handle; 138 *len = buffer->size; 139 140 return 0; 141} 142 143static struct sg_table *ion_cma_heap_map_dma(struct ion_heap *heap, 144 struct ion_buffer *buffer) 145{ 146 struct ion_cma_buffer_info *info = buffer->priv_virt; 147 148 return info->table; 149} 150 151static void ion_cma_heap_unmap_dma(struct ion_heap *heap, 152 struct ion_buffer *buffer) 153{ 154} 155 156static int ion_cma_mmap(struct ion_heap *mapper, struct ion_buffer *buffer, 157 struct vm_area_struct *vma) 158{ 159 struct ion_cma_heap *cma_heap = to_cma_heap(buffer->heap); 160 struct device *dev = cma_heap->dev; 161 struct ion_cma_buffer_info *info = buffer->priv_virt; 162 163 return dma_mmap_coherent(dev, vma, info->cpu_addr, info->handle, 164 buffer->size); 165} 166 167static void *ion_cma_map_kernel(struct ion_heap *heap, 168 struct ion_buffer *buffer) 169{ 170 struct ion_cma_buffer_info *info = buffer->priv_virt; 171 /* kernel memory mapping has been done at allocation time */ 172 return info->cpu_addr; 173} 174 175static void ion_cma_unmap_kernel(struct ion_heap *heap, 176 struct ion_buffer *buffer) 177{ 178} 179 180static struct ion_heap_ops ion_cma_ops = { 181 .allocate = ion_cma_allocate, 182 .free = ion_cma_free, 183 .map_dma = ion_cma_heap_map_dma, 184 .unmap_dma = ion_cma_heap_unmap_dma, 185 .phys = ion_cma_phys, 186 .map_user = ion_cma_mmap, 187 .map_kernel = ion_cma_map_kernel, 188 .unmap_kernel = ion_cma_unmap_kernel, 189}; 190 191struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data) 192{ 193 struct ion_cma_heap *cma_heap; 194 195 cma_heap = kzalloc(sizeof(struct ion_cma_heap), GFP_KERNEL); 196 197 if (!cma_heap) 198 return ERR_PTR(-ENOMEM); 199 200 cma_heap->heap.ops = &ion_cma_ops; 201 /* get device from private heaps data, later it will be 202 * used to make the link with reserved CMA memory */ 203 cma_heap->dev = data->priv; 204 cma_heap->heap.type = ION_HEAP_TYPE_DMA; 205 return &cma_heap->heap; 206} 207 208void ion_cma_heap_destroy(struct ion_heap *heap) 209{ 210 struct ion_cma_heap *cma_heap = to_cma_heap(heap); 211 212 kfree(cma_heap); 213} 214