| /* |
| * 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 (cnt <= 0) { |
| return -1; |
| } |
| |
| if (cnt == 1) { |
| 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 (bitmap->lock != NULL) { |
| _mali_osk_spinlock_term(bitmap->lock); |
| } |
| |
| if (bitmap->table != NULL) { |
| kfree(bitmap->table); |
| } |
| } |
| |