tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / gpu / arm / mali400 / r5p0_rel0 / linux / mali_ukk_mem.c
1 /*
2  * Copyright (C) 2010-2014 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 #include <linux/fs.h>       /* file system operations */
11 #include <asm/uaccess.h>    /* user space access */
12
13 #include "mali_ukk.h"
14 #include "mali_osk.h"
15 #include "mali_kernel_common.h"
16 #include "mali_session.h"
17 #include "mali_ukk_wrappers.h"
18
19 int mem_init_wrapper(struct mali_session_data *session_data, _mali_uk_init_mem_s __user *uargs)
20 {
21     _mali_uk_init_mem_s kargs;
22     _mali_osk_errcode_t err;
23
24     MALI_CHECK_NON_NULL(uargs, -EINVAL);
25
26     kargs.ctx = (uintptr_t)session_data;
27     err = _mali_ukk_init_mem(&kargs);
28     if (_MALI_OSK_ERR_OK != err)
29     {
30         return map_errcode(err);
31     }
32
33     if (0 != put_user(kargs.mali_address_base, &uargs->mali_address_base)) goto mem_init_rollback;
34     if (0 != put_user(kargs.memory_size, &uargs->memory_size)) goto mem_init_rollback;
35
36     return 0;
37
38 mem_init_rollback:
39         {
40                 _mali_uk_term_mem_s kargs;
41                 kargs.ctx = (uintptr_t)session_data;
42                 err = _mali_ukk_term_mem(&kargs);
43                 if (_MALI_OSK_ERR_OK != err)
44                 {
45                         MALI_DEBUG_PRINT(4, ("reverting _mali_ukk_init_mem, as a result of failing put_user(), failed\n"));
46                 }
47         }
48     return -EFAULT;
49 }
50
51 int mem_term_wrapper(struct mali_session_data *session_data, _mali_uk_term_mem_s __user *uargs)
52 {
53     _mali_uk_term_mem_s kargs;
54     _mali_osk_errcode_t err;
55
56     MALI_CHECK_NON_NULL(uargs, -EINVAL);
57
58     kargs.ctx = (uintptr_t)session_data;
59     err = _mali_ukk_term_mem(&kargs);
60     if (_MALI_OSK_ERR_OK != err)
61     {
62         return map_errcode(err);
63     }
64
65     return 0;
66 }
67
68 int mem_write_safe_wrapper(struct mali_session_data *session_data, _mali_uk_mem_write_safe_s __user * uargs)
69 {
70         _mali_uk_mem_write_safe_s kargs;
71         _mali_osk_errcode_t err;
72
73         MALI_CHECK_NON_NULL(uargs, -EINVAL);
74         MALI_CHECK_NON_NULL(session_data, -EINVAL);
75
76         if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_mem_write_safe_s))) {
77                 return -EFAULT;
78         }
79
80         kargs.ctx = (uintptr_t)session_data;
81
82         /* Check if we can access the buffers */
83         if (!access_ok(VERIFY_WRITE, kargs.dest, kargs.size)
84             || !access_ok(VERIFY_READ, kargs.src, kargs.size)) {
85                 return -EINVAL;
86         }
87
88         /* Check if size wraps */
89         if ((kargs.size + kargs.dest) <= kargs.dest
90             || (kargs.size + kargs.src) <= kargs.src) {
91                 return -EINVAL;
92         }
93
94         err = _mali_ukk_mem_write_safe(&kargs);
95         if (_MALI_OSK_ERR_OK != err) {
96                 return map_errcode(err);
97         }
98
99         if (0 != put_user(kargs.size, &uargs->size)) {
100                 return -EFAULT;
101         }
102
103         return 0;
104 }
105
106 int mem_map_ext_wrapper(struct mali_session_data *session_data, _mali_uk_map_external_mem_s __user *argument)
107 {
108         _mali_uk_map_external_mem_s uk_args;
109         _mali_osk_errcode_t err_code;
110
111         /* validate input */
112         /* the session_data pointer was validated by caller */
113         MALI_CHECK_NON_NULL(argument, -EINVAL);
114
115         /* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
116         if (0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_map_external_mem_s))) {
117                 return -EFAULT;
118         }
119
120         uk_args.ctx = (uintptr_t)session_data;
121         err_code = _mali_ukk_map_external_mem(&uk_args);
122
123         if (0 != put_user(uk_args.cookie, &argument->cookie)) {
124                 if (_MALI_OSK_ERR_OK == err_code) {
125                         /* Rollback */
126                         _mali_uk_unmap_external_mem_s uk_args_unmap;
127
128                         uk_args_unmap.ctx = (uintptr_t)session_data;
129                         uk_args_unmap.cookie = uk_args.cookie;
130                         err_code = _mali_ukk_unmap_external_mem(&uk_args_unmap);
131                         if (_MALI_OSK_ERR_OK != err_code) {
132                                 MALI_DEBUG_PRINT(4, ("reverting _mali_ukk_unmap_external_mem, as a result of failing put_user(), failed\n"));
133                         }
134                 }
135                 return -EFAULT;
136         }
137
138         /* Return the error that _mali_ukk_free_big_block produced */
139         return map_errcode(err_code);
140 }
141
142 int mem_unmap_ext_wrapper(struct mali_session_data *session_data, _mali_uk_unmap_external_mem_s __user *argument)
143 {
144         _mali_uk_unmap_external_mem_s uk_args;
145         _mali_osk_errcode_t err_code;
146
147         /* validate input */
148         /* the session_data pointer was validated by caller */
149         MALI_CHECK_NON_NULL(argument, -EINVAL);
150
151         /* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
152         if (0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_unmap_external_mem_s))) {
153                 return -EFAULT;
154         }
155
156         uk_args.ctx = (uintptr_t)session_data;
157         err_code = _mali_ukk_unmap_external_mem(&uk_args);
158
159         /* Return the error that _mali_ukk_free_big_block produced */
160         return map_errcode(err_code);
161 }
162
163 #if defined(CONFIG_MALI400_UMP)
164 int mem_release_ump_wrapper(struct mali_session_data *session_data, _mali_uk_release_ump_mem_s __user *argument)
165 {
166         _mali_uk_release_ump_mem_s uk_args;
167         _mali_osk_errcode_t err_code;
168
169         /* validate input */
170         /* the session_data pointer was validated by caller */
171         MALI_CHECK_NON_NULL(argument, -EINVAL);
172
173         /* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
174         if (0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_release_ump_mem_s))) {
175                 return -EFAULT;
176         }
177
178         uk_args.ctx = (uintptr_t)session_data;
179         err_code = _mali_ukk_release_ump_mem(&uk_args);
180
181         /* Return the error that _mali_ukk_free_big_block produced */
182         return map_errcode(err_code);
183 }
184
185 int mem_attach_ump_wrapper(struct mali_session_data *session_data, _mali_uk_attach_ump_mem_s __user *argument)
186 {
187         _mali_uk_attach_ump_mem_s uk_args;
188         _mali_osk_errcode_t err_code;
189
190         /* validate input */
191         /* the session_data pointer was validated by caller */
192         MALI_CHECK_NON_NULL(argument, -EINVAL);
193
194         /* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
195         if (0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_attach_ump_mem_s))) {
196                 return -EFAULT;
197         }
198
199         uk_args.ctx = (uintptr_t)session_data;
200         err_code = _mali_ukk_attach_ump_mem(&uk_args);
201
202         if (0 != put_user(uk_args.cookie, &argument->cookie)) {
203                 if (_MALI_OSK_ERR_OK == err_code) {
204                         /* Rollback */
205                         _mali_uk_release_ump_mem_s uk_args_unmap;
206
207                         uk_args_unmap.ctx = (uintptr_t)session_data;
208                         uk_args_unmap.cookie = uk_args.cookie;
209                         err_code = _mali_ukk_release_ump_mem(&uk_args_unmap);
210                         if (_MALI_OSK_ERR_OK != err_code) {
211                                 MALI_DEBUG_PRINT(4, ("reverting _mali_ukk_attach_mem, as a result of failing put_user(), failed\n"));
212                         }
213                 }
214                 return -EFAULT;
215         }
216
217         /* Return the error that _mali_ukk_map_external_ump_mem produced */
218         return map_errcode(err_code);
219 }
220 #endif /* CONFIG_MALI400_UMP */
221
222 int mem_query_mmu_page_table_dump_size_wrapper(struct mali_session_data *session_data, _mali_uk_query_mmu_page_table_dump_size_s __user *uargs)
223 {
224         _mali_uk_query_mmu_page_table_dump_size_s kargs;
225         _mali_osk_errcode_t err;
226
227         MALI_CHECK_NON_NULL(uargs, -EINVAL);
228         MALI_CHECK_NON_NULL(session_data, -EINVAL);
229
230         kargs.ctx = (uintptr_t)session_data;
231
232         err = _mali_ukk_query_mmu_page_table_dump_size(&kargs);
233         if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
234
235         if (0 != put_user(kargs.size, &uargs->size)) return -EFAULT;
236
237         return 0;
238 }
239
240 int mem_dump_mmu_page_table_wrapper(struct mali_session_data *session_data, _mali_uk_dump_mmu_page_table_s __user *uargs)
241 {
242         _mali_uk_dump_mmu_page_table_s kargs;
243         _mali_osk_errcode_t err;
244         void __user *user_buffer;
245         void *buffer = NULL;
246         int rc = -EFAULT;
247
248         /* validate input */
249         MALI_CHECK_NON_NULL(uargs, -EINVAL);
250         /* the session_data pointer was validated by caller */
251
252         if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_dump_mmu_page_table_s)))
253                 goto err_exit;
254
255         user_buffer = (void __user *)(uintptr_t)kargs.buffer;
256         if (!access_ok(VERIFY_WRITE, user_buffer, kargs.size))
257                 goto err_exit;
258
259         /* allocate temporary buffer (kernel side) to store mmu page table info */
260         if (kargs.size <= 0)
261                 return -EINVAL;
262         /* Allow at most 8MiB buffers, this is more than enough to dump a fully
263          * populated page table. */
264         if (kargs.size > SZ_8M)
265                 return -EINVAL;
266
267         buffer = (void *)(uintptr_t)_mali_osk_valloc(kargs.size);
268         if (NULL == buffer) {
269                 rc = -ENOMEM;
270                 goto err_exit;
271         }
272
273         kargs.ctx = (uintptr_t)session_data;
274         kargs.buffer = (uintptr_t)buffer;
275         err = _mali_ukk_dump_mmu_page_table(&kargs);
276         if (_MALI_OSK_ERR_OK != err) {
277                 rc = map_errcode(err);
278                 goto err_exit;
279         }
280
281         /* copy mmu page table info back to user space and update pointers */
282         if (0 != copy_to_user(user_buffer, buffer, kargs.size))
283                 goto err_exit;
284
285         kargs.register_writes = kargs.register_writes -
286                                 (uintptr_t)buffer + (uintptr_t)user_buffer;
287         kargs.page_table_dump = kargs.page_table_dump -
288                                 (uintptr_t)buffer + (uintptr_t)user_buffer;
289
290         if (0 != copy_to_user(uargs, &kargs, sizeof(kargs)))
291                 goto err_exit;
292
293         rc = 0;
294
295 err_exit:
296         if (buffer) _mali_osk_vfree(buffer);
297         return rc;
298 }
299
300 #if TIZEN_GLES_MEM_PROFILE
301 int mem_profile_gles_mem(struct mali_session_data *session_data,
302                                 _mali_uk_gles_mem_profiler_s __user *uargs)
303 {
304         _mali_uk_gles_mem_profiler_s kargs;
305         struct mali_session_gles_mem_profile_info *info;
306         struct mali_session_gles_mem_profile_api_info *api, *tmp;
307         mali_bool flag = MALI_FALSE;
308
309         MALI_CHECK_NON_NULL(uargs, -EINVAL);
310         MALI_CHECK_NON_NULL(session_data, -EINVAL);
311
312         if (copy_from_user(&kargs, uargs, sizeof(_mali_uk_gles_mem_profiler_s)))
313                 return -EFAULT;
314
315         kargs.ctx = (uintptr_t)session_data;
316
317         info = &session_data->gles_mem_profile_info[kargs.type];
318         if (!info) {
319                 MALI_PRINT_ERROR(("No info is available. Something wrong"));
320                 return -EINVAL;
321         }
322
323         _MALI_OSK_LIST_FOREACHENTRY(api, tmp, &(info->api_head),
324                         struct mali_session_gles_mem_profile_api_info, link) {
325                 if (api->id == (u16)kargs.entrypoint) {
326                         /* This API is recorded already. Update it. */
327                         api->size += kargs.size;
328                         info->size += kargs.size;
329                         flag = MALI_TRUE;
330                         break;
331                 }
332         }
333
334         if (flag == MALI_FALSE) {
335                 /*
336                  * This is the first time the API is recorded for this info.
337                  * So add it.
338                  */
339                 api = (struct mali_session_gles_mem_profile_api_info *)
340                         _mali_osk_calloc(1,
341                         sizeof(struct mali_session_gles_mem_profile_api_info));
342                 if (!api) {
343                         MALI_PRINT_ERROR(("Alloc failure"));
344                         return -ENOMEM;
345                 }
346                 memcpy(&api->api, &kargs.api, sizeof(api->api));
347
348                 api->id = (u16)kargs.entrypoint;
349                 api->size += kargs.size;
350                 info->size += kargs.size;
351
352                 mali_session_gles_mem_profile_api_add(info, api,
353                                                         &(info->api_head));
354         }
355
356         return 0;
357 }
358 #endif