2 * Copyright (C) 2010 ARM Limited. All rights reserved.
4 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
7 * A copy of the licence is included with the program, and can also be obtained from Free Software
8 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
11 /* create by boojin.kim@samsung.com */
12 /* needed to detect kernel version specific code */
13 #include <linux/version.h>
15 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
16 #include <linux/semaphore.h>
17 #else /* pre 2.6.26 the file was in the arch specific location */
18 #include <asm/semaphore.h>
22 #include <linux/slab.h>
23 #include <asm/atomic.h>
24 #include <linux/vmalloc.h>
25 #include <asm/cacheflush.h>
26 #include "ump_kernel_common.h"
27 #include "ump_kernel_memory_backend.h"
28 #include "ump_kernel_interface_ref_drv.h"
29 #include "ump_kernel_memory_backend_vcm.h"
30 #include "../common/ump_uk_types.h"
31 #include <linux/vcm-drv.h>
32 #include <plat/s5p-vcm.h>
33 #include <linux/dma-mapping.h>
35 #define UMP_REF_DRV_UK_VCM_DEV_G2D 10
37 typedef struct ump_vcm {
39 struct vcm_res *vcm_res;
43 typedef struct vcm_allocator {
44 struct semaphore mutex;
48 static void ump_vcm_free(void* ctx, ump_dd_mem * descriptor);
49 static int ump_vcm_allocate(void* ctx, ump_dd_mem * descriptor);
50 static void *vcm_res_get(ump_dd_mem *mem, void* args);
51 static void vcm_attr_set(ump_dd_mem *mem, void* args);
52 static int vcm_mem_allocator(vcm_allocator *info, ump_dd_mem *descriptor);
53 static void vcm_memory_backend_destroy(ump_memory_backend * backend);
57 * Create VCM memory backend
59 ump_memory_backend * ump_vcm_memory_backend_create(const int max_allocation)
61 ump_memory_backend * backend;
64 info = kmalloc(sizeof(vcm_allocator), GFP_KERNEL);
70 info->num_vcm_blocks = 0;
73 sema_init(&info->mutex, 1);
75 backend = kmalloc(sizeof(ump_memory_backend), GFP_KERNEL);
83 backend->allocate = ump_vcm_allocate;
84 backend->release = ump_vcm_free;
85 backend->shutdown = vcm_memory_backend_destroy;
86 backend->pre_allocate_physical_check = NULL;
87 backend->adjust_to_mali_phys = NULL;
89 backend->get = vcm_res_get;
90 backend->set = vcm_attr_set;
97 * Destroy specified VCM memory backend
99 static void vcm_memory_backend_destroy(ump_memory_backend * backend)
101 vcm_allocator * info = (vcm_allocator*)backend->ctx;
103 DBG_MSG_IF(1, 0 != info->num_pages_allocated, ("%d pages still in use during shutdown\n", info->num_pages_allocated));
110 * Allocate UMP memory
112 static int ump_vcm_allocate(void *ctx, ump_dd_mem * descriptor)
114 int ret; /* success */
116 struct ump_vcm *ump_vcm;
121 info = (vcm_allocator*)ctx;
123 ump_vcm = kmalloc(sizeof(struct ump_vcm), GFP_KERNEL);
129 ump_vcm->dev_id = (int)descriptor->backend_info & ~UMP_REF_DRV_UK_CONSTRAINT_USE_CACHE;
131 if(ump_vcm->dev_id == UMP_REF_DRV_UK_CONSTRAINT_NONE) { /* None */
132 ump_vcm->dev_id = UMP_REF_DRV_UK_VCM_DEV_G2D; /* this ID is G2D */
134 else if(ump_vcm->dev_id == UMP_REF_DRV_UK_CONSTRAINT_PHYSICALLY_LINEAR) { /* Physical Linear */
137 else { /* Other VCM */
138 ump_vcm->dev_id -= 2;
141 DBG_MSG(5, ("Device ID for VCM : %d\n", ump_vcm->dev_id));
142 ump_vcm->vcm = vcm_find_vcm(ump_vcm->dev_id);
148 descriptor->backend_info = (void*)ump_vcm;
150 if (down_interruptible(&info->mutex)) {
151 DBG_MSG(1, ("Failed to get mutex in ump_vcm_allocate\n"));
152 return 0; /* failure */
155 ret = vcm_mem_allocator(info, descriptor);
158 return ret; /* success */
161 static int vcm_mem_allocator(vcm_allocator *info, ump_dd_mem *descriptor)
163 unsigned long num_blocks;
165 struct vcm_phys *phys;
166 struct vcm_phys_part *part;
168 struct ump_vcm *ump_vcm;
170 ump_vcm = (struct ump_vcm*)descriptor->backend_info;
173 vcm_make_binding(ump_vcm->vcm, descriptor->size_bytes,
176 phys = ump_vcm->vcm_res->phys;
178 num_blocks = phys->count;
181 ("Allocating page array. Size: %lu, VCM Reservation : 0x%x\n",
182 phys->count * sizeof(ump_dd_physical_block),
183 ump_vcm->vcm_res->start));
185 /* Now, make a copy of the block information supplied by the user */
186 descriptor->block_array =
187 (ump_dd_physical_block *) vmalloc(sizeof(ump_dd_physical_block) *
190 if (NULL == descriptor->block_array) {
191 vfree(descriptor->block_array);
192 DBG_MSG(1, ("Could not allocate a mem handle for function.\n"));
193 return 0; /* failure */
196 for (i = 0; i < num_blocks; i++) {
197 descriptor->block_array[i].addr = part->start;
198 descriptor->block_array[i].size = part->size;
200 dmac_unmap_area(phys_to_virt(part->start), part->size, DMA_FROM_DEVICE);
201 outer_inv_range(part->start, part->start + part->size);
204 size_total += descriptor->block_array[i].size;
206 ("UMP memory created with VCM. addr 0x%x, size: 0x%x\n",
207 descriptor->block_array[i].addr,
208 descriptor->block_array[i].size));
211 descriptor->size_bytes = size_total;
212 descriptor->nr_blocks = num_blocks;
213 descriptor->ctx = NULL;
215 info->num_vcm_blocks += num_blocks;
220 * Free specified UMP memory
222 static void ump_vcm_free(void *ctx, ump_dd_mem * descriptor)
224 struct ump_vcm *ump_vcm;
230 ump_vcm = (struct ump_vcm*)descriptor->backend_info;
231 info = (vcm_allocator*)ctx;
233 BUG_ON(descriptor->nr_blocks > info->num_vcm_blocks);
235 if (down_interruptible(&info->mutex)) {
236 DBG_MSG(1, ("Failed to get mutex in ump_vcm_free\n"));
240 DBG_MSG(5, ("Releasing %lu VCM pages\n", descriptor->nr_blocks));
242 info->num_vcm_blocks -= descriptor->nr_blocks;
246 DBG_MSG(6, ("Freeing physical page by VCM\n"));
247 vcm_destroy_binding(ump_vcm->vcm_res);
249 ump_vcm->vcm_res = NULL;
252 vfree(descriptor->block_array);
255 static void *vcm_res_get(ump_dd_mem *mem, void *args)
257 struct ump_vcm *ump_vcm;
258 enum vcm_dev_id vcm_id;
260 ump_vcm = (struct ump_vcm*)mem->backend_info;
261 vcm_id = (enum vcm_dev_id)args;
263 if (vcm_reservation_in_vcm
264 (vcm_find_vcm(vcm_id), ump_vcm->vcm_res)
265 == S5PVCM_RES_NOT_IN_VCM)
268 return ump_vcm->vcm_res;
271 static void vcm_attr_set(ump_dd_mem *mem, void *args)
273 struct ump_vcm *ump_vcm, *ump_vcmh;
275 ump_vcm = (struct ump_vcm*)args;
277 ump_vcmh = kmalloc(sizeof(struct ump_vcm), GFP_KERNEL);
278 if (NULL == ump_vcmh)
283 ump_vcmh->dev_id = ump_vcm->dev_id;
284 ump_vcmh->vcm = ump_vcm->vcm;
285 ump_vcmh->vcm_res = ump_vcm->vcm_res;
287 mem->backend_info= (void*)ump_vcmh;