/*
|
* Copyright (C) 2013-2017 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;
|
}
|
|