1 /*
2 * dspapi.c
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * Common DSP API functions, also includes the wrapper
7 * functions called directly by the DeviceIOControl interface.
8 *
9 * Copyright (C) 2005-2006 Texas Instruments, Inc.
10 *
11 * This package is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 *
15 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19 #include <linux/types.h>
20
21 /* ----------------------------------- Host OS */
22 #include <dspbridge/host_os.h>
23
24 /* ----------------------------------- DSP/BIOS Bridge */
25 #include <dspbridge/dbdefs.h>
26
27 /* ----------------------------------- OS Adaptation Layer */
28 #include <dspbridge/ntfy.h>
29
30 /* ----------------------------------- Platform Manager */
31 #include <dspbridge/chnl.h>
32 #include <dspbridge/dev.h>
33 #include <dspbridge/drv.h>
34
35 #include <dspbridge/proc.h>
36 #include <dspbridge/strm.h>
37
38 /* ----------------------------------- Resource Manager */
39 #include <dspbridge/disp.h>
40 #include <dspbridge/mgr.h>
41 #include <dspbridge/node.h>
42 #include <dspbridge/rmm.h>
43
44 /* ----------------------------------- Others */
45 #include <dspbridge/msg.h>
46 #include <dspbridge/cmm.h>
47 #include <dspbridge/io.h>
48
49 /* ----------------------------------- This */
50 #include <dspbridge/dspapi.h>
51 #include <dspbridge/dbdcd.h>
52
53 #include <dspbridge/resourcecleanup.h>
54
55 /* ----------------------------------- Defines, Data Structures, Typedefs */
56 #define MAX_TRACEBUFLEN 255
57 #define MAX_LOADARGS 16
58 #define MAX_NODES 64
59 #define MAX_STREAMS 16
60 #define MAX_BUFS 64
61
62 /* Used to get dspbridge ioctl table */
63 #define DB_GET_IOC_TABLE(cmd) (DB_GET_MODULE(cmd) >> DB_MODULE_SHIFT)
64
65 /* Device IOCtl function pointer */
66 struct api_cmd {
67 u32(*fxn) (union trapped_args *args, void *pr_ctxt);
68 u32 index;
69 };
70
71 /* ----------------------------------- Globals */
72 static u32 api_c_refs;
73
74 /*
75 * Function tables.
76 * The order of these functions MUST be the same as the order of the command
77 * numbers defined in dspapi-ioctl.h This is how an IOCTL number in user mode
78 * turns into a function call in kernel mode.
79 */
80
81 /* MGR wrapper functions */
82 static struct api_cmd mgr_cmd[] = {
83 {mgrwrap_enum_node_info}, /* MGR_ENUMNODE_INFO */
84 {mgrwrap_enum_proc_info}, /* MGR_ENUMPROC_INFO */
85 {mgrwrap_register_object}, /* MGR_REGISTEROBJECT */
86 {mgrwrap_unregister_object}, /* MGR_UNREGISTEROBJECT */
87 {mgrwrap_wait_for_bridge_events}, /* MGR_WAIT */
88 {mgrwrap_get_process_resources_info}, /* MGR_GET_PROC_RES */
89 };
90
91 /* PROC wrapper functions */
92 static struct api_cmd proc_cmd[] = {
93 {procwrap_attach}, /* PROC_ATTACH */
94 {procwrap_ctrl}, /* PROC_CTRL */
95 {procwrap_detach}, /* PROC_DETACH */
96 {procwrap_enum_node_info}, /* PROC_ENUMNODE */
97 {procwrap_enum_resources}, /* PROC_ENUMRESOURCES */
98 {procwrap_get_state}, /* PROC_GET_STATE */
99 {procwrap_get_trace}, /* PROC_GET_TRACE */
100 {procwrap_load}, /* PROC_LOAD */
101 {procwrap_register_notify}, /* PROC_REGISTERNOTIFY */
102 {procwrap_start}, /* PROC_START */
103 {procwrap_reserve_memory}, /* PROC_RSVMEM */
104 {procwrap_un_reserve_memory}, /* PROC_UNRSVMEM */
105 {procwrap_map}, /* PROC_MAPMEM */
106 {procwrap_un_map}, /* PROC_UNMAPMEM */
107 {procwrap_flush_memory}, /* PROC_FLUSHMEMORY */
108 {procwrap_stop}, /* PROC_STOP */
109 {procwrap_invalidate_memory}, /* PROC_INVALIDATEMEMORY */
110 {procwrap_begin_dma}, /* PROC_BEGINDMA */
111 {procwrap_end_dma}, /* PROC_ENDDMA */
112 };
113
114 /* NODE wrapper functions */
115 static struct api_cmd node_cmd[] = {
116 {nodewrap_allocate}, /* NODE_ALLOCATE */
117 {nodewrap_alloc_msg_buf}, /* NODE_ALLOCMSGBUF */
118 {nodewrap_change_priority}, /* NODE_CHANGEPRIORITY */
119 {nodewrap_connect}, /* NODE_CONNECT */
120 {nodewrap_create}, /* NODE_CREATE */
121 {nodewrap_delete}, /* NODE_DELETE */
122 {nodewrap_free_msg_buf}, /* NODE_FREEMSGBUF */
123 {nodewrap_get_attr}, /* NODE_GETATTR */
124 {nodewrap_get_message}, /* NODE_GETMESSAGE */
125 {nodewrap_pause}, /* NODE_PAUSE */
126 {nodewrap_put_message}, /* NODE_PUTMESSAGE */
127 {nodewrap_register_notify}, /* NODE_REGISTERNOTIFY */
128 {nodewrap_run}, /* NODE_RUN */
129 {nodewrap_terminate}, /* NODE_TERMINATE */
130 {nodewrap_get_uuid_props}, /* NODE_GETUUIDPROPS */
131 };
132
133 /* STRM wrapper functions */
134 static struct api_cmd strm_cmd[] = {
135 {strmwrap_allocate_buffer}, /* STRM_ALLOCATEBUFFER */
136 {strmwrap_close}, /* STRM_CLOSE */
137 {strmwrap_free_buffer}, /* STRM_FREEBUFFER */
138 {strmwrap_get_event_handle}, /* STRM_GETEVENTHANDLE */
139 {strmwrap_get_info}, /* STRM_GETINFO */
140 {strmwrap_idle}, /* STRM_IDLE */
141 {strmwrap_issue}, /* STRM_ISSUE */
142 {strmwrap_open}, /* STRM_OPEN */
143 {strmwrap_reclaim}, /* STRM_RECLAIM */
144 {strmwrap_register_notify}, /* STRM_REGISTERNOTIFY */
145 {strmwrap_select}, /* STRM_SELECT */
146 };
147
148 /* CMM wrapper functions */
149 static struct api_cmd cmm_cmd[] = {
150 {cmmwrap_calloc_buf}, /* CMM_ALLOCBUF */
151 {cmmwrap_free_buf}, /* CMM_FREEBUF */
152 {cmmwrap_get_handle}, /* CMM_GETHANDLE */
153 {cmmwrap_get_info}, /* CMM_GETINFO */
154 };
155
156 /* Array used to store ioctl table sizes. It can hold up to 8 entries */
157 static u8 size_cmd[] = {
158 ARRAY_SIZE(mgr_cmd),
159 ARRAY_SIZE(proc_cmd),
160 ARRAY_SIZE(node_cmd),
161 ARRAY_SIZE(strm_cmd),
162 ARRAY_SIZE(cmm_cmd),
163 };
164
_cp_fm_usr(void * to,const void __user * from,int * err,unsigned long bytes)165 static inline void _cp_fm_usr(void *to, const void __user * from,
166 int *err, unsigned long bytes)
167 {
168 if (*err)
169 return;
170
171 if (unlikely(!from)) {
172 *err = -EFAULT;
173 return;
174 }
175
176 if (unlikely(copy_from_user(to, from, bytes)))
177 *err = -EFAULT;
178 }
179
180 #define CP_FM_USR(to, from, err, n) \
181 _cp_fm_usr(to, from, &(err), (n) * sizeof(*(to)))
182
_cp_to_usr(void __user * to,const void * from,int * err,unsigned long bytes)183 static inline void _cp_to_usr(void __user *to, const void *from,
184 int *err, unsigned long bytes)
185 {
186 if (*err)
187 return;
188
189 if (unlikely(!to)) {
190 *err = -EFAULT;
191 return;
192 }
193
194 if (unlikely(copy_to_user(to, from, bytes)))
195 *err = -EFAULT;
196 }
197
198 #define CP_TO_USR(to, from, err, n) \
199 _cp_to_usr(to, from, &(err), (n) * sizeof(*(from)))
200
201 /*
202 * ======== api_call_dev_ioctl ========
203 * Purpose:
204 * Call the (wrapper) function for the corresponding API IOCTL.
205 */
api_call_dev_ioctl(u32 cmd,union trapped_args * args,u32 * result,void * pr_ctxt)206 inline int api_call_dev_ioctl(u32 cmd, union trapped_args *args,
207 u32 *result, void *pr_ctxt)
208 {
209 u32(*ioctl_cmd) (union trapped_args *args, void *pr_ctxt) = NULL;
210 int i;
211
212 if (_IOC_TYPE(cmd) != DB) {
213 pr_err("%s: Incompatible dspbridge ioctl number\n", __func__);
214 goto err;
215 }
216
217 if (DB_GET_IOC_TABLE(cmd) > ARRAY_SIZE(size_cmd)) {
218 pr_err("%s: undefined ioctl module\n", __func__);
219 goto err;
220 }
221
222 /* Check the size of the required cmd table */
223 i = DB_GET_IOC(cmd);
224 if (i > size_cmd[DB_GET_IOC_TABLE(cmd)]) {
225 pr_err("%s: requested ioctl %d out of bounds for table %d\n",
226 __func__, i, DB_GET_IOC_TABLE(cmd));
227 goto err;
228 }
229
230 switch (DB_GET_MODULE(cmd)) {
231 case DB_MGR:
232 ioctl_cmd = mgr_cmd[i].fxn;
233 break;
234 case DB_PROC:
235 ioctl_cmd = proc_cmd[i].fxn;
236 break;
237 case DB_NODE:
238 ioctl_cmd = node_cmd[i].fxn;
239 break;
240 case DB_STRM:
241 ioctl_cmd = strm_cmd[i].fxn;
242 break;
243 case DB_CMM:
244 ioctl_cmd = cmm_cmd[i].fxn;
245 break;
246 }
247
248 if (!ioctl_cmd) {
249 pr_err("%s: requested ioctl not defined\n", __func__);
250 goto err;
251 } else {
252 *result = (*ioctl_cmd) (args, pr_ctxt);
253 }
254
255 return 0;
256
257 err:
258 return -EINVAL;
259 }
260
261 /*
262 * ======== api_exit ========
263 */
api_exit(void)264 void api_exit(void)
265 {
266 api_c_refs--;
267
268 if (api_c_refs == 0)
269 mgr_exit();
270 }
271
272 /*
273 * ======== api_init ========
274 * Purpose:
275 * Module initialization used by Bridge API.
276 */
api_init(void)277 bool api_init(void)
278 {
279 bool ret = true;
280
281 if (api_c_refs == 0)
282 ret = mgr_init();
283
284 if (ret)
285 api_c_refs++;
286
287 return ret;
288 }
289
290 /*
291 * ======== api_init_complete2 ========
292 * Purpose:
293 * Perform any required bridge initialization which cannot
294 * be performed in api_init() or dev_start_device() due
295 * to the fact that some services are not yet
296 * completely initialized.
297 * Parameters:
298 * Returns:
299 * 0: Allow this device to load
300 * -EPERM: Failure.
301 * Requires:
302 * Bridge API initialized.
303 * Ensures:
304 */
api_init_complete2(void)305 int api_init_complete2(void)
306 {
307 int status = 0;
308 struct cfg_devnode *dev_node;
309 struct dev_object *hdev_obj;
310 struct drv_data *drv_datap;
311 u8 dev_type;
312
313 /* Walk the list of DevObjects, get each devnode, and attempting to
314 * autostart the board. Note that this requires COF loading, which
315 * requires KFILE. */
316 for (hdev_obj = dev_get_first(); hdev_obj != NULL;
317 hdev_obj = dev_get_next(hdev_obj)) {
318 if (dev_get_dev_node(hdev_obj, &dev_node))
319 continue;
320
321 if (dev_get_dev_type(hdev_obj, &dev_type))
322 continue;
323
324 if ((dev_type == DSP_UNIT) || (dev_type == IVA_UNIT)) {
325 drv_datap = dev_get_drvdata(bridge);
326
327 if (drv_datap && drv_datap->base_img)
328 proc_auto_start(dev_node, hdev_obj);
329 }
330 }
331
332 return status;
333 }
334
335 /* TODO: Remove deprecated and not implemented ioctl wrappers */
336
337 /*
338 * ======== mgrwrap_enum_node_info ========
339 */
mgrwrap_enum_node_info(union trapped_args * args,void * pr_ctxt)340 u32 mgrwrap_enum_node_info(union trapped_args *args, void *pr_ctxt)
341 {
342 u8 *pndb_props;
343 u32 num_nodes;
344 int status = 0;
345 u32 size = args->args_mgr_enumnode_info.ndb_props_size;
346
347 if (size < sizeof(struct dsp_ndbprops))
348 return -EINVAL;
349
350 pndb_props = kmalloc(size, GFP_KERNEL);
351 if (pndb_props == NULL)
352 status = -ENOMEM;
353
354 if (!status) {
355 status =
356 mgr_enum_node_info(args->args_mgr_enumnode_info.node_id,
357 (struct dsp_ndbprops *)pndb_props, size,
358 &num_nodes);
359 }
360 CP_TO_USR(args->args_mgr_enumnode_info.ndb_props, pndb_props, status,
361 size);
362 CP_TO_USR(args->args_mgr_enumnode_info.num_nodes, &num_nodes, status,
363 1);
364 kfree(pndb_props);
365
366 return status;
367 }
368
369 /*
370 * ======== mgrwrap_enum_proc_info ========
371 */
mgrwrap_enum_proc_info(union trapped_args * args,void * pr_ctxt)372 u32 mgrwrap_enum_proc_info(union trapped_args *args, void *pr_ctxt)
373 {
374 u8 *processor_info;
375 u8 num_procs;
376 int status = 0;
377 u32 size = args->args_mgr_enumproc_info.processor_info_size;
378
379 if (size < sizeof(struct dsp_processorinfo))
380 return -EINVAL;
381
382 processor_info = kmalloc(size, GFP_KERNEL);
383 if (processor_info == NULL)
384 status = -ENOMEM;
385
386 if (!status) {
387 status =
388 mgr_enum_processor_info(args->args_mgr_enumproc_info.
389 processor_id,
390 (struct dsp_processorinfo *)
391 processor_info, size, &num_procs);
392 }
393 CP_TO_USR(args->args_mgr_enumproc_info.processor_info, processor_info,
394 status, size);
395 CP_TO_USR(args->args_mgr_enumproc_info.num_procs, &num_procs,
396 status, 1);
397 kfree(processor_info);
398
399 return status;
400 }
401
402 #define WRAP_MAP2CALLER(x) x
403 /*
404 * ======== mgrwrap_register_object ========
405 */
mgrwrap_register_object(union trapped_args * args,void * pr_ctxt)406 u32 mgrwrap_register_object(union trapped_args *args, void *pr_ctxt)
407 {
408 u32 ret;
409 struct dsp_uuid uuid_obj;
410 u32 path_size = 0;
411 char *psz_path_name = NULL;
412 int status = 0;
413
414 CP_FM_USR(&uuid_obj, args->args_mgr_registerobject.uuid_obj, status, 1);
415 if (status)
416 goto func_end;
417 path_size = strlen_user((char *)
418 args->args_mgr_registerobject.sz_path_name);
419 if (!path_size) {
420 status = -EINVAL;
421 goto func_end;
422 }
423
424 psz_path_name = kmalloc(path_size, GFP_KERNEL);
425 if (!psz_path_name) {
426 status = -ENOMEM;
427 goto func_end;
428 }
429 ret = strncpy_from_user(psz_path_name,
430 (char *)args->args_mgr_registerobject.
431 sz_path_name, path_size);
432 if (!ret) {
433 status = -EFAULT;
434 goto func_end;
435 }
436
437 if (args->args_mgr_registerobject.obj_type >= DSP_DCDMAXOBJTYPE) {
438 status = -EINVAL;
439 goto func_end;
440 }
441
442 status = dcd_register_object(&uuid_obj,
443 args->args_mgr_registerobject.obj_type,
444 (char *)psz_path_name);
445 func_end:
446 kfree(psz_path_name);
447 return status;
448 }
449
450 /*
451 * ======== mgrwrap_unregister_object ========
452 */
mgrwrap_unregister_object(union trapped_args * args,void * pr_ctxt)453 u32 mgrwrap_unregister_object(union trapped_args *args, void *pr_ctxt)
454 {
455 int status = 0;
456 struct dsp_uuid uuid_obj;
457
458 CP_FM_USR(&uuid_obj, args->args_mgr_registerobject.uuid_obj, status, 1);
459 if (status)
460 goto func_end;
461
462 status = dcd_unregister_object(&uuid_obj,
463 args->args_mgr_unregisterobject.
464 obj_type);
465 func_end:
466 return status;
467
468 }
469
470 /*
471 * ======== mgrwrap_wait_for_bridge_events ========
472 */
mgrwrap_wait_for_bridge_events(union trapped_args * args,void * pr_ctxt)473 u32 mgrwrap_wait_for_bridge_events(union trapped_args *args, void *pr_ctxt)
474 {
475 int status = 0;
476 struct dsp_notification *anotifications[MAX_EVENTS];
477 struct dsp_notification notifications[MAX_EVENTS];
478 u32 index, i;
479 u32 count = args->args_mgr_wait.count;
480
481 if (count > MAX_EVENTS)
482 status = -EINVAL;
483
484 /* get the array of pointers to user structures */
485 CP_FM_USR(anotifications, args->args_mgr_wait.anotifications,
486 status, count);
487 /* get the events */
488 for (i = 0; i < count; i++) {
489 CP_FM_USR(¬ifications[i], anotifications[i], status, 1);
490 if (status || !notifications[i].handle) {
491 status = -EINVAL;
492 break;
493 }
494 /* set the array of pointers to kernel structures */
495 anotifications[i] = ¬ifications[i];
496 }
497 if (!status) {
498 status = mgr_wait_for_bridge_events(anotifications, count,
499 &index,
500 args->args_mgr_wait.
501 timeout);
502 }
503 CP_TO_USR(args->args_mgr_wait.index, &index, status, 1);
504 return status;
505 }
506
507 /*
508 * ======== MGRWRAP_GetProcessResourceInfo ========
509 */
mgrwrap_get_process_resources_info(union trapped_args * args,void * pr_ctxt)510 u32 __deprecated mgrwrap_get_process_resources_info(union trapped_args * args,
511 void *pr_ctxt)
512 {
513 pr_err("%s: deprecated dspbridge ioctl\n", __func__);
514 return 0;
515 }
516
517 /*
518 * ======== procwrap_attach ========
519 */
procwrap_attach(union trapped_args * args,void * pr_ctxt)520 u32 procwrap_attach(union trapped_args *args, void *pr_ctxt)
521 {
522 void *processor;
523 int status = 0;
524 struct dsp_processorattrin proc_attr_in, *attr_in = NULL;
525
526 /* Optional argument */
527 if (args->args_proc_attach.attr_in) {
528 CP_FM_USR(&proc_attr_in, args->args_proc_attach.attr_in, status,
529 1);
530 if (!status)
531 attr_in = &proc_attr_in;
532 else
533 goto func_end;
534
535 }
536 status = proc_attach(args->args_proc_attach.processor_id, attr_in,
537 &processor, pr_ctxt);
538 CP_TO_USR(args->args_proc_attach.ph_processor, &processor, status, 1);
539 func_end:
540 return status;
541 }
542
543 /*
544 * ======== procwrap_ctrl ========
545 */
procwrap_ctrl(union trapped_args * args,void * pr_ctxt)546 u32 procwrap_ctrl(union trapped_args *args, void *pr_ctxt)
547 {
548 u32 cb_data_size, __user * psize = (u32 __user *)
549 args->args_proc_ctrl.args;
550 u8 *pargs = NULL;
551 int status = 0;
552 void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
553
554 if (psize) {
555 if (get_user(cb_data_size, psize)) {
556 status = -EPERM;
557 goto func_end;
558 }
559 cb_data_size += sizeof(u32);
560 pargs = kmalloc(cb_data_size, GFP_KERNEL);
561 if (pargs == NULL) {
562 status = -ENOMEM;
563 goto func_end;
564 }
565
566 CP_FM_USR(pargs, args->args_proc_ctrl.args, status,
567 cb_data_size);
568 }
569 if (!status) {
570 status = proc_ctrl(hprocessor,
571 args->args_proc_ctrl.cmd,
572 (struct dsp_cbdata *)pargs);
573 }
574
575 /* CP_TO_USR(args->args_proc_ctrl.args, pargs, status, 1); */
576 kfree(pargs);
577 func_end:
578 return status;
579 }
580
581 /*
582 * ======== procwrap_detach ========
583 */
procwrap_detach(union trapped_args * args,void * pr_ctxt)584 u32 __deprecated procwrap_detach(union trapped_args * args, void *pr_ctxt)
585 {
586 /* proc_detach called at bridge_release only */
587 pr_err("%s: deprecated dspbridge ioctl\n", __func__);
588 return 0;
589 }
590
591 /*
592 * ======== procwrap_enum_node_info ========
593 */
procwrap_enum_node_info(union trapped_args * args,void * pr_ctxt)594 u32 procwrap_enum_node_info(union trapped_args *args, void *pr_ctxt)
595 {
596 int status;
597 void *node_tab[MAX_NODES];
598 u32 num_nodes;
599 u32 alloc_cnt;
600 void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
601
602 if (!args->args_proc_enumnode_info.node_tab_size)
603 return -EINVAL;
604
605 status = proc_enum_nodes(hprocessor,
606 node_tab,
607 args->args_proc_enumnode_info.node_tab_size,
608 &num_nodes, &alloc_cnt);
609 CP_TO_USR(args->args_proc_enumnode_info.node_tab, node_tab, status,
610 num_nodes);
611 CP_TO_USR(args->args_proc_enumnode_info.num_nodes, &num_nodes,
612 status, 1);
613 CP_TO_USR(args->args_proc_enumnode_info.allocated, &alloc_cnt,
614 status, 1);
615 return status;
616 }
617
procwrap_end_dma(union trapped_args * args,void * pr_ctxt)618 u32 procwrap_end_dma(union trapped_args *args, void *pr_ctxt)
619 {
620 int status;
621
622 if (args->args_proc_dma.dir >= DMA_NONE)
623 return -EINVAL;
624
625 status = proc_end_dma(pr_ctxt,
626 args->args_proc_dma.mpu_addr,
627 args->args_proc_dma.size,
628 args->args_proc_dma.dir);
629 return status;
630 }
631
procwrap_begin_dma(union trapped_args * args,void * pr_ctxt)632 u32 procwrap_begin_dma(union trapped_args *args, void *pr_ctxt)
633 {
634 int status;
635
636 if (args->args_proc_dma.dir >= DMA_NONE)
637 return -EINVAL;
638
639 status = proc_begin_dma(pr_ctxt,
640 args->args_proc_dma.mpu_addr,
641 args->args_proc_dma.size,
642 args->args_proc_dma.dir);
643 return status;
644 }
645
646 /*
647 * ======== procwrap_flush_memory ========
648 */
procwrap_flush_memory(union trapped_args * args,void * pr_ctxt)649 u32 procwrap_flush_memory(union trapped_args *args, void *pr_ctxt)
650 {
651 int status;
652
653 if (args->args_proc_flushmemory.flags >
654 PROC_WRITEBACK_INVALIDATE_MEM)
655 return -EINVAL;
656
657 status = proc_flush_memory(pr_ctxt,
658 args->args_proc_flushmemory.mpu_addr,
659 args->args_proc_flushmemory.size,
660 args->args_proc_flushmemory.flags);
661 return status;
662 }
663
664 /*
665 * ======== procwrap_invalidate_memory ========
666 */
procwrap_invalidate_memory(union trapped_args * args,void * pr_ctxt)667 u32 procwrap_invalidate_memory(union trapped_args *args, void *pr_ctxt)
668 {
669 int status;
670
671 status =
672 proc_invalidate_memory(pr_ctxt,
673 args->args_proc_invalidatememory.mpu_addr,
674 args->args_proc_invalidatememory.size);
675 return status;
676 }
677
678 /*
679 * ======== procwrap_enum_resources ========
680 */
procwrap_enum_resources(union trapped_args * args,void * pr_ctxt)681 u32 procwrap_enum_resources(union trapped_args *args, void *pr_ctxt)
682 {
683 int status = 0;
684 struct dsp_resourceinfo resource_info;
685 void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
686
687 if (args->args_proc_enumresources.resource_info_size <
688 sizeof(struct dsp_resourceinfo))
689 return -EINVAL;
690
691 status =
692 proc_get_resource_info(hprocessor,
693 args->args_proc_enumresources.resource_type,
694 &resource_info,
695 args->args_proc_enumresources.
696 resource_info_size);
697
698 CP_TO_USR(args->args_proc_enumresources.resource_info, &resource_info,
699 status, 1);
700
701 return status;
702
703 }
704
705 /*
706 * ======== procwrap_get_state ========
707 */
procwrap_get_state(union trapped_args * args,void * pr_ctxt)708 u32 procwrap_get_state(union trapped_args *args, void *pr_ctxt)
709 {
710 int status;
711 struct dsp_processorstate proc_state;
712 void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
713
714 if (args->args_proc_getstate.state_info_size <
715 sizeof(struct dsp_processorstate))
716 return -EINVAL;
717
718 status = proc_get_state(hprocessor, &proc_state,
719 args->args_proc_getstate.state_info_size);
720 CP_TO_USR(args->args_proc_getstate.proc_state_obj, &proc_state, status,
721 1);
722 return status;
723
724 }
725
726 /*
727 * ======== procwrap_get_trace ========
728 */
procwrap_get_trace(union trapped_args * args,void * pr_ctxt)729 u32 procwrap_get_trace(union trapped_args *args, void *pr_ctxt)
730 {
731 int status;
732 u8 *pbuf;
733 void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
734
735 if (args->args_proc_gettrace.max_size > MAX_TRACEBUFLEN)
736 return -EINVAL;
737
738 pbuf = kzalloc(args->args_proc_gettrace.max_size, GFP_KERNEL);
739 if (pbuf != NULL) {
740 status = proc_get_trace(hprocessor, pbuf,
741 args->args_proc_gettrace.max_size);
742 } else {
743 status = -ENOMEM;
744 }
745 CP_TO_USR(args->args_proc_gettrace.buf, pbuf, status,
746 args->args_proc_gettrace.max_size);
747 kfree(pbuf);
748
749 return status;
750 }
751
752 /*
753 * ======== procwrap_load ========
754 */
procwrap_load(union trapped_args * args,void * pr_ctxt)755 u32 procwrap_load(union trapped_args *args, void *pr_ctxt)
756 {
757 s32 i, len;
758 int status = 0;
759 char *temp;
760 s32 count = args->args_proc_load.argc_index;
761 u8 **argv = NULL, **envp = NULL;
762 void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
763
764 if (count <= 0 || count > MAX_LOADARGS) {
765 status = -EINVAL;
766 goto func_cont;
767 }
768
769 argv = kmalloc(count * sizeof(u8 *), GFP_KERNEL);
770 if (!argv) {
771 status = -ENOMEM;
772 goto func_cont;
773 }
774
775 CP_FM_USR(argv, args->args_proc_load.user_args, status, count);
776 if (status) {
777 kfree(argv);
778 argv = NULL;
779 goto func_cont;
780 }
781
782 for (i = 0; i < count; i++) {
783 if (argv[i]) {
784 /* User space pointer to argument */
785 temp = (char *)argv[i];
786 /* len is increased by 1 to accommodate NULL */
787 len = strlen_user((char *)temp) + 1;
788 /* Kernel space pointer to argument */
789 argv[i] = kmalloc(len, GFP_KERNEL);
790 if (argv[i]) {
791 CP_FM_USR(argv[i], temp, status, len);
792 if (status) {
793 kfree(argv[i]);
794 argv[i] = NULL;
795 goto func_cont;
796 }
797 } else {
798 status = -ENOMEM;
799 goto func_cont;
800 }
801 }
802 }
803 /* TODO: validate this */
804 if (args->args_proc_load.user_envp) {
805 /* number of elements in the envp array including NULL */
806 count = 0;
807 do {
808 if (get_user(temp,
809 args->args_proc_load.user_envp + count)) {
810 status = -EFAULT;
811 goto func_cont;
812 }
813 count++;
814 } while (temp);
815 envp = kmalloc(count * sizeof(u8 *), GFP_KERNEL);
816 if (!envp) {
817 status = -ENOMEM;
818 goto func_cont;
819 }
820
821 CP_FM_USR(envp, args->args_proc_load.user_envp, status, count);
822 if (status) {
823 kfree(envp);
824 envp = NULL;
825 goto func_cont;
826 }
827 for (i = 0; envp[i]; i++) {
828 /* User space pointer to argument */
829 temp = (char *)envp[i];
830 /* len is increased by 1 to accommodate NULL */
831 len = strlen_user((char *)temp) + 1;
832 /* Kernel space pointer to argument */
833 envp[i] = kmalloc(len, GFP_KERNEL);
834 if (envp[i]) {
835 CP_FM_USR(envp[i], temp, status, len);
836 if (status) {
837 kfree(envp[i]);
838 envp[i] = NULL;
839 goto func_cont;
840 }
841 } else {
842 status = -ENOMEM;
843 goto func_cont;
844 }
845 }
846 }
847
848 if (!status) {
849 status = proc_load(hprocessor,
850 args->args_proc_load.argc_index,
851 (const char **)argv, (const char **)envp);
852 }
853 func_cont:
854 if (envp) {
855 i = 0;
856 while (envp[i])
857 kfree(envp[i++]);
858
859 kfree(envp);
860 }
861
862 if (argv) {
863 count = args->args_proc_load.argc_index;
864 for (i = 0; (i < count) && argv[i]; i++)
865 kfree(argv[i]);
866
867 kfree(argv);
868 }
869
870 return status;
871 }
872
873 /*
874 * ======== procwrap_map ========
875 */
procwrap_map(union trapped_args * args,void * pr_ctxt)876 u32 procwrap_map(union trapped_args *args, void *pr_ctxt)
877 {
878 int status;
879 void *map_addr;
880 void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
881
882 if (!args->args_proc_mapmem.size)
883 return -EINVAL;
884
885 status = proc_map(args->args_proc_mapmem.processor,
886 args->args_proc_mapmem.mpu_addr,
887 args->args_proc_mapmem.size,
888 args->args_proc_mapmem.req_addr, &map_addr,
889 args->args_proc_mapmem.map_attr, pr_ctxt);
890 if (!status) {
891 if (put_user(map_addr, args->args_proc_mapmem.map_addr)) {
892 status = -EINVAL;
893 proc_un_map(hprocessor, map_addr, pr_ctxt);
894 }
895
896 }
897 return status;
898 }
899
900 /*
901 * ======== procwrap_register_notify ========
902 */
procwrap_register_notify(union trapped_args * args,void * pr_ctxt)903 u32 procwrap_register_notify(union trapped_args *args, void *pr_ctxt)
904 {
905 int status;
906 struct dsp_notification notification;
907 void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
908
909 /* Initialize the notification data structure */
910 notification.name = NULL;
911 notification.handle = NULL;
912
913 status = proc_register_notify(hprocessor,
914 args->args_proc_register_notify.event_mask,
915 args->args_proc_register_notify.notify_type,
916 ¬ification);
917 CP_TO_USR(args->args_proc_register_notify.notification, ¬ification,
918 status, 1);
919 return status;
920 }
921
922 /*
923 * ======== procwrap_reserve_memory ========
924 */
procwrap_reserve_memory(union trapped_args * args,void * pr_ctxt)925 u32 procwrap_reserve_memory(union trapped_args *args, void *pr_ctxt)
926 {
927 int status;
928 void *prsv_addr;
929 void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
930
931 if ((args->args_proc_rsvmem.size <= 0) ||
932 (args->args_proc_rsvmem.size & (PG_SIZE4K - 1)) != 0)
933 return -EINVAL;
934
935 status = proc_reserve_memory(hprocessor,
936 args->args_proc_rsvmem.size, &prsv_addr,
937 pr_ctxt);
938 if (!status) {
939 if (put_user(prsv_addr, args->args_proc_rsvmem.rsv_addr)) {
940 status = -EINVAL;
941 proc_un_reserve_memory(args->args_proc_rsvmem.
942 processor, prsv_addr, pr_ctxt);
943 }
944 }
945 return status;
946 }
947
948 /*
949 * ======== procwrap_start ========
950 */
procwrap_start(union trapped_args * args,void * pr_ctxt)951 u32 procwrap_start(union trapped_args *args, void *pr_ctxt)
952 {
953 u32 ret;
954
955 ret = proc_start(((struct process_context *)pr_ctxt)->processor);
956 return ret;
957 }
958
959 /*
960 * ======== procwrap_un_map ========
961 */
procwrap_un_map(union trapped_args * args,void * pr_ctxt)962 u32 procwrap_un_map(union trapped_args *args, void *pr_ctxt)
963 {
964 int status;
965
966 status = proc_un_map(((struct process_context *)pr_ctxt)->processor,
967 args->args_proc_unmapmem.map_addr, pr_ctxt);
968 return status;
969 }
970
971 /*
972 * ======== procwrap_un_reserve_memory ========
973 */
procwrap_un_reserve_memory(union trapped_args * args,void * pr_ctxt)974 u32 procwrap_un_reserve_memory(union trapped_args *args, void *pr_ctxt)
975 {
976 int status;
977 void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
978
979 status = proc_un_reserve_memory(hprocessor,
980 args->args_proc_unrsvmem.rsv_addr,
981 pr_ctxt);
982 return status;
983 }
984
985 /*
986 * ======== procwrap_stop ========
987 */
procwrap_stop(union trapped_args * args,void * pr_ctxt)988 u32 procwrap_stop(union trapped_args *args, void *pr_ctxt)
989 {
990 u32 ret;
991
992 ret = proc_stop(((struct process_context *)pr_ctxt)->processor);
993
994 return ret;
995 }
996
997 /*
998 * ======== find_handle =========
999 */
find_node_handle(struct node_res_object ** noderes,void * pr_ctxt,void * hnode)1000 inline void find_node_handle(struct node_res_object **noderes,
1001 void *pr_ctxt, void *hnode)
1002 {
1003 rcu_read_lock();
1004 *noderes = idr_find(((struct process_context *)pr_ctxt)->node_id,
1005 (int)hnode - 1);
1006 rcu_read_unlock();
1007 return;
1008 }
1009
1010
1011 /*
1012 * ======== nodewrap_allocate ========
1013 */
nodewrap_allocate(union trapped_args * args,void * pr_ctxt)1014 u32 nodewrap_allocate(union trapped_args *args, void *pr_ctxt)
1015 {
1016 int status = 0;
1017 struct dsp_uuid node_uuid;
1018 u32 cb_data_size = 0;
1019 u32 __user *psize = (u32 __user *) args->args_node_allocate.args;
1020 u8 *pargs = NULL;
1021 struct dsp_nodeattrin proc_attr_in, *attr_in = NULL;
1022 struct node_res_object *node_res;
1023 int nodeid;
1024 void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
1025
1026 /* Optional argument */
1027 if (psize) {
1028 if (get_user(cb_data_size, psize))
1029 status = -EPERM;
1030
1031 cb_data_size += sizeof(u32);
1032 if (!status) {
1033 pargs = kmalloc(cb_data_size, GFP_KERNEL);
1034 if (pargs == NULL)
1035 status = -ENOMEM;
1036
1037 }
1038 CP_FM_USR(pargs, args->args_node_allocate.args, status,
1039 cb_data_size);
1040 }
1041 CP_FM_USR(&node_uuid, args->args_node_allocate.node_id_ptr, status, 1);
1042 if (status)
1043 goto func_cont;
1044 /* Optional argument */
1045 if (args->args_node_allocate.attr_in) {
1046 CP_FM_USR(&proc_attr_in, args->args_node_allocate.attr_in,
1047 status, 1);
1048 if (!status)
1049 attr_in = &proc_attr_in;
1050 else
1051 status = -ENOMEM;
1052
1053 }
1054 if (!status) {
1055 status = node_allocate(hprocessor,
1056 &node_uuid, (struct dsp_cbdata *)pargs,
1057 attr_in, &node_res, pr_ctxt);
1058 }
1059 if (!status) {
1060 nodeid = node_res->id + 1;
1061 CP_TO_USR(args->args_node_allocate.node, &nodeid,
1062 status, 1);
1063 if (status) {
1064 status = -EFAULT;
1065 node_delete(node_res, pr_ctxt);
1066 }
1067 }
1068 func_cont:
1069 kfree(pargs);
1070
1071 return status;
1072 }
1073
1074 /*
1075 * ======== nodewrap_alloc_msg_buf ========
1076 */
nodewrap_alloc_msg_buf(union trapped_args * args,void * pr_ctxt)1077 u32 nodewrap_alloc_msg_buf(union trapped_args *args, void *pr_ctxt)
1078 {
1079 int status = 0;
1080 struct dsp_bufferattr *pattr = NULL;
1081 struct dsp_bufferattr attr;
1082 u8 *pbuffer = NULL;
1083 struct node_res_object *node_res;
1084
1085 find_node_handle(&node_res, pr_ctxt,
1086 args->args_node_allocmsgbuf.node);
1087
1088 if (!node_res)
1089 return -EFAULT;
1090
1091 if (!args->args_node_allocmsgbuf.size)
1092 return -EINVAL;
1093
1094 if (args->args_node_allocmsgbuf.attr) { /* Optional argument */
1095 CP_FM_USR(&attr, args->args_node_allocmsgbuf.attr, status, 1);
1096 if (!status)
1097 pattr = &attr;
1098
1099 }
1100 /* argument */
1101 CP_FM_USR(&pbuffer, args->args_node_allocmsgbuf.buffer, status, 1);
1102 if (!status) {
1103 status = node_alloc_msg_buf(node_res->node,
1104 args->args_node_allocmsgbuf.size,
1105 pattr, &pbuffer);
1106 }
1107 CP_TO_USR(args->args_node_allocmsgbuf.buffer, &pbuffer, status, 1);
1108 return status;
1109 }
1110
1111 /*
1112 * ======== nodewrap_change_priority ========
1113 */
nodewrap_change_priority(union trapped_args * args,void * pr_ctxt)1114 u32 nodewrap_change_priority(union trapped_args *args, void *pr_ctxt)
1115 {
1116 u32 ret;
1117 struct node_res_object *node_res;
1118
1119 find_node_handle(&node_res, pr_ctxt,
1120 args->args_node_changepriority.node);
1121
1122 if (!node_res)
1123 return -EFAULT;
1124
1125 ret = node_change_priority(node_res->node,
1126 args->args_node_changepriority.prio);
1127
1128 return ret;
1129 }
1130
1131 /*
1132 * ======== nodewrap_connect ========
1133 */
nodewrap_connect(union trapped_args * args,void * pr_ctxt)1134 u32 nodewrap_connect(union trapped_args *args, void *pr_ctxt)
1135 {
1136 int status = 0;
1137 struct dsp_strmattr attrs;
1138 struct dsp_strmattr *pattrs = NULL;
1139 u32 cb_data_size;
1140 u32 __user *psize = (u32 __user *) args->args_node_connect.conn_param;
1141 u8 *pargs = NULL;
1142 struct node_res_object *node_res1, *node_res2;
1143 struct node_object *node1 = NULL, *node2 = NULL;
1144
1145 if ((int)args->args_node_connect.node != DSP_HGPPNODE) {
1146 find_node_handle(&node_res1, pr_ctxt,
1147 args->args_node_connect.node);
1148 if (node_res1)
1149 node1 = node_res1->node;
1150 } else {
1151 node1 = args->args_node_connect.node;
1152 }
1153
1154 if ((int)args->args_node_connect.other_node != DSP_HGPPNODE) {
1155 find_node_handle(&node_res2, pr_ctxt,
1156 args->args_node_connect.other_node);
1157 if (node_res2)
1158 node2 = node_res2->node;
1159 } else {
1160 node2 = args->args_node_connect.other_node;
1161 }
1162
1163 if (!node1 || !node2)
1164 return -EFAULT;
1165
1166 /* Optional argument */
1167 if (psize) {
1168 if (get_user(cb_data_size, psize))
1169 status = -EPERM;
1170
1171 cb_data_size += sizeof(u32);
1172 if (!status) {
1173 pargs = kmalloc(cb_data_size, GFP_KERNEL);
1174 if (pargs == NULL) {
1175 status = -ENOMEM;
1176 goto func_cont;
1177 }
1178
1179 }
1180 CP_FM_USR(pargs, args->args_node_connect.conn_param, status,
1181 cb_data_size);
1182 if (status)
1183 goto func_cont;
1184 }
1185 if (args->args_node_connect.attrs) { /* Optional argument */
1186 CP_FM_USR(&attrs, args->args_node_connect.attrs, status, 1);
1187 if (!status)
1188 pattrs = &attrs;
1189
1190 }
1191 if (!status) {
1192 status = node_connect(node1,
1193 args->args_node_connect.stream_id,
1194 node2,
1195 args->args_node_connect.other_stream,
1196 pattrs, (struct dsp_cbdata *)pargs);
1197 }
1198 func_cont:
1199 kfree(pargs);
1200
1201 return status;
1202 }
1203
1204 /*
1205 * ======== nodewrap_create ========
1206 */
nodewrap_create(union trapped_args * args,void * pr_ctxt)1207 u32 nodewrap_create(union trapped_args *args, void *pr_ctxt)
1208 {
1209 u32 ret;
1210 struct node_res_object *node_res;
1211
1212 find_node_handle(&node_res, pr_ctxt, args->args_node_create.node);
1213
1214 if (!node_res)
1215 return -EFAULT;
1216
1217 ret = node_create(node_res->node);
1218
1219 return ret;
1220 }
1221
1222 /*
1223 * ======== nodewrap_delete ========
1224 */
nodewrap_delete(union trapped_args * args,void * pr_ctxt)1225 u32 nodewrap_delete(union trapped_args *args, void *pr_ctxt)
1226 {
1227 u32 ret;
1228 struct node_res_object *node_res;
1229
1230 find_node_handle(&node_res, pr_ctxt, args->args_node_delete.node);
1231
1232 if (!node_res)
1233 return -EFAULT;
1234
1235 ret = node_delete(node_res, pr_ctxt);
1236
1237 return ret;
1238 }
1239
1240 /*
1241 * ======== nodewrap_free_msg_buf ========
1242 */
nodewrap_free_msg_buf(union trapped_args * args,void * pr_ctxt)1243 u32 nodewrap_free_msg_buf(union trapped_args *args, void *pr_ctxt)
1244 {
1245 int status = 0;
1246 struct dsp_bufferattr *pattr = NULL;
1247 struct dsp_bufferattr attr;
1248 struct node_res_object *node_res;
1249
1250 find_node_handle(&node_res, pr_ctxt, args->args_node_freemsgbuf.node);
1251
1252 if (!node_res)
1253 return -EFAULT;
1254
1255 if (args->args_node_freemsgbuf.attr) { /* Optional argument */
1256 CP_FM_USR(&attr, args->args_node_freemsgbuf.attr, status, 1);
1257 if (!status)
1258 pattr = &attr;
1259
1260 }
1261
1262 if (!args->args_node_freemsgbuf.buffer)
1263 return -EFAULT;
1264
1265 if (!status) {
1266 status = node_free_msg_buf(node_res->node,
1267 args->args_node_freemsgbuf.buffer,
1268 pattr);
1269 }
1270
1271 return status;
1272 }
1273
1274 /*
1275 * ======== nodewrap_get_attr ========
1276 */
nodewrap_get_attr(union trapped_args * args,void * pr_ctxt)1277 u32 nodewrap_get_attr(union trapped_args *args, void *pr_ctxt)
1278 {
1279 int status = 0;
1280 struct dsp_nodeattr attr;
1281 struct node_res_object *node_res;
1282
1283 find_node_handle(&node_res, pr_ctxt, args->args_node_getattr.node);
1284
1285 if (!node_res)
1286 return -EFAULT;
1287
1288 status = node_get_attr(node_res->node, &attr,
1289 args->args_node_getattr.attr_size);
1290 CP_TO_USR(args->args_node_getattr.attr, &attr, status, 1);
1291
1292 return status;
1293 }
1294
1295 /*
1296 * ======== nodewrap_get_message ========
1297 */
nodewrap_get_message(union trapped_args * args,void * pr_ctxt)1298 u32 nodewrap_get_message(union trapped_args *args, void *pr_ctxt)
1299 {
1300 int status;
1301 struct dsp_msg msg;
1302 struct node_res_object *node_res;
1303
1304 find_node_handle(&node_res, pr_ctxt, args->args_node_getmessage.node);
1305
1306 if (!node_res)
1307 return -EFAULT;
1308
1309 status = node_get_message(node_res->node, &msg,
1310 args->args_node_getmessage.timeout);
1311
1312 CP_TO_USR(args->args_node_getmessage.message, &msg, status, 1);
1313
1314 return status;
1315 }
1316
1317 /*
1318 * ======== nodewrap_pause ========
1319 */
nodewrap_pause(union trapped_args * args,void * pr_ctxt)1320 u32 nodewrap_pause(union trapped_args *args, void *pr_ctxt)
1321 {
1322 u32 ret;
1323 struct node_res_object *node_res;
1324
1325 find_node_handle(&node_res, pr_ctxt, args->args_node_pause.node);
1326
1327 if (!node_res)
1328 return -EFAULT;
1329
1330 ret = node_pause(node_res->node);
1331
1332 return ret;
1333 }
1334
1335 /*
1336 * ======== nodewrap_put_message ========
1337 */
nodewrap_put_message(union trapped_args * args,void * pr_ctxt)1338 u32 nodewrap_put_message(union trapped_args *args, void *pr_ctxt)
1339 {
1340 int status = 0;
1341 struct dsp_msg msg;
1342 struct node_res_object *node_res;
1343
1344 find_node_handle(&node_res, pr_ctxt, args->args_node_putmessage.node);
1345
1346 if (!node_res)
1347 return -EFAULT;
1348
1349 CP_FM_USR(&msg, args->args_node_putmessage.message, status, 1);
1350
1351 if (!status) {
1352 status =
1353 node_put_message(node_res->node, &msg,
1354 args->args_node_putmessage.timeout);
1355 }
1356
1357 return status;
1358 }
1359
1360 /*
1361 * ======== nodewrap_register_notify ========
1362 */
nodewrap_register_notify(union trapped_args * args,void * pr_ctxt)1363 u32 nodewrap_register_notify(union trapped_args *args, void *pr_ctxt)
1364 {
1365 int status = 0;
1366 struct dsp_notification notification;
1367 struct node_res_object *node_res;
1368
1369 find_node_handle(&node_res, pr_ctxt,
1370 args->args_node_registernotify.node);
1371
1372 if (!node_res)
1373 return -EFAULT;
1374
1375 /* Initialize the notification data structure */
1376 notification.name = NULL;
1377 notification.handle = NULL;
1378
1379 if (!args->args_proc_register_notify.event_mask)
1380 CP_FM_USR(¬ification,
1381 args->args_proc_register_notify.notification,
1382 status, 1);
1383
1384 status = node_register_notify(node_res->node,
1385 args->args_node_registernotify.event_mask,
1386 args->args_node_registernotify.
1387 notify_type, ¬ification);
1388 CP_TO_USR(args->args_node_registernotify.notification, ¬ification,
1389 status, 1);
1390 return status;
1391 }
1392
1393 /*
1394 * ======== nodewrap_run ========
1395 */
nodewrap_run(union trapped_args * args,void * pr_ctxt)1396 u32 nodewrap_run(union trapped_args *args, void *pr_ctxt)
1397 {
1398 u32 ret;
1399 struct node_res_object *node_res;
1400
1401 find_node_handle(&node_res, pr_ctxt, args->args_node_run.node);
1402
1403 if (!node_res)
1404 return -EFAULT;
1405
1406 ret = node_run(node_res->node);
1407
1408 return ret;
1409 }
1410
1411 /*
1412 * ======== nodewrap_terminate ========
1413 */
nodewrap_terminate(union trapped_args * args,void * pr_ctxt)1414 u32 nodewrap_terminate(union trapped_args *args, void *pr_ctxt)
1415 {
1416 int status;
1417 int tempstatus;
1418 struct node_res_object *node_res;
1419
1420 find_node_handle(&node_res, pr_ctxt, args->args_node_terminate.node);
1421
1422 if (!node_res)
1423 return -EFAULT;
1424
1425 status = node_terminate(node_res->node, &tempstatus);
1426
1427 CP_TO_USR(args->args_node_terminate.status, &tempstatus, status, 1);
1428
1429 return status;
1430 }
1431
1432 /*
1433 * ======== nodewrap_get_uuid_props ========
1434 */
nodewrap_get_uuid_props(union trapped_args * args,void * pr_ctxt)1435 u32 nodewrap_get_uuid_props(union trapped_args *args, void *pr_ctxt)
1436 {
1437 int status = 0;
1438 struct dsp_uuid node_uuid;
1439 struct dsp_ndbprops *pnode_props = NULL;
1440 void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
1441
1442 CP_FM_USR(&node_uuid, args->args_node_getuuidprops.node_id_ptr, status,
1443 1);
1444 if (status)
1445 goto func_cont;
1446 pnode_props = kmalloc(sizeof(struct dsp_ndbprops), GFP_KERNEL);
1447 if (pnode_props != NULL) {
1448 status =
1449 node_get_uuid_props(hprocessor, &node_uuid, pnode_props);
1450 CP_TO_USR(args->args_node_getuuidprops.node_props, pnode_props,
1451 status, 1);
1452 } else
1453 status = -ENOMEM;
1454 func_cont:
1455 kfree(pnode_props);
1456 return status;
1457 }
1458
1459 /*
1460 * ======== find_strm_handle =========
1461 */
find_strm_handle(struct strm_res_object ** strmres,void * pr_ctxt,void * hstream)1462 inline void find_strm_handle(struct strm_res_object **strmres,
1463 void *pr_ctxt, void *hstream)
1464 {
1465 rcu_read_lock();
1466 *strmres = idr_find(((struct process_context *)pr_ctxt)->stream_id,
1467 (int)hstream - 1);
1468 rcu_read_unlock();
1469 return;
1470 }
1471
1472 /*
1473 * ======== strmwrap_allocate_buffer ========
1474 */
strmwrap_allocate_buffer(union trapped_args * args,void * pr_ctxt)1475 u32 strmwrap_allocate_buffer(union trapped_args *args, void *pr_ctxt)
1476 {
1477 int status;
1478 u8 **ap_buffer = NULL;
1479 u32 num_bufs = args->args_strm_allocatebuffer.num_bufs;
1480 struct strm_res_object *strm_res;
1481
1482 find_strm_handle(&strm_res, pr_ctxt,
1483 args->args_strm_allocatebuffer.stream);
1484
1485 if (!strm_res)
1486 return -EFAULT;
1487
1488 if (num_bufs > MAX_BUFS)
1489 return -EINVAL;
1490
1491 ap_buffer = kmalloc((num_bufs * sizeof(u8 *)), GFP_KERNEL);
1492 if (ap_buffer == NULL)
1493 return -ENOMEM;
1494
1495 status = strm_allocate_buffer(strm_res,
1496 args->args_strm_allocatebuffer.size,
1497 ap_buffer, num_bufs, pr_ctxt);
1498 if (!status) {
1499 CP_TO_USR(args->args_strm_allocatebuffer.ap_buffer, ap_buffer,
1500 status, num_bufs);
1501 if (status) {
1502 status = -EFAULT;
1503 strm_free_buffer(strm_res,
1504 ap_buffer, num_bufs, pr_ctxt);
1505 }
1506 }
1507 kfree(ap_buffer);
1508
1509 return status;
1510 }
1511
1512 /*
1513 * ======== strmwrap_close ========
1514 */
strmwrap_close(union trapped_args * args,void * pr_ctxt)1515 u32 strmwrap_close(union trapped_args *args, void *pr_ctxt)
1516 {
1517 struct strm_res_object *strm_res;
1518
1519 find_strm_handle(&strm_res, pr_ctxt, args->args_strm_close.stream);
1520
1521 if (!strm_res)
1522 return -EFAULT;
1523
1524 return strm_close(strm_res, pr_ctxt);
1525 }
1526
1527 /*
1528 * ======== strmwrap_free_buffer ========
1529 */
strmwrap_free_buffer(union trapped_args * args,void * pr_ctxt)1530 u32 strmwrap_free_buffer(union trapped_args *args, void *pr_ctxt)
1531 {
1532 int status = 0;
1533 u8 **ap_buffer = NULL;
1534 u32 num_bufs = args->args_strm_freebuffer.num_bufs;
1535 struct strm_res_object *strm_res;
1536
1537 find_strm_handle(&strm_res, pr_ctxt,
1538 args->args_strm_freebuffer.stream);
1539
1540 if (!strm_res)
1541 return -EFAULT;
1542
1543 if (num_bufs > MAX_BUFS)
1544 return -EINVAL;
1545
1546 ap_buffer = kmalloc_array(num_bufs, sizeof(u8 *), GFP_KERNEL);
1547 if (ap_buffer == NULL)
1548 return -ENOMEM;
1549
1550 CP_FM_USR(ap_buffer, args->args_strm_freebuffer.ap_buffer, status,
1551 num_bufs);
1552
1553 if (!status)
1554 status = strm_free_buffer(strm_res,
1555 ap_buffer, num_bufs, pr_ctxt);
1556
1557 CP_TO_USR(args->args_strm_freebuffer.ap_buffer, ap_buffer, status,
1558 num_bufs);
1559 kfree(ap_buffer);
1560
1561 return status;
1562 }
1563
1564 /*
1565 * ======== strmwrap_get_event_handle ========
1566 */
strmwrap_get_event_handle(union trapped_args * args,void * pr_ctxt)1567 u32 __deprecated strmwrap_get_event_handle(union trapped_args * args,
1568 void *pr_ctxt)
1569 {
1570 pr_err("%s: deprecated dspbridge ioctl\n", __func__);
1571 return -ENOSYS;
1572 }
1573
1574 /*
1575 * ======== strmwrap_get_info ========
1576 */
strmwrap_get_info(union trapped_args * args,void * pr_ctxt)1577 u32 strmwrap_get_info(union trapped_args *args, void *pr_ctxt)
1578 {
1579 int status = 0;
1580 struct stream_info strm_info;
1581 struct dsp_streaminfo user;
1582 struct dsp_streaminfo *temp;
1583 struct strm_res_object *strm_res;
1584
1585 find_strm_handle(&strm_res, pr_ctxt,
1586 args->args_strm_getinfo.stream);
1587
1588 if (!strm_res)
1589 return -EFAULT;
1590
1591 CP_FM_USR(&strm_info, args->args_strm_getinfo.stream_info, status, 1);
1592 temp = strm_info.user_strm;
1593
1594 strm_info.user_strm = &user;
1595
1596 if (!status) {
1597 status = strm_get_info(strm_res->stream,
1598 &strm_info,
1599 args->args_strm_getinfo.
1600 stream_info_size);
1601 }
1602 CP_TO_USR(temp, strm_info.user_strm, status, 1);
1603 strm_info.user_strm = temp;
1604 CP_TO_USR(args->args_strm_getinfo.stream_info, &strm_info, status, 1);
1605 return status;
1606 }
1607
1608 /*
1609 * ======== strmwrap_idle ========
1610 */
strmwrap_idle(union trapped_args * args,void * pr_ctxt)1611 u32 strmwrap_idle(union trapped_args *args, void *pr_ctxt)
1612 {
1613 u32 ret;
1614 struct strm_res_object *strm_res;
1615
1616 find_strm_handle(&strm_res, pr_ctxt, args->args_strm_idle.stream);
1617
1618 if (!strm_res)
1619 return -EFAULT;
1620
1621 ret = strm_idle(strm_res->stream, args->args_strm_idle.flush_flag);
1622
1623 return ret;
1624 }
1625
1626 /*
1627 * ======== strmwrap_issue ========
1628 */
strmwrap_issue(union trapped_args * args,void * pr_ctxt)1629 u32 strmwrap_issue(union trapped_args *args, void *pr_ctxt)
1630 {
1631 int status = 0;
1632 struct strm_res_object *strm_res;
1633
1634 find_strm_handle(&strm_res, pr_ctxt, args->args_strm_issue.stream);
1635
1636 if (!strm_res)
1637 return -EFAULT;
1638
1639 if (!args->args_strm_issue.buffer)
1640 return -EFAULT;
1641
1642 /* No need of doing CP_FM_USR for the user buffer (pbuffer)
1643 as this is done in Bridge internal function bridge_chnl_add_io_req
1644 in chnl_sm.c */
1645 status = strm_issue(strm_res->stream,
1646 args->args_strm_issue.buffer,
1647 args->args_strm_issue.bytes,
1648 args->args_strm_issue.buf_size,
1649 args->args_strm_issue.arg);
1650
1651 return status;
1652 }
1653
1654 /*
1655 * ======== strmwrap_open ========
1656 */
strmwrap_open(union trapped_args * args,void * pr_ctxt)1657 u32 strmwrap_open(union trapped_args *args, void *pr_ctxt)
1658 {
1659 int status = 0;
1660 struct strm_attr attr;
1661 struct strm_res_object *strm_res_obj;
1662 struct dsp_streamattrin strm_attr_in;
1663 struct node_res_object *node_res;
1664 int strmid;
1665
1666 find_node_handle(&node_res, pr_ctxt, args->args_strm_open.node);
1667
1668 if (!node_res)
1669 return -EFAULT;
1670
1671 CP_FM_USR(&attr, args->args_strm_open.attr_in, status, 1);
1672
1673 if (attr.stream_attr_in != NULL) { /* Optional argument */
1674 CP_FM_USR(&strm_attr_in, attr.stream_attr_in, status, 1);
1675 if (!status) {
1676 attr.stream_attr_in = &strm_attr_in;
1677 if (attr.stream_attr_in->strm_mode == STRMMODE_LDMA)
1678 return -ENOSYS;
1679 }
1680
1681 }
1682 status = strm_open(node_res->node,
1683 args->args_strm_open.direction,
1684 args->args_strm_open.index, &attr, &strm_res_obj,
1685 pr_ctxt);
1686 if (!status) {
1687 strmid = strm_res_obj->id + 1;
1688 CP_TO_USR(args->args_strm_open.stream, &strmid, status, 1);
1689 }
1690 return status;
1691 }
1692
1693 /*
1694 * ======== strmwrap_reclaim ========
1695 */
strmwrap_reclaim(union trapped_args * args,void * pr_ctxt)1696 u32 strmwrap_reclaim(union trapped_args *args, void *pr_ctxt)
1697 {
1698 int status = 0;
1699 u8 *buf_ptr;
1700 u32 ul_bytes;
1701 u32 dw_arg;
1702 u32 ul_buf_size;
1703 struct strm_res_object *strm_res;
1704
1705 find_strm_handle(&strm_res, pr_ctxt, args->args_strm_reclaim.stream);
1706
1707 if (!strm_res)
1708 return -EFAULT;
1709
1710 status = strm_reclaim(strm_res->stream, &buf_ptr,
1711 &ul_bytes, &ul_buf_size, &dw_arg);
1712 CP_TO_USR(args->args_strm_reclaim.buf_ptr, &buf_ptr, status, 1);
1713 CP_TO_USR(args->args_strm_reclaim.bytes, &ul_bytes, status, 1);
1714 CP_TO_USR(args->args_strm_reclaim.arg, &dw_arg, status, 1);
1715
1716 if (args->args_strm_reclaim.buf_size_ptr != NULL) {
1717 CP_TO_USR(args->args_strm_reclaim.buf_size_ptr, &ul_buf_size,
1718 status, 1);
1719 }
1720
1721 return status;
1722 }
1723
1724 /*
1725 * ======== strmwrap_register_notify ========
1726 */
strmwrap_register_notify(union trapped_args * args,void * pr_ctxt)1727 u32 strmwrap_register_notify(union trapped_args *args, void *pr_ctxt)
1728 {
1729 int status = 0;
1730 struct dsp_notification notification;
1731 struct strm_res_object *strm_res;
1732
1733 find_strm_handle(&strm_res, pr_ctxt,
1734 args->args_strm_registernotify.stream);
1735
1736 if (!strm_res)
1737 return -EFAULT;
1738
1739 /* Initialize the notification data structure */
1740 notification.name = NULL;
1741 notification.handle = NULL;
1742
1743 status = strm_register_notify(strm_res->stream,
1744 args->args_strm_registernotify.event_mask,
1745 args->args_strm_registernotify.
1746 notify_type, ¬ification);
1747 CP_TO_USR(args->args_strm_registernotify.notification, ¬ification,
1748 status, 1);
1749
1750 return status;
1751 }
1752
1753 /*
1754 * ======== strmwrap_select ========
1755 */
strmwrap_select(union trapped_args * args,void * pr_ctxt)1756 u32 strmwrap_select(union trapped_args *args, void *pr_ctxt)
1757 {
1758 u32 mask;
1759 struct strm_object *strm_tab[MAX_STREAMS];
1760 int status = 0;
1761 struct strm_res_object *strm_res;
1762 int *ids[MAX_STREAMS];
1763 int i;
1764
1765 if (args->args_strm_select.strm_num > MAX_STREAMS)
1766 return -EINVAL;
1767
1768 CP_FM_USR(ids, args->args_strm_select.stream_tab, status,
1769 args->args_strm_select.strm_num);
1770
1771 if (status)
1772 return status;
1773
1774 for (i = 0; i < args->args_strm_select.strm_num; i++) {
1775 find_strm_handle(&strm_res, pr_ctxt, ids[i]);
1776
1777 if (!strm_res)
1778 return -EFAULT;
1779
1780 strm_tab[i] = strm_res->stream;
1781 }
1782
1783 if (!status) {
1784 status = strm_select(strm_tab, args->args_strm_select.strm_num,
1785 &mask, args->args_strm_select.timeout);
1786 }
1787 CP_TO_USR(args->args_strm_select.mask, &mask, status, 1);
1788 return status;
1789 }
1790
1791 /* CMM */
1792
1793 /*
1794 * ======== cmmwrap_calloc_buf ========
1795 */
cmmwrap_calloc_buf(union trapped_args * args,void * pr_ctxt)1796 u32 __deprecated cmmwrap_calloc_buf(union trapped_args * args, void *pr_ctxt)
1797 {
1798 /* This operation is done in kernel */
1799 pr_err("%s: deprecated dspbridge ioctl\n", __func__);
1800 return -ENOSYS;
1801 }
1802
1803 /*
1804 * ======== cmmwrap_free_buf ========
1805 */
cmmwrap_free_buf(union trapped_args * args,void * pr_ctxt)1806 u32 __deprecated cmmwrap_free_buf(union trapped_args * args, void *pr_ctxt)
1807 {
1808 /* This operation is done in kernel */
1809 pr_err("%s: deprecated dspbridge ioctl\n", __func__);
1810 return -ENOSYS;
1811 }
1812
1813 /*
1814 * ======== cmmwrap_get_handle ========
1815 */
cmmwrap_get_handle(union trapped_args * args,void * pr_ctxt)1816 u32 cmmwrap_get_handle(union trapped_args *args, void *pr_ctxt)
1817 {
1818 int status = 0;
1819 struct cmm_object *hcmm_mgr;
1820 void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
1821
1822 status = cmm_get_handle(hprocessor, &hcmm_mgr);
1823
1824 CP_TO_USR(args->args_cmm_gethandle.cmm_mgr, &hcmm_mgr, status, 1);
1825
1826 return status;
1827 }
1828
1829 /*
1830 * ======== cmmwrap_get_info ========
1831 */
cmmwrap_get_info(union trapped_args * args,void * pr_ctxt)1832 u32 cmmwrap_get_info(union trapped_args *args, void *pr_ctxt)
1833 {
1834 int status = 0;
1835 struct cmm_info cmm_info_obj;
1836
1837 status = cmm_get_info(args->args_cmm_getinfo.cmm_mgr, &cmm_info_obj);
1838
1839 CP_TO_USR(args->args_cmm_getinfo.cmm_info_obj, &cmm_info_obj, status,
1840 1);
1841
1842 return status;
1843 }
1844