ion_carveout_heap.c revision caaf3f12970057b32176eb333a1bfc3c6f67cbdd
1/* 2 * drivers/staging/android/ion/ion_carveout_heap.c 3 * 4 * Copyright (C) 2011 Google, Inc. 5 * 6 * This software is licensed under the terms of the GNU General Public 7 * License version 2, as published by the Free Software Foundation, and 8 * may be copied, distributed, and modified under those terms. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 */ 16#include <linux/spinlock.h> 17 18#include <linux/err.h> 19#include <linux/genalloc.h> 20#include <linux/io.h> 21#include <linux/mm.h> 22#include <linux/scatterlist.h> 23#include <linux/slab.h> 24#include <linux/vmalloc.h> 25#include "ion.h" 26#include "ion_priv.h" 27 28#include <asm/mach/map.h> 29 30struct ion_carveout_heap { 31 struct ion_heap heap; 32 struct gen_pool *pool; 33 ion_phys_addr_t base; 34}; 35 36ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap, 37 unsigned long size, 38 unsigned long align) 39{ 40 struct ion_carveout_heap *carveout_heap = 41 container_of(heap, struct ion_carveout_heap, heap); 42 unsigned long offset = gen_pool_alloc(carveout_heap->pool, size); 43 44 if (!offset) 45 return ION_CARVEOUT_ALLOCATE_FAIL; 46 47 return offset; 48} 49 50void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, 51 unsigned long size) 52{ 53 struct ion_carveout_heap *carveout_heap = 54 container_of(heap, struct ion_carveout_heap, heap); 55 56 if (addr == ION_CARVEOUT_ALLOCATE_FAIL) 57 return; 58 gen_pool_free(carveout_heap->pool, addr, size); 59} 60 61static int ion_carveout_heap_phys(struct ion_heap *heap, 62 struct ion_buffer *buffer, 63 ion_phys_addr_t *addr, size_t *len) 64{ 65 *addr = buffer->priv_phys; 66 *len = buffer->size; 67 return 0; 68} 69 70static int ion_carveout_heap_allocate(struct ion_heap *heap, 71 struct ion_buffer *buffer, 72 unsigned long size, unsigned long align, 73 unsigned long flags) 74{ 75 buffer->priv_phys = ion_carveout_allocate(heap, size, align); 76 return buffer->priv_phys == ION_CARVEOUT_ALLOCATE_FAIL ? -ENOMEM : 0; 77} 78 79static void ion_carveout_heap_free(struct ion_buffer *buffer) 80{ 81 struct ion_heap *heap = buffer->heap; 82 83 ion_carveout_free(heap, buffer->priv_phys, buffer->size); 84 buffer->priv_phys = ION_CARVEOUT_ALLOCATE_FAIL; 85} 86 87struct sg_table *ion_carveout_heap_map_dma(struct ion_heap *heap, 88 struct ion_buffer *buffer) 89{ 90 struct sg_table *table; 91 int ret; 92 93 table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); 94 if (!table) 95 return ERR_PTR(-ENOMEM); 96 ret = sg_alloc_table(table, 1, GFP_KERNEL); 97 if (ret) { 98 kfree(table); 99 return ERR_PTR(ret); 100 } 101 sg_set_page(table->sgl, phys_to_page(buffer->priv_phys), buffer->size, 102 0); 103 return table; 104} 105 106void ion_carveout_heap_unmap_dma(struct ion_heap *heap, 107 struct ion_buffer *buffer) 108{ 109 sg_free_table(buffer->sg_table); 110} 111 112void *ion_carveout_heap_map_kernel(struct ion_heap *heap, 113 struct ion_buffer *buffer) 114{ 115 int mtype = MT_MEMORY_NONCACHED; 116 117 if (buffer->flags & ION_FLAG_CACHED) 118 mtype = MT_MEMORY; 119 120 return __arm_ioremap(buffer->priv_phys, buffer->size, 121 mtype); 122} 123 124void ion_carveout_heap_unmap_kernel(struct ion_heap *heap, 125 struct ion_buffer *buffer) 126{ 127 __arm_iounmap(buffer->vaddr); 128 buffer->vaddr = NULL; 129 return; 130} 131 132int ion_carveout_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, 133 struct vm_area_struct *vma) 134{ 135 return remap_pfn_range(vma, vma->vm_start, 136 __phys_to_pfn(buffer->priv_phys) + vma->vm_pgoff, 137 vma->vm_end - vma->vm_start, 138 pgprot_noncached(vma->vm_page_prot)); 139} 140 141static struct ion_heap_ops carveout_heap_ops = { 142 .allocate = ion_carveout_heap_allocate, 143 .free = ion_carveout_heap_free, 144 .phys = ion_carveout_heap_phys, 145 .map_dma = ion_carveout_heap_map_dma, 146 .unmap_dma = ion_carveout_heap_unmap_dma, 147 .map_user = ion_carveout_heap_map_user, 148 .map_kernel = ion_carveout_heap_map_kernel, 149 .unmap_kernel = ion_carveout_heap_unmap_kernel, 150}; 151 152struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data) 153{ 154 struct ion_carveout_heap *carveout_heap; 155 156 carveout_heap = kzalloc(sizeof(struct ion_carveout_heap), GFP_KERNEL); 157 if (!carveout_heap) 158 return ERR_PTR(-ENOMEM); 159 160 carveout_heap->pool = gen_pool_create(12, -1); 161 if (!carveout_heap->pool) { 162 kfree(carveout_heap); 163 return ERR_PTR(-ENOMEM); 164 } 165 carveout_heap->base = heap_data->base; 166 gen_pool_add(carveout_heap->pool, carveout_heap->base, heap_data->size, 167 -1); 168 carveout_heap->heap.ops = &carveout_heap_ops; 169 carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT; 170 171 return &carveout_heap->heap; 172} 173 174void ion_carveout_heap_destroy(struct ion_heap *heap) 175{ 176 struct ion_carveout_heap *carveout_heap = 177 container_of(heap, struct ion_carveout_heap, heap); 178 179 gen_pool_destroy(carveout_heap->pool); 180 kfree(carveout_heap); 181 carveout_heap = NULL; 182} 183