tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / mali / common / mali_kernel_descriptor_mapping.c
1 /*
2  * Copyright (C) 2011-2012 ARM Limited. All rights reserved.
3  *
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  *
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10
11 #include "mali_kernel_common.h"
12 #include "mali_kernel_descriptor_mapping.h"
13 #include "mali_osk.h"
14 #include "mali_osk_bitops.h"
15
16 #define MALI_PAD_INT(x) (((x) + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1))
17
18 /**
19  * Allocate a descriptor table capable of holding 'count' mappings
20  * @param count Number of mappings in the table
21  * @return Pointer to a new table, NULL on error
22  */
23 static mali_descriptor_table * descriptor_table_alloc(int count);
24
25 /**
26  * Free a descriptor table
27  * @param table The table to free
28  */
29 static void descriptor_table_free(mali_descriptor_table * table);
30
31 mali_descriptor_mapping * mali_descriptor_mapping_create(int init_entries, int max_entries)
32 {
33         mali_descriptor_mapping * map = _mali_osk_calloc(1, sizeof(mali_descriptor_mapping));
34
35         init_entries = MALI_PAD_INT(init_entries);
36         max_entries = MALI_PAD_INT(max_entries);
37
38         if (NULL != map)
39         {
40                 map->table = descriptor_table_alloc(init_entries);
41                 if (NULL != map->table)
42                 {
43             map->lock = _mali_osk_lock_init( (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, _MALI_OSK_LOCK_ORDER_DESCRIPTOR_MAP);
44             if (NULL != map->lock)
45             {
46                             _mali_osk_set_nonatomic_bit(0, map->table->usage); /* reserve bit 0 to prevent NULL/zero logic to kick in */
47                             map->max_nr_mappings_allowed = max_entries;
48                             map->current_nr_mappings = init_entries;
49                             return map;
50             }
51                 descriptor_table_free(map->table);
52                 }
53                 _mali_osk_free(map);
54         }
55         return NULL;
56 }
57
58 void mali_descriptor_mapping_destroy(mali_descriptor_mapping * map)
59 {
60         descriptor_table_free(map->table);
61     _mali_osk_lock_term(map->lock);
62         _mali_osk_free(map);
63 }
64
65 _mali_osk_errcode_t mali_descriptor_mapping_allocate_mapping(mali_descriptor_mapping * map, void * target, int *odescriptor)
66 {
67         _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT;
68         int new_descriptor;
69
70     MALI_DEBUG_ASSERT_POINTER(map);
71     MALI_DEBUG_ASSERT_POINTER(odescriptor);
72
73     _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RW);
74         new_descriptor = _mali_osk_find_first_zero_bit(map->table->usage, map->current_nr_mappings);
75         if (new_descriptor == map->current_nr_mappings)
76         {
77                 /* no free descriptor, try to expand the table */
78                 mali_descriptor_table * new_table, * old_table;
79                 if (map->current_nr_mappings >= map->max_nr_mappings_allowed) goto unlock_and_exit;
80
81         map->current_nr_mappings += BITS_PER_LONG;
82                 new_table = descriptor_table_alloc(map->current_nr_mappings);
83                 if (NULL == new_table) goto unlock_and_exit;
84
85         old_table = map->table;
86                 _mali_osk_memcpy(new_table->usage, old_table->usage, (sizeof(unsigned long)*map->current_nr_mappings) / BITS_PER_LONG);
87                 _mali_osk_memcpy(new_table->mappings, old_table->mappings, map->current_nr_mappings * sizeof(void*));
88                 map->table = new_table;
89                 descriptor_table_free(old_table);
90         }
91
92         /* we have found a valid descriptor, set the value and usage bit */
93         _mali_osk_set_nonatomic_bit(new_descriptor, map->table->usage);
94         map->table->mappings[new_descriptor] = target;
95         *odescriptor = new_descriptor;
96     err = _MALI_OSK_ERR_OK;
97
98 unlock_and_exit:
99     _mali_osk_lock_signal(map->lock, _MALI_OSK_LOCKMODE_RW);
100     MALI_ERROR(err);
101 }
102
103 void mali_descriptor_mapping_call_for_each(mali_descriptor_mapping * map, void (*callback)(int, void*))
104 {
105         int i;
106
107         MALI_DEBUG_ASSERT_POINTER(map);
108         MALI_DEBUG_ASSERT_POINTER(callback);
109
110     _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RO);
111         /* id 0 is skipped as it's an reserved ID not mapping to anything */
112         for (i = 1; i < map->current_nr_mappings; ++i)
113         {
114                 if (_mali_osk_test_bit(i, map->table->usage))
115                 {
116                         callback(i, map->table->mappings[i]);
117                 }
118         }
119     _mali_osk_lock_signal(map->lock, _MALI_OSK_LOCKMODE_RO);
120 }
121
122 _mali_osk_errcode_t mali_descriptor_mapping_get(mali_descriptor_mapping * map, int descriptor, void** target)
123 {
124         _mali_osk_errcode_t result = _MALI_OSK_ERR_FAULT;
125         MALI_DEBUG_ASSERT_POINTER(map);
126     _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RO);
127         if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) )
128         {
129                 *target = map->table->mappings[descriptor];
130                 result = _MALI_OSK_ERR_OK;
131         }
132         else *target = NULL;
133     _mali_osk_lock_signal(map->lock, _MALI_OSK_LOCKMODE_RO);
134         MALI_ERROR(result);
135 }
136
137 _mali_osk_errcode_t mali_descriptor_mapping_set(mali_descriptor_mapping * map, int descriptor, void * target)
138 {
139         _mali_osk_errcode_t result = _MALI_OSK_ERR_FAULT;
140     _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RO);
141         if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) )
142         {
143                 map->table->mappings[descriptor] = target;
144                 result = _MALI_OSK_ERR_OK;
145         }
146     _mali_osk_lock_signal(map->lock, _MALI_OSK_LOCKMODE_RO);
147         MALI_ERROR(result);
148 }
149
150 void *mali_descriptor_mapping_free(mali_descriptor_mapping * map, int descriptor)
151 {
152         void *old_value = NULL;
153
154     _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RW);
155         if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) )
156         {
157                 old_value = map->table->mappings[descriptor];
158                 map->table->mappings[descriptor] = NULL;
159                 _mali_osk_clear_nonatomic_bit(descriptor, map->table->usage);
160         }
161     _mali_osk_lock_signal(map->lock, _MALI_OSK_LOCKMODE_RW);
162
163         return old_value;
164 }
165
166 static mali_descriptor_table * descriptor_table_alloc(int count)
167 {
168         mali_descriptor_table * table;
169
170         table = _mali_osk_calloc(1, sizeof(mali_descriptor_table) + ((sizeof(unsigned long) * count)/BITS_PER_LONG) + (sizeof(void*) * count));
171
172         if (NULL != table)
173         {
174                 table->usage = (u32*)((u8*)table + sizeof(mali_descriptor_table));
175                 table->mappings = (void**)((u8*)table + sizeof(mali_descriptor_table) + ((sizeof(unsigned long) * count)/BITS_PER_LONG));
176         }
177
178         return table;
179 }
180
181 static void descriptor_table_free(mali_descriptor_table * table)
182 {
183         _mali_osk_free(table);
184 }