1 /*
2  * strm.c
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * DSP/BIOS Bridge Stream Manager.
7  *
8  * Copyright (C) 2005-2006 Texas Instruments, Inc.
9  *
10  * This package is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17  */
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/sync.h>
32 
33 /*  ----------------------------------- Bridge Driver */
34 #include <dspbridge/dspdefs.h>
35 
36 /*  ----------------------------------- Resource Manager */
37 #include <dspbridge/nodepriv.h>
38 
39 /*  ----------------------------------- Others */
40 #include <dspbridge/cmm.h>
41 
42 /*  ----------------------------------- This */
43 #include <dspbridge/strm.h>
44 
45 #include <dspbridge/resourcecleanup.h>
46 
47 /*  ----------------------------------- Defines, Data Structures, Typedefs */
48 #define DEFAULTTIMEOUT      10000
49 #define DEFAULTNUMBUFS      2
50 
51 /*
52  *  ======== strm_mgr ========
53  *  The strm_mgr contains device information needed to open the underlying
54  *  channels of a stream.
55  */
56 struct strm_mgr {
57 	struct dev_object *dev_obj;	/* Device for this processor */
58 	struct chnl_mgr *chnl_mgr;	/* Channel manager */
59 	/* Function interface to Bridge driver */
60 	struct bridge_drv_interface *intf_fxns;
61 };
62 
63 /*
64  *  ======== strm_object ========
65  *  This object is allocated in strm_open().
66  */
67 struct strm_object {
68 	struct strm_mgr *strm_mgr_obj;
69 	struct chnl_object *chnl_obj;
70 	u32 dir;		/* DSP_TONODE or DSP_FROMNODE */
71 	u32 timeout;
72 	u32 num_bufs;		/* Max # of bufs allowed in stream */
73 	u32 bufs_in_strm;	/* Current # of bufs in stream */
74 	u32 bytes;		/* bytes transferred since idled */
75 	/* STREAM_IDLE, STREAM_READY, ... */
76 	enum dsp_streamstate strm_state;
77 	void *user_event;	/* Saved for strm_get_info() */
78 	enum dsp_strmmode strm_mode;	/* STRMMODE_[PROCCOPY][ZEROCOPY]... */
79 	u32 dma_chnl_id;	/* DMA chnl id */
80 	u32 dma_priority;	/* DMA priority:DMAPRI_[LOW][HIGH] */
81 	u32 segment_id;		/* >0 is SM segment.=0 is local heap */
82 	u32 buf_alignment;	/* Alignment for stream bufs */
83 	/* Stream's SM address translator */
84 	struct cmm_xlatorobject *xlator;
85 };
86 
87 /*  ----------------------------------- Globals */
88 static u32 refs;		/* module reference count */
89 
90 /*  ----------------------------------- Function Prototypes */
91 static int delete_strm(struct strm_object *stream_obj);
92 
93 /*
94  *  ======== strm_allocate_buffer ========
95  *  Purpose:
96  *      Allocates buffers for a stream.
97  */
strm_allocate_buffer(struct strm_res_object * strmres,u32 usize,u8 ** ap_buffer,u32 num_bufs,struct process_context * pr_ctxt)98 int strm_allocate_buffer(struct strm_res_object *strmres, u32 usize,
99 				u8 **ap_buffer, u32 num_bufs,
100 				struct process_context *pr_ctxt)
101 {
102 	int status = 0;
103 	u32 alloc_cnt = 0;
104 	u32 i;
105 	struct strm_object *stream_obj = strmres->stream;
106 
107 	DBC_REQUIRE(refs > 0);
108 	DBC_REQUIRE(ap_buffer != NULL);
109 
110 	if (stream_obj) {
111 		/*
112 		 * Allocate from segment specified at time of stream open.
113 		 */
114 		if (usize == 0)
115 			status = -EINVAL;
116 
117 	} else {
118 		status = -EFAULT;
119 	}
120 
121 	if (status)
122 		goto func_end;
123 
124 	for (i = 0; i < num_bufs; i++) {
125 		DBC_ASSERT(stream_obj->xlator != NULL);
126 		(void)cmm_xlator_alloc_buf(stream_obj->xlator, &ap_buffer[i],
127 					   usize);
128 		if (ap_buffer[i] == NULL) {
129 			status = -ENOMEM;
130 			alloc_cnt = i;
131 			break;
132 		}
133 	}
134 	if (status)
135 		strm_free_buffer(strmres, ap_buffer, alloc_cnt, pr_ctxt);
136 
137 	if (status)
138 		goto func_end;
139 
140 	drv_proc_update_strm_res(num_bufs, strmres);
141 
142 func_end:
143 	return status;
144 }
145 
146 /*
147  *  ======== strm_close ========
148  *  Purpose:
149  *      Close a stream opened with strm_open().
150  */
strm_close(struct strm_res_object * strmres,struct process_context * pr_ctxt)151 int strm_close(struct strm_res_object *strmres,
152 		      struct process_context *pr_ctxt)
153 {
154 	struct bridge_drv_interface *intf_fxns;
155 	struct chnl_info chnl_info_obj;
156 	int status = 0;
157 	struct strm_object *stream_obj = strmres->stream;
158 
159 	DBC_REQUIRE(refs > 0);
160 
161 	if (!stream_obj) {
162 		status = -EFAULT;
163 	} else {
164 		/* Have all buffers been reclaimed? If not, return
165 		 * -EPIPE */
166 		intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
167 		status =
168 		    (*intf_fxns->chnl_get_info) (stream_obj->chnl_obj,
169 						     &chnl_info_obj);
170 		DBC_ASSERT(!status);
171 
172 		if (chnl_info_obj.cio_cs > 0 || chnl_info_obj.cio_reqs > 0)
173 			status = -EPIPE;
174 		else
175 			status = delete_strm(stream_obj);
176 	}
177 
178 	if (status)
179 		goto func_end;
180 
181 	idr_remove(pr_ctxt->stream_id, strmres->id);
182 func_end:
183 	DBC_ENSURE(status == 0 || status == -EFAULT ||
184 		   status == -EPIPE || status == -EPERM);
185 
186 	dev_dbg(bridge, "%s: stream_obj: %p, status 0x%x\n", __func__,
187 		stream_obj, status);
188 	return status;
189 }
190 
191 /*
192  *  ======== strm_create ========
193  *  Purpose:
194  *      Create a STRM manager object.
195  */
strm_create(struct strm_mgr ** strm_man,struct dev_object * dev_obj)196 int strm_create(struct strm_mgr **strm_man,
197 		       struct dev_object *dev_obj)
198 {
199 	struct strm_mgr *strm_mgr_obj;
200 	int status = 0;
201 
202 	DBC_REQUIRE(refs > 0);
203 	DBC_REQUIRE(strm_man != NULL);
204 	DBC_REQUIRE(dev_obj != NULL);
205 
206 	*strm_man = NULL;
207 	/* Allocate STRM manager object */
208 	strm_mgr_obj = kzalloc(sizeof(struct strm_mgr), GFP_KERNEL);
209 	if (strm_mgr_obj == NULL)
210 		status = -ENOMEM;
211 	else
212 		strm_mgr_obj->dev_obj = dev_obj;
213 
214 	/* Get Channel manager and Bridge function interface */
215 	if (!status) {
216 		status = dev_get_chnl_mgr(dev_obj, &(strm_mgr_obj->chnl_mgr));
217 		if (!status) {
218 			(void)dev_get_intf_fxns(dev_obj,
219 						&(strm_mgr_obj->intf_fxns));
220 			DBC_ASSERT(strm_mgr_obj->intf_fxns != NULL);
221 		}
222 	}
223 
224 	if (!status)
225 		*strm_man = strm_mgr_obj;
226 	else
227 		kfree(strm_mgr_obj);
228 
229 	DBC_ENSURE((!status && *strm_man) || (status && *strm_man == NULL));
230 
231 	return status;
232 }
233 
234 /*
235  *  ======== strm_delete ========
236  *  Purpose:
237  *      Delete the STRM Manager Object.
238  */
strm_delete(struct strm_mgr * strm_mgr_obj)239 void strm_delete(struct strm_mgr *strm_mgr_obj)
240 {
241 	DBC_REQUIRE(refs > 0);
242 	DBC_REQUIRE(strm_mgr_obj);
243 
244 	kfree(strm_mgr_obj);
245 }
246 
247 /*
248  *  ======== strm_exit ========
249  *  Purpose:
250  *      Discontinue usage of STRM module.
251  */
strm_exit(void)252 void strm_exit(void)
253 {
254 	DBC_REQUIRE(refs > 0);
255 
256 	refs--;
257 
258 	DBC_ENSURE(refs >= 0);
259 }
260 
261 /*
262  *  ======== strm_free_buffer ========
263  *  Purpose:
264  *      Frees the buffers allocated for a stream.
265  */
strm_free_buffer(struct strm_res_object * strmres,u8 ** ap_buffer,u32 num_bufs,struct process_context * pr_ctxt)266 int strm_free_buffer(struct strm_res_object *strmres, u8 ** ap_buffer,
267 			    u32 num_bufs, struct process_context *pr_ctxt)
268 {
269 	int status = 0;
270 	u32 i = 0;
271 	struct strm_object *stream_obj = strmres->stream;
272 
273 	DBC_REQUIRE(refs > 0);
274 	DBC_REQUIRE(ap_buffer != NULL);
275 
276 	if (!stream_obj)
277 		status = -EFAULT;
278 
279 	if (!status) {
280 		for (i = 0; i < num_bufs; i++) {
281 			DBC_ASSERT(stream_obj->xlator != NULL);
282 			status =
283 			    cmm_xlator_free_buf(stream_obj->xlator,
284 						ap_buffer[i]);
285 			if (status)
286 				break;
287 			ap_buffer[i] = NULL;
288 		}
289 	}
290 	drv_proc_update_strm_res(num_bufs - i, strmres);
291 
292 	return status;
293 }
294 
295 /*
296  *  ======== strm_get_info ========
297  *  Purpose:
298  *      Retrieves information about a stream.
299  */
strm_get_info(struct strm_object * stream_obj,struct stream_info * stream_info,u32 stream_info_size)300 int strm_get_info(struct strm_object *stream_obj,
301 			 struct stream_info *stream_info,
302 			 u32 stream_info_size)
303 {
304 	struct bridge_drv_interface *intf_fxns;
305 	struct chnl_info chnl_info_obj;
306 	int status = 0;
307 	void *virt_base = NULL;	/* NULL if no SM used */
308 
309 	DBC_REQUIRE(refs > 0);
310 	DBC_REQUIRE(stream_info != NULL);
311 	DBC_REQUIRE(stream_info_size >= sizeof(struct stream_info));
312 
313 	if (!stream_obj) {
314 		status = -EFAULT;
315 	} else {
316 		if (stream_info_size < sizeof(struct stream_info)) {
317 			/* size of users info */
318 			status = -EINVAL;
319 		}
320 	}
321 	if (status)
322 		goto func_end;
323 
324 	intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
325 	status =
326 	    (*intf_fxns->chnl_get_info) (stream_obj->chnl_obj,
327 						  &chnl_info_obj);
328 	if (status)
329 		goto func_end;
330 
331 	if (stream_obj->xlator) {
332 		/* We have a translator */
333 		DBC_ASSERT(stream_obj->segment_id > 0);
334 		cmm_xlator_info(stream_obj->xlator, (u8 **) &virt_base, 0,
335 				stream_obj->segment_id, false);
336 	}
337 	stream_info->segment_id = stream_obj->segment_id;
338 	stream_info->strm_mode = stream_obj->strm_mode;
339 	stream_info->virt_base = virt_base;
340 	stream_info->user_strm->number_bufs_allowed = stream_obj->num_bufs;
341 	stream_info->user_strm->number_bufs_in_stream = chnl_info_obj.cio_cs +
342 	    chnl_info_obj.cio_reqs;
343 	/* # of bytes transferred since last call to DSPStream_Idle() */
344 	stream_info->user_strm->number_bytes = chnl_info_obj.bytes_tx;
345 	stream_info->user_strm->sync_object_handle = chnl_info_obj.event_obj;
346 	/* Determine stream state based on channel state and info */
347 	if (chnl_info_obj.state & CHNL_STATEEOS) {
348 		stream_info->user_strm->ss_stream_state = STREAM_DONE;
349 	} else {
350 		if (chnl_info_obj.cio_cs > 0)
351 			stream_info->user_strm->ss_stream_state = STREAM_READY;
352 		else if (chnl_info_obj.cio_reqs > 0)
353 			stream_info->user_strm->ss_stream_state =
354 			    STREAM_PENDING;
355 		else
356 			stream_info->user_strm->ss_stream_state = STREAM_IDLE;
357 
358 	}
359 func_end:
360 	return status;
361 }
362 
363 /*
364  *  ======== strm_idle ========
365  *  Purpose:
366  *      Idles a particular stream.
367  */
strm_idle(struct strm_object * stream_obj,bool flush_data)368 int strm_idle(struct strm_object *stream_obj, bool flush_data)
369 {
370 	struct bridge_drv_interface *intf_fxns;
371 	int status = 0;
372 
373 	DBC_REQUIRE(refs > 0);
374 
375 	if (!stream_obj) {
376 		status = -EFAULT;
377 	} else {
378 		intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
379 
380 		status = (*intf_fxns->chnl_idle) (stream_obj->chnl_obj,
381 						      stream_obj->timeout,
382 						      flush_data);
383 	}
384 
385 	dev_dbg(bridge, "%s: stream_obj: %p flush_data: 0x%x status: 0x%x\n",
386 		__func__, stream_obj, flush_data, status);
387 	return status;
388 }
389 
390 /*
391  *  ======== strm_init ========
392  *  Purpose:
393  *      Initialize the STRM module.
394  */
strm_init(void)395 bool strm_init(void)
396 {
397 	bool ret = true;
398 
399 	DBC_REQUIRE(refs >= 0);
400 
401 	if (ret)
402 		refs++;
403 
404 	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
405 
406 	return ret;
407 }
408 
409 /*
410  *  ======== strm_issue ========
411  *  Purpose:
412  *      Issues a buffer on a stream
413  */
strm_issue(struct strm_object * stream_obj,u8 * pbuf,u32 ul_bytes,u32 ul_buf_size,u32 dw_arg)414 int strm_issue(struct strm_object *stream_obj, u8 *pbuf, u32 ul_bytes,
415 		      u32 ul_buf_size, u32 dw_arg)
416 {
417 	struct bridge_drv_interface *intf_fxns;
418 	int status = 0;
419 	void *tmp_buf = NULL;
420 
421 	DBC_REQUIRE(refs > 0);
422 	DBC_REQUIRE(pbuf != NULL);
423 
424 	if (!stream_obj) {
425 		status = -EFAULT;
426 	} else {
427 		intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
428 
429 		if (stream_obj->segment_id != 0) {
430 			tmp_buf = cmm_xlator_translate(stream_obj->xlator,
431 						       (void *)pbuf,
432 						       CMM_VA2DSPPA);
433 			if (tmp_buf == NULL)
434 				status = -ESRCH;
435 
436 		}
437 		if (!status) {
438 			status = (*intf_fxns->chnl_add_io_req)
439 			    (stream_obj->chnl_obj, pbuf, ul_bytes, ul_buf_size,
440 			     (u32) tmp_buf, dw_arg);
441 		}
442 		if (status == -EIO)
443 			status = -ENOSR;
444 	}
445 
446 	dev_dbg(bridge, "%s: stream_obj: %p pbuf: %p ul_bytes: 0x%x dw_arg:"
447 		" 0x%x status: 0x%x\n", __func__, stream_obj, pbuf,
448 		ul_bytes, dw_arg, status);
449 	return status;
450 }
451 
452 /*
453  *  ======== strm_open ========
454  *  Purpose:
455  *      Open a stream for sending/receiving data buffers to/from a task or
456  *      XDAIS socket node on the DSP.
457  */
strm_open(struct node_object * hnode,u32 dir,u32 index,struct strm_attr * pattr,struct strm_res_object ** strmres,struct process_context * pr_ctxt)458 int strm_open(struct node_object *hnode, u32 dir, u32 index,
459 		     struct strm_attr *pattr,
460 		     struct strm_res_object **strmres,
461 		     struct process_context *pr_ctxt)
462 {
463 	struct strm_mgr *strm_mgr_obj;
464 	struct bridge_drv_interface *intf_fxns;
465 	u32 ul_chnl_id;
466 	struct strm_object *strm_obj = NULL;
467 	s8 chnl_mode;
468 	struct chnl_attr chnl_attr_obj;
469 	int status = 0;
470 	struct cmm_object *hcmm_mgr = NULL;	/* Shared memory manager hndl */
471 
472 	void *stream_res;
473 
474 	DBC_REQUIRE(refs > 0);
475 	DBC_REQUIRE(strmres != NULL);
476 	DBC_REQUIRE(pattr != NULL);
477 	*strmres = NULL;
478 	if (dir != DSP_TONODE && dir != DSP_FROMNODE) {
479 		status = -EPERM;
480 	} else {
481 		/* Get the channel id from the node (set in node_connect()) */
482 		status = node_get_channel_id(hnode, dir, index, &ul_chnl_id);
483 	}
484 	if (!status)
485 		status = node_get_strm_mgr(hnode, &strm_mgr_obj);
486 
487 	if (!status) {
488 		strm_obj = kzalloc(sizeof(struct strm_object), GFP_KERNEL);
489 		if (strm_obj == NULL) {
490 			status = -ENOMEM;
491 		} else {
492 			strm_obj->strm_mgr_obj = strm_mgr_obj;
493 			strm_obj->dir = dir;
494 			strm_obj->strm_state = STREAM_IDLE;
495 			strm_obj->user_event = pattr->user_event;
496 			if (pattr->stream_attr_in != NULL) {
497 				strm_obj->timeout =
498 				    pattr->stream_attr_in->timeout;
499 				strm_obj->num_bufs =
500 				    pattr->stream_attr_in->num_bufs;
501 				strm_obj->strm_mode =
502 				    pattr->stream_attr_in->strm_mode;
503 				strm_obj->segment_id =
504 				    pattr->stream_attr_in->segment_id;
505 				strm_obj->buf_alignment =
506 				    pattr->stream_attr_in->buf_alignment;
507 				strm_obj->dma_chnl_id =
508 				    pattr->stream_attr_in->dma_chnl_id;
509 				strm_obj->dma_priority =
510 				    pattr->stream_attr_in->dma_priority;
511 				chnl_attr_obj.uio_reqs =
512 				    pattr->stream_attr_in->num_bufs;
513 			} else {
514 				strm_obj->timeout = DEFAULTTIMEOUT;
515 				strm_obj->num_bufs = DEFAULTNUMBUFS;
516 				strm_obj->strm_mode = STRMMODE_PROCCOPY;
517 				strm_obj->segment_id = 0;	/* local mem */
518 				strm_obj->buf_alignment = 0;
519 				strm_obj->dma_chnl_id = 0;
520 				strm_obj->dma_priority = 0;
521 				chnl_attr_obj.uio_reqs = DEFAULTNUMBUFS;
522 			}
523 			chnl_attr_obj.reserved1 = NULL;
524 			/* DMA chnl flush timeout */
525 			chnl_attr_obj.reserved2 = strm_obj->timeout;
526 			chnl_attr_obj.event_obj = NULL;
527 			if (pattr->user_event != NULL)
528 				chnl_attr_obj.event_obj = pattr->user_event;
529 
530 		}
531 	}
532 	if (status)
533 		goto func_cont;
534 
535 	if ((pattr->virt_base == NULL) || !(pattr->virt_size > 0))
536 		goto func_cont;
537 
538 	/* No System DMA */
539 	DBC_ASSERT(strm_obj->strm_mode != STRMMODE_LDMA);
540 	/* Get the shared mem mgr for this streams dev object */
541 	status = dev_get_cmm_mgr(strm_mgr_obj->dev_obj, &hcmm_mgr);
542 	if (!status) {
543 		/*Allocate a SM addr translator for this strm. */
544 		status = cmm_xlator_create(&strm_obj->xlator, hcmm_mgr, NULL);
545 		if (!status) {
546 			DBC_ASSERT(strm_obj->segment_id > 0);
547 			/*  Set translators Virt Addr attributes */
548 			status = cmm_xlator_info(strm_obj->xlator,
549 						 (u8 **) &pattr->virt_base,
550 						 pattr->virt_size,
551 						 strm_obj->segment_id, true);
552 		}
553 	}
554 func_cont:
555 	if (!status) {
556 		/* Open channel */
557 		chnl_mode = (dir == DSP_TONODE) ?
558 		    CHNL_MODETODSP : CHNL_MODEFROMDSP;
559 		intf_fxns = strm_mgr_obj->intf_fxns;
560 		status = (*intf_fxns->chnl_open) (&(strm_obj->chnl_obj),
561 						      strm_mgr_obj->chnl_mgr,
562 						      chnl_mode, ul_chnl_id,
563 						      &chnl_attr_obj);
564 		if (status) {
565 			/*
566 			 * over-ride non-returnable status codes so we return
567 			 * something documented
568 			 */
569 			if (status != -ENOMEM && status !=
570 			    -EINVAL && status != -EPERM) {
571 				/*
572 				 * We got a status that's not return-able.
573 				 * Assert that we got something we were
574 				 * expecting (-EFAULT isn't acceptable,
575 				 * strm_mgr_obj->chnl_mgr better be valid or we
576 				 * assert here), and then return -EPERM.
577 				 */
578 				DBC_ASSERT(status == -ENOSR ||
579 					   status == -ECHRNG ||
580 					   status == -EALREADY ||
581 					   status == -EIO);
582 				status = -EPERM;
583 			}
584 		}
585 	}
586 	if (!status) {
587 		status = drv_proc_insert_strm_res_element(strm_obj,
588 							&stream_res, pr_ctxt);
589 		if (status)
590 			delete_strm(strm_obj);
591 		else
592 			*strmres = (struct strm_res_object *)stream_res;
593 	} else {
594 		(void)delete_strm(strm_obj);
595 	}
596 
597 	/* ensure we return a documented error code */
598 	DBC_ENSURE((!status && strm_obj) ||
599 		   (*strmres == NULL && (status == -EFAULT ||
600 					status == -EPERM
601 					|| status == -EINVAL)));
602 
603 	dev_dbg(bridge, "%s: hnode: %p dir: 0x%x index: 0x%x pattr: %p "
604 		"strmres: %p status: 0x%x\n", __func__,
605 		hnode, dir, index, pattr, strmres, status);
606 	return status;
607 }
608 
609 /*
610  *  ======== strm_reclaim ========
611  *  Purpose:
612  *      Relcaims a buffer from a stream.
613  */
strm_reclaim(struct strm_object * stream_obj,u8 ** buf_ptr,u32 * nbytes,u32 * buff_size,u32 * pdw_arg)614 int strm_reclaim(struct strm_object *stream_obj, u8 ** buf_ptr,
615 			u32 *nbytes, u32 *buff_size, u32 *pdw_arg)
616 {
617 	struct bridge_drv_interface *intf_fxns;
618 	struct chnl_ioc chnl_ioc_obj;
619 	int status = 0;
620 	void *tmp_buf = NULL;
621 
622 	DBC_REQUIRE(refs > 0);
623 	DBC_REQUIRE(buf_ptr != NULL);
624 	DBC_REQUIRE(nbytes != NULL);
625 	DBC_REQUIRE(pdw_arg != NULL);
626 
627 	if (!stream_obj) {
628 		status = -EFAULT;
629 		goto func_end;
630 	}
631 	intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
632 
633 	status =
634 	    (*intf_fxns->chnl_get_ioc) (stream_obj->chnl_obj,
635 					    stream_obj->timeout,
636 					    &chnl_ioc_obj);
637 	if (!status) {
638 		*nbytes = chnl_ioc_obj.byte_size;
639 		if (buff_size)
640 			*buff_size = chnl_ioc_obj.buf_size;
641 
642 		*pdw_arg = chnl_ioc_obj.arg;
643 		if (!CHNL_IS_IO_COMPLETE(chnl_ioc_obj)) {
644 			if (CHNL_IS_TIMED_OUT(chnl_ioc_obj)) {
645 				status = -ETIME;
646 			} else {
647 				/* Allow reclaims after idle to succeed */
648 				if (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj))
649 					status = -EPERM;
650 
651 			}
652 		}
653 		/* Translate zerocopy buffer if channel not canceled. */
654 		if (!status
655 		    && (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj))
656 		    && (stream_obj->strm_mode == STRMMODE_ZEROCOPY)) {
657 			/*
658 			 *  This is a zero-copy channel so chnl_ioc_obj.buf
659 			 *  contains the DSP address of SM. We need to
660 			 *  translate it to a virtual address for the user
661 			 *  thread to access.
662 			 *  Note: Could add CMM_DSPPA2VA to CMM in the future.
663 			 */
664 			tmp_buf = cmm_xlator_translate(stream_obj->xlator,
665 						       chnl_ioc_obj.buf,
666 						       CMM_DSPPA2PA);
667 			if (tmp_buf != NULL) {
668 				/* now convert this GPP Pa to Va */
669 				tmp_buf = cmm_xlator_translate(stream_obj->
670 							       xlator,
671 							       tmp_buf,
672 							       CMM_PA2VA);
673 			}
674 			if (tmp_buf == NULL)
675 				status = -ESRCH;
676 
677 			chnl_ioc_obj.buf = tmp_buf;
678 		}
679 		*buf_ptr = chnl_ioc_obj.buf;
680 	}
681 func_end:
682 	/* ensure we return a documented return code */
683 	DBC_ENSURE(!status || status == -EFAULT ||
684 		   status == -ETIME || status == -ESRCH ||
685 		   status == -EPERM);
686 
687 	dev_dbg(bridge, "%s: stream_obj: %p buf_ptr: %p nbytes: %p "
688 		"pdw_arg: %p status 0x%x\n", __func__, stream_obj,
689 		buf_ptr, nbytes, pdw_arg, status);
690 	return status;
691 }
692 
693 /*
694  *  ======== strm_register_notify ========
695  *  Purpose:
696  *      Register to be notified on specific events for this stream.
697  */
strm_register_notify(struct strm_object * stream_obj,u32 event_mask,u32 notify_type,struct dsp_notification * hnotification)698 int strm_register_notify(struct strm_object *stream_obj, u32 event_mask,
699 				u32 notify_type, struct dsp_notification
700 				* hnotification)
701 {
702 	struct bridge_drv_interface *intf_fxns;
703 	int status = 0;
704 
705 	DBC_REQUIRE(refs > 0);
706 	DBC_REQUIRE(hnotification != NULL);
707 
708 	if (!stream_obj) {
709 		status = -EFAULT;
710 	} else if ((event_mask & ~((DSP_STREAMIOCOMPLETION) |
711 				   DSP_STREAMDONE)) != 0) {
712 		status = -EINVAL;
713 	} else {
714 		if (notify_type != DSP_SIGNALEVENT)
715 			status = -ENOSYS;
716 
717 	}
718 	if (!status) {
719 		intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
720 
721 		status =
722 		    (*intf_fxns->chnl_register_notify) (stream_obj->
723 							    chnl_obj,
724 							    event_mask,
725 							    notify_type,
726 							    hnotification);
727 	}
728 	/* ensure we return a documented return code */
729 	DBC_ENSURE(!status || status == -EFAULT ||
730 		   status == -ETIME || status == -ESRCH ||
731 		   status == -ENOSYS || status == -EPERM);
732 	return status;
733 }
734 
735 /*
736  *  ======== strm_select ========
737  *  Purpose:
738  *      Selects a ready stream.
739  */
strm_select(struct strm_object ** strm_tab,u32 strms,u32 * pmask,u32 utimeout)740 int strm_select(struct strm_object **strm_tab, u32 strms,
741 		       u32 *pmask, u32 utimeout)
742 {
743 	u32 index;
744 	struct chnl_info chnl_info_obj;
745 	struct bridge_drv_interface *intf_fxns;
746 	struct sync_object **sync_events = NULL;
747 	u32 i;
748 	int status = 0;
749 
750 	DBC_REQUIRE(refs > 0);
751 	DBC_REQUIRE(strm_tab != NULL);
752 	DBC_REQUIRE(pmask != NULL);
753 	DBC_REQUIRE(strms > 0);
754 
755 	*pmask = 0;
756 	for (i = 0; i < strms; i++) {
757 		if (!strm_tab[i]) {
758 			status = -EFAULT;
759 			break;
760 		}
761 	}
762 	if (status)
763 		goto func_end;
764 
765 	/* Determine which channels have IO ready */
766 	for (i = 0; i < strms; i++) {
767 		intf_fxns = strm_tab[i]->strm_mgr_obj->intf_fxns;
768 		status = (*intf_fxns->chnl_get_info) (strm_tab[i]->chnl_obj,
769 							  &chnl_info_obj);
770 		if (status) {
771 			break;
772 		} else {
773 			if (chnl_info_obj.cio_cs > 0)
774 				*pmask |= (1 << i);
775 
776 		}
777 	}
778 	if (!status && utimeout > 0 && *pmask == 0) {
779 		/* Non-zero timeout */
780 		sync_events = kmalloc(strms * sizeof(struct sync_object *),
781 								GFP_KERNEL);
782 
783 		if (sync_events == NULL) {
784 			status = -ENOMEM;
785 		} else {
786 			for (i = 0; i < strms; i++) {
787 				intf_fxns =
788 				    strm_tab[i]->strm_mgr_obj->intf_fxns;
789 				status = (*intf_fxns->chnl_get_info)
790 				    (strm_tab[i]->chnl_obj, &chnl_info_obj);
791 				if (status)
792 					break;
793 				else
794 					sync_events[i] =
795 					    chnl_info_obj.sync_event;
796 
797 			}
798 		}
799 		if (!status) {
800 			status =
801 			    sync_wait_on_multiple_events(sync_events, strms,
802 							 utimeout, &index);
803 			if (!status) {
804 				/* Since we waited on the event, we have to
805 				 * reset it */
806 				sync_set_event(sync_events[index]);
807 				*pmask = 1 << index;
808 			}
809 		}
810 	}
811 func_end:
812 	kfree(sync_events);
813 
814 	DBC_ENSURE((!status && (*pmask != 0 || utimeout == 0)) ||
815 		   (status && *pmask == 0));
816 
817 	return status;
818 }
819 
820 /*
821  *  ======== delete_strm ========
822  *  Purpose:
823  *      Frees the resources allocated for a stream.
824  */
delete_strm(struct strm_object * stream_obj)825 static int delete_strm(struct strm_object *stream_obj)
826 {
827 	struct bridge_drv_interface *intf_fxns;
828 	int status = 0;
829 
830 	if (stream_obj) {
831 		if (stream_obj->chnl_obj) {
832 			intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
833 			/* Channel close can fail only if the channel handle
834 			 * is invalid. */
835 			status = (*intf_fxns->chnl_close)
836 					(stream_obj->chnl_obj);
837 		}
838 		/* Free all SM address translator resources */
839 		kfree(stream_obj->xlator);
840 		kfree(stream_obj);
841 	} else {
842 		status = -EFAULT;
843 	}
844 	return status;
845 }
846