1f5ba47127255992740028ef6c415294d0afbdcb
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / ump / common / ump_kernel_common.c
1 /*
2  * Copyright (C) 2010-2014, 2016 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                 MSG_ERR(("Failed to initiaze the UMP Device Driver"));
50                 return err;
51         }
52
53         /* Init the global device */
54         _mali_osk_memset(&device, 0, sizeof(device));
55
56         /* Create the descriptor map, which will be used for mapping secure ID to ump_dd_mem structs */
57         device.secure_id_map = ump_random_mapping_create();
58         if (NULL == device.secure_id_map) {
59                 MSG_ERR(("Failed to create secure id lookup table\n"));
60                 return _MALI_OSK_ERR_NOMEM;
61         }
62
63         /* Init memory backend */
64         device.backend = ump_memory_backend_create();
65         if (NULL == device.backend) {
66                 MSG_ERR(("Failed to create memory backend\n"));
67                 ump_random_mapping_destroy(device.secure_id_map);
68                 return _MALI_OSK_ERR_NOMEM;
69         }
70
71         return _MALI_OSK_ERR_OK;
72 }
73
74 void ump_kernel_destructor(void)
75 {
76         DEBUG_ASSERT_POINTER(device.secure_id_map);
77
78         ump_random_mapping_destroy(device.secure_id_map);
79         device.secure_id_map = NULL;
80
81         device.backend->shutdown(device.backend);
82         device.backend = NULL;
83
84         ump_memory_backend_destroy();
85
86         _ump_osk_term();
87 }
88
89 /** Creates a new UMP session
90  */
91 _mali_osk_errcode_t _ump_ukk_open(void **context)
92 {
93         struct ump_session_data *session_data;
94
95         /* allocated struct to track this session */
96         session_data = (struct ump_session_data *)_mali_osk_malloc(sizeof(struct ump_session_data));
97         if (NULL == session_data) {
98                 MSG_ERR(("Failed to allocate ump_session_data in ump_file_open()\n"));
99                 return _MALI_OSK_ERR_NOMEM;
100         }
101
102         session_data->lock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_UNORDERED, 0);
103         if (NULL == session_data->lock) {
104                 MSG_ERR(("Failed to initialize lock for ump_session_data in ump_file_open()\n"));
105                 _mali_osk_free(session_data);
106                 return _MALI_OSK_ERR_NOMEM;
107         }
108
109         session_data->cookies_map = ump_descriptor_mapping_create(
110                                             UMP_COOKIES_PER_SESSION_INITIAL,
111                                             UMP_COOKIES_PER_SESSION_MAXIMUM);
112
113         if (NULL == session_data->cookies_map) {
114                 MSG_ERR(("Failed to create descriptor mapping for _ump_ukk_map_mem cookies\n"));
115
116                 _mali_osk_mutex_term(session_data->lock);
117                 _mali_osk_free(session_data);
118                 return _MALI_OSK_ERR_NOMEM;
119         }
120
121         _MALI_OSK_INIT_LIST_HEAD(&session_data->list_head_session_memory_list);
122
123         _MALI_OSK_INIT_LIST_HEAD(&session_data->list_head_session_memory_mappings_list);
124
125         /* Since initial version of the UMP interface did not use the API_VERSION ioctl we have to assume
126            that it is this version, and not the "latest" one: UMP_IOCTL_API_VERSION
127            Current and later API versions would do an additional call to this IOCTL and update this variable
128            to the correct one.*/
129         session_data->api_version = MAKE_VERSION_ID(1);
130
131         *context = (void *)session_data;
132
133         session_data->cache_operations_ongoing = 0 ;
134         session_data->has_pending_level1_cache_flush = 0;
135
136         DBG_MSG(2, ("New session opened\n"));
137
138         return _MALI_OSK_ERR_OK;
139 }
140
141 _mali_osk_errcode_t _ump_ukk_close(void **context)
142 {
143         struct ump_session_data *session_data;
144         ump_session_memory_list_element *item;
145         ump_session_memory_list_element *tmp;
146
147         session_data = (struct ump_session_data *)*context;
148         if (NULL == session_data) {
149                 MSG_ERR(("Session data is NULL in _ump_ukk_close()\n"));
150                 return _MALI_OSK_ERR_INVALID_ARGS;
151         }
152
153         /* Unmap any descriptors mapped in. */
154         if (0 == _mali_osk_list_empty(&session_data->list_head_session_memory_mappings_list)) {
155                 ump_memory_allocation *descriptor;
156                 ump_memory_allocation *temp;
157
158                 DBG_MSG(1, ("Memory mappings found on session usage list during session termination\n"));
159
160                 /* use the 'safe' list iterator, since freeing removes the active block from the list we're iterating */
161                 _MALI_OSK_LIST_FOREACHENTRY(descriptor, temp, &session_data->list_head_session_memory_mappings_list, ump_memory_allocation, list) {
162                         _ump_uk_unmap_mem_s unmap_args;
163                         DBG_MSG(4, ("Freeing block with phys address 0x%x size 0x%x mapped in user space at 0x%x\n",
164                                     descriptor->phys_addr, descriptor->size, descriptor->mapping));
165                         unmap_args.ctx = (void *)session_data;
166                         unmap_args.mapping = descriptor->mapping;
167                         unmap_args.size = descriptor->size;
168                         unmap_args._ukk_private = NULL; /* NOTE: unused */
169                         unmap_args.cookie = descriptor->cookie;
170
171                         /* NOTE: This modifies the list_head_session_memory_mappings_list */
172                         _ump_ukk_unmap_mem(&unmap_args);
173                 }
174         }
175
176         /* ASSERT that we really did free everything, because _ump_ukk_unmap_mem()
177          * can fail silently. */
178         DEBUG_ASSERT(_mali_osk_list_empty(&session_data->list_head_session_memory_mappings_list));
179
180         _MALI_OSK_LIST_FOREACHENTRY(item, tmp, &session_data->list_head_session_memory_list, ump_session_memory_list_element, list) {
181                 _mali_osk_list_del(&item->list);
182                 DBG_MSG(2, ("Releasing UMP memory %u as part of file close\n", item->mem->secure_id));
183                 ump_dd_reference_release(item->mem);
184                 _mali_osk_free(item);
185         }
186
187         ump_descriptor_mapping_destroy(session_data->cookies_map);
188
189         _mali_osk_mutex_term(session_data->lock);
190         _mali_osk_free(session_data);
191
192         DBG_MSG(2, ("Session closed\n"));
193
194         return _MALI_OSK_ERR_OK;
195 }
196
197 _mali_osk_errcode_t _ump_ukk_map_mem(_ump_uk_map_mem_s *args)
198 {
199         struct ump_session_data *session_data;
200         ump_memory_allocation *descriptor;   /* Describes current mapping of memory */
201         _mali_osk_errcode_t err;
202         unsigned long offset = 0;
203         unsigned long left;
204         ump_dd_handle handle;  /* The real UMP handle for this memory. Its real datatype is ump_dd_mem*  */
205         ump_dd_mem *mem;       /* The real UMP memory. It is equal to the handle, but with exposed struct */
206         u32 block;
207         int map_id;
208
209         session_data = (ump_session_data *)args->ctx;
210         if (NULL == session_data) {
211                 MSG_ERR(("Session data is NULL in _ump_ukk_map_mem()\n"));
212                 return _MALI_OSK_ERR_INVALID_ARGS;
213         }
214
215         descriptor = (ump_memory_allocation *) _mali_osk_calloc(1, sizeof(ump_memory_allocation));
216         if (NULL == descriptor) {
217                 MSG_ERR(("ump_ukk_map_mem: descriptor allocation failed\n"));
218                 return _MALI_OSK_ERR_NOMEM;
219         }
220
221         handle = ump_dd_handle_create_from_secure_id(args->secure_id);
222         if (UMP_DD_HANDLE_INVALID == handle) {
223                 _mali_osk_free(descriptor);
224                 DBG_MSG(1, ("Trying to map unknown secure ID %u\n", args->secure_id));
225                 return _MALI_OSK_ERR_FAULT;
226         }
227
228         mem = (ump_dd_mem *)handle;
229         DEBUG_ASSERT(mem);
230         if (mem->size_bytes != args->size) {
231                 _mali_osk_free(descriptor);
232                 ump_dd_reference_release(handle);
233                 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));
234                 return _MALI_OSK_ERR_FAULT;
235         }
236
237         map_id = ump_descriptor_mapping_allocate_mapping(session_data->cookies_map, (void *) descriptor);
238
239         if (map_id < 0) {
240                 _mali_osk_free(descriptor);
241                 ump_dd_reference_release(handle);
242                 DBG_MSG(1, ("ump_ukk_map_mem: unable to allocate a descriptor_mapping for return cookie\n"));
243
244                 return _MALI_OSK_ERR_NOMEM;
245         }
246
247         descriptor->size = args->size;
248         descriptor->handle = handle;
249         descriptor->phys_addr = args->phys_addr;
250         descriptor->process_mapping_info = args->_ukk_private;
251         descriptor->ump_session = session_data;
252         descriptor->cookie = (u32)map_id;
253
254         if (mem->is_cached) {
255                 descriptor->is_cached = 1;
256                 args->is_cached       = 1;
257                 DBG_MSG(3, ("Mapping UMP secure_id: %d as cached.\n", args->secure_id));
258         } else {
259                 descriptor->is_cached = 0;
260                 args->is_cached       = 0;
261                 DBG_MSG(3, ("Mapping UMP secure_id: %d  as Uncached.\n", args->secure_id));
262         }
263
264         _mali_osk_list_init(&descriptor->list);
265
266         err = _ump_osk_mem_mapregion_init(descriptor);
267         if (_MALI_OSK_ERR_OK != err) {
268                 DBG_MSG(1, ("Failed to initialize memory mapping in _ump_ukk_map_mem(). ID: %u\n", args->secure_id));
269                 ump_descriptor_mapping_free(session_data->cookies_map, map_id);
270                 _mali_osk_free(descriptor);
271                 ump_dd_reference_release(mem);
272                 return err;
273         }
274
275         DBG_MSG(4, ("Mapping virtual to physical memory: ID: %u, size:%lu, first physical addr: 0x%08lx, number of regions: %lu\n",
276                     mem->secure_id,
277                     mem->size_bytes,
278                     ((NULL != mem->block_array) ? mem->block_array->addr : 0),
279                     mem->nr_blocks));
280
281         left = descriptor->size;
282         /* loop over all blocks and map them in */
283         for (block = 0; block < mem->nr_blocks; block++) {
284                 unsigned long size_to_map;
285
286                 if (left >  mem->block_array[block].size) {
287                         size_to_map = mem->block_array[block].size;
288                 } else {
289                         size_to_map = left;
290                 }
291
292                 if (_MALI_OSK_ERR_OK != _ump_osk_mem_mapregion_map(descriptor, offset, (u32 *) & (mem->block_array[block].addr), size_to_map)) {
293                         DBG_MSG(1, ("WARNING: _ump_ukk_map_mem failed to map memory into userspace\n"));
294                         ump_descriptor_mapping_free(session_data->cookies_map, map_id);
295                         ump_dd_reference_release(mem);
296                         _ump_osk_mem_mapregion_term(descriptor);
297                         _mali_osk_free(descriptor);
298                         return _MALI_OSK_ERR_FAULT;
299                 }
300                 left -= size_to_map;
301                 offset += size_to_map;
302         }
303
304         /* Add to the ump_memory_allocation tracking list */
305         _mali_osk_mutex_wait(session_data->lock);
306         _mali_osk_list_add(&descriptor->list, &session_data->list_head_session_memory_mappings_list);
307         _mali_osk_mutex_signal(session_data->lock);
308
309         args->mapping = descriptor->mapping;
310         args->cookie = descriptor->cookie;
311
312         return _MALI_OSK_ERR_OK;
313 }
314
315 void _ump_ukk_unmap_mem(_ump_uk_unmap_mem_s *args)
316 {
317         struct ump_session_data *session_data;
318         ump_memory_allocation *descriptor;
319         ump_dd_handle handle;
320
321         session_data = (ump_session_data *)args->ctx;
322
323         if (NULL == session_data) {
324                 MSG_ERR(("Session data is NULL in _ump_ukk_map_mem()\n"));
325                 return;
326         }
327
328         if (0 != ump_descriptor_mapping_get(session_data->cookies_map, (int)args->cookie, (void **)&descriptor)) {
329                 MSG_ERR(("_ump_ukk_map_mem: cookie 0x%X not found for this session\n", args->cookie));
330                 return;
331         }
332
333         DEBUG_ASSERT_POINTER(descriptor);
334
335         handle = descriptor->handle;
336         if (UMP_DD_HANDLE_INVALID == handle) {
337                 DBG_MSG(1, ("WARNING: Trying to unmap unknown handle: UNKNOWN\n"));
338                 return;
339         }
340
341         /* Remove the ump_memory_allocation from the list of tracked mappings */
342         _mali_osk_mutex_wait(session_data->lock);
343         _mali_osk_list_del(&descriptor->list);
344         _mali_osk_mutex_signal(session_data->lock);
345
346         ump_descriptor_mapping_free(session_data->cookies_map, (int)args->cookie);
347
348         ump_dd_reference_release(handle);
349
350         _ump_osk_mem_mapregion_term(descriptor);
351         _mali_osk_free(descriptor);
352 }
353
354 u32 _ump_ukk_report_memory_usage(void)
355 {
356         if (device.backend->stat)
357                 return device.backend->stat(device.backend);
358         else
359                 return 0;
360 }