ion_heap.c revision e3c2eb7cd9f291bf17ee056e388d0089cf378345
1/* 2 * drivers/staging/android/ion/ion_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/vmalloc.h> 21#include "ion.h" 22#include "ion_priv.h" 23 24void *ion_heap_map_kernel(struct ion_heap *heap, 25 struct ion_buffer *buffer) 26{ 27 struct scatterlist *sg; 28 int i, j; 29 void *vaddr; 30 pgprot_t pgprot; 31 struct sg_table *table = buffer->sg_table; 32 int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; 33 struct page **pages = vmalloc(sizeof(struct page *) * npages); 34 struct page **tmp = pages; 35 36 if (!pages) 37 return 0; 38 39 if (buffer->flags & ION_FLAG_CACHED) 40 pgprot = PAGE_KERNEL; 41 else 42 pgprot = pgprot_writecombine(PAGE_KERNEL); 43 44 for_each_sg(table->sgl, sg, table->nents, i) { 45 int npages_this_entry = PAGE_ALIGN(sg_dma_len(sg)) / PAGE_SIZE; 46 struct page *page = sg_page(sg); 47 BUG_ON(i >= npages); 48 for (j = 0; j < npages_this_entry; j++) { 49 *(tmp++) = page++; 50 } 51 } 52 vaddr = vmap(pages, npages, VM_MAP, pgprot); 53 vfree(pages); 54 55 return vaddr; 56} 57 58void ion_heap_unmap_kernel(struct ion_heap *heap, 59 struct ion_buffer *buffer) 60{ 61 vunmap(buffer->vaddr); 62} 63 64int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, 65 struct vm_area_struct *vma) 66{ 67 struct sg_table *table = buffer->sg_table; 68 unsigned long addr = vma->vm_start; 69 unsigned long offset = vma->vm_pgoff * PAGE_SIZE; 70 struct scatterlist *sg; 71 int i; 72 73 for_each_sg(table->sgl, sg, table->nents, i) { 74 struct page *page = sg_page(sg); 75 unsigned long remainder = vma->vm_end - addr; 76 unsigned long len = sg_dma_len(sg); 77 78 if (offset >= sg_dma_len(sg)) { 79 offset -= sg_dma_len(sg); 80 continue; 81 } else if (offset) { 82 page += offset / PAGE_SIZE; 83 len = sg_dma_len(sg) - offset; 84 offset = 0; 85 } 86 len = min(len, remainder); 87 remap_pfn_range(vma, addr, page_to_pfn(page), len, 88 vma->vm_page_prot); 89 addr += len; 90 if (addr >= vma->vm_end) 91 return 0; 92 } 93 return 0; 94} 95 96struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data) 97{ 98 struct ion_heap *heap = NULL; 99 100 switch (heap_data->type) { 101 case ION_HEAP_TYPE_SYSTEM_CONTIG: 102 heap = ion_system_contig_heap_create(heap_data); 103 break; 104 case ION_HEAP_TYPE_SYSTEM: 105 heap = ion_system_heap_create(heap_data); 106 break; 107 case ION_HEAP_TYPE_CARVEOUT: 108 heap = ion_carveout_heap_create(heap_data); 109 break; 110 case ION_HEAP_TYPE_CHUNK: 111 heap = ion_chunk_heap_create(heap_data); 112 break; 113 default: 114 pr_err("%s: Invalid heap type %d\n", __func__, 115 heap_data->type); 116 return ERR_PTR(-EINVAL); 117 } 118 119 if (IS_ERR_OR_NULL(heap)) { 120 pr_err("%s: error creating heap %s type %d base %lu size %u\n", 121 __func__, heap_data->name, heap_data->type, 122 heap_data->base, heap_data->size); 123 return ERR_PTR(-EINVAL); 124 } 125 126 heap->name = heap_data->name; 127 heap->id = heap_data->id; 128 return heap; 129} 130 131void ion_heap_destroy(struct ion_heap *heap) 132{ 133 if (!heap) 134 return; 135 136 switch (heap->type) { 137 case ION_HEAP_TYPE_SYSTEM_CONTIG: 138 ion_system_contig_heap_destroy(heap); 139 break; 140 case ION_HEAP_TYPE_SYSTEM: 141 ion_system_heap_destroy(heap); 142 break; 143 case ION_HEAP_TYPE_CARVEOUT: 144 ion_carveout_heap_destroy(heap); 145 break; 146 case ION_HEAP_TYPE_CHUNK: 147 ion_chunk_heap_destroy(heap); 148 break; 149 default: 150 pr_err("%s: Invalid heap type %d\n", __func__, 151 heap->type); 152 } 153} 154