| /* |
| * Copyright (C) 2013-2016 ARM Limited. All rights reserved. |
| * |
| * This program is free software and is provided to you under the terms of the GNU General Public License version 2 |
| * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. |
| * |
| * A copy of the licence is included with the program, and can also be obtained from Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| */ |
| |
| #include <linux/list.h> |
| #include <linux/mm.h> |
| #include <linux/mm_types.h> |
| #include <linux/fs.h> |
| #include <linux/dma-mapping.h> |
| #include <linux/slab.h> |
| #include <linux/platform_device.h> |
| |
| #include "mali_osk.h" |
| #include "mali_osk_mali.h" |
| #include "mali_kernel_linux.h" |
| #include "mali_scheduler.h" |
| #include "mali_memory_os_alloc.h" |
| #include "mali_memory_manager.h" |
| #include "mali_memory_virtual.h" |
| |
| |
| /** |
| *internal helper to link node into the rb-tree |
| */ |
| static inline void _mali_vma_offset_add_rb(struct mali_allocation_manager *mgr, |
| struct mali_vma_node *node) |
| { |
| struct rb_node **iter = &mgr->allocation_mgr_rb.rb_node; |
| struct rb_node *parent = NULL; |
| struct mali_vma_node *iter_node; |
| |
| while (likely(*iter)) { |
| parent = *iter; |
| iter_node = rb_entry(*iter, struct mali_vma_node, vm_rb); |
| |
| if (node->vm_node.start < iter_node->vm_node.start) |
| iter = &(*iter)->rb_left; |
| else if (node->vm_node.start > iter_node->vm_node.start) |
| iter = &(*iter)->rb_right; |
| else |
| MALI_DEBUG_ASSERT(0); |
| } |
| |
| rb_link_node(&node->vm_rb, parent, iter); |
| rb_insert_color(&node->vm_rb, &mgr->allocation_mgr_rb); |
| } |
| |
| /** |
| * mali_vma_offset_add() - Add offset node to RB Tree |
| */ |
| int mali_vma_offset_add(struct mali_allocation_manager *mgr, |
| struct mali_vma_node *node) |
| { |
| int ret = 0; |
| write_lock(&mgr->vm_lock); |
| |
| if (node->vm_node.allocated) { |
| goto out; |
| } |
| |
| _mali_vma_offset_add_rb(mgr, node); |
| /* set to allocated */ |
| node->vm_node.allocated = 1; |
| |
| out: |
| write_unlock(&mgr->vm_lock); |
| return ret; |
| } |
| |
| /** |
| * mali_vma_offset_remove() - Remove offset node from RB tree |
| */ |
| void mali_vma_offset_remove(struct mali_allocation_manager *mgr, |
| struct mali_vma_node *node) |
| { |
| write_lock(&mgr->vm_lock); |
| |
| if (node->vm_node.allocated) { |
| rb_erase(&node->vm_rb, &mgr->allocation_mgr_rb); |
| memset(&node->vm_node, 0, sizeof(node->vm_node)); |
| } |
| write_unlock(&mgr->vm_lock); |
| } |
| |
| /** |
| * mali_vma_offset_search - Search the node in RB tree |
| */ |
| struct mali_vma_node *mali_vma_offset_search(struct mali_allocation_manager *mgr, |
| unsigned long start, unsigned long pages) |
| { |
| struct mali_vma_node *node, *best; |
| struct rb_node *iter; |
| unsigned long offset; |
| read_lock(&mgr->vm_lock); |
| |
| iter = mgr->allocation_mgr_rb.rb_node; |
| best = NULL; |
| |
| while (likely(iter)) { |
| node = rb_entry(iter, struct mali_vma_node, vm_rb); |
| offset = node->vm_node.start; |
| if (start >= offset) { |
| iter = iter->rb_right; |
| best = node; |
| if (start == offset) |
| break; |
| } else { |
| iter = iter->rb_left; |
| } |
| } |
| |
| if (best) { |
| offset = best->vm_node.start + best->vm_node.size; |
| if (offset <= start + pages) |
| best = NULL; |
| } |
| read_unlock(&mgr->vm_lock); |
| |
| return best; |
| } |
| |