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