/* | |
* Copyright (C) 2010, 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. | |
*/ | |
/** | |
* @file mali_osk_bitmap.c | |
* Implementation of the OS abstraction layer for the kernel device driver | |
*/ | |
#include <linux/errno.h> | |
#include <linux/slab.h> | |
#include <linux/mm.h> | |
#include <linux/bitmap.h> | |
#include <linux/vmalloc.h> | |
#include "common/mali_kernel_common.h" | |
#include "mali_osk_types.h" | |
#include "mali_osk.h" | |
u32 _mali_osk_bitmap_alloc(struct _mali_osk_bitmap *bitmap) | |
{ | |
u32 obj; | |
MALI_DEBUG_ASSERT_POINTER(bitmap); | |
_mali_osk_spinlock_lock(bitmap->lock); | |
obj = find_next_zero_bit(bitmap->table, bitmap->max, bitmap->reserve); | |
if (obj < bitmap->max) { | |
set_bit(obj, bitmap->table); | |
} else { | |
obj = -1; | |
} | |
if (obj != -1) | |
--bitmap->avail; | |
_mali_osk_spinlock_unlock(bitmap->lock); | |
return obj; | |
} | |
void _mali_osk_bitmap_free(struct _mali_osk_bitmap *bitmap, u32 obj) | |
{ | |
MALI_DEBUG_ASSERT_POINTER(bitmap); | |
_mali_osk_bitmap_free_range(bitmap, obj, 1); | |
} | |
u32 _mali_osk_bitmap_alloc_range(struct _mali_osk_bitmap *bitmap, int cnt) | |
{ | |
u32 obj; | |
MALI_DEBUG_ASSERT_POINTER(bitmap); | |
if (0 >= cnt) { | |
return -1; | |
} | |
if (1 == cnt) { | |
return _mali_osk_bitmap_alloc(bitmap); | |
} | |
_mali_osk_spinlock_lock(bitmap->lock); | |
obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max, | |
bitmap->last, cnt, 0); | |
if (obj >= bitmap->max) { | |
obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max, | |
bitmap->reserve, cnt, 0); | |
} | |
if (obj < bitmap->max) { | |
bitmap_set(bitmap->table, obj, cnt); | |
bitmap->last = (obj + cnt); | |
if (bitmap->last >= bitmap->max) { | |
bitmap->last = bitmap->reserve; | |
} | |
} else { | |
obj = -1; | |
} | |
if (obj != -1) { | |
bitmap->avail -= cnt; | |
} | |
_mali_osk_spinlock_unlock(bitmap->lock); | |
return obj; | |
} | |
u32 _mali_osk_bitmap_avail(struct _mali_osk_bitmap *bitmap) | |
{ | |
MALI_DEBUG_ASSERT_POINTER(bitmap); | |
return bitmap->avail; | |
} | |
void _mali_osk_bitmap_free_range(struct _mali_osk_bitmap *bitmap, u32 obj, int cnt) | |
{ | |
MALI_DEBUG_ASSERT_POINTER(bitmap); | |
_mali_osk_spinlock_lock(bitmap->lock); | |
bitmap_clear(bitmap->table, obj, cnt); | |
bitmap->last = min(bitmap->last, obj); | |
bitmap->avail += cnt; | |
_mali_osk_spinlock_unlock(bitmap->lock); | |
} | |
int _mali_osk_bitmap_init(struct _mali_osk_bitmap *bitmap, u32 num, u32 reserve) | |
{ | |
MALI_DEBUG_ASSERT_POINTER(bitmap); | |
MALI_DEBUG_ASSERT(reserve <= num); | |
bitmap->reserve = reserve; | |
bitmap->last = reserve; | |
bitmap->max = num; | |
bitmap->avail = num - reserve; | |
bitmap->lock = _mali_osk_spinlock_init(_MALI_OSK_LOCKFLAG_UNORDERED, _MALI_OSK_LOCK_ORDER_FIRST); | |
if (!bitmap->lock) { | |
return _MALI_OSK_ERR_NOMEM; | |
} | |
bitmap->table = kzalloc(BITS_TO_LONGS(bitmap->max) * | |
sizeof(long), GFP_KERNEL); | |
if (!bitmap->table) { | |
_mali_osk_spinlock_term(bitmap->lock); | |
return _MALI_OSK_ERR_NOMEM; | |
} | |
return _MALI_OSK_ERR_OK; | |
} | |
void _mali_osk_bitmap_term(struct _mali_osk_bitmap *bitmap) | |
{ | |
MALI_DEBUG_ASSERT_POINTER(bitmap); | |
if (NULL != bitmap->lock) { | |
_mali_osk_spinlock_term(bitmap->lock); | |
} | |
if (NULL != bitmap->table) { | |
kfree(bitmap->table); | |
} | |
} | |