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