tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / ump / linux / ump_ukk_ref_wrappers.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 /**
12  * @file ump_ukk_wrappers.c
13  * Defines the wrapper functions which turn Linux IOCTL calls into _ukk_ calls for the reference implementation
14  */
15
16
17 #include <asm/uaccess.h>             /* user space access */
18
19 #include "ump_osk.h"
20 #include "ump_uk_types.h"
21 #include "ump_ukk.h"
22 #include "ump_kernel_common.h"
23 /* MALI_SEC */
24 #ifdef CONFIG_DMA_SHARED_BUFFER
25 #include <linux/scatterlist.h>
26 #include "ump_kernel_interface_ref_drv.h"
27 #include "mali_osk_list.h"
28 #include <linux/dma-buf.h>
29 #endif
30
31 /* FIXME */
32 struct device tmp_dev;
33
34 /*
35  * IOCTL operation; Allocate UMP memory
36  */
37 int ump_allocate_wrapper(u32 __user * argument, struct ump_session_data  * session_data)
38 {
39         _ump_uk_allocate_s user_interaction;
40         _mali_osk_errcode_t err;
41
42         /* Sanity check input parameters */
43         if (NULL == argument || NULL == session_data)
44         {
45                 MSG_ERR(("NULL parameter in ump_ioctl_allocate()\n"));
46                 return -ENOTTY;
47         }
48
49         /* Copy the user space memory to kernel space (so we safely can read it) */
50         if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction)))
51         {
52                 MSG_ERR(("copy_from_user() in ump_ioctl_allocate()\n"));
53                 return -EFAULT;
54         }
55
56         user_interaction.ctx = (void *) session_data;
57
58         err = _ump_ukk_allocate( &user_interaction );
59         if( _MALI_OSK_ERR_OK != err )
60         {
61                 DBG_MSG(1, ("_ump_ukk_allocate() failed in ump_ioctl_allocate()\n"));
62                 return map_errcode(err);
63         }
64         user_interaction.ctx = NULL;
65
66         if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction)))
67         {
68                 /* If the copy fails then we should release the memory. We can use the IOCTL release to accomplish this */
69                 _ump_uk_release_s release_args;
70
71                 MSG_ERR(("copy_to_user() failed in ump_ioctl_allocate()\n"));
72
73                 release_args.ctx = (void *) session_data;
74                 release_args.secure_id = user_interaction.secure_id;
75
76                 err = _ump_ukk_release( &release_args );
77                 if(_MALI_OSK_ERR_OK != err)
78                 {
79                         MSG_ERR(("_ump_ukk_release() also failed when trying to release newly allocated memory in ump_ioctl_allocate()\n"));
80                 }
81
82                 return -EFAULT;
83         }
84
85         return 0; /* success */
86 }
87
88 /* MALI_SEC */
89 #ifdef CONFIG_DMA_SHARED_BUFFER
90 static ump_dd_handle
91         get_ump_handle_from_dmabuf(struct ump_session_data *session_data,
92                                         struct dma_buf *dmabuf)
93 {
94         ump_session_memory_list_element *session_mem, *tmp;
95         struct dma_buf_attachment *attach;
96         ump_dd_handle ump_handle;
97
98         _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW);
99
100         _MALI_OSK_LIST_FOREACHENTRY(session_mem, tmp,
101                                 &session_data->list_head_session_memory_list,
102                                 ump_session_memory_list_element, list) {
103                 if (session_mem->mem->import_attach) {
104                         attach = session_mem->mem->import_attach;
105                         if (attach->dmabuf == dmabuf) {
106                                 _mali_osk_lock_signal(session_data->lock,
107                                                         _MALI_OSK_LOCKMODE_RW);
108                                 ump_handle = (ump_dd_handle)session_mem->mem;
109                                 return ump_handle;
110                         }
111                 }
112         }
113
114         _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW);
115
116         return NULL;
117 }
118
119 int ump_dmabuf_import_wrapper(u32 __user *argument,
120                                 struct ump_session_data  *session_data)
121 {
122         ump_session_memory_list_element *session = NULL;
123         struct ump_uk_dmabuf ump_dmabuf;
124         ump_dd_handle ump_handle;
125         ump_dd_physical_block *blocks = NULL;
126         struct dma_buf_attachment *attach = NULL;
127         struct dma_buf *dma_buf;
128         struct sg_table *sgt = NULL;
129         struct scatterlist *sgl;
130         unsigned long block_size;
131         unsigned int i = 0, npages;
132         int ret;
133
134         /* FIXME */
135         memset(&tmp_dev, 0x0, sizeof(struct device));
136
137         /* Sanity check input parameters */
138         if (!argument || !session_data) {
139                 MSG_ERR(("NULL parameter.\n"));
140                 return -EINVAL;
141         }
142
143         if (copy_from_user(&ump_dmabuf, argument,
144                                 sizeof(struct ump_uk_dmabuf))) {
145                 MSG_ERR(("copy_from_user() failed.\n"));
146                 return -EFAULT;
147         }
148
149         dma_buf = dma_buf_get(ump_dmabuf.fd);
150         if (IS_ERR(dma_buf))
151                 return PTR_ERR(dma_buf);
152
153         /*
154          * if already imported then increase a refcount to the ump descriptor
155          * and call dma_buf_put() and then go to found to return previous
156          * ump secure id.
157          */
158         ump_handle = get_ump_handle_from_dmabuf(session_data, dma_buf);
159         if (ump_handle) {
160                 dma_buf_put(dma_buf);
161                 goto found;
162         }
163
164         attach = dma_buf_attach(dma_buf, &tmp_dev);
165         if (IS_ERR(attach)) {
166                 ret = PTR_ERR(attach);
167                 goto err_dma_buf_put;
168         }
169
170         sgt = dma_buf_map_attachment(attach, DMA_NONE);
171         if (IS_ERR(sgt)) {
172                 ret = PTR_ERR(sgt);
173                 goto err_dma_buf_detach;
174         }
175
176         npages = sgt->nents;
177
178         /* really need? */
179         ump_dmabuf.ctx = (void *)session_data;
180
181         block_size = sizeof(ump_dd_physical_block) * npages;
182
183         blocks = (ump_dd_physical_block *)_mali_osk_malloc(block_size);
184         sgl = sgt->sgl;
185
186         while (i < npages) {
187                 blocks[i].addr = sg_phys(sgl);
188                 blocks[i].size = sgl->length;
189                 sgl = sg_next(sgl);
190                 i++;
191         }
192
193         /*
194          * Initialize the session memory list element, and add it
195          * to the session object
196          */
197         session = _mali_osk_calloc(1, sizeof(*session));
198         if (!session) {
199                 DBG_MSG(1, ("Failed to allocate session.\n"));
200                 ret = -EFAULT;
201                 goto err_free_block;
202         }
203
204         ump_handle = ump_dd_handle_create_from_phys_blocks(blocks, i);
205         if (UMP_DD_HANDLE_INVALID == ump_handle) {
206                 DBG_MSG(1, ("Failed to create ump handle.\n"));
207                 ret = -EFAULT;
208                 goto err_free_session;
209         }
210
211         session->mem = (ump_dd_mem *)ump_handle;
212         session->mem->import_attach = attach;
213         session->mem->sgt = sgt;
214
215         _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW);
216         _mali_osk_list_add(&(session->list),
217                         &(session_data->list_head_session_memory_list));
218         _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW);
219
220         _mali_osk_free(blocks);
221
222 found:
223         ump_dmabuf.secure_id = ump_dd_secure_id_get(ump_handle);
224         ump_dmabuf.size = ump_dd_size_get(ump_handle);
225
226         if (copy_to_user(argument, &ump_dmabuf,
227                                 sizeof(struct ump_uk_dmabuf))) {
228                 MSG_ERR(("copy_to_user() failed.\n"));
229                 if (session) {
230                         _mali_osk_lock_wait(session_data->lock,
231                                                         _MALI_OSK_LOCKMODE_RW);
232                         _mali_osk_list_del(&session->list);
233                         _mali_osk_lock_signal(session_data->lock,
234                                                         _MALI_OSK_LOCKMODE_RW);
235                         ump_dd_reference_release(ump_handle);
236                         _mali_osk_free(session);
237                 }
238                 return -EFAULT;
239         }
240
241         return 0;
242
243 err_free_session:
244         _mali_osk_free(session);
245 err_free_block:
246         _mali_osk_free(blocks);
247         dma_buf_unmap_attachment(attach, sgt, DMA_NONE);
248 err_dma_buf_detach:
249         dma_buf_detach(dma_buf, attach);
250 err_dma_buf_put:
251         dma_buf_put(dma_buf);
252         return ret;
253 }
254 #endif