mali mess
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / gpu / mt8127 / mali / mali / linux / mali_memory_block_alloc.c
CommitLineData
6fa3eb70
S
1/*
2 * This confidential and proprietary software may be used only as
3 * authorised by a licensing agreement from ARM Limited
02af6beb 4 * (C) COPYRIGHT 2008-2015 ARM Limited
6fa3eb70
S
5 * ALL RIGHTS RESERVED
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.
9 */
02af6beb 10
6fa3eb70
S
11#include "mali_kernel_common.h"
12#include "mali_memory.h"
13#include "mali_memory_block_alloc.h"
14#include "mali_osk.h"
15#include <linux/mutex.h>
6fa3eb70 16
6fa3eb70 17
02af6beb
S
18static mali_block_allocator *mali_mem_block_gobal_allocator = NULL;
19
20unsigned long _mali_blk_item_get_phy_addr(mali_block_item *item)
21{
22 return (item->phy_addr & ~(MALI_BLOCK_REF_MASK));
23}
6fa3eb70
S
24
25
02af6beb
S
26unsigned long _mali_blk_item_get_pfn(mali_block_item *item)
27{
28 return (item->phy_addr / MALI_BLOCK_SIZE);
29}
30
31
32u32 mali_mem_block_get_ref_count(mali_page_node *node)
33{
34 MALI_DEBUG_ASSERT(node->type == MALI_PAGE_NODE_BLOCK);
35 return (node->blk_it->phy_addr & MALI_BLOCK_REF_MASK);
36}
37
6fa3eb70 38
02af6beb
S
39/* Increase the refence count
40* It not atomic, so it need to get sp_lock before call this function
41*/
6fa3eb70 42
02af6beb 43u32 mali_mem_block_add_ref(mali_page_node *node)
6fa3eb70 44{
02af6beb
S
45 MALI_DEBUG_ASSERT(node->type == MALI_PAGE_NODE_BLOCK);
46 MALI_DEBUG_ASSERT(mali_mem_block_get_ref_count(node) < MALI_BLOCK_MAX_REF_COUNT);
47 return (node->blk_it->phy_addr++ & MALI_BLOCK_REF_MASK);
6fa3eb70
S
48}
49
02af6beb
S
50/* Decase the refence count
51* It not atomic, so it need to get sp_lock before call this function
52*/
53u32 mali_mem_block_dec_ref(mali_page_node *node)
6fa3eb70 54{
02af6beb
S
55 MALI_DEBUG_ASSERT(node->type == MALI_PAGE_NODE_BLOCK);
56 MALI_DEBUG_ASSERT(mali_mem_block_get_ref_count(node) > 0);
57 return (node->blk_it->phy_addr-- & MALI_BLOCK_REF_MASK);
58}
59
60
61static mali_block_allocator *mali_mem_block_allocator_create(u32 base_address, u32 size)
62{
63 mali_block_allocator *info;
6fa3eb70
S
64 u32 usable_size;
65 u32 num_blocks;
02af6beb
S
66 mali_page_node *m_node;
67 mali_block_item *mali_blk_items = NULL;
68 int i = 0;
6fa3eb70
S
69
70 usable_size = size & ~(MALI_BLOCK_SIZE - 1);
71 MALI_DEBUG_PRINT(3, ("Mali block allocator create for region starting at 0x%08X length 0x%08X\n", base_address, size));
72 MALI_DEBUG_PRINT(4, ("%d usable bytes\n", usable_size));
73 num_blocks = usable_size / MALI_BLOCK_SIZE;
74 MALI_DEBUG_PRINT(4, ("which becomes %d blocks\n", num_blocks));
75
76 if (usable_size == 0) {
77 MALI_DEBUG_PRINT(1, ("Memory block of size %d is unusable\n", size));
78 return NULL;
79 }
80
02af6beb 81 info = _mali_osk_calloc(1, sizeof(mali_block_allocator));
6fa3eb70 82 if (NULL != info) {
02af6beb
S
83 INIT_LIST_HEAD(&info->free);
84 spin_lock_init(&info->sp_lock);
85 info->total_num = num_blocks;
86 mali_blk_items = _mali_osk_calloc(1, sizeof(mali_block_item) * num_blocks);
87
88 if (mali_blk_items) {
89 info->items = mali_blk_items;
90 /* add blocks(4k size) to free list*/
91 for (i = 0 ; i < num_blocks ; i++) {
92 /* add block information*/
93 mali_blk_items[i].phy_addr = base_address + (i * MALI_BLOCK_SIZE);
94 /* add to free list */
95 m_node = _mali_page_node_allocate(MALI_PAGE_NODE_BLOCK);
96 if (m_node == NULL)
97 goto fail;
98 _mali_page_node_add_block_item(m_node, &(mali_blk_items[i]));
99 list_add_tail(&m_node->list, &info->free);
100 atomic_add(1, &info->free_num);
6fa3eb70 101 }
02af6beb 102 return info;
6fa3eb70 103 }
6fa3eb70 104 }
02af6beb
S
105fail:
106 mali_mem_block_allocator_destroy();
6fa3eb70
S
107 return NULL;
108}
109
02af6beb 110void mali_mem_block_allocator_destroy(void)
6fa3eb70 111{
02af6beb
S
112 struct mali_page_node *m_page, *m_tmp;
113 mali_block_allocator *info = mali_mem_block_gobal_allocator;
114 MALI_DEBUG_ASSERT_POINTER(info);
115 MALI_DEBUG_PRINT(4, ("Memory block destroy !\n"));
6fa3eb70 116
02af6beb
S
117 if (NULL == info)
118 return;
6fa3eb70 119
02af6beb
S
120 list_for_each_entry_safe(m_page, m_tmp , &info->free, list) {
121 MALI_DEBUG_ASSERT(m_page->type == MALI_PAGE_NODE_BLOCK);
122 list_del(&m_page->list);
123 kfree(m_page);
124 }
6fa3eb70 125
02af6beb 126 _mali_osk_free(info->items);
6fa3eb70
S
127 _mali_osk_free(info);
128}
129
02af6beb 130u32 mali_mem_block_release(mali_mem_backend *mem_bkend)
6fa3eb70 131{
02af6beb
S
132 mali_mem_allocation *alloc = mem_bkend->mali_allocation;
133 u32 free_pages_nr = 0;
134 MALI_DEBUG_ASSERT(mem_bkend->type == MALI_MEM_BLOCK);
135
136 /* Unmap the memory from the mali virtual address space. */
137 mali_mem_block_mali_unmap(alloc);
138 mutex_lock(&mem_bkend->mutex);
139 free_pages_nr = mali_mem_block_free(&mem_bkend->block_mem);
140 mutex_unlock(&mem_bkend->mutex);
141 return free_pages_nr;
6fa3eb70
S
142}
143
6fa3eb70 144
02af6beb
S
145int mali_mem_block_alloc(mali_mem_block_mem *block_mem, u32 size)
146{
147 struct mali_page_node *m_page, *m_tmp;
148 size_t page_count = PAGE_ALIGN(size) / _MALI_OSK_MALI_PAGE_SIZE;
149 mali_block_allocator *info = mali_mem_block_gobal_allocator;
150 MALI_DEBUG_ASSERT_POINTER(info);
6fa3eb70 151
02af6beb
S
152 MALI_DEBUG_PRINT(4, ("BLOCK Mem: Allocate size = 0x%x\n", size));
153 /*do some init */
154 INIT_LIST_HEAD(&block_mem->pfns);
155
156 spin_lock(&info->sp_lock);
157 /*check if have enough space*/
158 if (atomic_read(&info->free_num) > page_count) {
159 list_for_each_entry_safe(m_page, m_tmp , &info->free, list) {
160 if (page_count > 0) {
161 MALI_DEBUG_ASSERT(m_page->type == MALI_PAGE_NODE_BLOCK);
162 MALI_DEBUG_ASSERT(mali_mem_block_get_ref_count(m_page) == 0);
163 list_move(&m_page->list, &block_mem->pfns);
164 block_mem->count++;
165 atomic_dec(&info->free_num);
166 _mali_page_node_ref(m_page);
167 } else {
168 break;
169 }
170 page_count--;
6fa3eb70 171 }
02af6beb
S
172 } else {
173 /* can't allocate from BLOCK memory*/
174 spin_unlock(&info->sp_lock);
175 return -1;
6fa3eb70
S
176 }
177
02af6beb 178 spin_unlock(&info->sp_lock);
6fa3eb70
S
179 return 0;
180}
181
02af6beb 182u32 mali_mem_block_free(mali_mem_block_mem *block_mem)
6fa3eb70 183{
02af6beb 184 u32 free_pages_nr = 0;
6fa3eb70 185
02af6beb
S
186 free_pages_nr = mali_mem_block_free_list(&block_mem->pfns);
187 MALI_DEBUG_PRINT(4, ("BLOCK Mem free : allocated size = 0x%x, free size = 0x%x\n", block_mem->count * _MALI_OSK_MALI_PAGE_SIZE,
188 free_pages_nr * _MALI_OSK_MALI_PAGE_SIZE));
189 block_mem->count = 0;
190 MALI_DEBUG_ASSERT(list_empty(&block_mem->pfns));
6fa3eb70 191
02af6beb
S
192 return free_pages_nr;
193}
6fa3eb70 194
6fa3eb70 195
02af6beb
S
196u32 mali_mem_block_free_list(struct list_head *list)
197{
198 struct mali_page_node *m_page, *m_tmp;
199 mali_block_allocator *info = mali_mem_block_gobal_allocator;
200 u32 free_pages_nr = 0;
201
202 if (info) {
203 spin_lock(&info->sp_lock);
204 list_for_each_entry_safe(m_page, m_tmp , list, list) {
205 if (1 == _mali_page_node_get_ref_count(m_page)) {
206 free_pages_nr++;
207 }
208 mali_mem_block_free_node(m_page);
209 }
210 spin_unlock(&info->sp_lock);
6fa3eb70 211 }
02af6beb
S
212 return free_pages_nr;
213}
6fa3eb70 214
02af6beb
S
215/* free the node,*/
216void mali_mem_block_free_node(struct mali_page_node *node)
217{
218 mali_block_allocator *info = mali_mem_block_gobal_allocator;
219
220 /* only handle BLOCK node */
221 if (node->type == MALI_PAGE_NODE_BLOCK && info) {
222 /*Need to make this atomic?*/
223 if (1 == _mali_page_node_get_ref_count(node)) {
224 /*Move to free list*/
225 _mali_page_node_unref(node);
226 list_move_tail(&node->list, &info->free);
227 atomic_add(1, &info->free_num);
6fa3eb70 228 } else {
02af6beb
S
229 _mali_page_node_unref(node);
230 list_del(&node->list);
231 kfree(node);
6fa3eb70 232 }
02af6beb
S
233 }
234}
6fa3eb70 235
02af6beb
S
236/* unref the node, but not free it */
237_mali_osk_errcode_t mali_mem_block_unref_node(struct mali_page_node *node)
238{
239 mali_block_allocator *info = mali_mem_block_gobal_allocator;
240 mali_page_node *new_node;
241
242 /* only handle BLOCK node */
243 if (node->type == MALI_PAGE_NODE_BLOCK && info) {
244 /*Need to make this atomic?*/
245 if (1 == _mali_page_node_get_ref_count(node)) {
246 /* allocate a new node, Add to free list, keep the old node*/
247 _mali_page_node_unref(node);
248 new_node = _mali_page_node_allocate(MALI_PAGE_NODE_BLOCK);
249 if (new_node) {
250 memcpy(new_node, node, sizeof(mali_page_node));
251 list_add(&new_node->list, &info->free);
252 atomic_add(1, &info->free_num);
253 } else
254 return _MALI_OSK_ERR_FAULT;
6fa3eb70 255
02af6beb
S
256 } else {
257 _mali_page_node_unref(node);
6fa3eb70 258 }
6fa3eb70 259 }
02af6beb
S
260 return _MALI_OSK_ERR_OK;
261}
6fa3eb70 262
6fa3eb70 263
02af6beb
S
264int mali_mem_block_mali_map(mali_mem_block_mem *block_mem, struct mali_session_data *session, u32 vaddr, u32 props)
265{
266 struct mali_page_directory *pagedir = session->page_directory;
267 struct mali_page_node *m_page;
268 dma_addr_t phys;
269 u32 virt = vaddr;
270 u32 prop = props;
271
272 list_for_each_entry(m_page, &block_mem->pfns, list) {
273 MALI_DEBUG_ASSERT(m_page->type == MALI_PAGE_NODE_BLOCK);
274 phys = _mali_page_node_get_phy_addr(m_page);
275#if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT)
276 /* Verify that the "physical" address is 32-bit and
277 * usable for Mali, when on a system with bus addresses
278 * wider than 32-bit. */
279 MALI_DEBUG_ASSERT(0 == (phys >> 32));
280#endif
281 mali_mmu_pagedir_update(pagedir, virt, (mali_dma_addr)phys, MALI_MMU_PAGE_SIZE, prop);
282 virt += MALI_MMU_PAGE_SIZE;
283 }
6fa3eb70 284
02af6beb 285 return 0;
6fa3eb70
S
286}
287
02af6beb 288void mali_mem_block_mali_unmap(mali_mem_allocation *alloc)
6fa3eb70 289{
02af6beb
S
290 struct mali_session_data *session;
291 MALI_DEBUG_ASSERT_POINTER(alloc);
292 session = alloc->session;
293 MALI_DEBUG_ASSERT_POINTER(session);
294
295 mali_session_memory_lock(session);
296 mali_mem_mali_map_free(session, alloc->psize, alloc->mali_vma_node.vm_node.start,
297 alloc->flags);
298 mali_session_memory_unlock(session);
299}
6fa3eb70 300
6fa3eb70 301
02af6beb
S
302int mali_mem_block_cpu_map(mali_mem_backend *mem_bkend, struct vm_area_struct *vma)
303{
304 int ret;
305 mali_mem_block_mem *block_mem = &mem_bkend->block_mem;
306 unsigned long addr = vma->vm_start;
307 struct mali_page_node *m_page;
308 MALI_DEBUG_ASSERT(mem_bkend->type == MALI_MEM_BLOCK);
6fa3eb70 309
02af6beb
S
310 list_for_each_entry(m_page, &block_mem->pfns, list) {
311 MALI_DEBUG_ASSERT(m_page->type == MALI_PAGE_NODE_BLOCK);
312 ret = vm_insert_pfn(vma, addr, _mali_page_node_get_pfn(m_page));
6fa3eb70 313
02af6beb
S
314 if (unlikely(0 != ret)) {
315 return -EFAULT;
316 }
317 addr += _MALI_OSK_MALI_PAGE_SIZE;
6fa3eb70 318
6fa3eb70
S
319 }
320
02af6beb 321 return 0;
6fa3eb70
S
322}
323
6fa3eb70
S
324
325_mali_osk_errcode_t mali_memory_core_resource_dedicated_memory(u32 start, u32 size)
326{
02af6beb 327 mali_block_allocator *allocator;
6fa3eb70
S
328
329 /* Do the low level linux operation first */
330
331 /* Request ownership of the memory */
332 if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(start, size, "Dedicated Mali GPU memory")) {
333 MALI_DEBUG_PRINT(1, ("Failed to request memory region for frame buffer (0x%08X - 0x%08X)\n", start, start + size - 1));
334 return _MALI_OSK_ERR_FAULT;
335 }
336
337 /* Create generic block allocator object to handle it */
02af6beb 338 allocator = mali_mem_block_allocator_create(start, size);
6fa3eb70
S
339
340 if (NULL == allocator) {
341 MALI_DEBUG_PRINT(1, ("Memory bank registration failed\n"));
342 _mali_osk_mem_unreqregion(start, size);
343 MALI_ERROR(_MALI_OSK_ERR_FAULT);
344 }
345
02af6beb 346 mali_mem_block_gobal_allocator = (mali_block_allocator *)allocator;
6fa3eb70
S
347
348 return _MALI_OSK_ERR_OK;
349}
02af6beb
S
350
351mali_bool mali_memory_have_dedicated_memory(void)
352{
353 return mali_mem_block_gobal_allocator ? MALI_TRUE : MALI_FALSE;
354}
355
356u32 mali_mem_block_allocator_stat(void)
357{
358 mali_block_allocator *allocator = mali_mem_block_gobal_allocator;
359 MALI_DEBUG_ASSERT_POINTER(allocator);
360
361 return (allocator->total_num - atomic_read(&allocator->free_num)) * _MALI_OSK_MALI_PAGE_SIZE;
362}