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