2 * This confidential and proprietary software may be used only as
3 * authorised by a licensing agreement from ARM Limited
4 * (C) COPYRIGHT 2008-2013 ARM Limited
6 * The entire notice above must be reproduced on all authorised
7 * copies and copies may only be made to the extent permitted
8 * by a licensing agreement from ARM Limited.
10 #include "mali_kernel_common.h"
11 #include "mali_memory.h"
12 #include "mali_memory_block_alloc.h"
14 #include <linux/mutex.h>
15 #define MALI_BLOCK_SIZE (256UL * 1024UL) /* 256 kB, remember to keep the ()s */
18 struct block_info *next;
21 typedef struct block_info block_info;
24 typedef struct block_allocator {
26 block_info *all_blocks;
27 block_info *first_free;
34 static block_allocator *mali_mem_block_gobal_allocator = NULL;
36 MALI_STATIC_INLINE u32 get_phys(block_allocator *info, block_info *block)
38 return info->base + ((block - info->all_blocks) * MALI_BLOCK_SIZE);
41 mali_mem_allocator *mali_mem_block_allocator_create(u32 base_address, u32 cpu_usage_adjust, u32 size)
43 block_allocator *info;
47 usable_size = size & ~(MALI_BLOCK_SIZE - 1);
48 MALI_DEBUG_PRINT(3, ("Mali block allocator create for region starting at 0x%08X length 0x%08X\n", base_address, size));
49 MALI_DEBUG_PRINT(4, ("%d usable bytes\n", usable_size));
50 num_blocks = usable_size / MALI_BLOCK_SIZE;
51 MALI_DEBUG_PRINT(4, ("which becomes %d blocks\n", num_blocks));
53 if (usable_size == 0) {
54 MALI_DEBUG_PRINT(1, ("Memory block of size %d is unusable\n", size));
58 info = _mali_osk_malloc(sizeof(block_allocator));
60 mutex_init(&info->mutex);
61 info->all_blocks = _mali_osk_malloc(sizeof(block_info) * num_blocks);
62 if (NULL != info->all_blocks) {
64 info->first_free = NULL;
65 info->num_blocks = num_blocks;
66 info->free_blocks = num_blocks;
68 info->base = base_address;
69 info->cpu_usage_adjust = cpu_usage_adjust;
71 for ( i = 0; i < num_blocks; i++) {
72 info->all_blocks[i].next = info->first_free;
73 info->first_free = &info->all_blocks[i];
76 return (mali_mem_allocator *)info;
84 void mali_mem_block_allocator_destroy(mali_mem_allocator *allocator)
86 block_allocator *info = (block_allocator*)allocator;
88 info = mali_mem_block_gobal_allocator;
89 if (NULL == info) return;
91 MALI_DEBUG_ASSERT_POINTER(info);
93 _mali_osk_free(info->all_blocks);
97 static void mali_mem_block_mali_map(mali_mem_allocation *descriptor, u32 phys, u32 virt, u32 size)
99 struct mali_page_directory *pagedir = descriptor->session->page_directory;
100 u32 prop = descriptor->mali_mapping.properties;
104 mali_mmu_pagedir_update(pagedir, virt + offset, phys + offset, MALI_MMU_PAGE_SIZE, prop);
106 size -= MALI_MMU_PAGE_SIZE;
107 offset += MALI_MMU_PAGE_SIZE;
111 static int mali_mem_block_cpu_map(mali_mem_allocation *descriptor, struct vm_area_struct *vma, u32 mali_phys, u32 mapping_offset, u32 size, u32 cpu_usage_adjust)
113 u32 virt = vma->vm_start + mapping_offset;
114 u32 cpu_phys = mali_phys + cpu_usage_adjust;
119 ret = vm_insert_pfn(vma, virt + offset, __phys_to_pfn(cpu_phys + offset));
122 MALI_DEBUG_PRINT(1, ("Block allocator: Failed to insert pfn into vma\n"));
126 size -= MALI_MMU_PAGE_SIZE;
127 offset += MALI_MMU_PAGE_SIZE;
133 mali_mem_allocation *mali_mem_block_alloc(u32 mali_addr, u32 size, struct vm_area_struct *vma, struct mali_session_data *session)
135 _mali_osk_errcode_t err;
136 mali_mem_allocation *descriptor;
137 block_allocator *info;
139 block_info *last_allocated = NULL;
140 block_allocator_allocation *ret_allocation;
143 size = ALIGN(size, MALI_BLOCK_SIZE);
145 info = mali_mem_block_gobal_allocator;
146 if (NULL == info) return NULL;
149 MALI_DEBUG_ASSERT(0 != left);
151 descriptor = mali_mem_descriptor_create(session, MALI_MEM_BLOCK);
152 if (NULL == descriptor) {
156 descriptor->mali_mapping.addr = mali_addr;
157 descriptor->size = size;
158 descriptor->cpu_mapping.addr = (void __user*)vma->vm_start;
159 descriptor->cpu_mapping.ref = 1;
161 if (VM_SHARED == (VM_SHARED & vma->vm_flags)) {
162 descriptor->mali_mapping.properties = MALI_MMU_FLAGS_DEFAULT;
164 /* Cached Mali memory mapping */
165 descriptor->mali_mapping.properties = MALI_MMU_FLAGS_FORCE_GP_READ_ALLOCATE;
166 vma->vm_flags |= VM_SHARED;
169 ret_allocation = &descriptor->block_mem.mem;
171 ret_allocation->mapping_length = 0;
173 _mali_osk_mutex_wait(session->memory_lock);
174 mutex_lock(&info->mutex);
176 if (left > (info->free_blocks * MALI_BLOCK_SIZE)) {
177 MALI_DEBUG_PRINT(2, ("Mali block allocator: not enough free blocks to service allocation (%u)\n", left));
178 mutex_unlock(&info->mutex);
179 _mali_osk_mutex_signal(session->memory_lock);
180 mali_mem_descriptor_destroy(descriptor);
184 err = mali_mem_mali_map_prepare(descriptor);
185 if (_MALI_OSK_ERR_OK != err) {
186 mutex_unlock(&info->mutex);
187 _mali_osk_mutex_signal(session->memory_lock);
188 mali_mem_descriptor_destroy(descriptor);
192 while ((left > 0) && (info->first_free)) {
195 u32 current_mapping_size;
197 block = info->first_free;
198 info->first_free = info->first_free->next;
199 block->next = last_allocated;
200 last_allocated = block;
202 phys_addr = get_phys(info, block);
204 if (MALI_BLOCK_SIZE < left) {
205 current_mapping_size = MALI_BLOCK_SIZE;
207 current_mapping_size = left;
210 mali_mem_block_mali_map(descriptor, phys_addr, mali_addr + offset, current_mapping_size);
211 if (mali_mem_block_cpu_map(descriptor, vma, phys_addr, offset, current_mapping_size, info->cpu_usage_adjust)) {
212 /* release all memory back to the pool */
213 while (last_allocated) {
214 /* This relinks every block we've just allocated back into the free-list */
215 block = last_allocated->next;
216 last_allocated->next = info->first_free;
217 info->first_free = last_allocated;
218 last_allocated = block;
221 mutex_unlock(&info->mutex);
222 _mali_osk_mutex_signal(session->memory_lock);
224 mali_mem_mali_map_free(descriptor);
225 mali_mem_descriptor_destroy(descriptor);
230 left -= current_mapping_size;
231 offset += current_mapping_size;
232 ret_allocation->mapping_length += current_mapping_size;
237 mutex_unlock(&info->mutex);
238 _mali_osk_mutex_signal(session->memory_lock);
240 MALI_DEBUG_ASSERT(0 == left);
242 /* Record all the information about this allocation */
243 ret_allocation->last_allocated = last_allocated;
244 ret_allocation->info = info;
249 void mali_mem_block_release(mali_mem_allocation *descriptor)
251 block_allocator *info = descriptor->block_mem.mem.info;
252 block_info *block, *next;
253 block_allocator_allocation *allocation = &descriptor->block_mem.mem;
255 MALI_DEBUG_ASSERT(MALI_MEM_BLOCK == descriptor->type);
257 block = allocation->last_allocated;
259 MALI_DEBUG_ASSERT_POINTER(block);
262 mali_mem_mali_map_free(descriptor);
264 mutex_lock(&info->mutex);
267 MALI_DEBUG_ASSERT(!((block < info->all_blocks) || (block > (info->all_blocks + info->num_blocks))));
271 /* relink into free-list */
272 block->next = info->first_free;
273 info->first_free = block;
275 /* advance the loop */
281 mutex_unlock(&info->mutex);
284 u32 mali_mem_block_allocator_stat(void)
286 block_allocator *info = (block_allocator *)mali_mem_block_gobal_allocator;
288 if (NULL == info) return 0;
290 MALI_DEBUG_ASSERT_POINTER(info);
292 return (info->num_blocks - info->free_blocks) * MALI_BLOCK_SIZE;
295 _mali_osk_errcode_t mali_memory_core_resource_dedicated_memory(u32 start, u32 size)
297 mali_mem_allocator *allocator;
299 /* Do the low level linux operation first */
301 /* Request ownership of the memory */
302 if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(start, size, "Dedicated Mali GPU memory")) {
303 MALI_DEBUG_PRINT(1, ("Failed to request memory region for frame buffer (0x%08X - 0x%08X)\n", start, start + size - 1));
304 return _MALI_OSK_ERR_FAULT;
307 /* Create generic block allocator object to handle it */
308 allocator = mali_mem_block_allocator_create(start, 0 /* cpu_usage_adjust */, size);
310 if (NULL == allocator) {
311 MALI_DEBUG_PRINT(1, ("Memory bank registration failed\n"));
312 _mali_osk_mem_unreqregion(start, size);
313 MALI_ERROR(_MALI_OSK_ERR_FAULT);
316 mali_mem_block_gobal_allocator = (block_allocator*)allocator;
318 return _MALI_OSK_ERR_OK;