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