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