ion_system_heap.c revision 0de9577b5e708b903a58a9d5e91d6474daa29c2d
1/* 2 * drivers/staging/android/ion/ion_system_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 17#include <linux/err.h> 18#include <linux/mm.h> 19#include <linux/scatterlist.h> 20#include <linux/slab.h> 21#include <linux/vmalloc.h> 22#include "ion.h" 23#include "ion_priv.h" 24 25static int ion_system_heap_allocate(struct ion_heap *heap, 26 struct ion_buffer *buffer, 27 unsigned long size, unsigned long align, 28 unsigned long flags) 29{ 30 struct sg_table *table; 31 struct scatterlist *sg; 32 int i, j; 33 int npages = PAGE_ALIGN(size) / PAGE_SIZE; 34 35 table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); 36 if (!table) 37 return -ENOMEM; 38 i = sg_alloc_table(table, npages, GFP_KERNEL); 39 if (i) 40 goto err0; 41 for_each_sg(table->sgl, sg, table->nents, i) { 42 struct page *page; 43 page = alloc_page(GFP_HIGHUSER | __GFP_ZERO); 44 if (!page) 45 goto err1; 46 sg_set_page(sg, page, PAGE_SIZE, 0); 47 } 48 buffer->priv_virt = table; 49 return 0; 50err1: 51 for_each_sg(table->sgl, sg, i, j) 52 __free_page(sg_page(sg)); 53 sg_free_table(table); 54err0: 55 kfree(table); 56 return -ENOMEM; 57} 58 59void ion_system_heap_free(struct ion_buffer *buffer) 60{ 61 int i; 62 struct scatterlist *sg; 63 struct sg_table *table = buffer->priv_virt; 64 65 for_each_sg(table->sgl, sg, table->nents, i) 66 __free_page(sg_page(sg)); 67 if (buffer->sg_table) 68 sg_free_table(buffer->sg_table); 69 kfree(buffer->sg_table); 70} 71 72struct sg_table *ion_system_heap_map_dma(struct ion_heap *heap, 73 struct ion_buffer *buffer) 74{ 75 return buffer->priv_virt; 76} 77 78void ion_system_heap_unmap_dma(struct ion_heap *heap, 79 struct ion_buffer *buffer) 80{ 81 return; 82} 83 84void *ion_system_heap_map_kernel(struct ion_heap *heap, 85 struct ion_buffer *buffer) 86{ 87 struct scatterlist *sg; 88 int i; 89 void *vaddr; 90 struct sg_table *table = buffer->priv_virt; 91 struct page **pages = kmalloc(sizeof(struct page *) * table->nents, 92 GFP_KERNEL); 93 94 for_each_sg(table->sgl, sg, table->nents, i) 95 pages[i] = sg_page(sg); 96 vaddr = vmap(pages, table->nents, VM_MAP, PAGE_KERNEL); 97 kfree(pages); 98 99 return vaddr; 100} 101 102void ion_system_heap_unmap_kernel(struct ion_heap *heap, 103 struct ion_buffer *buffer) 104{ 105 vunmap(buffer->vaddr); 106} 107 108int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, 109 struct vm_area_struct *vma) 110{ 111 struct sg_table *table = buffer->priv_virt; 112 unsigned long addr = vma->vm_start; 113 unsigned long offset = vma->vm_pgoff; 114 struct scatterlist *sg; 115 int i; 116 117 for_each_sg(table->sgl, sg, table->nents, i) { 118 if (offset) { 119 offset--; 120 continue; 121 } 122 vm_insert_page(vma, addr, sg_page(sg)); 123 addr += PAGE_SIZE; 124 } 125 return 0; 126} 127 128static struct ion_heap_ops vmalloc_ops = { 129 .allocate = ion_system_heap_allocate, 130 .free = ion_system_heap_free, 131 .map_dma = ion_system_heap_map_dma, 132 .unmap_dma = ion_system_heap_unmap_dma, 133 .map_kernel = ion_system_heap_map_kernel, 134 .unmap_kernel = ion_system_heap_unmap_kernel, 135 .map_user = ion_system_heap_map_user, 136}; 137 138struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused) 139{ 140 struct ion_heap *heap; 141 142 heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL); 143 if (!heap) 144 return ERR_PTR(-ENOMEM); 145 heap->ops = &vmalloc_ops; 146 heap->type = ION_HEAP_TYPE_SYSTEM; 147 return heap; 148} 149 150void ion_system_heap_destroy(struct ion_heap *heap) 151{ 152 kfree(heap); 153} 154 155static int ion_system_contig_heap_allocate(struct ion_heap *heap, 156 struct ion_buffer *buffer, 157 unsigned long len, 158 unsigned long align, 159 unsigned long flags) 160{ 161 buffer->priv_virt = kzalloc(len, GFP_KERNEL); 162 if (!buffer->priv_virt) 163 return -ENOMEM; 164 return 0; 165} 166 167void ion_system_contig_heap_free(struct ion_buffer *buffer) 168{ 169 kfree(buffer->priv_virt); 170} 171 172static int ion_system_contig_heap_phys(struct ion_heap *heap, 173 struct ion_buffer *buffer, 174 ion_phys_addr_t *addr, size_t *len) 175{ 176 *addr = virt_to_phys(buffer->priv_virt); 177 *len = buffer->size; 178 return 0; 179} 180 181struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap, 182 struct ion_buffer *buffer) 183{ 184 struct sg_table *table; 185 int ret; 186 187 table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); 188 if (!table) 189 return ERR_PTR(-ENOMEM); 190 ret = sg_alloc_table(table, 1, GFP_KERNEL); 191 if (ret) { 192 kfree(table); 193 return ERR_PTR(ret); 194 } 195 sg_set_page(table->sgl, virt_to_page(buffer->priv_virt), buffer->size, 196 0); 197 return table; 198} 199 200int ion_system_contig_heap_map_user(struct ion_heap *heap, 201 struct ion_buffer *buffer, 202 struct vm_area_struct *vma) 203{ 204 unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv_virt)); 205 return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff, 206 vma->vm_end - vma->vm_start, 207 vma->vm_page_prot); 208 209} 210 211static struct ion_heap_ops kmalloc_ops = { 212 .allocate = ion_system_contig_heap_allocate, 213 .free = ion_system_contig_heap_free, 214 .phys = ion_system_contig_heap_phys, 215 .map_dma = ion_system_contig_heap_map_dma, 216 .unmap_dma = ion_system_heap_unmap_dma, 217 .map_kernel = ion_system_heap_map_kernel, 218 .unmap_kernel = ion_system_heap_unmap_kernel, 219 .map_user = ion_system_contig_heap_map_user, 220}; 221 222struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused) 223{ 224 struct ion_heap *heap; 225 226 heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL); 227 if (!heap) 228 return ERR_PTR(-ENOMEM); 229 heap->ops = &kmalloc_ops; 230 heap->type = ION_HEAP_TYPE_SYSTEM_CONTIG; 231 return heap; 232} 233 234void ion_system_contig_heap_destroy(struct ion_heap *heap) 235{ 236 kfree(heap); 237} 238 239