ion_system_heap.c revision 56a7c1851341a2fa9bd115746c1310411a6537a1
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 pgprot_t pgprot; 91 struct sg_table *table = buffer->priv_virt; 92 struct page **pages = kmalloc(sizeof(struct page *) * table->nents, 93 GFP_KERNEL); 94 95 for_each_sg(table->sgl, sg, table->nents, i) 96 pages[i] = sg_page(sg); 97 98 if (buffer->flags & ION_FLAG_CACHED) 99 pgprot = PAGE_KERNEL; 100 else 101 pgprot = pgprot_writecombine(PAGE_KERNEL); 102 103 vaddr = vmap(pages, table->nents, VM_MAP, pgprot); 104 kfree(pages); 105 106 return vaddr; 107} 108 109void ion_system_heap_unmap_kernel(struct ion_heap *heap, 110 struct ion_buffer *buffer) 111{ 112 vunmap(buffer->vaddr); 113} 114 115int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, 116 struct vm_area_struct *vma) 117{ 118 struct sg_table *table = buffer->priv_virt; 119 unsigned long addr = vma->vm_start; 120 unsigned long offset = vma->vm_pgoff; 121 struct scatterlist *sg; 122 int i; 123 124 for_each_sg(table->sgl, sg, table->nents, i) { 125 if (offset) { 126 offset--; 127 continue; 128 } 129 vm_insert_page(vma, addr, sg_page(sg)); 130 addr += PAGE_SIZE; 131 } 132 return 0; 133} 134 135static struct ion_heap_ops vmalloc_ops = { 136 .allocate = ion_system_heap_allocate, 137 .free = ion_system_heap_free, 138 .map_dma = ion_system_heap_map_dma, 139 .unmap_dma = ion_system_heap_unmap_dma, 140 .map_kernel = ion_system_heap_map_kernel, 141 .unmap_kernel = ion_system_heap_unmap_kernel, 142 .map_user = ion_system_heap_map_user, 143}; 144 145struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused) 146{ 147 struct ion_heap *heap; 148 149 heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL); 150 if (!heap) 151 return ERR_PTR(-ENOMEM); 152 heap->ops = &vmalloc_ops; 153 heap->type = ION_HEAP_TYPE_SYSTEM; 154 return heap; 155} 156 157void ion_system_heap_destroy(struct ion_heap *heap) 158{ 159 kfree(heap); 160} 161 162static int ion_system_contig_heap_allocate(struct ion_heap *heap, 163 struct ion_buffer *buffer, 164 unsigned long len, 165 unsigned long align, 166 unsigned long flags) 167{ 168 buffer->priv_virt = kzalloc(len, GFP_KERNEL); 169 if (!buffer->priv_virt) 170 return -ENOMEM; 171 return 0; 172} 173 174void ion_system_contig_heap_free(struct ion_buffer *buffer) 175{ 176 kfree(buffer->priv_virt); 177} 178 179static int ion_system_contig_heap_phys(struct ion_heap *heap, 180 struct ion_buffer *buffer, 181 ion_phys_addr_t *addr, size_t *len) 182{ 183 *addr = virt_to_phys(buffer->priv_virt); 184 *len = buffer->size; 185 return 0; 186} 187 188struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap, 189 struct ion_buffer *buffer) 190{ 191 struct sg_table *table; 192 int ret; 193 194 table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); 195 if (!table) 196 return ERR_PTR(-ENOMEM); 197 ret = sg_alloc_table(table, 1, GFP_KERNEL); 198 if (ret) { 199 kfree(table); 200 return ERR_PTR(ret); 201 } 202 sg_set_page(table->sgl, virt_to_page(buffer->priv_virt), buffer->size, 203 0); 204 return table; 205} 206 207void ion_system_contig_heap_unmap_dma(struct ion_heap *heap, 208 struct ion_buffer *buffer) 209{ 210 sg_free_table(buffer->sg_table); 211 kfree(buffer->sg_table); 212} 213 214int ion_system_contig_heap_map_user(struct ion_heap *heap, 215 struct ion_buffer *buffer, 216 struct vm_area_struct *vma) 217{ 218 unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv_virt)); 219 return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff, 220 vma->vm_end - vma->vm_start, 221 vma->vm_page_prot); 222 223} 224 225static struct ion_heap_ops kmalloc_ops = { 226 .allocate = ion_system_contig_heap_allocate, 227 .free = ion_system_contig_heap_free, 228 .phys = ion_system_contig_heap_phys, 229 .map_dma = ion_system_contig_heap_map_dma, 230 .unmap_dma = ion_system_contig_heap_unmap_dma, 231 .map_kernel = ion_system_heap_map_kernel, 232 .unmap_kernel = ion_system_heap_unmap_kernel, 233 .map_user = ion_system_contig_heap_map_user, 234}; 235 236struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused) 237{ 238 struct ion_heap *heap; 239 240 heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL); 241 if (!heap) 242 return ERR_PTR(-ENOMEM); 243 heap->ops = &kmalloc_ops; 244 heap->type = ION_HEAP_TYPE_SYSTEM_CONTIG; 245 return heap; 246} 247 248void ion_system_contig_heap_destroy(struct ion_heap *heap) 249{ 250 kfree(heap); 251} 252 253