ion_system_heap.c revision b0599c014028eb19d0e0b2cd82390555a8eef22d
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 <asm/page.h> 18#include <linux/dma-mapping.h> 19#include <linux/err.h> 20#include <linux/highmem.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 28struct page_info { 29 struct page *page; 30 unsigned long order; 31 struct list_head list; 32}; 33 34static unsigned int orders[] = {8, 4, 0}; 35 36static struct page_info *alloc_largest_available(unsigned long size, 37 bool split_pages, 38 unsigned int max_order) 39{ 40 struct page *page; 41 struct page_info *info; 42 int i; 43 44 for (i = 0; i < ARRAY_SIZE(orders); i++) { 45 if (size < (1 << orders[i]) * PAGE_SIZE) 46 continue; 47 if (max_order < orders[i]) 48 continue; 49 page = alloc_pages(GFP_HIGHUSER | __GFP_ZERO | 50 __GFP_NOWARN | __GFP_NORETRY, orders[i]); 51 if (!page) 52 continue; 53 if (split_pages) 54 split_page(page, orders[i]); 55 info = kmalloc(sizeof(struct page_info *), GFP_KERNEL); 56 info->page = page; 57 info->order = orders[i]; 58 return info; 59 } 60 return NULL; 61} 62 63static int ion_system_heap_allocate(struct ion_heap *heap, 64 struct ion_buffer *buffer, 65 unsigned long size, unsigned long align, 66 unsigned long flags) 67{ 68 struct sg_table *table; 69 struct scatterlist *sg; 70 int ret; 71 struct list_head pages; 72 struct page_info *info, *tmp_info; 73 int i = 0; 74 long size_remaining = PAGE_ALIGN(size); 75 bool split_pages = ion_buffer_fault_user_mappings(buffer); 76 77 78 unsigned int max_order = orders[0]; 79 80 INIT_LIST_HEAD(&pages); 81 while (size_remaining > 0) { 82 info = alloc_largest_available(size_remaining, split_pages, 83 max_order); 84 if (!info) 85 goto err; 86 list_add_tail(&info->list, &pages); 87 size_remaining -= (1 << info->order) * PAGE_SIZE; 88 max_order = info->order; 89 i++; 90 } 91 92 table = kmalloc(sizeof(struct sg_table), GFP_KERNEL); 93 if (!table) 94 goto err; 95 96 if (split_pages) 97 ret = sg_alloc_table(table, PAGE_ALIGN(size) / PAGE_SIZE, 98 GFP_KERNEL); 99 else 100 ret = sg_alloc_table(table, i, GFP_KERNEL); 101 102 if (ret) 103 goto err1; 104 105 sg = table->sgl; 106 list_for_each_entry_safe(info, tmp_info, &pages, list) { 107 struct page *page = info->page; 108 109 if (split_pages) { 110 for (i = 0; i < (1 << info->order); i++) { 111 sg_set_page(sg, page + i, PAGE_SIZE, 0); 112 sg = sg_next(sg); 113 } 114 } else { 115 sg_set_page(sg, page, (1 << info->order) * PAGE_SIZE, 116 0); 117 sg = sg_next(sg); 118 } 119 list_del(&info->list); 120 kfree(info); 121 } 122 123 dma_sync_sg_for_device(NULL, table->sgl, table->nents, 124 DMA_BIDIRECTIONAL); 125 126 buffer->priv_virt = table; 127 return 0; 128err1: 129 kfree(table); 130err: 131 list_for_each_entry(info, &pages, list) { 132 if (split_pages) 133 for (i = 0; i < (1 << info->order); i++) 134 __free_page(info->page + i); 135 else 136 __free_pages(info->page, info->order); 137 138 kfree(info); 139 } 140 return -ENOMEM; 141} 142 143void ion_system_heap_free(struct ion_buffer *buffer) 144{ 145 int i; 146 struct scatterlist *sg; 147 struct sg_table *table = buffer->priv_virt; 148 149 for_each_sg(table->sgl, sg, table->nents, i) 150 __free_pages(sg_page(sg), get_order(sg_dma_len(sg))); 151 if (buffer->sg_table) 152 sg_free_table(buffer->sg_table); 153 kfree(buffer->sg_table); 154} 155 156struct sg_table *ion_system_heap_map_dma(struct ion_heap *heap, 157 struct ion_buffer *buffer) 158{ 159 return buffer->priv_virt; 160} 161 162void ion_system_heap_unmap_dma(struct ion_heap *heap, 163 struct ion_buffer *buffer) 164{ 165 return; 166} 167 168void *ion_system_heap_map_kernel(struct ion_heap *heap, 169 struct ion_buffer *buffer) 170{ 171 struct scatterlist *sg; 172 int i, j; 173 void *vaddr; 174 pgprot_t pgprot; 175 struct sg_table *table = buffer->priv_virt; 176 int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; 177 struct page **pages = kzalloc(sizeof(struct page *) * npages, 178 GFP_KERNEL); 179 struct page **tmp = pages; 180 181 if (buffer->flags & ION_FLAG_CACHED) 182 pgprot = PAGE_KERNEL; 183 else 184 pgprot = pgprot_writecombine(PAGE_KERNEL); 185 186 for_each_sg(table->sgl, sg, table->nents, i) { 187 int npages_this_entry = PAGE_ALIGN(sg_dma_len(sg)) / PAGE_SIZE; 188 struct page *page = sg_page(sg); 189 BUG_ON(i >= npages); 190 for (j = 0; j < npages_this_entry; j++) { 191 *(tmp++) = page++; 192 } 193 } 194 vaddr = vmap(pages, npages, VM_MAP, pgprot); 195 kfree(pages); 196 197 return vaddr; 198} 199 200void ion_system_heap_unmap_kernel(struct ion_heap *heap, 201 struct ion_buffer *buffer) 202{ 203 vunmap(buffer->vaddr); 204} 205 206int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, 207 struct vm_area_struct *vma) 208{ 209 struct sg_table *table = buffer->priv_virt; 210 unsigned long addr = vma->vm_start; 211 unsigned long offset = vma->vm_pgoff; 212 struct scatterlist *sg; 213 int i; 214 215 for_each_sg(table->sgl, sg, table->nents, i) { 216 if (offset) { 217 offset--; 218 continue; 219 } 220 remap_pfn_range(vma, addr, page_to_pfn(sg_page(sg)), 221 sg_dma_len(sg), vma->vm_page_prot); 222 addr += sg_dma_len(sg); 223 if (addr >= vma->vm_end) 224 return 0; 225 } 226 return 0; 227} 228 229static struct ion_heap_ops vmalloc_ops = { 230 .allocate = ion_system_heap_allocate, 231 .free = ion_system_heap_free, 232 .map_dma = ion_system_heap_map_dma, 233 .unmap_dma = ion_system_heap_unmap_dma, 234 .map_kernel = ion_system_heap_map_kernel, 235 .unmap_kernel = ion_system_heap_unmap_kernel, 236 .map_user = ion_system_heap_map_user, 237}; 238 239struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused) 240{ 241 struct ion_heap *heap; 242 243 heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL); 244 if (!heap) 245 return ERR_PTR(-ENOMEM); 246 heap->ops = &vmalloc_ops; 247 heap->type = ION_HEAP_TYPE_SYSTEM; 248 return heap; 249} 250 251void ion_system_heap_destroy(struct ion_heap *heap) 252{ 253 kfree(heap); 254} 255 256static int ion_system_contig_heap_allocate(struct ion_heap *heap, 257 struct ion_buffer *buffer, 258 unsigned long len, 259 unsigned long align, 260 unsigned long flags) 261{ 262 buffer->priv_virt = kzalloc(len, GFP_KERNEL); 263 if (!buffer->priv_virt) 264 return -ENOMEM; 265 return 0; 266} 267 268void ion_system_contig_heap_free(struct ion_buffer *buffer) 269{ 270 kfree(buffer->priv_virt); 271} 272 273static int ion_system_contig_heap_phys(struct ion_heap *heap, 274 struct ion_buffer *buffer, 275 ion_phys_addr_t *addr, size_t *len) 276{ 277 *addr = virt_to_phys(buffer->priv_virt); 278 *len = buffer->size; 279 return 0; 280} 281 282struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap, 283 struct ion_buffer *buffer) 284{ 285 struct sg_table *table; 286 int ret; 287 288 table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); 289 if (!table) 290 return ERR_PTR(-ENOMEM); 291 ret = sg_alloc_table(table, 1, GFP_KERNEL); 292 if (ret) { 293 kfree(table); 294 return ERR_PTR(ret); 295 } 296 sg_set_page(table->sgl, virt_to_page(buffer->priv_virt), buffer->size, 297 0); 298 return table; 299} 300 301void ion_system_contig_heap_unmap_dma(struct ion_heap *heap, 302 struct ion_buffer *buffer) 303{ 304 sg_free_table(buffer->sg_table); 305 kfree(buffer->sg_table); 306} 307 308int ion_system_contig_heap_map_user(struct ion_heap *heap, 309 struct ion_buffer *buffer, 310 struct vm_area_struct *vma) 311{ 312 unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv_virt)); 313 return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff, 314 vma->vm_end - vma->vm_start, 315 vma->vm_page_prot); 316 317} 318 319static struct ion_heap_ops kmalloc_ops = { 320 .allocate = ion_system_contig_heap_allocate, 321 .free = ion_system_contig_heap_free, 322 .phys = ion_system_contig_heap_phys, 323 .map_dma = ion_system_contig_heap_map_dma, 324 .unmap_dma = ion_system_contig_heap_unmap_dma, 325 .map_kernel = ion_system_heap_map_kernel, 326 .unmap_kernel = ion_system_heap_unmap_kernel, 327 .map_user = ion_system_contig_heap_map_user, 328}; 329 330struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused) 331{ 332 struct ion_heap *heap; 333 334 heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL); 335 if (!heap) 336 return ERR_PTR(-ENOMEM); 337 heap->ops = &kmalloc_ops; 338 heap->type = ION_HEAP_TYPE_SYSTEM_CONTIG; 339 return heap; 340} 341 342void ion_system_contig_heap_destroy(struct ion_heap *heap) 343{ 344 kfree(heap); 345} 346 347