upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / media / video / samsung / ump / common / ump_kernel_api.c
1 /*
2  * Copyright (C) 2010 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_osk.h"
12 #include "mali_osk_list.h"
13 #include "ump_osk.h"
14 #include "ump_uk_types.h"
15 #include "ump_kernel_interface.h"
16 #include "ump_kernel_common.h"
17
18 #include <asm/cacheflush.h>
19
20
21
22 /* ---------------- UMP kernel space API functions follows ---------------- */
23
24
25
26 UMP_KERNEL_API_EXPORT ump_secure_id ump_dd_secure_id_get(ump_dd_handle memh)
27 {
28         ump_dd_mem * mem = (ump_dd_mem *)memh;
29
30         DEBUG_ASSERT_POINTER(mem);
31
32         DBG_MSG(5, ("Returning secure ID. ID: %u\n", mem->secure_id));
33
34         return mem->secure_id;
35 }
36
37
38
39 UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_secure_id(ump_secure_id secure_id)
40 {
41         ump_dd_mem * mem;
42
43         _mali_osk_lock_wait(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
44
45         DBG_MSG(5, ("Getting handle from secure ID. ID: %u\n", secure_id));
46         if (0 != ump_descriptor_mapping_get(device.secure_id_map, (int)secure_id, (void**)&mem))
47         {
48                 _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
49                 DBG_MSG(1, ("Secure ID not found. ID: %u\n", secure_id));
50                 return UMP_DD_HANDLE_INVALID;
51         }
52
53         ump_dd_reference_add(mem);
54
55         _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
56
57         return (ump_dd_handle)mem;
58 }
59
60 UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_get(ump_secure_id secure_id)
61 {
62         ump_dd_mem * mem;
63
64         _mali_osk_lock_wait(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
65
66         DBG_MSG(5, ("Getting handle from secure ID. ID: %u\n", secure_id));
67         if (0 != ump_descriptor_mapping_get(device.secure_id_map, (int)secure_id, (void**)&mem))
68         {
69                 _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
70                 DBG_MSG(1, ("Secure ID not found. ID: %u\n", secure_id));
71                 return UMP_DD_HANDLE_INVALID;
72         }
73
74         _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
75
76         return (ump_dd_handle)mem;
77 }
78
79 UMP_KERNEL_API_EXPORT unsigned long ump_dd_phys_block_count_get(ump_dd_handle memh)
80 {
81         ump_dd_mem * mem = (ump_dd_mem*) memh;
82
83         DEBUG_ASSERT_POINTER(mem);
84
85         return mem->nr_blocks;
86 }
87
88
89
90 UMP_KERNEL_API_EXPORT ump_dd_status_code ump_dd_phys_blocks_get(ump_dd_handle memh, ump_dd_physical_block * blocks, unsigned long num_blocks)
91 {
92         ump_dd_mem * mem = (ump_dd_mem *)memh;
93
94         DEBUG_ASSERT_POINTER(mem);
95
96         if (blocks == NULL)
97         {
98                 DBG_MSG(1, ("NULL parameter in ump_dd_phys_blocks_get()\n"));
99                 return UMP_DD_INVALID;
100         }
101
102         if (mem->nr_blocks != num_blocks)
103         {
104                 DBG_MSG(1, ("Specified number of blocks do not match actual number of blocks\n"));
105                 return UMP_DD_INVALID;
106         }
107
108         DBG_MSG(5, ("Returning physical block information. ID: %u\n", mem->secure_id));
109
110         _mali_osk_memcpy(blocks, mem->block_array, sizeof(ump_dd_physical_block) * mem->nr_blocks);
111
112         return UMP_DD_SUCCESS;
113 }
114
115
116
117 UMP_KERNEL_API_EXPORT ump_dd_status_code ump_dd_phys_block_get(ump_dd_handle memh, unsigned long index, ump_dd_physical_block * block)
118 {
119         ump_dd_mem * mem = (ump_dd_mem *)memh;
120
121         DEBUG_ASSERT_POINTER(mem);
122
123         if (block == NULL)
124         {
125                 DBG_MSG(1, ("NULL parameter in ump_dd_phys_block_get()\n"));
126                 return UMP_DD_INVALID;
127         }
128
129         if (index >= mem->nr_blocks)
130         {
131                 DBG_MSG(5, ("Invalid index specified in ump_dd_phys_block_get()\n"));
132                 return UMP_DD_INVALID;
133         }
134
135         DBG_MSG(5, ("Returning physical block information. ID: %u, index: %lu\n", mem->secure_id, index));
136
137         *block = mem->block_array[index];
138
139         return UMP_DD_SUCCESS;
140 }
141
142
143
144 UMP_KERNEL_API_EXPORT unsigned long ump_dd_size_get(ump_dd_handle memh)
145 {
146         ump_dd_mem * mem = (ump_dd_mem*)memh;
147
148         DEBUG_ASSERT_POINTER(mem);
149
150         DBG_MSG(5, ("Returning size. ID: %u, size: %lu\n", mem->secure_id, mem->size_bytes));
151
152         return mem->size_bytes;
153 }
154
155
156
157 UMP_KERNEL_API_EXPORT void ump_dd_reference_add(ump_dd_handle memh)
158 {
159         ump_dd_mem * mem = (ump_dd_mem*)memh;
160         int new_ref;
161
162         DEBUG_ASSERT_POINTER(mem);
163
164         new_ref = _ump_osk_atomic_inc_and_read(&mem->ref_count);
165
166         DBG_MSG(4, ("Memory reference incremented. ID: %u, new value: %d\n", mem->secure_id, new_ref));
167 }
168
169
170
171 UMP_KERNEL_API_EXPORT void ump_dd_reference_release(ump_dd_handle memh)
172 {
173         int new_ref;
174         ump_dd_mem * mem = (ump_dd_mem*)memh;
175
176         DEBUG_ASSERT_POINTER(mem);
177
178         /* We must hold this mutex while doing the atomic_dec_and_read, to protect
179         that elements in the ump_descriptor_mapping table is always valid.  If they
180         are not, userspace may accidently map in this secure_ids right before its freed
181         giving a mapped backdoor into unallocated memory.*/
182         _mali_osk_lock_wait(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
183
184         new_ref = _ump_osk_atomic_dec_and_read(&mem->ref_count);
185
186         DBG_MSG(4, ("Memory reference decremented. ID: %u, new value: %d\n", mem->secure_id, new_ref));
187
188         if (0 == new_ref)
189         {
190                 DBG_MSG(3, ("Final release of memory. ID: %u\n", mem->secure_id));
191
192                 ump_descriptor_mapping_free(device.secure_id_map, (int)mem->secure_id);
193
194                 _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
195                 mem->release_func(mem->ctx, mem);
196                 _mali_osk_free(mem);
197         }
198         else
199         {
200                 _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
201         }
202 }
203
204
205
206 /* --------------- Handling of user space requests follows --------------- */
207
208
209 _mali_osk_errcode_t _ump_uku_get_api_version( _ump_uk_api_version_s *args )
210 {
211         ump_session_data * session_data;
212
213         DEBUG_ASSERT_POINTER( args );
214         DEBUG_ASSERT_POINTER( args->ctx );
215
216         session_data = (ump_session_data *)args->ctx;
217
218         /* check compatability */
219         if (args->version == UMP_IOCTL_API_VERSION)
220         {
221                 DBG_MSG(3, ("API version set to newest %d (compatible)\n", GET_VERSION(args->version)));
222                 args->compatible = 1;
223                 session_data->api_version = args->version;
224         }
225         else if (args->version == MAKE_VERSION_ID(1))
226         {
227                 DBG_MSG(2, ("API version set to depricated: %d (compatible)\n", GET_VERSION(args->version)));
228                 args->compatible = 1;
229                 session_data->api_version = args->version;
230         }
231         else
232         {
233                 DBG_MSG(2, ("API version set to %d (incompatible with client version %d)\n", GET_VERSION(UMP_IOCTL_API_VERSION), GET_VERSION(args->version)));
234                 args->compatible = 0;
235                 args->version = UMP_IOCTL_API_VERSION; /* report our version */
236         }
237
238         return _MALI_OSK_ERR_OK;
239 }
240
241
242 _mali_osk_errcode_t _ump_ukk_release( _ump_uk_release_s *release_info )
243 {
244         ump_session_memory_list_element * session_memory_element;
245         ump_session_memory_list_element * tmp;
246         ump_session_data * session_data;
247         _mali_osk_errcode_t ret = _MALI_OSK_ERR_INVALID_FUNC;
248         int secure_id;
249
250         DEBUG_ASSERT_POINTER( release_info );
251         DEBUG_ASSERT_POINTER( release_info->ctx );
252
253         /* Retreive the session data */
254         session_data = (ump_session_data*)release_info->ctx;
255
256         /* If there are many items in the memory session list we
257          * could be de-referencing this pointer a lot so keep a local copy
258          */
259         secure_id = release_info->secure_id;
260
261         DBG_MSG(4, ("Releasing memory with IOCTL, ID: %u\n", secure_id));
262
263         /* Iterate through the memory list looking for the requested secure ID */
264         _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW);
265         _MALI_OSK_LIST_FOREACHENTRY(session_memory_element, tmp, &session_data->list_head_session_memory_list, ump_session_memory_list_element, list)
266         {
267                 if ( session_memory_element->mem->secure_id == secure_id)
268                 {
269                         ump_dd_mem *release_mem;
270
271                         release_mem = session_memory_element->mem;
272                         _mali_osk_list_del(&session_memory_element->list);
273                         ump_dd_reference_release(release_mem);
274                         _mali_osk_free(session_memory_element);
275
276                         ret = _MALI_OSK_ERR_OK;
277                         break;
278                 }
279         }
280
281         _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW);
282         DBG_MSG_IF(1, _MALI_OSK_ERR_OK != ret, ("UMP memory with ID %u does not belong to this session.\n", secure_id));
283
284         DBG_MSG(4, ("_ump_ukk_release() returning 0x%x\n", ret));
285         return ret;
286 }
287
288 _mali_osk_errcode_t _ump_ukk_size_get( _ump_uk_size_get_s *user_interaction )
289 {
290         ump_dd_mem * mem;
291         _mali_osk_errcode_t ret = _MALI_OSK_ERR_FAULT;
292
293         DEBUG_ASSERT_POINTER( user_interaction );
294
295         /* We lock the mappings so things don't get removed while we are looking for the memory */
296         _mali_osk_lock_wait(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
297         if (0 == ump_descriptor_mapping_get(device.secure_id_map, (int)user_interaction->secure_id, (void**)&mem))
298         {
299                 user_interaction->size = mem->size_bytes;
300                 DBG_MSG(4, ("Returning size. ID: %u, size: %lu ", (ump_secure_id)user_interaction->secure_id, (unsigned long)user_interaction->size));
301                 ret = _MALI_OSK_ERR_OK;
302         }
303         else
304         {
305                  user_interaction->size = 0;
306                 DBG_MSG(1, ("Failed to look up mapping in ump_ioctl_size_get(). ID: %u\n", (ump_secure_id)user_interaction->secure_id));
307         }
308
309         _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
310         return ret;
311 }
312
313
314
315 void _ump_ukk_msync( _ump_uk_msync_s *args )
316 {
317         ump_dd_mem * mem = NULL;
318
319         if (args->op == _UMP_UK_MSYNC_CLEAN_ALL_AND_INVALIDATE_ALL)
320         {
321                 __cpuc_flush_kern_all();
322                 smp_call_function(__cpuc_flush_kern_all, NULL, 1);
323                 outer_flush_all();
324                 return;
325         }
326
327         _mali_osk_lock_wait(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
328         ump_descriptor_mapping_get(device.secure_id_map, (int)args->secure_id, (void**)&mem);
329         _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
330
331         if (NULL==mem)
332         {
333                 DBG_MSG(1, ("Failed to look up mapping in _ump_ukk_msync(). ID: %u\n", (ump_secure_id)args->secure_id));
334                 return;
335         }
336
337         /* Returns the cache settings back to Userspace */
338         args->is_cached=mem->is_cached;
339
340         /* If this flag is the only one set, we should not do the actual flush, only the readout */
341         if ( _UMP_UK_MSYNC_READOUT_CACHE_ENABLED==args->op )
342         {
343                 DBG_MSG(3, ("_ump_ukk_msync READOUT  ID: %u Enabled: %d\n", (ump_secure_id)args->secure_id, mem->is_cached));
344                 return;
345         }
346
347         /* Nothing to do if the memory is not caches */
348         if ( 0==mem->is_cached )
349         {
350                 DBG_MSG(3, ("_ump_ukk_msync IGNORING ID: %u Enabled: %d  OP: %d\n", (ump_secure_id)args->secure_id, mem->is_cached, args->op));
351                 return ;
352         }
353         DBG_MSG(3, ("_ump_ukk_msync FLUSHING ID: %u Enabled: %d  OP: %d\n", (ump_secure_id)args->secure_id, mem->is_cached, args->op));
354
355         /* The actual cache flush - Implemented for each OS*/
356         _ump_osk_msync( mem , args->op, (u32)args->mapping, (u32)args->address, args->size);
357 }