ion_system_heap.c revision 4d5ca3299fb7b27ceb6c33a62bc10ce4d408dc0b
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 buffer->priv_virt = vmalloc_user(size); 31 if (!buffer->priv_virt) 32 return -ENOMEM; 33 return 0; 34} 35 36void ion_system_heap_free(struct ion_buffer *buffer) 37{ 38 vfree(buffer->priv_virt); 39} 40 41struct sg_table *ion_system_heap_map_dma(struct ion_heap *heap, 42 struct ion_buffer *buffer) 43{ 44 struct sg_table *table; 45 struct scatterlist *sg; 46 int i; 47 int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; 48 void *vaddr = buffer->priv_virt; 49 int ret; 50 51 table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); 52 if (!table) 53 return ERR_PTR(-ENOMEM); 54 ret = sg_alloc_table(table, npages, GFP_KERNEL); 55 if (ret) 56 goto err0; 57 for_each_sg(table->sgl, sg, table->nents, i) { 58 struct page *page; 59 page = vmalloc_to_page(vaddr); 60 if (!page) { 61 ret = -ENOMEM; 62 goto err1; 63 } 64 sg_set_page(sg, page, PAGE_SIZE, 0); 65 vaddr += PAGE_SIZE; 66 } 67 return table; 68err1: 69 sg_free_table(table); 70err0: 71 kfree(table); 72 return ERR_PTR(ret); 73} 74 75void ion_system_heap_unmap_dma(struct ion_heap *heap, 76 struct ion_buffer *buffer) 77{ 78 if (buffer->sg_table) 79 sg_free_table(buffer->sg_table); 80 kfree(buffer->sg_table); 81} 82 83void *ion_system_heap_map_kernel(struct ion_heap *heap, 84 struct ion_buffer *buffer) 85{ 86 return buffer->priv_virt; 87} 88 89void ion_system_heap_unmap_kernel(struct ion_heap *heap, 90 struct ion_buffer *buffer) 91{ 92} 93 94int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, 95 struct vm_area_struct *vma) 96{ 97 return remap_vmalloc_range(vma, buffer->priv_virt, vma->vm_pgoff); 98} 99 100static struct ion_heap_ops vmalloc_ops = { 101 .allocate = ion_system_heap_allocate, 102 .free = ion_system_heap_free, 103 .map_dma = ion_system_heap_map_dma, 104 .unmap_dma = ion_system_heap_unmap_dma, 105 .map_kernel = ion_system_heap_map_kernel, 106 .unmap_kernel = ion_system_heap_unmap_kernel, 107 .map_user = ion_system_heap_map_user, 108}; 109 110struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused) 111{ 112 struct ion_heap *heap; 113 114 heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL); 115 if (!heap) 116 return ERR_PTR(-ENOMEM); 117 heap->ops = &vmalloc_ops; 118 heap->type = ION_HEAP_TYPE_SYSTEM; 119 return heap; 120} 121 122void ion_system_heap_destroy(struct ion_heap *heap) 123{ 124 kfree(heap); 125} 126 127static int ion_system_contig_heap_allocate(struct ion_heap *heap, 128 struct ion_buffer *buffer, 129 unsigned long len, 130 unsigned long align, 131 unsigned long flags) 132{ 133 buffer->priv_virt = kzalloc(len, GFP_KERNEL); 134 if (!buffer->priv_virt) 135 return -ENOMEM; 136 return 0; 137} 138 139void ion_system_contig_heap_free(struct ion_buffer *buffer) 140{ 141 kfree(buffer->priv_virt); 142} 143 144static int ion_system_contig_heap_phys(struct ion_heap *heap, 145 struct ion_buffer *buffer, 146 ion_phys_addr_t *addr, size_t *len) 147{ 148 *addr = virt_to_phys(buffer->priv_virt); 149 *len = buffer->size; 150 return 0; 151} 152 153struct sg_table *ion_system_contig_heap_map_dma(struct ion_heap *heap, 154 struct ion_buffer *buffer) 155{ 156 struct sg_table *table; 157 int ret; 158 159 table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); 160 if (!table) 161 return ERR_PTR(-ENOMEM); 162 ret = sg_alloc_table(table, 1, GFP_KERNEL); 163 if (ret) { 164 kfree(table); 165 return ERR_PTR(ret); 166 } 167 sg_set_page(table->sgl, virt_to_page(buffer->priv_virt), buffer->size, 168 0); 169 return table; 170} 171 172int ion_system_contig_heap_map_user(struct ion_heap *heap, 173 struct ion_buffer *buffer, 174 struct vm_area_struct *vma) 175{ 176 unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv_virt)); 177 return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff, 178 vma->vm_end - vma->vm_start, 179 vma->vm_page_prot); 180 181} 182 183static struct ion_heap_ops kmalloc_ops = { 184 .allocate = ion_system_contig_heap_allocate, 185 .free = ion_system_contig_heap_free, 186 .phys = ion_system_contig_heap_phys, 187 .map_dma = ion_system_contig_heap_map_dma, 188 .unmap_dma = ion_system_heap_unmap_dma, 189 .map_kernel = ion_system_heap_map_kernel, 190 .unmap_kernel = ion_system_heap_unmap_kernel, 191 .map_user = ion_system_contig_heap_map_user, 192}; 193 194struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused) 195{ 196 struct ion_heap *heap; 197 198 heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL); 199 if (!heap) 200 return ERR_PTR(-ENOMEM); 201 heap->ops = &kmalloc_ops; 202 heap->type = ION_HEAP_TYPE_SYSTEM_CONTIG; 203 return heap; 204} 205 206void ion_system_contig_heap_destroy(struct ion_heap *heap) 207{ 208 kfree(heap); 209} 210 211