Branch data Line data Source code
1 : : /*
2 : : ****************************************************************************
3 : : * Copyright 2011-2012 Broadcom Corporation. All rights reserved.
4 : : *
5 : : * Unless you and Broadcom execute a separate written software license
6 : : * agreement governing use of this software, this software is licensed to you
7 : : * under the terms of the GNU General Public License version 2, available at
8 : : * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
9 : : *
10 : : * Notwithstanding the above, under no circumstances may you combine this
11 : : * software in any way with any other Broadcom software provided under a
12 : : * license other than the GPL, without Broadcom's express prior written
13 : : * consent.
14 : : ****************************************************************************
15 : : */
16 : :
17 : : /* ---- Include Files ----------------------------------------------------- */
18 : :
19 : : #include <linux/cdev.h>
20 : : #include <linux/broadcom/vc_mem.h>
21 : : #include <linux/device.h>
22 : : #include <linux/debugfs.h>
23 : : #include <linux/dma-mapping.h>
24 : : #include <linux/dma-buf.h>
25 : : #include <linux/errno.h>
26 : : #include <linux/fs.h>
27 : : #include <linux/hugetlb.h>
28 : : #include <linux/ioctl.h>
29 : : #include <linux/kernel.h>
30 : : #include <linux/list.h>
31 : : #include <linux/module.h>
32 : : #include <linux/mm.h>
33 : : #include <linux/of.h>
34 : : #include <linux/platform_device.h>
35 : : #include <linux/pfn.h>
36 : : #include <linux/proc_fs.h>
37 : : #include <linux/pagemap.h>
38 : : #include <linux/semaphore.h>
39 : : #include <linux/slab.h>
40 : : #include <linux/seq_file.h>
41 : : #include <linux/types.h>
42 : : #include <asm/cacheflush.h>
43 : :
44 : : #include "vchiq_connected.h"
45 : : #include "vc_vchi_sm.h"
46 : :
47 : : #include <linux/broadcom/vmcs_sm_ioctl.h>
48 : : #include "vc_sm_knl.h"
49 : :
50 : : /* ---- Private Constants and Types --------------------------------------- */
51 : :
52 : : #define DEVICE_NAME "vcsm"
53 : : #define DRIVER_NAME "bcm2835-vcsm"
54 : : #define DEVICE_MINOR 0
55 : :
56 : : #define VC_SM_DIR_ROOT_NAME "vc-smem"
57 : : #define VC_SM_DIR_ALLOC_NAME "alloc"
58 : : #define VC_SM_STATE "state"
59 : : #define VC_SM_STATS "statistics"
60 : : #define VC_SM_RESOURCES "resources"
61 : : #define VC_SM_DEBUG "debug"
62 : : #define VC_SM_WRITE_BUF_SIZE 128
63 : :
64 : : /* Statistics tracked per resource and globally. */
65 : : enum sm_stats_t {
66 : : /* Attempt. */
67 : : ALLOC,
68 : : FREE,
69 : : LOCK,
70 : : UNLOCK,
71 : : MAP,
72 : : FLUSH,
73 : : INVALID,
74 : : IMPORT,
75 : :
76 : : END_ATTEMPT,
77 : :
78 : : /* Failure. */
79 : : ALLOC_FAIL,
80 : : FREE_FAIL,
81 : : LOCK_FAIL,
82 : : UNLOCK_FAIL,
83 : : MAP_FAIL,
84 : : FLUSH_FAIL,
85 : : INVALID_FAIL,
86 : : IMPORT_FAIL,
87 : :
88 : : END_ALL,
89 : :
90 : : };
91 : :
92 : : static const char *const sm_stats_human_read[] = {
93 : : "Alloc",
94 : : "Free",
95 : : "Lock",
96 : : "Unlock",
97 : : "Map",
98 : : "Cache Flush",
99 : : "Cache Invalidate",
100 : : "Import",
101 : : };
102 : :
103 : : typedef int (*VC_SM_SHOW) (struct seq_file *s, void *v);
104 : : struct sm_pde_t {
105 : : VC_SM_SHOW show; /* Debug fs function hookup. */
106 : : struct dentry *dir_entry; /* Debug fs directory entry. */
107 : : void *priv_data; /* Private data */
108 : :
109 : : };
110 : :
111 : : /* Single resource allocation tracked for all devices. */
112 : : struct sm_mmap {
113 : : struct list_head map_list; /* Linked list of maps. */
114 : :
115 : : struct sm_resource_t *resource; /* Pointer to the resource. */
116 : :
117 : : pid_t res_pid; /* PID owning that resource. */
118 : : unsigned int res_vc_hdl; /* Resource handle (videocore). */
119 : : unsigned int res_usr_hdl; /* Resource handle (user). */
120 : :
121 : : unsigned long res_addr; /* Mapped virtual address. */
122 : : struct vm_area_struct *vma; /* VM area for this mapping. */
123 : : unsigned int ref_count; /* Reference count to this vma. */
124 : :
125 : : /* Used to link maps associated with a resource. */
126 : : struct list_head resource_map_list;
127 : : };
128 : :
129 : : /* Single resource allocation tracked for each opened device. */
130 : : struct sm_resource_t {
131 : : struct list_head resource_list; /* List of resources. */
132 : : struct list_head global_resource_list; /* Global list of resources. */
133 : :
134 : : pid_t pid; /* PID owning that resource. */
135 : : uint32_t res_guid; /* Unique identifier. */
136 : : uint32_t lock_count; /* Lock count for this resource. */
137 : : uint32_t ref_count; /* Ref count for this resource. */
138 : :
139 : : uint32_t res_handle; /* Resource allocation handle. */
140 : : void *res_base_mem; /* Resource base memory address. */
141 : : uint32_t res_size; /* Resource size allocated. */
142 : : enum vmcs_sm_cache_e res_cached; /* Resource cache type. */
143 : : struct sm_resource_t *res_shared; /* Shared resource */
144 : :
145 : : enum sm_stats_t res_stats[END_ALL]; /* Resource statistics. */
146 : :
147 : : uint8_t map_count; /* Counter of mappings for this resource. */
148 : : struct list_head map_list; /* Maps associated with a resource. */
149 : :
150 : : /* DMABUF related fields */
151 : : struct dma_buf *dma_buf;
152 : : struct dma_buf_attachment *attach;
153 : : struct sg_table *sgt;
154 : : dma_addr_t dma_addr;
155 : :
156 : : struct sm_priv_data_t *private;
157 : : bool map; /* whether to map pages up front */
158 : : };
159 : :
160 : : /* Private file data associated with each opened device. */
161 : : struct sm_priv_data_t {
162 : : struct list_head resource_list; /* List of resources. */
163 : :
164 : : pid_t pid; /* PID of creator. */
165 : :
166 : : struct dentry *dir_pid; /* Debug fs entries root. */
167 : : struct sm_pde_t dir_stats; /* Debug fs entries statistics sub-tree. */
168 : : struct sm_pde_t dir_res; /* Debug fs resource sub-tree. */
169 : :
170 : : int restart_sys; /* Tracks restart on interrupt. */
171 : : enum vc_sm_msg_type int_action; /* Interrupted action. */
172 : : uint32_t int_trans_id; /* Interrupted transaction. */
173 : :
174 : : };
175 : :
176 : : /* Global state information. */
177 : : struct sm_state_t {
178 : : struct platform_device *pdev;
179 : : struct sm_instance *sm_handle; /* Handle for videocore service. */
180 : : struct dentry *dir_root; /* Debug fs entries root. */
181 : : struct dentry *dir_alloc; /* Debug fs entries allocations. */
182 : : struct sm_pde_t dir_stats; /* Debug fs entries statistics sub-tree. */
183 : : struct sm_pde_t dir_state; /* Debug fs entries state sub-tree. */
184 : : struct dentry *debug; /* Debug fs entries debug. */
185 : :
186 : : struct mutex map_lock; /* Global map lock. */
187 : : struct list_head map_list; /* List of maps. */
188 : : struct list_head resource_list; /* List of resources. */
189 : :
190 : : enum sm_stats_t deceased[END_ALL]; /* Natural termination stats. */
191 : : enum sm_stats_t terminated[END_ALL]; /* Forced termination stats. */
192 : : uint32_t res_deceased_cnt; /* Natural termination counter. */
193 : : uint32_t res_terminated_cnt; /* Forced termination counter. */
194 : :
195 : : struct cdev sm_cdev; /* Device. */
196 : : dev_t sm_devid; /* Device identifier. */
197 : : struct class *sm_class; /* Class. */
198 : : struct device *sm_dev; /* Device. */
199 : :
200 : : struct sm_priv_data_t *data_knl; /* Kernel internal data tracking. */
201 : :
202 : : struct mutex lock; /* Global lock. */
203 : : uint32_t guid; /* GUID (next) tracker. */
204 : :
205 : : };
206 : :
207 : : /* ---- Private Variables ----------------------------------------------- */
208 : :
209 : : static struct sm_state_t *sm_state;
210 : : static int sm_inited;
211 : :
212 : : #if 0
213 : : static const char *const sm_cache_map_vector[] = {
214 : : "(null)",
215 : : "host",
216 : : "videocore",
217 : : "host+videocore",
218 : : };
219 : : #endif
220 : :
221 : : /* ---- Private Function Prototypes -------------------------------------- */
222 : :
223 : : /* ---- Private Functions ------------------------------------------------ */
224 : :
225 : : static inline unsigned int vcaddr_to_pfn(unsigned long vc_addr)
226 : : {
227 : : unsigned long pfn = vc_addr & 0x3FFFFFFF;
228 : :
229 : : pfn += mm_vc_mem_phys_addr;
230 : : pfn >>= PAGE_SHIFT;
231 : : return pfn;
232 : : }
233 : :
234 : : /*
235 : : * Carries over to the state statistics the statistics once owned by a deceased
236 : : * resource.
237 : : */
238 : 0 : static void vc_sm_resource_deceased(struct sm_resource_t *p_res, int terminated)
239 : : {
240 : 0 : if (sm_state != NULL) {
241 : 0 : if (p_res != NULL) {
242 : : int ix;
243 : :
244 : 0 : if (terminated)
245 : 0 : sm_state->res_terminated_cnt++;
246 : : else
247 : 0 : sm_state->res_deceased_cnt++;
248 : :
249 : 0 : for (ix = 0; ix < END_ALL; ix++) {
250 : 0 : if (terminated)
251 : 0 : sm_state->terminated[ix] +=
252 : 0 : p_res->res_stats[ix];
253 : : else
254 : 0 : sm_state->deceased[ix] +=
255 : 0 : p_res->res_stats[ix];
256 : : }
257 : : }
258 : : }
259 : 0 : }
260 : :
261 : : /*
262 : : * Fetch a videocore handle corresponding to a mapping of the pid+address
263 : : * returns 0 (ie NULL) if no such handle exists in the global map.
264 : : */
265 : 0 : static unsigned int vmcs_sm_vc_handle_from_pid_and_address(unsigned int pid,
266 : : unsigned int addr)
267 : : {
268 : : struct sm_mmap *map = NULL;
269 : : unsigned int handle = 0;
270 : :
271 : 0 : if (!sm_state || addr == 0)
272 : : goto out;
273 : :
274 : 0 : mutex_lock(&(sm_state->map_lock));
275 : :
276 : : /* Lookup the resource. */
277 : 0 : if (!list_empty(&sm_state->map_list)) {
278 : 0 : list_for_each_entry(map, &sm_state->map_list, map_list) {
279 : 0 : if (map->res_pid != pid)
280 : 0 : continue;
281 : 0 : if (addr < map->res_addr ||
282 : 0 : addr >= (map->res_addr + map->resource->res_size))
283 : 0 : continue;
284 : :
285 : : pr_debug("[%s]: global map %p (pid %u, addr %lx) -> vc-hdl %x (usr-hdl %x)\n",
286 : : __func__, map, map->res_pid, map->res_addr,
287 : : map->res_vc_hdl, map->res_usr_hdl);
288 : :
289 : 0 : handle = map->res_vc_hdl;
290 : 0 : break;
291 : : }
292 : : }
293 : :
294 : 0 : mutex_unlock(&(sm_state->map_lock));
295 : :
296 : : out:
297 : : /*
298 : : * Use a debug log here as it may be a valid situation that we query
299 : : * for something that is not mapped, we do not want a kernel log each
300 : : * time around.
301 : : *
302 : : * There are other error log that would pop up accordingly if someone
303 : : * subsequently tries to use something invalid after being told not to
304 : : * use it...
305 : : */
306 : : if (handle == 0) {
307 : : pr_debug("[%s]: not a valid map (pid %u, addr %x)\n",
308 : : __func__, pid, addr);
309 : : }
310 : :
311 : 0 : return handle;
312 : : }
313 : :
314 : : /*
315 : : * Fetch a user handle corresponding to a mapping of the pid+address
316 : : * returns 0 (ie NULL) if no such handle exists in the global map.
317 : : */
318 : 0 : static unsigned int vmcs_sm_usr_handle_from_pid_and_address(unsigned int pid,
319 : : unsigned int addr)
320 : : {
321 : : struct sm_mmap *map = NULL;
322 : : unsigned int handle = 0;
323 : :
324 : 0 : if (!sm_state || addr == 0)
325 : : goto out;
326 : :
327 : 0 : mutex_lock(&(sm_state->map_lock));
328 : :
329 : : /* Lookup the resource. */
330 : 0 : if (!list_empty(&sm_state->map_list)) {
331 : 0 : list_for_each_entry(map, &sm_state->map_list, map_list) {
332 : 0 : if (map->res_pid != pid)
333 : 0 : continue;
334 : 0 : if (addr < map->res_addr ||
335 : 0 : addr >= (map->res_addr + map->resource->res_size))
336 : 0 : continue;
337 : :
338 : : pr_debug("[%s]: global map %p (pid %u, addr %lx) -> usr-hdl %x (vc-hdl %x)\n",
339 : : __func__, map, map->res_pid, map->res_addr,
340 : : map->res_usr_hdl, map->res_vc_hdl);
341 : :
342 : 0 : handle = map->res_usr_hdl;
343 : 0 : break;
344 : : }
345 : : }
346 : :
347 : 0 : mutex_unlock(&(sm_state->map_lock));
348 : :
349 : : out:
350 : : /*
351 : : * Use a debug log here as it may be a valid situation that we query
352 : : * for something that is not mapped yet.
353 : : *
354 : : * There are other error log that would pop up accordingly if someone
355 : : * subsequently tries to use something invalid after being told not to
356 : : * use it...
357 : : */
358 : : if (handle == 0)
359 : : pr_debug("[%s]: not a valid map (pid %u, addr %x)\n",
360 : : __func__, pid, addr);
361 : :
362 : 0 : return handle;
363 : : }
364 : :
365 : : #if defined(DO_NOT_USE)
366 : : /*
367 : : * Fetch an address corresponding to a mapping of the pid+handle
368 : : * returns 0 (ie NULL) if no such address exists in the global map.
369 : : */
370 : : static unsigned int vmcs_sm_usr_address_from_pid_and_vc_handle(unsigned int pid,
371 : : unsigned int hdl)
372 : : {
373 : : struct sm_mmap *map = NULL;
374 : : unsigned int addr = 0;
375 : :
376 : : if (sm_state == NULL || hdl == 0)
377 : : goto out;
378 : :
379 : : mutex_lock(&(sm_state->map_lock));
380 : :
381 : : /* Lookup the resource. */
382 : : if (!list_empty(&sm_state->map_list)) {
383 : : list_for_each_entry(map, &sm_state->map_list, map_list) {
384 : : if (map->res_pid != pid || map->res_vc_hdl != hdl)
385 : : continue;
386 : :
387 : : pr_debug("[%s]: global map %p (pid %u, vc-hdl %x, usr-hdl %x) -> addr %lx\n",
388 : : __func__, map, map->res_pid, map->res_vc_hdl,
389 : : map->res_usr_hdl, map->res_addr);
390 : :
391 : : addr = map->res_addr;
392 : : break;
393 : : }
394 : : }
395 : :
396 : : mutex_unlock(&(sm_state->map_lock));
397 : :
398 : : out:
399 : : /*
400 : : * Use a debug log here as it may be a valid situation that we query
401 : : * for something that is not mapped, we do not want a kernel log each
402 : : * time around.
403 : : *
404 : : * There are other error log that would pop up accordingly if someone
405 : : * subsequently tries to use something invalid after being told not to
406 : : * use it...
407 : : */
408 : : if (addr == 0)
409 : : pr_debug("[%s]: not a valid map (pid %u, hdl %x)\n",
410 : : __func__, pid, hdl);
411 : :
412 : : return addr;
413 : : }
414 : : #endif
415 : :
416 : : /*
417 : : * Fetch an address corresponding to a mapping of the pid+handle
418 : : * returns 0 (ie NULL) if no such address exists in the global map.
419 : : */
420 : 0 : static unsigned int vmcs_sm_usr_address_from_pid_and_usr_handle(unsigned int
421 : : pid,
422 : : unsigned int
423 : : hdl)
424 : : {
425 : : struct sm_mmap *map = NULL;
426 : : unsigned int addr = 0;
427 : :
428 : 0 : if (sm_state == NULL || hdl == 0)
429 : : goto out;
430 : :
431 : 0 : mutex_lock(&(sm_state->map_lock));
432 : :
433 : : /* Lookup the resource. */
434 : 0 : if (!list_empty(&sm_state->map_list)) {
435 : 0 : list_for_each_entry(map, &sm_state->map_list, map_list) {
436 : 0 : if (map->res_pid != pid || map->res_usr_hdl != hdl)
437 : 0 : continue;
438 : :
439 : : pr_debug("[%s]: global map %p (pid %u, vc-hdl %x, usr-hdl %x) -> addr %lx\n",
440 : : __func__, map, map->res_pid, map->res_vc_hdl,
441 : : map->res_usr_hdl, map->res_addr);
442 : :
443 : 0 : addr = map->res_addr;
444 : 0 : break;
445 : : }
446 : : }
447 : :
448 : 0 : mutex_unlock(&(sm_state->map_lock));
449 : :
450 : : out:
451 : : /*
452 : : * Use a debug log here as it may be a valid situation that we query
453 : : * for something that is not mapped, we do not want a kernel log each
454 : : * time around.
455 : : *
456 : : * There are other error log that would pop up accordingly if someone
457 : : * subsequently tries to use something invalid after being told not to
458 : : * use it...
459 : : */
460 : : if (addr == 0)
461 : : pr_debug("[%s]: not a valid map (pid %u, hdl %x)\n", __func__,
462 : : pid, hdl);
463 : :
464 : 0 : return addr;
465 : : }
466 : :
467 : : /* Adds a resource mapping to the global data list. */
468 : 0 : static void vmcs_sm_add_map(struct sm_state_t *state,
469 : : struct sm_resource_t *resource, struct sm_mmap *map)
470 : : {
471 : 0 : mutex_lock(&(state->map_lock));
472 : :
473 : : /* Add to the global list of mappings */
474 : 0 : list_add(&map->map_list, &state->map_list);
475 : :
476 : : /* Add to the list of mappings for this resource */
477 : 0 : list_add(&map->resource_map_list, &resource->map_list);
478 : 0 : resource->map_count++;
479 : :
480 : 0 : mutex_unlock(&(state->map_lock));
481 : :
482 : : pr_debug("[%s]: added map %p (pid %u, vc-hdl %x, usr-hdl %x, addr %lx)\n",
483 : : __func__, map, map->res_pid, map->res_vc_hdl,
484 : : map->res_usr_hdl, map->res_addr);
485 : 0 : }
486 : :
487 : : /* Removes a resource mapping from the global data list. */
488 : 0 : static void vmcs_sm_remove_map(struct sm_state_t *state,
489 : : struct sm_resource_t *resource,
490 : : struct sm_mmap *map)
491 : : {
492 : 0 : mutex_lock(&(state->map_lock));
493 : :
494 : : /* Remove from the global list of mappings */
495 : : list_del(&map->map_list);
496 : :
497 : : /* Remove from the list of mapping for this resource */
498 : : list_del(&map->resource_map_list);
499 : 0 : if (resource->map_count > 0)
500 : 0 : resource->map_count--;
501 : :
502 : 0 : mutex_unlock(&(state->map_lock));
503 : :
504 : : pr_debug("[%s]: removed map %p (pid %d, vc-hdl %x, usr-hdl %x, addr %lx)\n",
505 : : __func__, map, map->res_pid, map->res_vc_hdl, map->res_usr_hdl,
506 : : map->res_addr);
507 : :
508 : 0 : kfree(map);
509 : 0 : }
510 : :
511 : : /* Read callback for the global state proc entry. */
512 : 0 : static int vc_sm_global_state_show(struct seq_file *s, void *v)
513 : : {
514 : : struct sm_mmap *map = NULL;
515 : : struct sm_resource_t *resource = NULL;
516 : : int map_count = 0;
517 : : int resource_count = 0;
518 : :
519 : 0 : if (sm_state == NULL)
520 : : return 0;
521 : :
522 : 0 : seq_printf(s, "\nVC-ServiceHandle 0x%x\n",
523 : 0 : (unsigned int)sm_state->sm_handle);
524 : :
525 : : /* Log all applicable mapping(s). */
526 : :
527 : 0 : mutex_lock(&(sm_state->map_lock));
528 : 0 : seq_puts(s, "\nResources\n");
529 : 0 : if (!list_empty(&sm_state->resource_list)) {
530 : 0 : list_for_each_entry(resource, &sm_state->resource_list,
531 : : global_resource_list) {
532 : 0 : resource_count++;
533 : :
534 : 0 : seq_printf(s, "\nResource %p\n",
535 : : resource);
536 : 0 : seq_printf(s, " PID %u\n",
537 : : resource->pid);
538 : 0 : seq_printf(s, " RES_GUID 0x%x\n",
539 : : resource->res_guid);
540 : 0 : seq_printf(s, " LOCK_COUNT %u\n",
541 : : resource->lock_count);
542 : 0 : seq_printf(s, " REF_COUNT %u\n",
543 : : resource->ref_count);
544 : 0 : seq_printf(s, " res_handle 0x%X\n",
545 : : resource->res_handle);
546 : 0 : seq_printf(s, " res_base_mem %p\n",
547 : : resource->res_base_mem);
548 : 0 : seq_printf(s, " SIZE %d\n",
549 : : resource->res_size);
550 : 0 : seq_printf(s, " DMABUF %p\n",
551 : : resource->dma_buf);
552 : 0 : seq_printf(s, " ATTACH %p\n",
553 : : resource->attach);
554 : 0 : seq_printf(s, " SGT %p\n",
555 : : resource->sgt);
556 : 0 : seq_printf(s, " DMA_ADDR %pad\n",
557 : : &resource->dma_addr);
558 : : }
559 : : }
560 : 0 : seq_printf(s, "\n\nTotal resource count: %d\n\n", resource_count);
561 : :
562 : 0 : seq_puts(s, "\nMappings\n");
563 : 0 : if (!list_empty(&sm_state->map_list)) {
564 : 0 : list_for_each_entry(map, &sm_state->map_list, map_list) {
565 : 0 : map_count++;
566 : :
567 : 0 : seq_printf(s, "\nMapping 0x%x\n",
568 : : (unsigned int)map);
569 : 0 : seq_printf(s, " TGID %u\n",
570 : : map->res_pid);
571 : 0 : seq_printf(s, " VC-HDL 0x%x\n",
572 : : map->res_vc_hdl);
573 : 0 : seq_printf(s, " USR-HDL 0x%x\n",
574 : : map->res_usr_hdl);
575 : 0 : seq_printf(s, " USR-ADDR 0x%lx\n",
576 : : map->res_addr);
577 : 0 : seq_printf(s, " SIZE %d\n",
578 : 0 : map->resource->res_size);
579 : : }
580 : : }
581 : :
582 : 0 : mutex_unlock(&(sm_state->map_lock));
583 : 0 : seq_printf(s, "\n\nTotal map count: %d\n\n", map_count);
584 : :
585 : 0 : return 0;
586 : : }
587 : :
588 : 0 : static int vc_sm_global_statistics_show(struct seq_file *s, void *v)
589 : : {
590 : : int ix;
591 : :
592 : : /* Global state tracked statistics. */
593 : 0 : if (sm_state != NULL) {
594 : 0 : seq_puts(s, "\nDeceased Resources Statistics\n");
595 : :
596 : 0 : seq_printf(s, "\nNatural Cause (%u occurences)\n",
597 : 0 : sm_state->res_deceased_cnt);
598 : 0 : for (ix = 0; ix < END_ATTEMPT; ix++) {
599 : 0 : if (sm_state->deceased[ix] > 0) {
600 : 0 : seq_printf(s, " %u\t%s\n",
601 : : sm_state->deceased[ix],
602 : : sm_stats_human_read[ix]);
603 : : }
604 : : }
605 : 0 : seq_puts(s, "\n");
606 : 0 : for (ix = 0; ix < END_ATTEMPT; ix++) {
607 : 0 : if (sm_state->deceased[ix + END_ATTEMPT] > 0) {
608 : 0 : seq_printf(s, " %u\tFAILED %s\n",
609 : : sm_state->deceased[ix + END_ATTEMPT],
610 : : sm_stats_human_read[ix]);
611 : : }
612 : : }
613 : :
614 : 0 : seq_printf(s, "\nForcefull (%u occurences)\n",
615 : 0 : sm_state->res_terminated_cnt);
616 : 0 : for (ix = 0; ix < END_ATTEMPT; ix++) {
617 : 0 : if (sm_state->terminated[ix] > 0) {
618 : 0 : seq_printf(s, " %u\t%s\n",
619 : : sm_state->terminated[ix],
620 : : sm_stats_human_read[ix]);
621 : : }
622 : : }
623 : 0 : seq_puts(s, "\n");
624 : 0 : for (ix = 0; ix < END_ATTEMPT; ix++) {
625 : 0 : if (sm_state->terminated[ix + END_ATTEMPT] > 0) {
626 : 0 : seq_printf(s, " %u\tFAILED %s\n",
627 : : sm_state->terminated[ix +
628 : : END_ATTEMPT],
629 : : sm_stats_human_read[ix]);
630 : : }
631 : : }
632 : : }
633 : :
634 : 0 : return 0;
635 : : }
636 : :
637 : : #if 0
638 : : /* Read callback for the statistics proc entry. */
639 : : static int vc_sm_statistics_show(struct seq_file *s, void *v)
640 : : {
641 : : int ix;
642 : : struct sm_priv_data_t *file_data;
643 : : struct sm_resource_t *resource;
644 : : int res_count = 0;
645 : : struct sm_pde_t *p_pde;
646 : :
647 : : p_pde = (struct sm_pde_t *)(s->private);
648 : : file_data = (struct sm_priv_data_t *)(p_pde->priv_data);
649 : :
650 : : if (file_data == NULL)
651 : : return 0;
652 : :
653 : : /* Per process statistics. */
654 : :
655 : : seq_printf(s, "\nStatistics for TGID %d\n", file_data->pid);
656 : :
657 : : mutex_lock(&(sm_state->map_lock));
658 : :
659 : : if (!list_empty(&file_data->resource_list)) {
660 : : list_for_each_entry(resource, &file_data->resource_list,
661 : : resource_list) {
662 : : res_count++;
663 : :
664 : : seq_printf(s, "\nGUID: 0x%x\n\n",
665 : : resource->res_guid);
666 : : for (ix = 0; ix < END_ATTEMPT; ix++) {
667 : : if (resource->res_stats[ix] > 0) {
668 : : seq_printf(s,
669 : : " %u\t%s\n",
670 : : resource->res_stats[ix],
671 : : sm_stats_human_read[ix]);
672 : : }
673 : : }
674 : : seq_puts(s, "\n");
675 : : for (ix = 0; ix < END_ATTEMPT; ix++) {
676 : : if (resource->res_stats[ix + END_ATTEMPT] > 0) {
677 : : seq_printf(s,
678 : : " %u\tFAILED %s\n",
679 : : resource->res_stats[
680 : : ix + END_ATTEMPT],
681 : : sm_stats_human_read[ix]);
682 : : }
683 : : }
684 : : }
685 : : }
686 : :
687 : : mutex_unlock(&(sm_state->map_lock));
688 : :
689 : : seq_printf(s, "\nResources Count %d\n", res_count);
690 : :
691 : : return 0;
692 : : }
693 : : #endif
694 : :
695 : : #if 0
696 : : /* Read callback for the allocation proc entry. */
697 : : static int vc_sm_alloc_show(struct seq_file *s, void *v)
698 : : {
699 : : struct sm_priv_data_t *file_data;
700 : : struct sm_resource_t *resource;
701 : : int alloc_count = 0;
702 : : struct sm_pde_t *p_pde;
703 : :
704 : : p_pde = (struct sm_pde_t *)(s->private);
705 : : file_data = (struct sm_priv_data_t *)(p_pde->priv_data);
706 : :
707 : : if (!file_data)
708 : : return 0;
709 : :
710 : : /* Per process statistics. */
711 : : seq_printf(s, "\nAllocation for TGID %d\n", file_data->pid);
712 : :
713 : : mutex_lock(&(sm_state->map_lock));
714 : :
715 : : if (!list_empty(&file_data->resource_list)) {
716 : : list_for_each_entry(resource, &file_data->resource_list,
717 : : resource_list) {
718 : : alloc_count++;
719 : :
720 : : seq_printf(s, "\nGUID: 0x%x\n",
721 : : resource->res_guid);
722 : : seq_printf(s, "Lock Count: %u\n",
723 : : resource->lock_count);
724 : : seq_printf(s, "Mapped: %s\n",
725 : : (resource->map_count ? "yes" : "no"));
726 : : seq_printf(s, "VC-handle: 0x%x\n",
727 : : resource->res_handle);
728 : : seq_printf(s, "VC-address: 0x%p\n",
729 : : resource->res_base_mem);
730 : : seq_printf(s, "VC-size (bytes): %u\n",
731 : : resource->res_size);
732 : : seq_printf(s, "Cache: %s\n",
733 : : sm_cache_map_vector[resource->res_cached]);
734 : : }
735 : : }
736 : :
737 : : mutex_unlock(&(sm_state->map_lock));
738 : :
739 : : seq_printf(s, "\n\nTotal allocation count: %d\n\n", alloc_count);
740 : :
741 : : return 0;
742 : : }
743 : : #endif
744 : :
745 : 0 : static int vc_sm_seq_file_show(struct seq_file *s, void *v)
746 : : {
747 : : struct sm_pde_t *sm_pde;
748 : :
749 : 0 : sm_pde = (struct sm_pde_t *)(s->private);
750 : :
751 : 0 : if (sm_pde && sm_pde->show)
752 : 0 : sm_pde->show(s, v);
753 : :
754 : 0 : return 0;
755 : : }
756 : :
757 : 0 : static int vc_sm_single_open(struct inode *inode, struct file *file)
758 : : {
759 : 0 : return single_open(file, vc_sm_seq_file_show, inode->i_private);
760 : : }
761 : :
762 : : static const struct file_operations vc_sm_debug_fs_fops = {
763 : : .open = vc_sm_single_open,
764 : : .read = seq_read,
765 : : .llseek = seq_lseek,
766 : : .release = single_release,
767 : : };
768 : :
769 : : /*
770 : : * Adds a resource to the private data list which tracks all the allocated
771 : : * data.
772 : : */
773 : 0 : static void vmcs_sm_add_resource(struct sm_priv_data_t *privdata,
774 : : struct sm_resource_t *resource)
775 : : {
776 : 0 : mutex_lock(&(sm_state->map_lock));
777 : 0 : list_add(&resource->resource_list, &privdata->resource_list);
778 : 0 : list_add(&resource->global_resource_list, &sm_state->resource_list);
779 : 0 : mutex_unlock(&(sm_state->map_lock));
780 : :
781 : : pr_debug("[%s]: added resource %p (base addr %p, hdl %x, size %u, cache %u)\n",
782 : : __func__, resource, resource->res_base_mem,
783 : : resource->res_handle, resource->res_size, resource->res_cached);
784 : 0 : }
785 : :
786 : : /*
787 : : * Locates a resource and acquire a reference on it.
788 : : * The resource won't be deleted while there is a reference on it.
789 : : */
790 : 0 : static struct sm_resource_t *vmcs_sm_acquire_resource(struct sm_priv_data_t
791 : : *private,
792 : : unsigned int res_guid)
793 : : {
794 : : struct sm_resource_t *resource, *ret = NULL;
795 : :
796 : 0 : mutex_lock(&(sm_state->map_lock));
797 : :
798 : 0 : list_for_each_entry(resource, &private->resource_list, resource_list) {
799 : 0 : if (resource->res_guid != res_guid)
800 : 0 : continue;
801 : :
802 : : pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
803 : : __func__, resource, resource->res_guid,
804 : : resource->res_base_mem, resource->res_handle,
805 : : resource->res_size, resource->res_cached);
806 : 0 : resource->ref_count++;
807 : 0 : ret = resource;
808 : 0 : break;
809 : : }
810 : :
811 : 0 : mutex_unlock(&(sm_state->map_lock));
812 : :
813 : 0 : return ret;
814 : : }
815 : :
816 : : /*
817 : : * Locates a resource and acquire a reference on it.
818 : : * The resource won't be deleted while there is a reference on it.
819 : : */
820 : 0 : static struct sm_resource_t *vmcs_sm_acquire_first_resource(
821 : : struct sm_priv_data_t *private)
822 : : {
823 : : struct sm_resource_t *resource, *ret = NULL;
824 : :
825 : 0 : mutex_lock(&(sm_state->map_lock));
826 : :
827 : 0 : list_for_each_entry(resource, &private->resource_list, resource_list) {
828 : : pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
829 : : __func__, resource, resource->res_guid,
830 : : resource->res_base_mem, resource->res_handle,
831 : : resource->res_size, resource->res_cached);
832 : 0 : resource->ref_count++;
833 : : ret = resource;
834 : 0 : break;
835 : : }
836 : :
837 : 0 : mutex_unlock(&(sm_state->map_lock));
838 : :
839 : 0 : return ret;
840 : : }
841 : :
842 : : /*
843 : : * Locates a resource and acquire a reference on it.
844 : : * The resource won't be deleted while there is a reference on it.
845 : : */
846 : 0 : static struct sm_resource_t *vmcs_sm_acquire_global_resource(unsigned int
847 : : res_guid)
848 : : {
849 : : struct sm_resource_t *resource, *ret = NULL;
850 : :
851 : 0 : mutex_lock(&(sm_state->map_lock));
852 : :
853 : 0 : list_for_each_entry(resource, &sm_state->resource_list,
854 : : global_resource_list) {
855 : 0 : if (resource->res_guid != res_guid)
856 : 0 : continue;
857 : :
858 : : pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
859 : : __func__, resource, resource->res_guid,
860 : : resource->res_base_mem, resource->res_handle,
861 : : resource->res_size, resource->res_cached);
862 : 0 : resource->ref_count++;
863 : 0 : ret = resource;
864 : 0 : break;
865 : : }
866 : :
867 : 0 : mutex_unlock(&(sm_state->map_lock));
868 : :
869 : 0 : return ret;
870 : : }
871 : :
872 : : /*
873 : : * Release a previously acquired resource.
874 : : * The resource will be deleted when its refcount reaches 0.
875 : : */
876 : 0 : static void vmcs_sm_release_resource(struct sm_resource_t *resource, int force)
877 : : {
878 : 0 : struct sm_priv_data_t *private = resource->private;
879 : : struct sm_mmap *map, *map_tmp;
880 : : struct sm_resource_t *res_tmp;
881 : : int ret;
882 : :
883 : 0 : mutex_lock(&(sm_state->map_lock));
884 : :
885 : 0 : if (--resource->ref_count) {
886 : 0 : if (force)
887 : 0 : pr_err("[%s]: resource %p in use\n", __func__, resource);
888 : :
889 : 0 : mutex_unlock(&(sm_state->map_lock));
890 : 0 : return;
891 : : }
892 : :
893 : : /* Time to free the resource. Start by removing it from the list */
894 : : list_del(&resource->resource_list);
895 : : list_del(&resource->global_resource_list);
896 : :
897 : : /*
898 : : * Walk the global resource list, find out if the resource is used
899 : : * somewhere else. In which case we don't want to delete it.
900 : : */
901 : 0 : list_for_each_entry(res_tmp, &sm_state->resource_list,
902 : : global_resource_list) {
903 : 0 : if (res_tmp->res_handle == resource->res_handle) {
904 : 0 : resource->res_handle = 0;
905 : 0 : break;
906 : : }
907 : : }
908 : :
909 : 0 : mutex_unlock(&(sm_state->map_lock));
910 : :
911 : : pr_debug("[%s]: freeing data - guid %x, hdl %x, base address %p\n",
912 : : __func__, resource->res_guid, resource->res_handle,
913 : : resource->res_base_mem);
914 : 0 : resource->res_stats[FREE]++;
915 : :
916 : : /* Make sure the resource we're removing is unmapped first */
917 : 0 : if (resource->map_count && !list_empty(&resource->map_list)) {
918 : 0 : down_write(¤t->mm->mmap_sem);
919 : 0 : list_for_each_entry_safe(map, map_tmp, &resource->map_list,
920 : : resource_map_list) {
921 : 0 : ret =
922 : 0 : do_munmap(current->mm, map->res_addr,
923 : : resource->res_size, NULL);
924 : 0 : if (ret) {
925 : 0 : pr_err("[%s]: could not unmap resource %p\n",
926 : : __func__, resource);
927 : : }
928 : : }
929 : 0 : up_write(¤t->mm->mmap_sem);
930 : : }
931 : :
932 : : /* Free up the videocore allocated resource. */
933 : 0 : if (resource->res_handle) {
934 : 0 : struct vc_sm_free_t free = {
935 : 0 : resource->res_handle, (uint32_t)resource->res_base_mem
936 : : };
937 : 0 : int status = vc_vchi_sm_free(sm_state->sm_handle, &free,
938 : : &private->int_trans_id);
939 : 0 : if (status != 0 && status != -EINTR) {
940 : 0 : pr_err("[%s]: failed to free memory on videocore (status: %u, trans_id: %u)\n",
941 : : __func__, status, private->int_trans_id);
942 : 0 : resource->res_stats[FREE_FAIL]++;
943 : : ret = -EPERM;
944 : : }
945 : : }
946 : :
947 : 0 : if (resource->sgt)
948 : 0 : dma_buf_unmap_attachment(resource->attach, resource->sgt,
949 : : DMA_BIDIRECTIONAL);
950 : 0 : if (resource->attach)
951 : 0 : dma_buf_detach(resource->dma_buf, resource->attach);
952 : 0 : if (resource->dma_buf)
953 : 0 : dma_buf_put(resource->dma_buf);
954 : :
955 : : /* Free up the shared resource. */
956 : 0 : if (resource->res_shared)
957 : 0 : vmcs_sm_release_resource(resource->res_shared, 0);
958 : :
959 : : /* Free up the local resource tracking this allocation. */
960 : 0 : vc_sm_resource_deceased(resource, force);
961 : 0 : kfree(resource);
962 : : }
963 : :
964 : : /*
965 : : * Dump the map table for the driver. If process is -1, dumps the whole table,
966 : : * if process is a valid pid (non -1) dump only the entries associated with the
967 : : * pid of interest.
968 : : */
969 : 0 : static void vmcs_sm_host_walk_map_per_pid(int pid)
970 : : {
971 : : struct sm_mmap *map = NULL;
972 : :
973 : : /* Make sure the device was started properly. */
974 : 0 : if (sm_state == NULL) {
975 : 0 : pr_err("[%s]: invalid device\n", __func__);
976 : 0 : return;
977 : : }
978 : :
979 : 0 : mutex_lock(&(sm_state->map_lock));
980 : :
981 : : /* Log all applicable mapping(s). */
982 : 0 : if (!list_empty(&sm_state->map_list)) {
983 : 0 : list_for_each_entry(map, &sm_state->map_list, map_list) {
984 : 0 : if (pid == -1 || map->res_pid == pid) {
985 : 0 : pr_info("[%s]: tgid: %u - vc-hdl: %x, usr-hdl: %x, usr-addr: %lx\n",
986 : : __func__, map->res_pid, map->res_vc_hdl,
987 : : map->res_usr_hdl, map->res_addr);
988 : : }
989 : : }
990 : : }
991 : :
992 : 0 : mutex_unlock(&(sm_state->map_lock));
993 : : }
994 : :
995 : : /*
996 : : * Dump the allocation table from host side point of view. This only dumps the
997 : : * data allocated for this process/device referenced by the file_data.
998 : : */
999 : 0 : static void vmcs_sm_host_walk_alloc(struct sm_priv_data_t *file_data)
1000 : : {
1001 : : struct sm_resource_t *resource = NULL;
1002 : :
1003 : : /* Make sure the device was started properly. */
1004 : 0 : if ((sm_state == NULL) || (file_data == NULL)) {
1005 : 0 : pr_err("[%s]: invalid device\n", __func__);
1006 : 0 : return;
1007 : : }
1008 : :
1009 : 0 : mutex_lock(&(sm_state->map_lock));
1010 : :
1011 : 0 : if (!list_empty(&file_data->resource_list)) {
1012 : 0 : list_for_each_entry(resource, &file_data->resource_list,
1013 : : resource_list) {
1014 : 0 : pr_info("[%s]: guid: %x - hdl: %x, vc-mem: %p, size: %u, cache: %u\n",
1015 : : __func__, resource->res_guid, resource->res_handle,
1016 : : resource->res_base_mem, resource->res_size,
1017 : : resource->res_cached);
1018 : : }
1019 : : }
1020 : :
1021 : 0 : mutex_unlock(&(sm_state->map_lock));
1022 : : }
1023 : :
1024 : : /* Create support for private data tracking. */
1025 : 2 : static struct sm_priv_data_t *vc_sm_create_priv_data(pid_t id)
1026 : : {
1027 : : char alloc_name[32];
1028 : : struct sm_priv_data_t *file_data = NULL;
1029 : :
1030 : : /* Allocate private structure. */
1031 : 2 : file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
1032 : :
1033 : 2 : if (!file_data) {
1034 : 0 : pr_err("[%s]: cannot allocate file data\n", __func__);
1035 : 0 : goto out;
1036 : : }
1037 : :
1038 : 2 : snprintf(alloc_name, sizeof(alloc_name), "%d", id);
1039 : :
1040 : 2 : INIT_LIST_HEAD(&file_data->resource_list);
1041 : 2 : file_data->pid = id;
1042 : 2 : file_data->dir_pid = debugfs_create_dir(alloc_name,
1043 : 2 : sm_state->dir_alloc);
1044 : : #if 0
1045 : : /* TODO: fix this to support querying statistics per pid */
1046 : :
1047 : : if (IS_ERR_OR_NULL(file_data->dir_pid)) {
1048 : : file_data->dir_pid = NULL;
1049 : : } else {
1050 : : struct dentry *dir_entry;
1051 : :
1052 : : dir_entry = debugfs_create_file(VC_SM_RESOURCES, 0444,
1053 : : file_data->dir_pid, file_data,
1054 : : vc_sm_debug_fs_fops);
1055 : :
1056 : : file_data->dir_res.dir_entry = dir_entry;
1057 : : file_data->dir_res.priv_data = file_data;
1058 : : file_data->dir_res.show = &vc_sm_alloc_show;
1059 : :
1060 : : dir_entry = debugfs_create_file(VC_SM_STATS, 0444,
1061 : : file_data->dir_pid, file_data,
1062 : : vc_sm_debug_fs_fops);
1063 : :
1064 : : file_data->dir_res.dir_entry = dir_entry;
1065 : : file_data->dir_res.priv_data = file_data;
1066 : : file_data->dir_res.show = &vc_sm_statistics_show;
1067 : : }
1068 : : pr_debug("[%s]: private data allocated %p\n", __func__, file_data);
1069 : :
1070 : : #endif
1071 : : out:
1072 : 2 : return file_data;
1073 : : }
1074 : :
1075 : : /*
1076 : : * Open the device. Creates a private state to help track all allocation
1077 : : * associated with this device.
1078 : : */
1079 : 0 : static int vc_sm_open(struct inode *inode, struct file *file)
1080 : : {
1081 : : int ret = 0;
1082 : :
1083 : : /* Make sure the device was started properly. */
1084 : 0 : if (!sm_state) {
1085 : 0 : pr_err("[%s]: invalid device\n", __func__);
1086 : : ret = -EPERM;
1087 : 0 : goto out;
1088 : : }
1089 : :
1090 : 0 : file->private_data = vc_sm_create_priv_data(current->tgid);
1091 : 0 : if (file->private_data == NULL) {
1092 : 0 : pr_err("[%s]: failed to create data tracker\n", __func__);
1093 : :
1094 : : ret = -ENOMEM;
1095 : 0 : goto out;
1096 : : }
1097 : :
1098 : : out:
1099 : 0 : return ret;
1100 : : }
1101 : :
1102 : : /*
1103 : : * Close the device. Free up all resources still associated with this device
1104 : : * at the time.
1105 : : */
1106 : 0 : static int vc_sm_release(struct inode *inode, struct file *file)
1107 : : {
1108 : 0 : struct sm_priv_data_t *file_data =
1109 : : (struct sm_priv_data_t *)file->private_data;
1110 : : struct sm_resource_t *resource;
1111 : : int ret = 0;
1112 : :
1113 : : /* Make sure the device was started properly. */
1114 : 0 : if (sm_state == NULL || file_data == NULL) {
1115 : 0 : pr_err("[%s]: invalid device\n", __func__);
1116 : : ret = -EPERM;
1117 : 0 : goto out;
1118 : : }
1119 : :
1120 : : pr_debug("[%s]: using private data %p\n", __func__, file_data);
1121 : :
1122 : 0 : if (file_data->restart_sys == -EINTR) {
1123 : : struct vc_sm_action_clean_t action_clean;
1124 : :
1125 : : pr_debug("[%s]: releasing following EINTR on %u (trans_id: %u) (likely due to signal)...\n",
1126 : : __func__, file_data->int_action,
1127 : : file_data->int_trans_id);
1128 : :
1129 : 0 : action_clean.res_action = file_data->int_action;
1130 : 0 : action_clean.action_trans_id = file_data->int_trans_id;
1131 : :
1132 : 0 : vc_vchi_sm_clean_up(sm_state->sm_handle, &action_clean);
1133 : : }
1134 : :
1135 : 0 : while ((resource = vmcs_sm_acquire_first_resource(file_data)) != NULL) {
1136 : 0 : vmcs_sm_release_resource(resource, 0);
1137 : 0 : vmcs_sm_release_resource(resource, 1);
1138 : : }
1139 : :
1140 : : /* Remove the corresponding proc entry. */
1141 : 0 : debugfs_remove_recursive(file_data->dir_pid);
1142 : :
1143 : : /* Terminate the private data. */
1144 : 0 : kfree(file_data);
1145 : :
1146 : : out:
1147 : 0 : return ret;
1148 : : }
1149 : :
1150 : 0 : static void vcsm_vma_open(struct vm_area_struct *vma)
1151 : : {
1152 : 0 : struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data;
1153 : :
1154 : : pr_debug("[%s]: virt %lx-%lx, pid %i, pfn %i\n",
1155 : : __func__, vma->vm_start, vma->vm_end, (int)current->tgid,
1156 : : (int)vma->vm_pgoff);
1157 : :
1158 : 0 : map->ref_count++;
1159 : 0 : }
1160 : :
1161 : 0 : static void vcsm_vma_close(struct vm_area_struct *vma)
1162 : : {
1163 : 0 : struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data;
1164 : :
1165 : : pr_debug("[%s]: virt %lx-%lx, pid %i, pfn %i\n",
1166 : : __func__, vma->vm_start, vma->vm_end, (int)current->tgid,
1167 : : (int)vma->vm_pgoff);
1168 : :
1169 : 0 : map->ref_count--;
1170 : :
1171 : : /* Remove from the map table. */
1172 : 0 : if (map->ref_count == 0)
1173 : 0 : vmcs_sm_remove_map(sm_state, map->resource, map);
1174 : 0 : }
1175 : :
1176 : 0 : static vm_fault_t vcsm_vma_fault(struct vm_fault *vmf)
1177 : : {
1178 : 0 : struct sm_mmap *map = (struct sm_mmap *)vmf->vma->vm_private_data;
1179 : 0 : struct sm_resource_t *resource = map->resource;
1180 : : pgoff_t page_offset;
1181 : : unsigned long pfn;
1182 : : vm_fault_t ret;
1183 : :
1184 : : /* Lock the resource if necessary. */
1185 : 0 : if (!resource->lock_count) {
1186 : : struct vc_sm_lock_unlock_t lock_unlock;
1187 : : struct vc_sm_lock_result_t lock_result;
1188 : : int status;
1189 : :
1190 : 0 : lock_unlock.res_handle = resource->res_handle;
1191 : 0 : lock_unlock.res_mem = (uint32_t)resource->res_base_mem;
1192 : :
1193 : : pr_debug("[%s]: attempt to lock data - hdl %x, base address %p\n",
1194 : : __func__, lock_unlock.res_handle,
1195 : : (void *)lock_unlock.res_mem);
1196 : :
1197 : : /* Lock the videocore allocated resource. */
1198 : 0 : status = vc_vchi_sm_lock(sm_state->sm_handle,
1199 : : &lock_unlock, &lock_result, 0);
1200 : 0 : if (status || !lock_result.res_mem) {
1201 : 0 : pr_err("[%s]: failed to lock memory on videocore (status: %u)\n",
1202 : : __func__, status);
1203 : 0 : resource->res_stats[LOCK_FAIL]++;
1204 : 0 : return VM_FAULT_SIGBUS;
1205 : : }
1206 : :
1207 : : pfn = vcaddr_to_pfn((unsigned long)resource->res_base_mem);
1208 : : outer_inv_range(__pfn_to_phys(pfn),
1209 : : __pfn_to_phys(pfn) + resource->res_size);
1210 : :
1211 : 0 : resource->res_stats[LOCK]++;
1212 : 0 : resource->lock_count++;
1213 : :
1214 : : /* Keep track of the new base memory. */
1215 : 0 : if (lock_result.res_mem &&
1216 : 0 : lock_result.res_old_mem &&
1217 : : (lock_result.res_mem != lock_result.res_old_mem)) {
1218 : 0 : resource->res_base_mem = (void *)lock_result.res_mem;
1219 : : }
1220 : : }
1221 : :
1222 : : /* We don't use vmf->pgoff since that has the fake offset */
1223 : 0 : page_offset = ((unsigned long)vmf->address - vmf->vma->vm_start);
1224 : 0 : pfn = (uint32_t)resource->res_base_mem & 0x3FFFFFFF;
1225 : 0 : pfn += mm_vc_mem_phys_addr;
1226 : 0 : pfn += page_offset;
1227 : 0 : pfn >>= PAGE_SHIFT;
1228 : :
1229 : : /* Finally, remap it */
1230 : 0 : ret = vmf_insert_pfn(vmf->vma, (unsigned long)vmf->address, pfn);
1231 : 0 : if (ret != VM_FAULT_NOPAGE)
1232 : 0 : pr_err("[%s]: failed to map page pfn:%lx virt:%lx ret:%d\n", __func__,
1233 : : pfn, (unsigned long)vmf->address, ret);
1234 : 0 : return ret;
1235 : : }
1236 : :
1237 : : static const struct vm_operations_struct vcsm_vm_ops = {
1238 : : .open = vcsm_vma_open,
1239 : : .close = vcsm_vma_close,
1240 : : .fault = vcsm_vma_fault,
1241 : : };
1242 : :
1243 : : /* Converts VCSM_CACHE_OP_* to an operating function. */
1244 : 0 : static void (*cache_op_to_func(const unsigned cache_op))
1245 : : (const void*, const void*)
1246 : : {
1247 : 0 : switch (cache_op) {
1248 : : case VCSM_CACHE_OP_NOP:
1249 : : return NULL;
1250 : :
1251 : : case VCSM_CACHE_OP_INV:
1252 : 0 : return dmac_inv_range;
1253 : :
1254 : : case VCSM_CACHE_OP_CLEAN:
1255 : 0 : return dmac_clean_range;
1256 : :
1257 : : case VCSM_CACHE_OP_FLUSH:
1258 : 0 : return dmac_flush_range;
1259 : :
1260 : : default:
1261 : 0 : pr_err("[%s]: Invalid cache_op: 0x%08x\n", __func__, cache_op);
1262 : 0 : return NULL;
1263 : : }
1264 : : }
1265 : :
1266 : : /*
1267 : : * Clean/invalid/flush cache of which buffer is already pinned (i.e. accessed).
1268 : : */
1269 : 0 : static int clean_invalid_contiguous_mem_2d(const void __user *addr,
1270 : : const size_t block_count, const size_t block_size, const size_t stride,
1271 : : const unsigned cache_op)
1272 : : {
1273 : : size_t i;
1274 : : void (*op_fn)(const void*, const void*);
1275 : :
1276 : 0 : if (!block_size) {
1277 : 0 : pr_err("[%s]: size cannot be 0\n", __func__);
1278 : 0 : return -EINVAL;
1279 : : }
1280 : :
1281 : 0 : op_fn = cache_op_to_func(cache_op);
1282 : 0 : if (op_fn == NULL)
1283 : : return -EINVAL;
1284 : :
1285 : 0 : for (i = 0; i < block_count; i ++, addr += stride)
1286 : 0 : op_fn(addr, addr + block_size);
1287 : :
1288 : : return 0;
1289 : : }
1290 : :
1291 : : /* Clean/invalid/flush cache of which buffer may be non-pinned. */
1292 : : /* The caller must lock current->mm->mmap_sem for read. */
1293 : 0 : static int clean_invalid_mem_walk(unsigned long addr, const size_t size,
1294 : : const unsigned cache_op)
1295 : : {
1296 : : pgd_t *pgd;
1297 : : pud_t *pud;
1298 : : pmd_t *pmd;
1299 : : pte_t *pte;
1300 : : unsigned long pgd_next, pud_next, pmd_next;
1301 : 0 : const unsigned long end = ALIGN(addr + size, PAGE_SIZE);
1302 : : void (*op_fn)(const void*, const void*);
1303 : :
1304 : 0 : addr &= PAGE_MASK;
1305 : :
1306 : 0 : if (addr >= end)
1307 : : return 0;
1308 : :
1309 : 0 : op_fn = cache_op_to_func(cache_op);
1310 : 0 : if (op_fn == NULL)
1311 : : return -EINVAL;
1312 : :
1313 : : /* Walk PGD */
1314 : 0 : pgd = pgd_offset(current->mm, addr);
1315 : : do {
1316 : 0 : pgd_next = pgd_addr_end(addr, end);
1317 : :
1318 : : if (pgd_none(*pgd) || pgd_bad(*pgd))
1319 : : continue;
1320 : :
1321 : : /* Walk PUD */
1322 : : pud = pud_offset(pgd, addr);
1323 : : do {
1324 : : pud_next = pud_addr_end(addr, pgd_next);
1325 : : if (pud_none(*pud) || pud_bad(*pud))
1326 : : continue;
1327 : :
1328 : : /* Walk PMD */
1329 : : pmd = pmd_offset(pud, addr);
1330 : : do {
1331 : : pmd_next = pmd_addr_end(addr, pud_next);
1332 : 0 : if (pmd_none(*pmd) || pmd_bad(*pmd))
1333 : 0 : continue;
1334 : :
1335 : : /* Walk PTE */
1336 : 0 : pte = pte_offset_map(pmd, addr);
1337 : : do {
1338 : 0 : if (pte_none(*pte) || !pte_present(*pte))
1339 : 0 : continue;
1340 : :
1341 : 0 : op_fn((const void __user*) addr,
1342 : 0 : (const void __user*) (addr + PAGE_SIZE));
1343 : 0 : } while (pte++, addr += PAGE_SIZE, addr != pmd_next);
1344 : : pte_unmap(pte);
1345 : :
1346 : : } while (pmd++, addr = pmd_next, addr != pud_next);
1347 : :
1348 : : } while (pud++, addr = pud_next, addr != pgd_next);
1349 : :
1350 : 0 : } while (pgd++, addr = pgd_next, addr != end);
1351 : :
1352 : : return 0;
1353 : : }
1354 : :
1355 : : /* Clean/invalid/flush cache of buffer in resource */
1356 : 0 : static int clean_invalid_resource_walk(const void __user *addr,
1357 : : const size_t size, const unsigned cache_op, const int usr_hdl,
1358 : : struct sm_resource_t *resource)
1359 : : {
1360 : : int err;
1361 : : enum sm_stats_t stat_attempt, stat_failure;
1362 : : void __user *res_addr;
1363 : :
1364 : 0 : if (resource == NULL) {
1365 : 0 : pr_err("[%s]: resource is NULL\n", __func__);
1366 : 0 : return -EINVAL;
1367 : : }
1368 : 0 : if (resource->res_cached != VMCS_SM_CACHE_HOST &&
1369 : : resource->res_cached != VMCS_SM_CACHE_BOTH)
1370 : : return 0;
1371 : :
1372 : 0 : switch (cache_op) {
1373 : : case VCSM_CACHE_OP_NOP:
1374 : : return 0;
1375 : : case VCSM_CACHE_OP_INV:
1376 : : stat_attempt = INVALID;
1377 : : stat_failure = INVALID_FAIL;
1378 : : break;
1379 : : case VCSM_CACHE_OP_CLEAN:
1380 : : /* Like the original VMCS_SM_CMD_CLEAN_INVALID ioctl handler does. */
1381 : : stat_attempt = FLUSH;
1382 : : stat_failure = FLUSH_FAIL;
1383 : 0 : break;
1384 : : case VCSM_CACHE_OP_FLUSH:
1385 : : stat_attempt = FLUSH;
1386 : : stat_failure = FLUSH_FAIL;
1387 : 0 : break;
1388 : : default:
1389 : 0 : pr_err("[%s]: Invalid cache_op: 0x%08x\n", __func__, cache_op);
1390 : 0 : return -EINVAL;
1391 : : }
1392 : 0 : resource->res_stats[stat_attempt]++;
1393 : :
1394 : 0 : if (size > resource->res_size) {
1395 : 0 : pr_err("[%s]: size (0x%08zu) is larger than res_size (0x%08zu)\n",
1396 : : __func__, size, resource->res_size);
1397 : 0 : return -EFAULT;
1398 : : }
1399 : 0 : res_addr = (void __user*) vmcs_sm_usr_address_from_pid_and_usr_handle(
1400 : 0 : current->tgid, usr_hdl);
1401 : 0 : if (res_addr == NULL) {
1402 : 0 : pr_err("[%s]: Failed to get user address "
1403 : : "from pid (%d) and user handle (%d)\n", __func__, current->tgid,
1404 : : resource->res_handle);
1405 : 0 : return -EINVAL;
1406 : : }
1407 : 0 : if (!(res_addr <= addr && addr + size <= res_addr + resource->res_size)) {
1408 : 0 : pr_err("[%s]: Addr (0x%p-0x%p) out of range (0x%p-0x%p)\n",
1409 : : __func__, addr, addr + size, res_addr,
1410 : : res_addr + resource->res_size);
1411 : 0 : return -EFAULT;
1412 : : }
1413 : :
1414 : 0 : down_read(¤t->mm->mmap_sem);
1415 : 0 : err = clean_invalid_mem_walk((unsigned long) addr, size, cache_op);
1416 : 0 : up_read(¤t->mm->mmap_sem);
1417 : :
1418 : 0 : if (err)
1419 : 0 : resource->res_stats[stat_failure]++;
1420 : :
1421 : 0 : return err;
1422 : : }
1423 : :
1424 : : /* Map an allocated data into something that the user space. */
1425 : 0 : static int vc_sm_mmap(struct file *file, struct vm_area_struct *vma)
1426 : : {
1427 : : int ret = 0;
1428 : 0 : struct sm_priv_data_t *file_data =
1429 : : (struct sm_priv_data_t *)file->private_data;
1430 : : struct sm_resource_t *resource = NULL;
1431 : : struct sm_mmap *map = NULL;
1432 : :
1433 : : /* Make sure the device was started properly. */
1434 : 0 : if ((sm_state == NULL) || (file_data == NULL)) {
1435 : 0 : pr_err("[%s]: invalid device\n", __func__);
1436 : 0 : return -EPERM;
1437 : : }
1438 : :
1439 : : pr_debug("[%s]: private data %p, guid %x\n", __func__, file_data,
1440 : : ((unsigned int)vma->vm_pgoff << PAGE_SHIFT));
1441 : :
1442 : : /*
1443 : : * We lookup to make sure that the data we are being asked to mmap is
1444 : : * something that we allocated.
1445 : : *
1446 : : * We use the offset information as the key to tell us which resource
1447 : : * we are mapping.
1448 : : */
1449 : 0 : resource = vmcs_sm_acquire_resource(file_data,
1450 : 0 : ((unsigned int)vma->vm_pgoff <<
1451 : : PAGE_SHIFT));
1452 : 0 : if (resource == NULL) {
1453 : 0 : pr_err("[%s]: failed to locate resource for guid %x\n", __func__,
1454 : : ((unsigned int)vma->vm_pgoff << PAGE_SHIFT));
1455 : 0 : return -ENOMEM;
1456 : : }
1457 : :
1458 : : pr_debug("[%s]: guid %x, tgid %u, %u, %u\n",
1459 : : __func__, resource->res_guid, current->tgid, resource->pid,
1460 : : file_data->pid);
1461 : :
1462 : : /* Check permissions. */
1463 : 0 : if (resource->pid && (resource->pid != current->tgid)) {
1464 : 0 : pr_err("[%s]: current tgid %u != %u owner\n",
1465 : : __func__, current->tgid, resource->pid);
1466 : : ret = -EPERM;
1467 : 0 : goto error;
1468 : : }
1469 : :
1470 : : /* Verify that what we are asked to mmap is proper. */
1471 : 0 : if (resource->res_size != (unsigned int)(vma->vm_end - vma->vm_start)) {
1472 : 0 : pr_err("[%s]: size inconsistency (resource: %u - mmap: %u)\n",
1473 : : __func__,
1474 : : resource->res_size,
1475 : : (unsigned int)(vma->vm_end - vma->vm_start));
1476 : :
1477 : : ret = -EINVAL;
1478 : 0 : goto error;
1479 : : }
1480 : :
1481 : : /*
1482 : : * Keep track of the tuple in the global resource list such that one
1483 : : * can do a mapping lookup for address/memory handle.
1484 : : */
1485 : 0 : map = kzalloc(sizeof(*map), GFP_KERNEL);
1486 : 0 : if (map == NULL) {
1487 : 0 : pr_err("[%s]: failed to allocate global tracking resource\n",
1488 : : __func__);
1489 : : ret = -ENOMEM;
1490 : 0 : goto error;
1491 : : }
1492 : :
1493 : 0 : map->res_pid = current->tgid;
1494 : 0 : map->res_vc_hdl = resource->res_handle;
1495 : 0 : map->res_usr_hdl = resource->res_guid;
1496 : 0 : map->res_addr = (unsigned long)vma->vm_start;
1497 : 0 : map->resource = resource;
1498 : 0 : map->vma = vma;
1499 : 0 : vmcs_sm_add_map(sm_state, resource, map);
1500 : :
1501 : : /*
1502 : : * We are not actually mapping the pages, we just provide a fault
1503 : : * handler to allow pages to be mapped when accessed
1504 : : */
1505 : 0 : vma->vm_flags |=
1506 : : VM_IO | VM_PFNMAP | VM_DONTCOPY | VM_DONTEXPAND;
1507 : 0 : vma->vm_ops = &vcsm_vm_ops;
1508 : 0 : vma->vm_private_data = map;
1509 : :
1510 : : /* vm_pgoff is the first PFN of the mapped memory */
1511 : 0 : vma->vm_pgoff = (unsigned long)resource->res_base_mem & 0x3FFFFFFF;
1512 : 0 : vma->vm_pgoff += mm_vc_mem_phys_addr;
1513 : 0 : vma->vm_pgoff >>= PAGE_SHIFT;
1514 : :
1515 : 0 : if ((resource->res_cached == VMCS_SM_CACHE_NONE) ||
1516 : : (resource->res_cached == VMCS_SM_CACHE_VC)) {
1517 : : /* Allocated non host cached memory, honour it. */
1518 : 0 : vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
1519 : : }
1520 : :
1521 : : pr_debug("[%s]: resource %p (guid %x) - cnt %u, base address %p, handle %x, size %u (%u), cache %u\n",
1522 : : __func__,
1523 : : resource, resource->res_guid, resource->lock_count,
1524 : : resource->res_base_mem, resource->res_handle,
1525 : : resource->res_size, (unsigned int)(vma->vm_end - vma->vm_start),
1526 : : resource->res_cached);
1527 : :
1528 : : pr_debug("[%s]: resource %p (base address %p, handle %x) - map-count %d, usr-addr %x\n",
1529 : : __func__, resource, resource->res_base_mem,
1530 : : resource->res_handle, resource->map_count,
1531 : : (unsigned int)vma->vm_start);
1532 : :
1533 : : vcsm_vma_open(vma);
1534 : 0 : resource->res_stats[MAP]++;
1535 : 0 : vmcs_sm_release_resource(resource, 0);
1536 : :
1537 : 0 : if (resource->map) {
1538 : : /* We don't use vmf->pgoff since that has the fake offset */
1539 : : unsigned long addr;
1540 : :
1541 : 0 : for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) {
1542 : : /* Finally, remap it */
1543 : 0 : unsigned long pfn = (unsigned long)resource->res_base_mem & 0x3FFFFFFF;
1544 : :
1545 : 0 : pfn += mm_vc_mem_phys_addr;
1546 : 0 : pfn += addr - vma->vm_start;
1547 : 0 : pfn >>= PAGE_SHIFT;
1548 : 0 : ret = vmf_insert_pfn(vma, addr, pfn);
1549 : : }
1550 : : }
1551 : :
1552 : : return 0;
1553 : :
1554 : : error:
1555 : 0 : resource->res_stats[MAP_FAIL]++;
1556 : 0 : vmcs_sm_release_resource(resource, 0);
1557 : 0 : return ret;
1558 : : }
1559 : :
1560 : : /* Allocate a shared memory handle and block. */
1561 : 0 : static int vc_sm_ioctl_alloc(struct sm_priv_data_t *private,
1562 : : struct vmcs_sm_ioctl_alloc *ioparam)
1563 : : {
1564 : : int ret = 0;
1565 : : int status;
1566 : : struct sm_resource_t *resource;
1567 : 0 : struct vc_sm_alloc_t alloc = { 0 };
1568 : 0 : struct vc_sm_alloc_result_t result = { 0 };
1569 : 0 : enum vmcs_sm_cache_e cached = ioparam->cached;
1570 : : bool map = false;
1571 : :
1572 : : /* flag to requst buffer is mapped up front, rather than lazily */
1573 : 0 : if (cached & 0x80) {
1574 : : map = true;
1575 : 0 : cached &= ~0x80;
1576 : : }
1577 : :
1578 : : /* Setup our allocation parameters */
1579 : 0 : alloc.type = ((cached == VMCS_SM_CACHE_VC)
1580 : 0 : || (cached ==
1581 : 0 : VMCS_SM_CACHE_BOTH)) ? VC_SM_ALLOC_CACHED :
1582 : : VC_SM_ALLOC_NON_CACHED;
1583 : 0 : alloc.base_unit = ioparam->size;
1584 : 0 : alloc.num_unit = ioparam->num;
1585 : 0 : alloc.allocator = current->tgid;
1586 : : /* Align to kernel page size */
1587 : 0 : alloc.alignement = 4096;
1588 : : /* Align the size to the kernel page size */
1589 : 0 : alloc.base_unit =
1590 : 0 : (alloc.base_unit + alloc.alignement - 1) & ~(alloc.alignement - 1);
1591 : 0 : if (*ioparam->name) {
1592 : 0 : memcpy(alloc.name, ioparam->name, sizeof(alloc.name) - 1);
1593 : : } else {
1594 : 0 : memcpy(alloc.name, VMCS_SM_RESOURCE_NAME_DEFAULT,
1595 : : sizeof(VMCS_SM_RESOURCE_NAME_DEFAULT));
1596 : : }
1597 : :
1598 : : pr_debug("[%s]: attempt to allocate \"%s\" data - type %u, base %u (%u), num %u, alignement %u\n",
1599 : : __func__, alloc.name, alloc.type, ioparam->size,
1600 : : alloc.base_unit, alloc.num_unit, alloc.alignement);
1601 : :
1602 : : /* Allocate local resource to track this allocation. */
1603 : 0 : resource = kzalloc(sizeof(*resource), GFP_KERNEL);
1604 : 0 : if (!resource) {
1605 : : ret = -ENOMEM;
1606 : : goto error;
1607 : : }
1608 : 0 : INIT_LIST_HEAD(&resource->map_list);
1609 : 0 : resource->ref_count++;
1610 : 0 : resource->pid = current->tgid;
1611 : :
1612 : : /* Allocate the videocore resource. */
1613 : 0 : status = vc_vchi_sm_alloc(sm_state->sm_handle, &alloc, &result,
1614 : : &private->int_trans_id);
1615 : 0 : if (status == -EINTR) {
1616 : : pr_debug("[%s]: requesting allocate memory action restart (trans_id: %u)\n",
1617 : : __func__, private->int_trans_id);
1618 : : ret = -ERESTARTSYS;
1619 : 0 : private->restart_sys = -EINTR;
1620 : 0 : private->int_action = VC_SM_MSG_TYPE_ALLOC;
1621 : 0 : goto error;
1622 : 0 : } else if (status != 0 || !result.res_mem) {
1623 : 0 : pr_err("[%s]: failed to allocate memory on videocore (status: %u, trans_id: %u)\n",
1624 : : __func__, status, private->int_trans_id);
1625 : : ret = -ENOMEM;
1626 : 0 : resource->res_stats[ALLOC_FAIL]++;
1627 : 0 : goto error;
1628 : : }
1629 : :
1630 : : /* Keep track of the resource we created. */
1631 : 0 : resource->private = private;
1632 : 0 : resource->res_handle = result.res_handle;
1633 : 0 : resource->res_base_mem = (void *)result.res_mem;
1634 : 0 : resource->res_size = alloc.base_unit * alloc.num_unit;
1635 : 0 : resource->res_cached = cached;
1636 : 0 : resource->map = map;
1637 : :
1638 : : /*
1639 : : * Kernel/user GUID. This global identifier is used for mmap'ing the
1640 : : * allocated region from user space, it is passed as the mmap'ing
1641 : : * offset, we use it to 'hide' the videocore handle/address.
1642 : : */
1643 : 0 : mutex_lock(&sm_state->lock);
1644 : 0 : resource->res_guid = ++sm_state->guid;
1645 : 0 : mutex_unlock(&sm_state->lock);
1646 : 0 : resource->res_guid <<= PAGE_SHIFT;
1647 : :
1648 : 0 : vmcs_sm_add_resource(private, resource);
1649 : :
1650 : : pr_debug("[%s]: allocated data - guid %x, hdl %x, base address %p, size %d, cache %d\n",
1651 : : __func__, resource->res_guid, resource->res_handle,
1652 : : resource->res_base_mem, resource->res_size,
1653 : : resource->res_cached);
1654 : :
1655 : : /* We're done */
1656 : 0 : resource->res_stats[ALLOC]++;
1657 : 0 : ioparam->handle = resource->res_guid;
1658 : 0 : return 0;
1659 : :
1660 : : error:
1661 : 0 : pr_err("[%s]: failed to allocate \"%s\" data (%i) - type %u, base %u (%u), num %u, alignment %u\n",
1662 : : __func__, alloc.name, ret, alloc.type, ioparam->size,
1663 : : alloc.base_unit, alloc.num_unit, alloc.alignement);
1664 : 0 : if (resource != NULL) {
1665 : 0 : vc_sm_resource_deceased(resource, 1);
1666 : 0 : kfree(resource);
1667 : : }
1668 : 0 : return ret;
1669 : : }
1670 : :
1671 : : /* Share an allocate memory handle and block.*/
1672 : 0 : static int vc_sm_ioctl_alloc_share(struct sm_priv_data_t *private,
1673 : : struct vmcs_sm_ioctl_alloc_share *ioparam)
1674 : : {
1675 : : struct sm_resource_t *resource, *shared_resource;
1676 : : int ret = 0;
1677 : :
1678 : : pr_debug("[%s]: attempt to share resource %u\n", __func__,
1679 : : ioparam->handle);
1680 : :
1681 : 0 : shared_resource = vmcs_sm_acquire_global_resource(ioparam->handle);
1682 : 0 : if (shared_resource == NULL) {
1683 : : ret = -ENOMEM;
1684 : : goto error;
1685 : : }
1686 : :
1687 : : /* Allocate local resource to track this allocation. */
1688 : 0 : resource = kzalloc(sizeof(*resource), GFP_KERNEL);
1689 : 0 : if (resource == NULL) {
1690 : 0 : pr_err("[%s]: failed to allocate local tracking resource\n",
1691 : : __func__);
1692 : : ret = -ENOMEM;
1693 : 0 : goto error;
1694 : : }
1695 : 0 : INIT_LIST_HEAD(&resource->map_list);
1696 : 0 : resource->ref_count++;
1697 : 0 : resource->pid = current->tgid;
1698 : :
1699 : : /* Keep track of the resource we created. */
1700 : 0 : resource->private = private;
1701 : 0 : resource->res_handle = shared_resource->res_handle;
1702 : 0 : resource->res_base_mem = shared_resource->res_base_mem;
1703 : 0 : resource->res_size = shared_resource->res_size;
1704 : 0 : resource->res_cached = shared_resource->res_cached;
1705 : 0 : resource->res_shared = shared_resource;
1706 : :
1707 : 0 : mutex_lock(&sm_state->lock);
1708 : 0 : resource->res_guid = ++sm_state->guid;
1709 : 0 : mutex_unlock(&sm_state->lock);
1710 : 0 : resource->res_guid <<= PAGE_SHIFT;
1711 : :
1712 : 0 : vmcs_sm_add_resource(private, resource);
1713 : :
1714 : : pr_debug("[%s]: allocated data - guid %x, hdl %x, base address %p, size %d, cache %d\n",
1715 : : __func__, resource->res_guid, resource->res_handle,
1716 : : resource->res_base_mem, resource->res_size,
1717 : : resource->res_cached);
1718 : :
1719 : : /* We're done */
1720 : 0 : resource->res_stats[ALLOC]++;
1721 : 0 : ioparam->handle = resource->res_guid;
1722 : 0 : ioparam->size = resource->res_size;
1723 : 0 : return 0;
1724 : :
1725 : : error:
1726 : 0 : pr_err("[%s]: failed to share %u\n", __func__, ioparam->handle);
1727 : 0 : if (shared_resource != NULL)
1728 : 0 : vmcs_sm_release_resource(shared_resource, 0);
1729 : :
1730 : : return ret;
1731 : : }
1732 : :
1733 : : /* Free a previously allocated shared memory handle and block.*/
1734 : 0 : static int vc_sm_ioctl_free(struct sm_priv_data_t *private,
1735 : : struct vmcs_sm_ioctl_free *ioparam)
1736 : : {
1737 : 0 : struct sm_resource_t *resource =
1738 : 0 : vmcs_sm_acquire_resource(private, ioparam->handle);
1739 : :
1740 : 0 : if (resource == NULL) {
1741 : 0 : pr_err("[%s]: resource for guid %u does not exist\n", __func__,
1742 : : ioparam->handle);
1743 : 0 : return -EINVAL;
1744 : : }
1745 : :
1746 : : /* Check permissions. */
1747 : 0 : if (resource->pid && (resource->pid != current->tgid)) {
1748 : 0 : pr_err("[%s]: current tgid %u != %u owner\n",
1749 : : __func__, current->tgid, resource->pid);
1750 : 0 : vmcs_sm_release_resource(resource, 0);
1751 : 0 : return -EPERM;
1752 : : }
1753 : :
1754 : 0 : vmcs_sm_release_resource(resource, 0);
1755 : 0 : vmcs_sm_release_resource(resource, 0);
1756 : 0 : return 0;
1757 : : }
1758 : :
1759 : : /* Resize a previously allocated shared memory handle and block. */
1760 : 0 : static int vc_sm_ioctl_resize(struct sm_priv_data_t *private,
1761 : : struct vmcs_sm_ioctl_resize *ioparam)
1762 : : {
1763 : : int ret = 0;
1764 : : int status;
1765 : : struct vc_sm_resize_t resize;
1766 : : struct sm_resource_t *resource;
1767 : :
1768 : : /* Locate resource from GUID. */
1769 : 0 : resource = vmcs_sm_acquire_resource(private, ioparam->handle);
1770 : 0 : if (!resource) {
1771 : 0 : pr_err("[%s]: failed resource - guid %x\n",
1772 : : __func__, ioparam->handle);
1773 : : ret = -EFAULT;
1774 : 0 : goto error;
1775 : : }
1776 : :
1777 : : /*
1778 : : * If the resource is locked, its reference count will be not NULL,
1779 : : * in which case we will not be allowed to resize it anyways, so
1780 : : * reject the attempt here.
1781 : : */
1782 : 0 : if (resource->lock_count != 0) {
1783 : 0 : pr_err("[%s]: cannot resize - guid %x, ref-cnt %d\n",
1784 : : __func__, ioparam->handle, resource->lock_count);
1785 : : ret = -EFAULT;
1786 : 0 : goto error;
1787 : : }
1788 : :
1789 : : /* Check permissions. */
1790 : 0 : if (resource->pid && (resource->pid != current->tgid)) {
1791 : 0 : pr_err("[%s]: current tgid %u != %u owner\n", __func__,
1792 : : current->tgid, resource->pid);
1793 : : ret = -EPERM;
1794 : 0 : goto error;
1795 : : }
1796 : :
1797 : 0 : if (resource->map_count != 0) {
1798 : 0 : pr_err("[%s]: cannot resize - guid %x, ref-cnt %d\n",
1799 : : __func__, ioparam->handle, resource->map_count);
1800 : : ret = -EFAULT;
1801 : 0 : goto error;
1802 : : }
1803 : :
1804 : 0 : resize.res_handle = resource->res_handle;
1805 : 0 : resize.res_mem = (uint32_t)resource->res_base_mem;
1806 : 0 : resize.res_new_size = ioparam->new_size;
1807 : :
1808 : : pr_debug("[%s]: attempt to resize data - guid %x, hdl %x, base address %p\n",
1809 : : __func__, ioparam->handle, resize.res_handle,
1810 : : (void *)resize.res_mem);
1811 : :
1812 : : /* Resize the videocore allocated resource. */
1813 : 0 : status = vc_vchi_sm_resize(sm_state->sm_handle, &resize,
1814 : : &private->int_trans_id);
1815 : 0 : if (status == -EINTR) {
1816 : : pr_debug("[%s]: requesting resize memory action restart (trans_id: %u)\n",
1817 : : __func__, private->int_trans_id);
1818 : : ret = -ERESTARTSYS;
1819 : 0 : private->restart_sys = -EINTR;
1820 : 0 : private->int_action = VC_SM_MSG_TYPE_RESIZE;
1821 : 0 : goto error;
1822 : 0 : } else if (status) {
1823 : 0 : pr_err("[%s]: failed to resize memory on videocore (status: %u, trans_id: %u)\n",
1824 : : __func__, status, private->int_trans_id);
1825 : : ret = -EPERM;
1826 : 0 : goto error;
1827 : : }
1828 : :
1829 : : pr_debug("[%s]: success to resize data - hdl %x, size %d -> %d\n",
1830 : : __func__, resize.res_handle, resource->res_size,
1831 : : resize.res_new_size);
1832 : :
1833 : : /* Successfully resized, save the information and inform the user. */
1834 : 0 : ioparam->old_size = resource->res_size;
1835 : 0 : resource->res_size = resize.res_new_size;
1836 : :
1837 : : error:
1838 : 0 : if (resource)
1839 : 0 : vmcs_sm_release_resource(resource, 0);
1840 : :
1841 : 0 : return ret;
1842 : : }
1843 : :
1844 : : /* Lock a previously allocated shared memory handle and block. */
1845 : 0 : static int vc_sm_ioctl_lock(struct sm_priv_data_t *private,
1846 : : struct vmcs_sm_ioctl_lock_unlock *ioparam,
1847 : : int change_cache, enum vmcs_sm_cache_e cache_type,
1848 : : unsigned int vc_addr)
1849 : : {
1850 : : int status;
1851 : : struct vc_sm_lock_unlock_t lock;
1852 : : struct vc_sm_lock_result_t result;
1853 : : struct sm_resource_t *resource;
1854 : : int ret = 0;
1855 : : struct sm_mmap *map, *map_tmp;
1856 : : unsigned long phys_addr;
1857 : :
1858 : : map = NULL;
1859 : :
1860 : : /* Locate resource from GUID. */
1861 : 0 : resource = vmcs_sm_acquire_resource(private, ioparam->handle);
1862 : 0 : if (resource == NULL) {
1863 : : ret = -EINVAL;
1864 : : goto error;
1865 : : }
1866 : :
1867 : : /* Check permissions. */
1868 : 0 : if (resource->pid && (resource->pid != current->tgid)) {
1869 : 0 : pr_err("[%s]: current tgid %u != %u owner\n", __func__,
1870 : : current->tgid, resource->pid);
1871 : : ret = -EPERM;
1872 : 0 : goto error;
1873 : : }
1874 : :
1875 : 0 : lock.res_handle = resource->res_handle;
1876 : 0 : lock.res_mem = (uint32_t)resource->res_base_mem;
1877 : :
1878 : : /* Take the lock and get the address to be mapped. */
1879 : 0 : if (vc_addr == 0) {
1880 : : pr_debug("[%s]: attempt to lock data - guid %x, hdl %x, base address %p\n",
1881 : : __func__, ioparam->handle, lock.res_handle,
1882 : : (void *)lock.res_mem);
1883 : :
1884 : : /* Lock the videocore allocated resource. */
1885 : 0 : status = vc_vchi_sm_lock(sm_state->sm_handle, &lock, &result,
1886 : : &private->int_trans_id);
1887 : 0 : if (status == -EINTR) {
1888 : : pr_debug("[%s]: requesting lock memory action restart (trans_id: %u)\n",
1889 : : __func__, private->int_trans_id);
1890 : : ret = -ERESTARTSYS;
1891 : 0 : private->restart_sys = -EINTR;
1892 : 0 : private->int_action = VC_SM_MSG_TYPE_LOCK;
1893 : 0 : goto error;
1894 : 0 : } else if (status ||
1895 : 0 : (!status && !(void *)result.res_mem)) {
1896 : 0 : pr_err("[%s]: failed to lock memory on videocore (status: %u, trans_id: %u)\n",
1897 : : __func__, status, private->int_trans_id);
1898 : : ret = -EPERM;
1899 : 0 : resource->res_stats[LOCK_FAIL]++;
1900 : 0 : goto error;
1901 : : }
1902 : :
1903 : : pr_debug("[%s]: succeed to lock data - hdl %x, base address %p (%p), ref-cnt %d\n",
1904 : : __func__, lock.res_handle, (void *)result.res_mem,
1905 : : (void *)lock.res_mem, resource->lock_count);
1906 : : }
1907 : : /* Lock assumed taken already, address to be mapped is known. */
1908 : : else
1909 : 0 : resource->res_base_mem = (void *)vc_addr;
1910 : :
1911 : 0 : resource->res_stats[LOCK]++;
1912 : 0 : resource->lock_count++;
1913 : :
1914 : : /* Keep track of the new base memory allocation if it has changed. */
1915 : 0 : if ((vc_addr == 0) &&
1916 : 0 : ((void *)result.res_mem) &&
1917 : 0 : ((void *)result.res_old_mem) &&
1918 : : (result.res_mem != result.res_old_mem)) {
1919 : 0 : resource->res_base_mem = (void *)result.res_mem;
1920 : :
1921 : : /* Kernel allocated resources. */
1922 : 0 : if (resource->pid == 0) {
1923 : 0 : if (!list_empty(&resource->map_list)) {
1924 : 0 : list_for_each_entry_safe(map, map_tmp,
1925 : : &resource->map_list,
1926 : : resource_map_list) {
1927 : 0 : if (map->res_addr) {
1928 : 0 : iounmap((void *)map->res_addr);
1929 : 0 : map->res_addr = 0;
1930 : :
1931 : 0 : vmcs_sm_remove_map(sm_state,
1932 : : map->resource,
1933 : : map);
1934 : 0 : break;
1935 : : }
1936 : : }
1937 : : }
1938 : : }
1939 : : }
1940 : :
1941 : 0 : if (change_cache)
1942 : 0 : resource->res_cached = cache_type;
1943 : :
1944 : 0 : if (resource->map_count) {
1945 : 0 : ioparam->addr =
1946 : 0 : vmcs_sm_usr_address_from_pid_and_usr_handle(
1947 : 0 : current->tgid, ioparam->handle);
1948 : :
1949 : : pr_debug("[%s] map_count %d private->pid %d current->tgid %d hnd %x addr %u\n",
1950 : : __func__, resource->map_count, private->pid,
1951 : : current->tgid, ioparam->handle, ioparam->addr);
1952 : : } else {
1953 : : /* Kernel allocated resources. */
1954 : 0 : if (resource->pid == 0) {
1955 : : pr_debug("[%s]: attempt mapping kernel resource - guid %x, hdl %x\n",
1956 : : __func__, ioparam->handle, lock.res_handle);
1957 : :
1958 : 0 : ioparam->addr = 0;
1959 : :
1960 : 0 : map = kzalloc(sizeof(*map), GFP_KERNEL);
1961 : 0 : if (map == NULL) {
1962 : 0 : pr_err("[%s]: failed allocating tracker\n",
1963 : : __func__);
1964 : : ret = -ENOMEM;
1965 : 0 : goto error;
1966 : : } else {
1967 : 0 : phys_addr = (uint32_t)resource->res_base_mem &
1968 : : 0x3FFFFFFF;
1969 : 0 : phys_addr += mm_vc_mem_phys_addr;
1970 : 0 : if (resource->res_cached
1971 : : == VMCS_SM_CACHE_HOST) {
1972 : 0 : ioparam->addr = (unsigned long)
1973 : : /* TODO - make cached work */
1974 : 0 : ioremap_nocache(phys_addr,
1975 : : resource->res_size);
1976 : :
1977 : : pr_debug("[%s]: mapping kernel - guid %x, hdl %x - cached mapping %u\n",
1978 : : __func__, ioparam->handle,
1979 : : lock.res_handle, ioparam->addr);
1980 : : } else {
1981 : 0 : ioparam->addr = (unsigned long)
1982 : 0 : ioremap_nocache(phys_addr,
1983 : : resource->res_size);
1984 : :
1985 : : pr_debug("[%s]: mapping kernel- guid %x, hdl %x - non cached mapping %u\n",
1986 : : __func__, ioparam->handle,
1987 : : lock.res_handle, ioparam->addr);
1988 : : }
1989 : :
1990 : 0 : map->res_pid = 0;
1991 : 0 : map->res_vc_hdl = resource->res_handle;
1992 : 0 : map->res_usr_hdl = resource->res_guid;
1993 : 0 : map->res_addr = ioparam->addr;
1994 : 0 : map->resource = resource;
1995 : 0 : map->vma = NULL;
1996 : :
1997 : 0 : vmcs_sm_add_map(sm_state, resource, map);
1998 : : }
1999 : : } else
2000 : 0 : ioparam->addr = 0;
2001 : : }
2002 : :
2003 : : error:
2004 : 0 : if (resource)
2005 : 0 : vmcs_sm_release_resource(resource, 0);
2006 : :
2007 : 0 : return ret;
2008 : : }
2009 : :
2010 : : /* Unlock a previously allocated shared memory handle and block.*/
2011 : 0 : static int vc_sm_ioctl_unlock(struct sm_priv_data_t *private,
2012 : : struct vmcs_sm_ioctl_lock_unlock *ioparam,
2013 : : int flush, int wait_reply, int no_vc_unlock)
2014 : : {
2015 : : int status;
2016 : : struct vc_sm_lock_unlock_t unlock;
2017 : : struct sm_mmap *map, *map_tmp;
2018 : : struct sm_resource_t *resource;
2019 : : int ret = 0;
2020 : :
2021 : : map = NULL;
2022 : :
2023 : : /* Locate resource from GUID. */
2024 : 0 : resource = vmcs_sm_acquire_resource(private, ioparam->handle);
2025 : 0 : if (resource == NULL) {
2026 : : ret = -EINVAL;
2027 : : goto error;
2028 : : }
2029 : :
2030 : : /* Check permissions. */
2031 : 0 : if (resource->pid && (resource->pid != current->tgid)) {
2032 : 0 : pr_err("[%s]: current tgid %u != %u owner\n",
2033 : : __func__, current->tgid, resource->pid);
2034 : : ret = -EPERM;
2035 : 0 : goto error;
2036 : : }
2037 : :
2038 : 0 : unlock.res_handle = resource->res_handle;
2039 : 0 : unlock.res_mem = (uint32_t)resource->res_base_mem;
2040 : :
2041 : : pr_debug("[%s]: attempt to unlock data - guid %x, hdl %x, base address %p\n",
2042 : : __func__, ioparam->handle, unlock.res_handle,
2043 : : (void *)unlock.res_mem);
2044 : :
2045 : : /* User space allocated resources. */
2046 : 0 : if (resource->pid) {
2047 : : /* Flush if requested */
2048 : 0 : if (resource->res_cached && flush) {
2049 : : dma_addr_t phys_addr = 0;
2050 : :
2051 : 0 : resource->res_stats[FLUSH]++;
2052 : :
2053 : : phys_addr =
2054 : : (dma_addr_t)((uint32_t)resource->res_base_mem &
2055 : : 0x3FFFFFFF);
2056 : : phys_addr += (dma_addr_t)mm_vc_mem_phys_addr;
2057 : :
2058 : : /* L1 cache flush */
2059 : 0 : down_read(¤t->mm->mmap_sem);
2060 : 0 : list_for_each_entry(map, &resource->map_list,
2061 : : resource_map_list) {
2062 : 0 : if (map->vma) {
2063 : 0 : const unsigned long start = map->vma->vm_start;
2064 : 0 : const unsigned long end = map->vma->vm_end;
2065 : :
2066 : 0 : ret = clean_invalid_mem_walk(start, end - start,
2067 : : VCSM_CACHE_OP_FLUSH);
2068 : 0 : if (ret)
2069 : : goto error;
2070 : : }
2071 : : }
2072 : 0 : up_read(¤t->mm->mmap_sem);
2073 : :
2074 : : /* L2 cache flush */
2075 : : outer_clean_range(phys_addr,
2076 : : phys_addr +
2077 : : (size_t) resource->res_size);
2078 : : }
2079 : :
2080 : : /* We need to zap all the vmas associated with this resource */
2081 : 0 : if (resource->lock_count == 1) {
2082 : 0 : down_read(¤t->mm->mmap_sem);
2083 : 0 : list_for_each_entry(map, &resource->map_list,
2084 : : resource_map_list) {
2085 : 0 : if (map->vma) {
2086 : 0 : zap_vma_ptes(map->vma,
2087 : : map->vma->vm_start,
2088 : 0 : map->vma->vm_end -
2089 : 0 : map->vma->vm_start);
2090 : : }
2091 : : }
2092 : 0 : up_read(¤t->mm->mmap_sem);
2093 : : }
2094 : : }
2095 : : /* Kernel allocated resources. */
2096 : : else {
2097 : : /* Global + Taken in this context */
2098 : 0 : if (resource->ref_count == 2) {
2099 : 0 : if (!list_empty(&resource->map_list)) {
2100 : 0 : list_for_each_entry_safe(map, map_tmp,
2101 : : &resource->map_list,
2102 : : resource_map_list) {
2103 : 0 : if (map->res_addr) {
2104 : 0 : if (flush &&
2105 : 0 : (resource->res_cached ==
2106 : : VMCS_SM_CACHE_HOST)) {
2107 : : unsigned long
2108 : : phys_addr;
2109 : : phys_addr = (uint32_t)
2110 : : resource->res_base_mem & 0x3FFFFFFF;
2111 : : phys_addr +=
2112 : : mm_vc_mem_phys_addr;
2113 : :
2114 : : /* L1 cache flush */
2115 : 0 : dmac_flush_range((const
2116 : : void
2117 : : *)
2118 : 0 : map->res_addr, (const void *)
2119 : 0 : (map->res_addr + resource->res_size));
2120 : :
2121 : : /* L2 cache flush */
2122 : : outer_clean_range
2123 : : (phys_addr,
2124 : : phys_addr +
2125 : : (size_t)
2126 : : resource->res_size);
2127 : : }
2128 : :
2129 : 0 : iounmap((void *)map->res_addr);
2130 : 0 : map->res_addr = 0;
2131 : :
2132 : 0 : vmcs_sm_remove_map(sm_state,
2133 : : map->resource,
2134 : : map);
2135 : 0 : break;
2136 : : }
2137 : : }
2138 : : }
2139 : : }
2140 : : }
2141 : :
2142 : 0 : if (resource->lock_count) {
2143 : : /* Bypass the videocore unlock. */
2144 : 0 : if (no_vc_unlock)
2145 : : status = 0;
2146 : : /* Unlock the videocore allocated resource. */
2147 : : else {
2148 : 0 : status =
2149 : 0 : vc_vchi_sm_unlock(sm_state->sm_handle, &unlock,
2150 : : &private->int_trans_id,
2151 : : wait_reply);
2152 : 0 : if (status == -EINTR) {
2153 : : pr_debug("[%s]: requesting unlock memory action restart (trans_id: %u)\n",
2154 : : __func__, private->int_trans_id);
2155 : :
2156 : : ret = -ERESTARTSYS;
2157 : 0 : resource->res_stats[UNLOCK]--;
2158 : 0 : private->restart_sys = -EINTR;
2159 : 0 : private->int_action = VC_SM_MSG_TYPE_UNLOCK;
2160 : 0 : goto error;
2161 : 0 : } else if (status != 0) {
2162 : 0 : pr_err("[%s]: failed to unlock vc mem (status: %u, trans_id: %u)\n",
2163 : : __func__, status, private->int_trans_id);
2164 : :
2165 : : ret = -EPERM;
2166 : 0 : resource->res_stats[UNLOCK_FAIL]++;
2167 : 0 : goto error;
2168 : : }
2169 : : }
2170 : :
2171 : 0 : resource->res_stats[UNLOCK]++;
2172 : 0 : resource->lock_count--;
2173 : : }
2174 : :
2175 : : pr_debug("[%s]: success to unlock data - hdl %x, base address %p, ref-cnt %d\n",
2176 : : __func__, unlock.res_handle, (void *)unlock.res_mem,
2177 : : resource->lock_count);
2178 : :
2179 : : error:
2180 : 0 : if (resource)
2181 : 0 : vmcs_sm_release_resource(resource, 0);
2182 : :
2183 : 0 : return ret;
2184 : : }
2185 : :
2186 : : /* Import a contiguous block of memory to be shared with VC. */
2187 : 0 : static int vc_sm_ioctl_import_dmabuf(struct sm_priv_data_t *private,
2188 : : struct vmcs_sm_ioctl_import_dmabuf *ioparam,
2189 : : struct dma_buf *src_dma_buf)
2190 : : {
2191 : : int ret = 0;
2192 : : int status;
2193 : : struct sm_resource_t *resource = NULL;
2194 : 0 : struct vc_sm_import import = { 0 };
2195 : 0 : struct vc_sm_import_result result = { 0 };
2196 : : struct dma_buf *dma_buf;
2197 : : struct dma_buf_attachment *attach = NULL;
2198 : : struct sg_table *sgt = NULL;
2199 : :
2200 : : /* Setup our allocation parameters */
2201 : 0 : if (src_dma_buf) {
2202 : 0 : get_dma_buf(src_dma_buf);
2203 : : dma_buf = src_dma_buf;
2204 : : } else {
2205 : 0 : dma_buf = dma_buf_get(ioparam->dmabuf_fd);
2206 : : }
2207 : 0 : if (IS_ERR(dma_buf))
2208 : 0 : return PTR_ERR(dma_buf);
2209 : :
2210 : 0 : attach = dma_buf_attach(dma_buf, &sm_state->pdev->dev);
2211 : 0 : if (IS_ERR(attach)) {
2212 : : ret = PTR_ERR(attach);
2213 : 0 : goto error;
2214 : : }
2215 : :
2216 : 0 : sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
2217 : 0 : if (IS_ERR(sgt)) {
2218 : : ret = PTR_ERR(sgt);
2219 : 0 : goto error;
2220 : : }
2221 : :
2222 : : /* Verify that the address block is contiguous */
2223 : 0 : if (sgt->nents != 1) {
2224 : : ret = -ENOMEM;
2225 : : goto error;
2226 : : }
2227 : :
2228 : 0 : import.type = ((ioparam->cached == VMCS_SM_CACHE_VC) ||
2229 : : (ioparam->cached == VMCS_SM_CACHE_BOTH)) ?
2230 : 0 : VC_SM_ALLOC_CACHED : VC_SM_ALLOC_NON_CACHED;
2231 : 0 : import.addr = (uint32_t)sg_dma_address(sgt->sgl);
2232 : 0 : import.size = sg_dma_len(sgt->sgl);
2233 : 0 : import.allocator = current->tgid;
2234 : :
2235 : 0 : if (*ioparam->name)
2236 : 0 : memcpy(import.name, ioparam->name, sizeof(import.name) - 1);
2237 : : else
2238 : 0 : memcpy(import.name, VMCS_SM_RESOURCE_NAME_DEFAULT,
2239 : : sizeof(VMCS_SM_RESOURCE_NAME_DEFAULT));
2240 : :
2241 : : pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %p, size %u\n",
2242 : : __func__, import.name, import.type,
2243 : : (void *)import.addr, import.size);
2244 : :
2245 : : /* Allocate local resource to track this allocation. */
2246 : 0 : resource = kzalloc(sizeof(*resource), GFP_KERNEL);
2247 : 0 : if (!resource) {
2248 : : ret = -ENOMEM;
2249 : : goto error;
2250 : : }
2251 : 0 : INIT_LIST_HEAD(&resource->map_list);
2252 : 0 : resource->ref_count++;
2253 : 0 : resource->pid = current->tgid;
2254 : :
2255 : : /* Allocate the videocore resource. */
2256 : 0 : status = vc_vchi_sm_import(sm_state->sm_handle, &import, &result,
2257 : : &private->int_trans_id);
2258 : 0 : if (status == -EINTR) {
2259 : : pr_debug("[%s]: requesting import memory action restart (trans_id: %u)\n",
2260 : : __func__, private->int_trans_id);
2261 : : ret = -ERESTARTSYS;
2262 : 0 : private->restart_sys = -EINTR;
2263 : 0 : private->int_action = VC_SM_MSG_TYPE_IMPORT;
2264 : 0 : goto error;
2265 : 0 : } else if (status || !result.res_handle) {
2266 : : pr_debug("[%s]: failed to import memory on videocore (status: %u, trans_id: %u)\n",
2267 : : __func__, status, private->int_trans_id);
2268 : : ret = -ENOMEM;
2269 : 0 : resource->res_stats[ALLOC_FAIL]++;
2270 : 0 : goto error;
2271 : : }
2272 : :
2273 : : /* Keep track of the resource we created. */
2274 : 0 : resource->private = private;
2275 : 0 : resource->res_handle = result.res_handle;
2276 : 0 : resource->res_size = import.size;
2277 : 0 : resource->res_cached = ioparam->cached;
2278 : :
2279 : 0 : resource->dma_buf = dma_buf;
2280 : 0 : resource->attach = attach;
2281 : 0 : resource->sgt = sgt;
2282 : 0 : resource->dma_addr = sg_dma_address(sgt->sgl);
2283 : :
2284 : : /*
2285 : : * Kernel/user GUID. This global identifier is used for mmap'ing the
2286 : : * allocated region from user space, it is passed as the mmap'ing
2287 : : * offset, we use it to 'hide' the videocore handle/address.
2288 : : */
2289 : 0 : mutex_lock(&sm_state->lock);
2290 : 0 : resource->res_guid = ++sm_state->guid;
2291 : 0 : mutex_unlock(&sm_state->lock);
2292 : 0 : resource->res_guid <<= PAGE_SHIFT;
2293 : :
2294 : 0 : vmcs_sm_add_resource(private, resource);
2295 : :
2296 : : /* We're done */
2297 : 0 : resource->res_stats[IMPORT]++;
2298 : 0 : ioparam->handle = resource->res_guid;
2299 : 0 : return 0;
2300 : :
2301 : : error:
2302 : 0 : if (resource) {
2303 : 0 : resource->res_stats[IMPORT_FAIL]++;
2304 : 0 : vc_sm_resource_deceased(resource, 1);
2305 : 0 : kfree(resource);
2306 : : }
2307 : 0 : if (sgt)
2308 : 0 : dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
2309 : 0 : if (attach)
2310 : 0 : dma_buf_detach(dma_buf, attach);
2311 : 0 : dma_buf_put(dma_buf);
2312 : 0 : return ret;
2313 : : }
2314 : :
2315 : : /* Handle control from host. */
2316 : 0 : static long vc_sm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2317 : : {
2318 : : int ret = 0;
2319 : 0 : unsigned int cmdnr = _IOC_NR(cmd);
2320 : 0 : struct sm_priv_data_t *file_data =
2321 : : (struct sm_priv_data_t *)file->private_data;
2322 : : struct sm_resource_t *resource = NULL;
2323 : :
2324 : : /* Validate we can work with this device. */
2325 : 0 : if ((sm_state == NULL) || (file_data == NULL)) {
2326 : 0 : pr_err("[%s]: invalid device\n", __func__);
2327 : : ret = -EPERM;
2328 : 0 : goto out;
2329 : : }
2330 : :
2331 : : pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
2332 : : current->tgid, file_data->pid);
2333 : :
2334 : : /* Action is a re-post of a previously interrupted action? */
2335 : 0 : if (file_data->restart_sys == -EINTR) {
2336 : : struct vc_sm_action_clean_t action_clean;
2337 : :
2338 : : pr_debug("[%s]: clean up of action %u (trans_id: %u) following EINTR\n",
2339 : : __func__, file_data->int_action,
2340 : : file_data->int_trans_id);
2341 : :
2342 : 0 : action_clean.res_action = file_data->int_action;
2343 : 0 : action_clean.action_trans_id = file_data->int_trans_id;
2344 : :
2345 : 0 : vc_vchi_sm_clean_up(sm_state->sm_handle, &action_clean);
2346 : :
2347 : 0 : file_data->restart_sys = 0;
2348 : : }
2349 : :
2350 : : /* Now process the command. */
2351 : 0 : switch (cmdnr) {
2352 : : /* New memory allocation.
2353 : : */
2354 : : case VMCS_SM_CMD_ALLOC:
2355 : : {
2356 : : struct vmcs_sm_ioctl_alloc ioparam;
2357 : :
2358 : : /* Get the parameter data. */
2359 : 0 : if (copy_from_user
2360 : : (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
2361 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2362 : : __func__, cmdnr);
2363 : : ret = -EFAULT;
2364 : 0 : goto out;
2365 : : }
2366 : :
2367 : 0 : ret = vc_sm_ioctl_alloc(file_data, &ioparam);
2368 : 0 : if (!ret &&
2369 : 0 : (copy_to_user((void *)arg,
2370 : : &ioparam, sizeof(ioparam)) != 0)) {
2371 : 0 : struct vmcs_sm_ioctl_free freeparam = {
2372 : 0 : ioparam.handle
2373 : : };
2374 : 0 : pr_err("[%s]: failed to copy-to-user for cmd %x\n",
2375 : : __func__, cmdnr);
2376 : 0 : vc_sm_ioctl_free(file_data, &freeparam);
2377 : : ret = -EFAULT;
2378 : : }
2379 : :
2380 : : /* Done. */
2381 : : goto out;
2382 : : }
2383 : : break;
2384 : :
2385 : : /* Share existing memory allocation. */
2386 : : case VMCS_SM_CMD_ALLOC_SHARE:
2387 : : {
2388 : : struct vmcs_sm_ioctl_alloc_share ioparam;
2389 : :
2390 : : /* Get the parameter data. */
2391 : 0 : if (copy_from_user
2392 : : (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
2393 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2394 : : __func__, cmdnr);
2395 : : ret = -EFAULT;
2396 : 0 : goto out;
2397 : : }
2398 : :
2399 : 0 : ret = vc_sm_ioctl_alloc_share(file_data, &ioparam);
2400 : :
2401 : : /* Copy result back to user. */
2402 : 0 : if (!ret
2403 : 0 : && copy_to_user((void *)arg, &ioparam,
2404 : : sizeof(ioparam)) != 0) {
2405 : 0 : struct vmcs_sm_ioctl_free freeparam = {
2406 : 0 : ioparam.handle
2407 : : };
2408 : 0 : pr_err("[%s]: failed to copy-to-user for cmd %x\n",
2409 : : __func__, cmdnr);
2410 : 0 : vc_sm_ioctl_free(file_data, &freeparam);
2411 : : ret = -EFAULT;
2412 : : }
2413 : :
2414 : : /* Done. */
2415 : : goto out;
2416 : : }
2417 : : break;
2418 : :
2419 : : case VMCS_SM_CMD_IMPORT_DMABUF:
2420 : : {
2421 : : struct vmcs_sm_ioctl_import_dmabuf ioparam;
2422 : :
2423 : : /* Get the parameter data. */
2424 : 0 : if (copy_from_user
2425 : : (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
2426 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2427 : : __func__, cmdnr);
2428 : : ret = -EFAULT;
2429 : 0 : goto out;
2430 : : }
2431 : :
2432 : 0 : ret = vc_sm_ioctl_import_dmabuf(file_data, &ioparam,
2433 : : NULL);
2434 : 0 : if (!ret &&
2435 : 0 : (copy_to_user((void *)arg,
2436 : : &ioparam, sizeof(ioparam)) != 0)) {
2437 : 0 : struct vmcs_sm_ioctl_free freeparam = {
2438 : 0 : ioparam.handle
2439 : : };
2440 : 0 : pr_err("[%s]: failed to copy-to-user for cmd %x\n",
2441 : : __func__, cmdnr);
2442 : 0 : vc_sm_ioctl_free(file_data, &freeparam);
2443 : : ret = -EFAULT;
2444 : : }
2445 : :
2446 : : /* Done. */
2447 : : goto out;
2448 : : }
2449 : : break;
2450 : :
2451 : : /* Lock (attempt to) *and* register a cache behavior change. */
2452 : : case VMCS_SM_CMD_LOCK_CACHE:
2453 : : {
2454 : : struct vmcs_sm_ioctl_lock_cache ioparam;
2455 : : struct vmcs_sm_ioctl_lock_unlock lock;
2456 : :
2457 : : /* Get parameter data. */
2458 : 0 : if (copy_from_user
2459 : : (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
2460 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2461 : : __func__, cmdnr);
2462 : : ret = -EFAULT;
2463 : 0 : goto out;
2464 : : }
2465 : :
2466 : 0 : lock.handle = ioparam.handle;
2467 : 0 : ret =
2468 : 0 : vc_sm_ioctl_lock(file_data, &lock, 1,
2469 : : ioparam.cached, 0);
2470 : :
2471 : : /* Done. */
2472 : 0 : goto out;
2473 : : }
2474 : : break;
2475 : :
2476 : : /* Lock (attempt to) existing memory allocation. */
2477 : : case VMCS_SM_CMD_LOCK:
2478 : : {
2479 : : struct vmcs_sm_ioctl_lock_unlock ioparam;
2480 : :
2481 : : /* Get parameter data. */
2482 : 0 : if (copy_from_user
2483 : : (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
2484 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2485 : : __func__, cmdnr);
2486 : : ret = -EFAULT;
2487 : 0 : goto out;
2488 : : }
2489 : :
2490 : 0 : ret = vc_sm_ioctl_lock(file_data, &ioparam, 0, 0, 0);
2491 : :
2492 : : /* Copy result back to user. */
2493 : 0 : if (copy_to_user((void *)arg, &ioparam, sizeof(ioparam))
2494 : : != 0) {
2495 : 0 : pr_err("[%s]: failed to copy-to-user for cmd %x\n",
2496 : : __func__, cmdnr);
2497 : : ret = -EFAULT;
2498 : : }
2499 : :
2500 : : /* Done. */
2501 : : goto out;
2502 : : }
2503 : : break;
2504 : :
2505 : : /* Unlock (attempt to) existing memory allocation. */
2506 : : case VMCS_SM_CMD_UNLOCK:
2507 : : {
2508 : : struct vmcs_sm_ioctl_lock_unlock ioparam;
2509 : :
2510 : : /* Get parameter data. */
2511 : 0 : if (copy_from_user
2512 : : (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
2513 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2514 : : __func__, cmdnr);
2515 : : ret = -EFAULT;
2516 : 0 : goto out;
2517 : : }
2518 : :
2519 : 0 : ret = vc_sm_ioctl_unlock(file_data, &ioparam, 0, 1, 0);
2520 : :
2521 : : /* Done. */
2522 : 0 : goto out;
2523 : : }
2524 : : break;
2525 : :
2526 : : /* Resize (attempt to) existing memory allocation. */
2527 : : case VMCS_SM_CMD_RESIZE:
2528 : : {
2529 : : struct vmcs_sm_ioctl_resize ioparam;
2530 : :
2531 : : /* Get parameter data. */
2532 : 0 : if (copy_from_user
2533 : : (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
2534 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2535 : : __func__, cmdnr);
2536 : : ret = -EFAULT;
2537 : 0 : goto out;
2538 : : }
2539 : :
2540 : 0 : ret = vc_sm_ioctl_resize(file_data, &ioparam);
2541 : :
2542 : : /* Copy result back to user. */
2543 : 0 : if (copy_to_user((void *)arg, &ioparam, sizeof(ioparam))
2544 : : != 0) {
2545 : 0 : pr_err("[%s]: failed to copy-to-user for cmd %x\n",
2546 : : __func__, cmdnr);
2547 : : ret = -EFAULT;
2548 : : }
2549 : : goto out;
2550 : : }
2551 : : break;
2552 : :
2553 : : /* Terminate existing memory allocation.
2554 : : */
2555 : : case VMCS_SM_CMD_FREE:
2556 : : {
2557 : : struct vmcs_sm_ioctl_free ioparam;
2558 : :
2559 : : /* Get parameter data.
2560 : : */
2561 : 0 : if (copy_from_user
2562 : : (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
2563 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2564 : : __func__, cmdnr);
2565 : : ret = -EFAULT;
2566 : 0 : goto out;
2567 : : }
2568 : :
2569 : 0 : ret = vc_sm_ioctl_free(file_data, &ioparam);
2570 : :
2571 : : /* Done.
2572 : : */
2573 : 0 : goto out;
2574 : : }
2575 : : break;
2576 : :
2577 : : /* Walk allocation on videocore, information shows up in the
2578 : : ** videocore log.
2579 : : */
2580 : : case VMCS_SM_CMD_VC_WALK_ALLOC:
2581 : : {
2582 : : pr_debug("[%s]: invoking walk alloc\n", __func__);
2583 : :
2584 : 0 : if (vc_vchi_sm_walk_alloc(sm_state->sm_handle) != 0)
2585 : 0 : pr_err("[%s]: failed to walk-alloc on videocore\n",
2586 : : __func__);
2587 : :
2588 : : /* Done.
2589 : : */
2590 : : goto out;
2591 : : }
2592 : : break;
2593 : : /* Walk mapping table on host, information shows up in the
2594 : : ** kernel log.
2595 : : */
2596 : : case VMCS_SM_CMD_HOST_WALK_MAP:
2597 : : {
2598 : : /* Use pid of -1 to tell to walk the whole map. */
2599 : 0 : vmcs_sm_host_walk_map_per_pid(-1);
2600 : :
2601 : : /* Done. */
2602 : 0 : goto out;
2603 : : }
2604 : : break;
2605 : :
2606 : : /* Walk mapping table per process on host. */
2607 : : case VMCS_SM_CMD_HOST_WALK_PID_ALLOC:
2608 : : {
2609 : : struct vmcs_sm_ioctl_walk ioparam;
2610 : :
2611 : : /* Get parameter data. */
2612 : 0 : if (copy_from_user(&ioparam,
2613 : : (void *)arg, sizeof(ioparam)) != 0) {
2614 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2615 : : __func__, cmdnr);
2616 : : ret = -EFAULT;
2617 : 0 : goto out;
2618 : : }
2619 : :
2620 : 0 : vmcs_sm_host_walk_alloc(file_data);
2621 : :
2622 : : /* Done. */
2623 : 0 : goto out;
2624 : : }
2625 : : break;
2626 : :
2627 : : /* Walk allocation per process on host. */
2628 : : case VMCS_SM_CMD_HOST_WALK_PID_MAP:
2629 : : {
2630 : : struct vmcs_sm_ioctl_walk ioparam;
2631 : :
2632 : : /* Get parameter data. */
2633 : 0 : if (copy_from_user(&ioparam,
2634 : : (void *)arg, sizeof(ioparam)) != 0) {
2635 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2636 : : __func__, cmdnr);
2637 : : ret = -EFAULT;
2638 : 0 : goto out;
2639 : : }
2640 : :
2641 : 0 : vmcs_sm_host_walk_map_per_pid(ioparam.pid);
2642 : :
2643 : : /* Done. */
2644 : 0 : goto out;
2645 : : }
2646 : : break;
2647 : :
2648 : : /* Gets the size of the memory associated with a user handle. */
2649 : : case VMCS_SM_CMD_SIZE_USR_HANDLE:
2650 : : {
2651 : : struct vmcs_sm_ioctl_size ioparam;
2652 : :
2653 : : /* Get parameter data. */
2654 : 0 : if (copy_from_user(&ioparam,
2655 : : (void *)arg, sizeof(ioparam)) != 0) {
2656 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2657 : : __func__, cmdnr);
2658 : : ret = -EFAULT;
2659 : 0 : goto out;
2660 : : }
2661 : :
2662 : : /* Locate resource from GUID. */
2663 : 0 : resource =
2664 : 0 : vmcs_sm_acquire_resource(file_data, ioparam.handle);
2665 : 0 : if (resource != NULL) {
2666 : 0 : ioparam.size = resource->res_size;
2667 : 0 : vmcs_sm_release_resource(resource, 0);
2668 : : } else {
2669 : 0 : ioparam.size = 0;
2670 : : }
2671 : :
2672 : 0 : if (copy_to_user((void *)arg,
2673 : : &ioparam, sizeof(ioparam)) != 0) {
2674 : 0 : pr_err("[%s]: failed to copy-to-user for cmd %x\n",
2675 : : __func__, cmdnr);
2676 : : ret = -EFAULT;
2677 : : }
2678 : :
2679 : : /* Done. */
2680 : : goto out;
2681 : : }
2682 : : break;
2683 : :
2684 : : /* Verify we are dealing with a valid resource. */
2685 : : case VMCS_SM_CMD_CHK_USR_HANDLE:
2686 : : {
2687 : : struct vmcs_sm_ioctl_chk ioparam;
2688 : :
2689 : : /* Get parameter data. */
2690 : 0 : if (copy_from_user(&ioparam,
2691 : : (void *)arg, sizeof(ioparam)) != 0) {
2692 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2693 : : __func__, cmdnr);
2694 : :
2695 : : ret = -EFAULT;
2696 : 0 : goto out;
2697 : : }
2698 : :
2699 : : /* Locate resource from GUID. */
2700 : 0 : resource =
2701 : 0 : vmcs_sm_acquire_resource(file_data, ioparam.handle);
2702 : 0 : if (resource == NULL)
2703 : : ret = -EINVAL;
2704 : : /*
2705 : : * If the resource is cacheable, return additional
2706 : : * information that may be needed to flush the cache.
2707 : : */
2708 : 0 : else if ((resource->res_cached == VMCS_SM_CACHE_HOST) ||
2709 : : (resource->res_cached == VMCS_SM_CACHE_BOTH)) {
2710 : 0 : ioparam.addr =
2711 : 0 : vmcs_sm_usr_address_from_pid_and_usr_handle
2712 : 0 : (current->tgid, ioparam.handle);
2713 : 0 : ioparam.size = resource->res_size;
2714 : 0 : ioparam.cache = resource->res_cached;
2715 : : } else {
2716 : 0 : ioparam.addr = 0;
2717 : 0 : ioparam.size = 0;
2718 : 0 : ioparam.cache = resource->res_cached;
2719 : : }
2720 : :
2721 : 0 : if (resource)
2722 : 0 : vmcs_sm_release_resource(resource, 0);
2723 : :
2724 : 0 : if (copy_to_user((void *)arg,
2725 : : &ioparam, sizeof(ioparam)) != 0) {
2726 : 0 : pr_err("[%s]: failed to copy-to-user for cmd %x\n",
2727 : : __func__, cmdnr);
2728 : : ret = -EFAULT;
2729 : : }
2730 : :
2731 : : /* Done. */
2732 : : goto out;
2733 : : }
2734 : : break;
2735 : :
2736 : : /*
2737 : : * Maps a user handle given the process and the virtual address.
2738 : : */
2739 : : case VMCS_SM_CMD_MAPPED_USR_HANDLE:
2740 : : {
2741 : : struct vmcs_sm_ioctl_map ioparam;
2742 : :
2743 : : /* Get parameter data. */
2744 : 0 : if (copy_from_user(&ioparam,
2745 : : (void *)arg, sizeof(ioparam)) != 0) {
2746 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2747 : : __func__, cmdnr);
2748 : :
2749 : : ret = -EFAULT;
2750 : 0 : goto out;
2751 : : }
2752 : :
2753 : 0 : ioparam.handle =
2754 : 0 : vmcs_sm_usr_handle_from_pid_and_address(
2755 : : ioparam.pid, ioparam.addr);
2756 : :
2757 : 0 : resource =
2758 : : vmcs_sm_acquire_resource(file_data, ioparam.handle);
2759 : 0 : if ((resource != NULL)
2760 : 0 : && ((resource->res_cached == VMCS_SM_CACHE_HOST)
2761 : 0 : || (resource->res_cached ==
2762 : : VMCS_SM_CACHE_BOTH))) {
2763 : 0 : ioparam.size = resource->res_size;
2764 : : } else {
2765 : 0 : ioparam.size = 0;
2766 : : }
2767 : :
2768 : 0 : if (resource)
2769 : 0 : vmcs_sm_release_resource(resource, 0);
2770 : :
2771 : 0 : if (copy_to_user((void *)arg,
2772 : : &ioparam, sizeof(ioparam)) != 0) {
2773 : 0 : pr_err("[%s]: failed to copy-to-user for cmd %x\n",
2774 : : __func__, cmdnr);
2775 : : ret = -EFAULT;
2776 : : }
2777 : :
2778 : : /* Done. */
2779 : : goto out;
2780 : : }
2781 : : break;
2782 : :
2783 : : /*
2784 : : * Maps a videocore handle given process and virtual address.
2785 : : */
2786 : : case VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR:
2787 : : {
2788 : : struct vmcs_sm_ioctl_map ioparam;
2789 : :
2790 : : /* Get parameter data. */
2791 : 0 : if (copy_from_user(&ioparam,
2792 : : (void *)arg, sizeof(ioparam)) != 0) {
2793 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2794 : : __func__, cmdnr);
2795 : : ret = -EFAULT;
2796 : 0 : goto out;
2797 : : }
2798 : :
2799 : 0 : ioparam.handle = vmcs_sm_vc_handle_from_pid_and_address(
2800 : : ioparam.pid, ioparam.addr);
2801 : :
2802 : 0 : if (copy_to_user((void *)arg,
2803 : : &ioparam, sizeof(ioparam)) != 0) {
2804 : 0 : pr_err("[%s]: failed to copy-to-user for cmd %x\n",
2805 : : __func__, cmdnr);
2806 : :
2807 : : ret = -EFAULT;
2808 : : }
2809 : :
2810 : : /* Done. */
2811 : : goto out;
2812 : : }
2813 : : break;
2814 : :
2815 : : /* Maps a videocore handle given process and user handle. */
2816 : : case VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL:
2817 : : {
2818 : : struct vmcs_sm_ioctl_map ioparam;
2819 : :
2820 : : /* Get parameter data. */
2821 : 0 : if (copy_from_user(&ioparam,
2822 : : (void *)arg, sizeof(ioparam)) != 0) {
2823 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2824 : : __func__, cmdnr);
2825 : : ret = -EFAULT;
2826 : 0 : goto out;
2827 : : }
2828 : :
2829 : : /* Locate resource from GUID. */
2830 : 0 : resource =
2831 : 0 : vmcs_sm_acquire_resource(file_data, ioparam.handle);
2832 : 0 : if (resource != NULL) {
2833 : 0 : ioparam.handle = resource->res_handle;
2834 : 0 : vmcs_sm_release_resource(resource, 0);
2835 : : } else {
2836 : 0 : ioparam.handle = 0;
2837 : : }
2838 : :
2839 : 0 : if (copy_to_user((void *)arg,
2840 : : &ioparam, sizeof(ioparam)) != 0) {
2841 : 0 : pr_err("[%s]: failed to copy-to-user for cmd %x\n",
2842 : : __func__, cmdnr);
2843 : :
2844 : : ret = -EFAULT;
2845 : : }
2846 : :
2847 : : /* Done. */
2848 : : goto out;
2849 : : }
2850 : : break;
2851 : :
2852 : : /*
2853 : : * Maps a videocore address given process and videocore handle.
2854 : : */
2855 : : case VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL:
2856 : : {
2857 : : struct vmcs_sm_ioctl_map ioparam;
2858 : :
2859 : : /* Get parameter data. */
2860 : 0 : if (copy_from_user(&ioparam,
2861 : : (void *)arg, sizeof(ioparam)) != 0) {
2862 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2863 : : __func__, cmdnr);
2864 : :
2865 : : ret = -EFAULT;
2866 : 0 : goto out;
2867 : : }
2868 : :
2869 : : /* Locate resource from GUID. */
2870 : 0 : resource =
2871 : 0 : vmcs_sm_acquire_resource(file_data, ioparam.handle);
2872 : 0 : if (resource != NULL) {
2873 : 0 : ioparam.addr =
2874 : 0 : (unsigned int)resource->res_base_mem;
2875 : 0 : vmcs_sm_release_resource(resource, 0);
2876 : : } else {
2877 : 0 : ioparam.addr = 0;
2878 : : }
2879 : :
2880 : 0 : if (copy_to_user((void *)arg,
2881 : : &ioparam, sizeof(ioparam)) != 0) {
2882 : 0 : pr_err("[%s]: failed to copy-to-user for cmd %x\n",
2883 : : __func__, cmdnr);
2884 : : ret = -EFAULT;
2885 : : }
2886 : :
2887 : : /* Done. */
2888 : : goto out;
2889 : : }
2890 : : break;
2891 : :
2892 : : /* Maps a user address given process and vc handle. */
2893 : : case VMCS_SM_CMD_MAPPED_USR_ADDRESS:
2894 : : {
2895 : : struct vmcs_sm_ioctl_map ioparam;
2896 : :
2897 : : /* Get parameter data. */
2898 : 0 : if (copy_from_user(&ioparam,
2899 : : (void *)arg, sizeof(ioparam)) != 0) {
2900 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2901 : : __func__, cmdnr);
2902 : : ret = -EFAULT;
2903 : 0 : goto out;
2904 : : }
2905 : :
2906 : : /*
2907 : : * Return the address information from the mapping,
2908 : : * 0 (ie NULL) if it cannot locate the actual mapping.
2909 : : */
2910 : 0 : ioparam.addr =
2911 : 0 : vmcs_sm_usr_address_from_pid_and_usr_handle
2912 : : (ioparam.pid, ioparam.handle);
2913 : :
2914 : 0 : if (copy_to_user((void *)arg,
2915 : : &ioparam, sizeof(ioparam)) != 0) {
2916 : 0 : pr_err("[%s]: failed to copy-to-user for cmd %x\n",
2917 : : __func__, cmdnr);
2918 : : ret = -EFAULT;
2919 : : }
2920 : :
2921 : : /* Done. */
2922 : : goto out;
2923 : : }
2924 : : break;
2925 : :
2926 : : /* Flush the cache for a given mapping. */
2927 : : case VMCS_SM_CMD_FLUSH:
2928 : : {
2929 : : struct vmcs_sm_ioctl_cache ioparam;
2930 : :
2931 : : /* Get parameter data. */
2932 : 0 : if (copy_from_user(&ioparam,
2933 : : (void *)arg, sizeof(ioparam)) != 0) {
2934 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2935 : : __func__, cmdnr);
2936 : : ret = -EFAULT;
2937 : 0 : goto out;
2938 : : }
2939 : :
2940 : : /* Locate resource from GUID. */
2941 : 0 : resource =
2942 : 0 : vmcs_sm_acquire_resource(file_data, ioparam.handle);
2943 : 0 : if (resource == NULL) {
2944 : : ret = -EINVAL;
2945 : : goto out;
2946 : : }
2947 : :
2948 : 0 : ret = clean_invalid_resource_walk((void __user*) ioparam.addr,
2949 : 0 : ioparam.size, VCSM_CACHE_OP_FLUSH, ioparam.handle,
2950 : : resource);
2951 : 0 : vmcs_sm_release_resource(resource, 0);
2952 : 0 : if (ret)
2953 : : goto out;
2954 : : }
2955 : 0 : break;
2956 : :
2957 : : /* Invalidate the cache for a given mapping. */
2958 : : case VMCS_SM_CMD_INVALID:
2959 : : {
2960 : : struct vmcs_sm_ioctl_cache ioparam;
2961 : :
2962 : : /* Get parameter data. */
2963 : 0 : if (copy_from_user(&ioparam,
2964 : : (void *)arg, sizeof(ioparam)) != 0) {
2965 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2966 : : __func__, cmdnr);
2967 : : ret = -EFAULT;
2968 : 0 : goto out;
2969 : : }
2970 : :
2971 : : /* Locate resource from GUID. */
2972 : 0 : resource =
2973 : 0 : vmcs_sm_acquire_resource(file_data, ioparam.handle);
2974 : 0 : if (resource == NULL) {
2975 : : ret = -EINVAL;
2976 : : goto out;
2977 : : }
2978 : :
2979 : 0 : ret = clean_invalid_resource_walk((void __user*) ioparam.addr,
2980 : 0 : ioparam.size, VCSM_CACHE_OP_INV, ioparam.handle, resource);
2981 : 0 : vmcs_sm_release_resource(resource, 0);
2982 : 0 : if (ret)
2983 : : goto out;
2984 : : }
2985 : 0 : break;
2986 : :
2987 : : /* Flush/Invalidate the cache for a given mapping. */
2988 : : case VMCS_SM_CMD_CLEAN_INVALID:
2989 : : {
2990 : : int i;
2991 : : struct vmcs_sm_ioctl_clean_invalid ioparam;
2992 : :
2993 : : /* Get parameter data. */
2994 : 0 : if (copy_from_user(&ioparam,
2995 : : (void *)arg, sizeof(ioparam)) != 0) {
2996 : 0 : pr_err("[%s]: failed to copy-from-user for cmd %x\n",
2997 : : __func__, cmdnr);
2998 : : ret = -EFAULT;
2999 : 0 : goto out;
3000 : : }
3001 : 0 : for (i = 0; i < sizeof(ioparam.s) / sizeof(*ioparam.s); i++) {
3002 : 0 : if (ioparam.s[i].cmd == VCSM_CACHE_OP_NOP)
3003 : : break;
3004 : :
3005 : : /* Locate resource from GUID. */
3006 : 0 : resource =
3007 : 0 : vmcs_sm_acquire_resource(file_data, ioparam.s[i].handle);
3008 : 0 : if (resource == NULL) {
3009 : : ret = -EINVAL;
3010 : : goto out;
3011 : : }
3012 : :
3013 : 0 : ret = clean_invalid_resource_walk(
3014 : 0 : (void __user*) ioparam.s[i].addr, ioparam.s[i].size,
3015 : 0 : ioparam.s[i].cmd, ioparam.s[i].handle, resource);
3016 : 0 : vmcs_sm_release_resource(resource, 0);
3017 : 0 : if (ret)
3018 : : goto out;
3019 : : }
3020 : : }
3021 : 0 : break;
3022 : : /*
3023 : : * Flush/Invalidate the cache for a given mapping.
3024 : : * Blocks must be pinned (i.e. accessed) before this call.
3025 : : */
3026 : : case VMCS_SM_CMD_CLEAN_INVALID2:
3027 : : {
3028 : : int i;
3029 : : struct vmcs_sm_ioctl_clean_invalid2 ioparam;
3030 : : struct vmcs_sm_ioctl_clean_invalid_block *block = NULL;
3031 : :
3032 : : /* Get parameter data. */
3033 : 0 : if (copy_from_user(&ioparam,
3034 : : (void *)arg, sizeof(ioparam)) != 0) {
3035 : 0 : pr_err("[%s]: failed to copy-from-user header for cmd %x\n",
3036 : : __func__, cmdnr);
3037 : : ret = -EFAULT;
3038 : 0 : goto out;
3039 : : }
3040 : 0 : block = kmalloc(ioparam.op_count *
3041 : : sizeof(struct vmcs_sm_ioctl_clean_invalid_block),
3042 : : GFP_KERNEL);
3043 : 0 : if (!block) {
3044 : : ret = -EFAULT;
3045 : : goto out;
3046 : : }
3047 : 0 : if (copy_from_user(block,
3048 : 0 : (void *)(arg + sizeof(ioparam)), ioparam.op_count * sizeof(struct vmcs_sm_ioctl_clean_invalid_block)) != 0) {
3049 : 0 : pr_err("[%s]: failed to copy-from-user payload for cmd %x\n",
3050 : : __func__, cmdnr);
3051 : : ret = -EFAULT;
3052 : 0 : goto out;
3053 : : }
3054 : :
3055 : 0 : for (i = 0; i < ioparam.op_count; i++) {
3056 : 0 : const struct vmcs_sm_ioctl_clean_invalid_block * const op = block + i;
3057 : :
3058 : 0 : if (op->invalidate_mode == VCSM_CACHE_OP_NOP)
3059 : 0 : continue;
3060 : :
3061 : 0 : ret = clean_invalid_contiguous_mem_2d(
3062 : 0 : (void __user*) op->start_address, op->block_count,
3063 : : op->block_size, op->inter_block_stride,
3064 : : op->invalidate_mode);
3065 : 0 : if (ret)
3066 : : break;
3067 : : }
3068 : 0 : kfree(block);
3069 : : }
3070 : 0 : break;
3071 : :
3072 : : default:
3073 : : {
3074 : : ret = -EINVAL;
3075 : : goto out;
3076 : : }
3077 : : break;
3078 : : }
3079 : :
3080 : : out:
3081 : 0 : return ret;
3082 : : }
3083 : :
3084 : : /* Device operations that we managed in this driver. */
3085 : : static const struct file_operations vmcs_sm_ops = {
3086 : : .owner = THIS_MODULE,
3087 : : .unlocked_ioctl = vc_sm_ioctl,
3088 : : .open = vc_sm_open,
3089 : : .release = vc_sm_release,
3090 : : .mmap = vc_sm_mmap,
3091 : : };
3092 : :
3093 : : /* Creation of device. */
3094 : 2 : static int vc_sm_create_sharedmemory(void)
3095 : : {
3096 : : int ret;
3097 : :
3098 : 2 : if (sm_state == NULL) {
3099 : : ret = -ENOMEM;
3100 : : goto out;
3101 : : }
3102 : :
3103 : : /* Create a device class for creating dev nodes. */
3104 : 2 : sm_state->sm_class = class_create(THIS_MODULE, "vc-sm");
3105 : 2 : if (IS_ERR(sm_state->sm_class)) {
3106 : 0 : pr_err("[%s]: unable to create device class\n", __func__);
3107 : 0 : ret = PTR_ERR(sm_state->sm_class);
3108 : 0 : goto out;
3109 : : }
3110 : :
3111 : : /* Create a character driver. */
3112 : 2 : ret = alloc_chrdev_region(&sm_state->sm_devid,
3113 : : DEVICE_MINOR, 1, DEVICE_NAME);
3114 : 2 : if (ret != 0) {
3115 : 0 : pr_err("[%s]: unable to allocate device number\n", __func__);
3116 : 0 : goto out_dev_class_destroy;
3117 : : }
3118 : :
3119 : 2 : cdev_init(&sm_state->sm_cdev, &vmcs_sm_ops);
3120 : 2 : ret = cdev_add(&sm_state->sm_cdev, sm_state->sm_devid, 1);
3121 : 2 : if (ret != 0) {
3122 : 0 : pr_err("[%s]: unable to register device\n", __func__);
3123 : 0 : goto out_chrdev_unreg;
3124 : : }
3125 : :
3126 : : /* Create a device node. */
3127 : 2 : sm_state->sm_dev = device_create(sm_state->sm_class,
3128 : : NULL,
3129 : 2 : MKDEV(MAJOR(sm_state->sm_devid),
3130 : : DEVICE_MINOR), NULL,
3131 : : DEVICE_NAME);
3132 : 2 : if (IS_ERR(sm_state->sm_dev)) {
3133 : 0 : pr_err("[%s]: unable to create device node\n", __func__);
3134 : 0 : ret = PTR_ERR(sm_state->sm_dev);
3135 : : goto out_chrdev_del;
3136 : : }
3137 : :
3138 : : goto out;
3139 : :
3140 : : out_chrdev_del:
3141 : 0 : cdev_del(&sm_state->sm_cdev);
3142 : : out_chrdev_unreg:
3143 : 0 : unregister_chrdev_region(sm_state->sm_devid, 1);
3144 : : out_dev_class_destroy:
3145 : 0 : class_destroy(sm_state->sm_class);
3146 : 0 : sm_state->sm_class = NULL;
3147 : : out:
3148 : 2 : return ret;
3149 : : }
3150 : :
3151 : : /* Termination of the device. */
3152 : 0 : static int vc_sm_remove_sharedmemory(void)
3153 : : {
3154 : : int ret;
3155 : :
3156 : 0 : if (sm_state == NULL) {
3157 : : /* Nothing to do. */
3158 : : ret = 0;
3159 : : goto out;
3160 : : }
3161 : :
3162 : : /* Remove the sharedmemory character driver. */
3163 : 0 : cdev_del(&sm_state->sm_cdev);
3164 : :
3165 : : /* Unregister region. */
3166 : 0 : unregister_chrdev_region(sm_state->sm_devid, 1);
3167 : :
3168 : : ret = 0;
3169 : 0 : goto out;
3170 : :
3171 : : out:
3172 : 0 : return ret;
3173 : : }
3174 : :
3175 : : /* Videocore connected. */
3176 : 2 : static void vc_sm_connected_init(void)
3177 : : {
3178 : : int ret;
3179 : : VCHI_INSTANCE_T vchi_instance;
3180 : :
3181 : 2 : pr_info("[%s]: start\n", __func__);
3182 : :
3183 : : /*
3184 : : * Initialize and create a VCHI connection for the shared memory service
3185 : : * running on videocore.
3186 : : */
3187 : 2 : ret = vchi_initialise(&vchi_instance);
3188 : 2 : if (ret != 0) {
3189 : 0 : pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n",
3190 : : __func__, ret);
3191 : :
3192 : : ret = -EIO;
3193 : 0 : goto err_free_mem;
3194 : : }
3195 : :
3196 : 2 : ret = vchi_connect(vchi_instance);
3197 : 2 : if (ret != 0) {
3198 : 0 : pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
3199 : : __func__, ret);
3200 : :
3201 : : ret = -EIO;
3202 : 0 : goto err_free_mem;
3203 : : }
3204 : :
3205 : : /* Initialize an instance of the shared memory service. */
3206 : 2 : sm_state->sm_handle =
3207 : 2 : vc_vchi_sm_init(vchi_instance);
3208 : 2 : if (sm_state->sm_handle == NULL) {
3209 : 0 : pr_err("[%s]: failed to initialize shared memory service\n",
3210 : : __func__);
3211 : :
3212 : : ret = -EPERM;
3213 : 0 : goto err_free_mem;
3214 : : }
3215 : :
3216 : : /* Create a debug fs directory entry (root). */
3217 : 2 : sm_state->dir_root = debugfs_create_dir(VC_SM_DIR_ROOT_NAME, NULL);
3218 : 2 : if (!sm_state->dir_root) {
3219 : 0 : pr_err("[%s]: failed to create \'%s\' directory entry\n",
3220 : : __func__, VC_SM_DIR_ROOT_NAME);
3221 : :
3222 : : ret = -EPERM;
3223 : 0 : goto err_stop_sm_service;
3224 : : }
3225 : :
3226 : 2 : sm_state->dir_state.show = &vc_sm_global_state_show;
3227 : 2 : sm_state->dir_state.dir_entry = debugfs_create_file(VC_SM_STATE,
3228 : 2 : 0444, sm_state->dir_root, &sm_state->dir_state,
3229 : : &vc_sm_debug_fs_fops);
3230 : :
3231 : 2 : sm_state->dir_stats.show = &vc_sm_global_statistics_show;
3232 : 2 : sm_state->dir_stats.dir_entry = debugfs_create_file(VC_SM_STATS,
3233 : 2 : 0444, sm_state->dir_root, &sm_state->dir_stats,
3234 : : &vc_sm_debug_fs_fops);
3235 : :
3236 : : /* Create the proc entry children. */
3237 : 2 : sm_state->dir_alloc = debugfs_create_dir(VC_SM_DIR_ALLOC_NAME,
3238 : 2 : sm_state->dir_root);
3239 : :
3240 : : /* Create a shared memory device. */
3241 : 2 : ret = vc_sm_create_sharedmemory();
3242 : 2 : if (ret != 0) {
3243 : 0 : pr_err("[%s]: failed to create shared memory device\n",
3244 : : __func__);
3245 : 0 : goto err_remove_debugfs;
3246 : : }
3247 : :
3248 : 2 : INIT_LIST_HEAD(&sm_state->map_list);
3249 : 2 : INIT_LIST_HEAD(&sm_state->resource_list);
3250 : :
3251 : 2 : sm_state->data_knl = vc_sm_create_priv_data(0);
3252 : 2 : if (sm_state->data_knl == NULL) {
3253 : 0 : pr_err("[%s]: failed to create kernel private data tracker\n",
3254 : : __func__);
3255 : : goto err_remove_shared_memory;
3256 : : }
3257 : :
3258 : : /* Done! */
3259 : 2 : sm_inited = 1;
3260 : 2 : goto out;
3261 : :
3262 : : err_remove_shared_memory:
3263 : 0 : vc_sm_remove_sharedmemory();
3264 : : err_remove_debugfs:
3265 : 0 : debugfs_remove_recursive(sm_state->dir_root);
3266 : : err_stop_sm_service:
3267 : 0 : vc_vchi_sm_stop(&sm_state->sm_handle);
3268 : : err_free_mem:
3269 : 0 : kfree(sm_state);
3270 : : out:
3271 : 2 : pr_info("[%s]: end - returning %d\n", __func__, ret);
3272 : 2 : }
3273 : :
3274 : : /* Driver loading. */
3275 : 3 : static int bcm2835_vcsm_probe(struct platform_device *pdev)
3276 : : {
3277 : 3 : pr_info("vc-sm: Videocore shared memory driver\n");
3278 : :
3279 : 3 : sm_state = kzalloc(sizeof(*sm_state), GFP_KERNEL);
3280 : 3 : if (!sm_state)
3281 : : return -ENOMEM;
3282 : 3 : sm_state->pdev = pdev;
3283 : 3 : mutex_init(&sm_state->lock);
3284 : 3 : mutex_init(&sm_state->map_lock);
3285 : :
3286 : 3 : vchiq_add_connected_callback(vc_sm_connected_init);
3287 : 3 : return 0;
3288 : : }
3289 : :
3290 : : /* Driver unloading. */
3291 : 0 : static int bcm2835_vcsm_remove(struct platform_device *pdev)
3292 : : {
3293 : : pr_debug("[%s]: start\n", __func__);
3294 : 0 : if (sm_inited) {
3295 : : /* Remove shared memory device. */
3296 : 0 : vc_sm_remove_sharedmemory();
3297 : :
3298 : : /* Remove all proc entries. */
3299 : 0 : debugfs_remove_recursive(sm_state->dir_root);
3300 : :
3301 : : /* Stop the videocore shared memory service. */
3302 : 0 : vc_vchi_sm_stop(&sm_state->sm_handle);
3303 : :
3304 : : /* Free the memory for the state structure. */
3305 : : mutex_destroy(&(sm_state->map_lock));
3306 : 0 : kfree(sm_state);
3307 : : }
3308 : :
3309 : : pr_debug("[%s]: end\n", __func__);
3310 : 0 : return 0;
3311 : : }
3312 : :
3313 : : #if defined(__KERNEL__)
3314 : : /* Allocate a shared memory handle and block. */
3315 : 0 : int vc_sm_alloc(struct vc_sm_alloc_t *alloc, int *handle)
3316 : : {
3317 : 0 : struct vmcs_sm_ioctl_alloc ioparam = { 0 };
3318 : : int ret;
3319 : : struct sm_resource_t *resource;
3320 : :
3321 : : /* Validate we can work with this device. */
3322 : 0 : if (sm_state == NULL || alloc == NULL || handle == NULL) {
3323 : 0 : pr_err("[%s]: invalid input\n", __func__);
3324 : 0 : return -EPERM;
3325 : : }
3326 : :
3327 : 0 : ioparam.size = alloc->base_unit;
3328 : 0 : ioparam.num = alloc->num_unit;
3329 : 0 : ioparam.cached =
3330 : 0 : alloc->type == VC_SM_ALLOC_CACHED ? VMCS_SM_CACHE_VC : 0;
3331 : :
3332 : 0 : ret = vc_sm_ioctl_alloc(sm_state->data_knl, &ioparam);
3333 : :
3334 : 0 : if (ret == 0) {
3335 : 0 : resource =
3336 : 0 : vmcs_sm_acquire_resource(sm_state->data_knl,
3337 : : ioparam.handle);
3338 : 0 : if (resource) {
3339 : 0 : resource->pid = 0;
3340 : 0 : vmcs_sm_release_resource(resource, 0);
3341 : :
3342 : : /* Assign valid handle at this time. */
3343 : 0 : *handle = ioparam.handle;
3344 : : } else {
3345 : : ret = -ENOMEM;
3346 : : }
3347 : : }
3348 : :
3349 : 0 : return ret;
3350 : : }
3351 : : EXPORT_SYMBOL_GPL(vc_sm_alloc);
3352 : :
3353 : : /* Get an internal resource handle mapped from the external one. */
3354 : 0 : int vc_sm_int_handle(int handle)
3355 : : {
3356 : : struct sm_resource_t *resource;
3357 : : int ret = 0;
3358 : :
3359 : : /* Validate we can work with this device. */
3360 : 0 : if (sm_state == NULL || handle == 0) {
3361 : 0 : pr_err("[%s]: invalid input\n", __func__);
3362 : 0 : return 0;
3363 : : }
3364 : :
3365 : : /* Locate resource from GUID. */
3366 : 0 : resource = vmcs_sm_acquire_resource(sm_state->data_knl, handle);
3367 : 0 : if (resource) {
3368 : 0 : ret = resource->res_handle;
3369 : 0 : vmcs_sm_release_resource(resource, 0);
3370 : : }
3371 : :
3372 : 0 : return ret;
3373 : : }
3374 : : EXPORT_SYMBOL_GPL(vc_sm_int_handle);
3375 : :
3376 : : /* Free a previously allocated shared memory handle and block. */
3377 : 0 : int vc_sm_free(int handle)
3378 : : {
3379 : 0 : struct vmcs_sm_ioctl_free ioparam = { handle };
3380 : :
3381 : : /* Validate we can work with this device. */
3382 : 0 : if (sm_state == NULL || handle == 0) {
3383 : 0 : pr_err("[%s]: invalid input\n", __func__);
3384 : 0 : return -EPERM;
3385 : : }
3386 : :
3387 : 0 : return vc_sm_ioctl_free(sm_state->data_knl, &ioparam);
3388 : : }
3389 : : EXPORT_SYMBOL_GPL(vc_sm_free);
3390 : :
3391 : : /* Lock a memory handle for use by kernel. */
3392 : 0 : int vc_sm_lock(int handle, enum vc_sm_lock_cache_mode mode,
3393 : : unsigned long *data)
3394 : : {
3395 : : struct vmcs_sm_ioctl_lock_unlock ioparam;
3396 : : int ret;
3397 : :
3398 : : /* Validate we can work with this device. */
3399 : 0 : if (sm_state == NULL || handle == 0 || data == NULL) {
3400 : 0 : pr_err("[%s]: invalid input\n", __func__);
3401 : 0 : return -EPERM;
3402 : : }
3403 : :
3404 : 0 : *data = 0;
3405 : :
3406 : 0 : ioparam.handle = handle;
3407 : 0 : ret = vc_sm_ioctl_lock(sm_state->data_knl,
3408 : : &ioparam,
3409 : : 1,
3410 : : ((mode ==
3411 : : VC_SM_LOCK_CACHED) ? VMCS_SM_CACHE_HOST :
3412 : : VMCS_SM_CACHE_NONE), 0);
3413 : :
3414 : 0 : *data = ioparam.addr;
3415 : 0 : return ret;
3416 : : }
3417 : : EXPORT_SYMBOL_GPL(vc_sm_lock);
3418 : :
3419 : : /* Unlock a memory handle in use by kernel. */
3420 : 0 : int vc_sm_unlock(int handle, int flush, int no_vc_unlock)
3421 : : {
3422 : : struct vmcs_sm_ioctl_lock_unlock ioparam;
3423 : :
3424 : : /* Validate we can work with this device. */
3425 : 0 : if (sm_state == NULL || handle == 0) {
3426 : 0 : pr_err("[%s]: invalid input\n", __func__);
3427 : 0 : return -EPERM;
3428 : : }
3429 : :
3430 : 0 : ioparam.handle = handle;
3431 : 0 : return vc_sm_ioctl_unlock(sm_state->data_knl,
3432 : : &ioparam, flush, 0, no_vc_unlock);
3433 : : }
3434 : : EXPORT_SYMBOL_GPL(vc_sm_unlock);
3435 : :
3436 : : /* Map a shared memory region for use by kernel. */
3437 : 0 : int vc_sm_map(int handle, unsigned int sm_addr,
3438 : : enum vc_sm_lock_cache_mode mode, unsigned long *data)
3439 : : {
3440 : : struct vmcs_sm_ioctl_lock_unlock ioparam;
3441 : : int ret;
3442 : :
3443 : : /* Validate we can work with this device. */
3444 : 0 : if (sm_state == NULL || handle == 0 || data == NULL || sm_addr == 0) {
3445 : 0 : pr_err("[%s]: invalid input\n", __func__);
3446 : 0 : return -EPERM;
3447 : : }
3448 : :
3449 : 0 : *data = 0;
3450 : :
3451 : 0 : ioparam.handle = handle;
3452 : 0 : ret = vc_sm_ioctl_lock(sm_state->data_knl,
3453 : : &ioparam,
3454 : : 1,
3455 : : ((mode ==
3456 : : VC_SM_LOCK_CACHED) ? VMCS_SM_CACHE_HOST :
3457 : : VMCS_SM_CACHE_NONE), sm_addr);
3458 : :
3459 : 0 : *data = ioparam.addr;
3460 : 0 : return ret;
3461 : : }
3462 : : EXPORT_SYMBOL_GPL(vc_sm_map);
3463 : :
3464 : : /* Import a dmabuf to be shared with VC. */
3465 : 0 : int vc_sm_import_dmabuf(struct dma_buf *dmabuf, int *handle)
3466 : : {
3467 : 0 : struct vmcs_sm_ioctl_import_dmabuf ioparam = { 0 };
3468 : : int ret;
3469 : : struct sm_resource_t *resource;
3470 : :
3471 : : /* Validate we can work with this device. */
3472 : 0 : if (!sm_state || !dmabuf || !handle) {
3473 : 0 : pr_err("[%s]: invalid input\n", __func__);
3474 : 0 : return -EPERM;
3475 : : }
3476 : :
3477 : : ioparam.cached = 0;
3478 : 0 : strcpy(ioparam.name, "KRNL DMABUF");
3479 : :
3480 : 0 : ret = vc_sm_ioctl_import_dmabuf(sm_state->data_knl, &ioparam, dmabuf);
3481 : :
3482 : 0 : if (!ret) {
3483 : 0 : resource = vmcs_sm_acquire_resource(sm_state->data_knl,
3484 : : ioparam.handle);
3485 : 0 : if (resource) {
3486 : 0 : resource->pid = 0;
3487 : 0 : vmcs_sm_release_resource(resource, 0);
3488 : :
3489 : : /* Assign valid handle at this time.*/
3490 : 0 : *handle = ioparam.handle;
3491 : : } else {
3492 : : ret = -ENOMEM;
3493 : : }
3494 : : }
3495 : :
3496 : 0 : return ret;
3497 : : }
3498 : : EXPORT_SYMBOL_GPL(vc_sm_import_dmabuf);
3499 : : #endif
3500 : :
3501 : : /*
3502 : : * Register the driver with device tree
3503 : : */
3504 : :
3505 : : static const struct of_device_id bcm2835_vcsm_of_match[] = {
3506 : : {.compatible = "raspberrypi,bcm2835-vcsm",},
3507 : : { /* sentinel */ },
3508 : : };
3509 : :
3510 : : MODULE_DEVICE_TABLE(of, bcm2835_vcsm_of_match);
3511 : :
3512 : : static struct platform_driver bcm2835_vcsm_driver = {
3513 : : .probe = bcm2835_vcsm_probe,
3514 : : .remove = bcm2835_vcsm_remove,
3515 : : .driver = {
3516 : : .name = DRIVER_NAME,
3517 : : .owner = THIS_MODULE,
3518 : : .of_match_table = bcm2835_vcsm_of_match,
3519 : : },
3520 : : };
3521 : :
3522 : 3 : module_platform_driver(bcm2835_vcsm_driver);
3523 : :
3524 : : MODULE_AUTHOR("Broadcom");
3525 : : MODULE_DESCRIPTION("VideoCore SharedMemory Driver");
3526 : : MODULE_LICENSE("GPL v2");
|