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