tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / ump / common / ump_kernel_common.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_osk.h"
13 #include "mali_osk_bitops.h"
14 #include "mali_osk_list.h"
15 #include "ump_osk.h"
16 #include "ump_uk_types.h"
17 #include "ump_ukk.h"
18 #include "ump_kernel_common.h"
19 #include "ump_kernel_descriptor_mapping.h"
20 #include "ump_kernel_memory_backend.h"
21
22
23
24 /**
25  * Define the initial and maximum size of number of secure_ids on the system
26  */
27 #define UMP_SECURE_ID_TABLE_ENTRIES_INITIAL (128  )
28 #define UMP_SECURE_ID_TABLE_ENTRIES_MAXIMUM (4096 )
29
30
31 /**
32  * Define the initial and maximum size of the ump_session_data::cookies_map,
33  * which is a \ref ump_descriptor_mapping. This limits how many secure_ids
34  * may be mapped into a particular process using _ump_ukk_map_mem().
35  */
36
37 #define UMP_COOKIES_PER_SESSION_INITIAL (UMP_SECURE_ID_TABLE_ENTRIES_INITIAL )
38 #define UMP_COOKIES_PER_SESSION_MAXIMUM (UMP_SECURE_ID_TABLE_ENTRIES_MAXIMUM)
39
40 struct ump_dev device;
41
42 _mali_osk_errcode_t ump_kernel_constructor(void)
43 {
44         _mali_osk_errcode_t err;
45
46         /* Perform OS Specific initialization */
47         err = _ump_osk_init();
48         if( _MALI_OSK_ERR_OK != err )
49         {
50                 MSG_ERR(("Failed to initiaze the UMP Device Driver"));
51                 return err;
52         }
53
54         /* Init the global device */
55         _mali_osk_memset(&device, 0, sizeof(device) );
56
57         /* Create the descriptor map, which will be used for mapping secure ID to ump_dd_mem structs */
58         device.secure_id_map_lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0 , 0);
59         if (NULL == device.secure_id_map_lock)
60         {
61                 MSG_ERR(("Failed to create OSK lock for secure id lookup table\n"));
62                 return _MALI_OSK_ERR_NOMEM;
63         }
64
65         device.secure_id_map = ump_descriptor_mapping_create(UMP_SECURE_ID_TABLE_ENTRIES_INITIAL, UMP_SECURE_ID_TABLE_ENTRIES_MAXIMUM);
66         if (NULL == device.secure_id_map)
67         {
68                 _mali_osk_lock_term(device.secure_id_map_lock);
69                 MSG_ERR(("Failed to create secure id lookup table\n"));
70                 return _MALI_OSK_ERR_NOMEM;
71         }
72
73         /* Init memory backend */
74         device.backend = ump_memory_backend_create();
75         if (NULL == device.backend)
76         {
77                 MSG_ERR(("Failed to create memory backend\n"));
78                 _mali_osk_lock_term(device.secure_id_map_lock);
79                 ump_descriptor_mapping_destroy(device.secure_id_map);
80                 return _MALI_OSK_ERR_NOMEM;
81         }
82
83         return _MALI_OSK_ERR_OK;
84 }
85
86 void ump_kernel_destructor(void)
87 {
88         DEBUG_ASSERT_POINTER(device.secure_id_map);
89         DEBUG_ASSERT_POINTER(device.secure_id_map_lock);
90
91         _mali_osk_lock_term(device.secure_id_map_lock);
92         device.secure_id_map_lock = NULL;
93
94         ump_descriptor_mapping_destroy(device.secure_id_map);
95         device.secure_id_map = NULL;
96
97         device.backend->shutdown(device.backend);
98         device.backend = NULL;
99
100         ump_memory_backend_destroy();
101
102         _ump_osk_term();
103 }
104
105 /** Creates a new UMP session
106  */
107 _mali_osk_errcode_t _ump_ukk_open( void** context )
108 {
109         struct ump_session_data * session_data;
110
111         /* allocated struct to track this session */
112         session_data = (struct ump_session_data *)_mali_osk_malloc(sizeof(struct ump_session_data));
113         if (NULL == session_data)
114         {
115                 MSG_ERR(("Failed to allocate ump_session_data in ump_file_open()\n"));
116                 return _MALI_OSK_ERR_NOMEM;
117         }
118
119         session_data->lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 0);
120         if( NULL == session_data->lock )
121         {
122                 MSG_ERR(("Failed to initialize lock for ump_session_data in ump_file_open()\n"));
123                 _mali_osk_free(session_data);
124                 return _MALI_OSK_ERR_NOMEM;
125         }
126
127         session_data->cookies_map = ump_descriptor_mapping_create( UMP_COOKIES_PER_SESSION_INITIAL, UMP_COOKIES_PER_SESSION_MAXIMUM );
128
129         if ( NULL == session_data->cookies_map )
130         {
131                 MSG_ERR(("Failed to create descriptor mapping for _ump_ukk_map_mem cookies\n"));
132
133                 _mali_osk_lock_term( session_data->lock );
134                 _mali_osk_free( session_data );
135                 return _MALI_OSK_ERR_NOMEM;
136         }
137
138         _MALI_OSK_INIT_LIST_HEAD(&session_data->list_head_session_memory_list);
139
140         _MALI_OSK_INIT_LIST_HEAD(&session_data->list_head_session_memory_mappings_list);
141
142         /* Since initial version of the UMP interface did not use the API_VERSION ioctl we have to assume
143            that it is this version, and not the "latest" one: UMP_IOCTL_API_VERSION
144            Current and later API versions would do an additional call to this IOCTL and update this variable
145            to the correct one.*/
146         session_data->api_version = MAKE_VERSION_ID(1);
147
148         *context = (void*)session_data;
149
150         session_data->cache_operations_ongoing = 0 ;
151         session_data->has_pending_level1_cache_flush = 0;
152
153         DBG_MSG(2, ("New session opened\n"));
154
155         return _MALI_OSK_ERR_OK;
156 }
157
158 _mali_osk_errcode_t _ump_ukk_close( void** context )
159 {
160         struct ump_session_data * session_data;
161         ump_session_memory_list_element * item;
162         ump_session_memory_list_element * tmp;
163
164         session_data = (struct ump_session_data *)*context;
165         if (NULL == session_data)
166         {
167                 MSG_ERR(("Session data is NULL in _ump_ukk_close()\n"));
168                 return _MALI_OSK_ERR_INVALID_ARGS;
169         }
170
171         /* Unmap any descriptors mapped in. */
172         if (0 == _mali_osk_list_empty(&session_data->list_head_session_memory_mappings_list))
173         {
174                 ump_memory_allocation *descriptor;
175                 ump_memory_allocation *temp;
176
177                 DBG_MSG(1, ("Memory mappings found on session usage list during session termination\n"));
178
179                 /* use the 'safe' list iterator, since freeing removes the active block from the list we're iterating */
180                 _MALI_OSK_LIST_FOREACHENTRY(descriptor, temp, &session_data->list_head_session_memory_mappings_list, ump_memory_allocation, list)
181                 {
182                         _ump_uk_unmap_mem_s unmap_args;
183                         DBG_MSG(4, ("Freeing block with phys address 0x%x size 0x%x mapped in user space at 0x%x\n",
184                                     descriptor->phys_addr, descriptor->size, descriptor->mapping));
185                         unmap_args.ctx = (void*)session_data;
186                         unmap_args.mapping = descriptor->mapping;
187                         unmap_args.size = descriptor->size;
188                         unmap_args._ukk_private = NULL; /* NOTE: unused */
189                         unmap_args.cookie = descriptor->cookie;
190
191                         /* NOTE: This modifies the list_head_session_memory_mappings_list */
192                         _ump_ukk_unmap_mem( &unmap_args );
193                 }
194         }
195
196         /* ASSERT that we really did free everything, because _ump_ukk_unmap_mem()
197          * can fail silently. */
198         DEBUG_ASSERT( _mali_osk_list_empty(&session_data->list_head_session_memory_mappings_list) );
199
200         _MALI_OSK_LIST_FOREACHENTRY(item, tmp, &session_data->list_head_session_memory_list, ump_session_memory_list_element, list)
201         {
202                 _mali_osk_list_del(&item->list);
203                 DBG_MSG(2, ("Releasing UMP memory %u as part of file close\n", item->mem->secure_id));
204                 ump_dd_reference_release(item->mem);
205                 _mali_osk_free(item);
206         }
207
208         ump_descriptor_mapping_destroy( session_data->cookies_map );
209
210         _mali_osk_lock_term(session_data->lock);
211         _mali_osk_free(session_data);
212
213         DBG_MSG(2, ("Session closed\n"));
214
215         return _MALI_OSK_ERR_OK;
216 }
217
218 _mali_osk_errcode_t _ump_ukk_map_mem( _ump_uk_map_mem_s *args )
219 {
220         struct ump_session_data * session_data;
221         ump_memory_allocation * descriptor;  /* Describes current mapping of memory */
222         _mali_osk_errcode_t err;
223         unsigned long offset = 0;
224         unsigned long left;
225         ump_dd_handle handle;  /* The real UMP handle for this memory. Its real datatype is ump_dd_mem*  */
226         ump_dd_mem * mem;      /* The real UMP memory. It is equal to the handle, but with exposed struct */
227         u32 block;
228         int map_id;
229
230         session_data = (ump_session_data *)args->ctx;
231         if( NULL == session_data )
232         {
233                 MSG_ERR(("Session data is NULL in _ump_ukk_map_mem()\n"));
234                 return _MALI_OSK_ERR_INVALID_ARGS;
235         }
236         /* MALI_SEC */
237         /* SEC kernel stability 2012-02-17 */
238         if (NULL == session_data->cookies_map)
239         {
240                 MSG_ERR(("session_data->cookies_map is NULL in _ump_ukk_map_mem()\n"));
241                 return _MALI_OSK_ERR_INVALID_ARGS;
242         }
243         descriptor = (ump_memory_allocation*) _mali_osk_calloc( 1, sizeof(ump_memory_allocation));
244         if (NULL == descriptor)
245         {
246                 MSG_ERR(("ump_ukk_map_mem: descriptor allocation failed\n"));
247                 return _MALI_OSK_ERR_NOMEM;
248         }
249
250         handle = ump_dd_handle_create_from_secure_id(args->secure_id);
251         if ( UMP_DD_HANDLE_INVALID == handle)
252         {
253                 _mali_osk_free(descriptor);
254                 DBG_MSG(1, ("Trying to map unknown secure ID %u\n", args->secure_id));
255                 return _MALI_OSK_ERR_FAULT;
256         }
257
258         mem = (ump_dd_mem*)handle;
259         DEBUG_ASSERT(mem);
260         if (mem->size_bytes != args->size)
261         {
262                 _mali_osk_free(descriptor);
263                 ump_dd_reference_release(handle);
264                 DBG_MSG(1, ("Trying to map too much or little. ID: %u, virtual size=%lu, UMP size: %lu\n", args->secure_id, args->size, mem->size_bytes));
265                 return _MALI_OSK_ERR_FAULT;
266         }
267
268         map_id = ump_descriptor_mapping_allocate_mapping( session_data->cookies_map, (void*) descriptor );
269
270         if (map_id < 0)
271         {
272                 _mali_osk_free(descriptor);
273                 ump_dd_reference_release(handle);
274                 DBG_MSG(1, ("ump_ukk_map_mem: unable to allocate a descriptor_mapping for return cookie\n"));
275
276                 return _MALI_OSK_ERR_NOMEM;
277         }
278
279         descriptor->size = args->size;
280         descriptor->handle = handle;
281         descriptor->phys_addr = args->phys_addr;
282         descriptor->process_mapping_info = args->_ukk_private;
283         descriptor->ump_session = session_data;
284         descriptor->cookie = (u32)map_id;
285
286         if ( mem->is_cached )
287         {
288                 descriptor->is_cached = 1;
289                 args->is_cached       = 1;
290                 DBG_MSG(3, ("Mapping UMP secure_id: %d as cached.\n", args->secure_id));
291         }
292         else if ( args->is_cached) /* MALI_SEC */
293         {
294                 mem->is_cached = 1;
295                 descriptor->is_cached = 1;
296                 DBG_MSG(3, ("Warning mapping UMP secure_id: %d. As cached, while it was allocated uncached.\n", args->secure_id));
297         }
298         else
299         {
300                 descriptor->is_cached = 0;
301                 args->is_cached       = 0;
302                 DBG_MSG(3, ("Mapping UMP secure_id: %d  as Uncached.\n", args->secure_id));
303         }
304
305         _mali_osk_list_init( &descriptor->list );
306
307         err = _ump_osk_mem_mapregion_init( descriptor );
308         if( _MALI_OSK_ERR_OK != err )
309         {
310                 DBG_MSG(1, ("Failed to initialize memory mapping in _ump_ukk_map_mem(). ID: %u\n", args->secure_id));
311                 ump_descriptor_mapping_free( session_data->cookies_map, map_id );
312                 _mali_osk_free(descriptor);
313                 ump_dd_reference_release(mem);
314                 return err;
315         }
316
317         DBG_MSG(4, ("Mapping virtual to physical memory: ID: %u, size:%lu, first physical addr: 0x%08lx, number of regions: %lu\n",
318                 mem->secure_id,
319                 mem->size_bytes,
320                 ((NULL != mem->block_array) ? mem->block_array->addr : 0),
321                 mem->nr_blocks));
322
323         left = descriptor->size;
324         /* loop over all blocks and map them in */
325         for (block = 0; block < mem->nr_blocks; block++)
326         {
327                 unsigned long size_to_map;
328
329                 if (left >  mem->block_array[block].size)
330                 {
331                         size_to_map = mem->block_array[block].size;
332                 }
333                 else
334                 {
335                         size_to_map = left;
336                 }
337
338                 if (_MALI_OSK_ERR_OK != _ump_osk_mem_mapregion_map(descriptor, offset, (u32 *)&(mem->block_array[block].addr), size_to_map ) )
339                 {
340                         DBG_MSG(1, ("WARNING: _ump_ukk_map_mem failed to map memory into userspace\n"));
341                         ump_descriptor_mapping_free( session_data->cookies_map, map_id );
342                         ump_dd_reference_release(mem);
343                         _ump_osk_mem_mapregion_term( descriptor );
344                         _mali_osk_free(descriptor);
345                         return _MALI_OSK_ERR_FAULT;
346                 }
347                 left -= size_to_map;
348                 offset += size_to_map;
349         }
350
351         /* Add to the ump_memory_allocation tracking list */
352         _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW);
353         _mali_osk_list_add( &descriptor->list, &session_data->list_head_session_memory_mappings_list );
354         _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW);
355
356         args->mapping = descriptor->mapping;
357         args->cookie = descriptor->cookie;
358
359         return _MALI_OSK_ERR_OK;
360 }
361
362 void _ump_ukk_unmap_mem( _ump_uk_unmap_mem_s *args )
363 {
364         struct ump_session_data * session_data;
365         ump_memory_allocation * descriptor;
366         ump_dd_handle handle;
367
368         session_data = (ump_session_data *)args->ctx;
369
370         if( NULL == session_data )
371         {
372                 MSG_ERR(("Session data is NULL in _ump_ukk_map_mem()\n"));
373                 return;
374         }
375         /* MALI_SEC */
376         /* SEC kernel stability 2012-02-17 */
377         if (NULL == session_data->cookies_map)
378         {
379                 MSG_ERR(("session_data->cookies_map is NULL in _ump_ukk_map_mem()\n"));
380                 return;
381         }
382         if (0 != ump_descriptor_mapping_get( session_data->cookies_map, (int)args->cookie, (void**)&descriptor) )
383         {
384                 MSG_ERR(("_ump_ukk_map_mem: cookie 0x%X not found for this session\n", args->cookie ));
385                 return;
386         }
387
388         DEBUG_ASSERT_POINTER(descriptor);
389
390         handle = descriptor->handle;
391         if ( UMP_DD_HANDLE_INVALID == handle)
392         {
393                 DBG_MSG(1, ("WARNING: Trying to unmap unknown handle: UNKNOWN\n"));
394                 return;
395         }
396
397         /* Remove the ump_memory_allocation from the list of tracked mappings */
398         _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW);
399         _mali_osk_list_del( &descriptor->list );
400         _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW);
401
402         ump_descriptor_mapping_free( session_data->cookies_map, (int)args->cookie );
403
404         ump_dd_reference_release(handle);
405
406         _ump_osk_mem_mapregion_term( descriptor );
407         _mali_osk_free(descriptor);
408 }
409
410 u32 _ump_ukk_report_memory_usage( void )
411 {
412         if(device.backend->stat)
413                 return device.backend->stat(device.backend);
414         else
415                 return 0;
416 }