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