upload tizen1.0 source
[kernel/linux-2.6.36.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/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  */
57 struct 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  */
68 struct 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 */
89 static u32 refs;                /* module reference count */
90
91 /*  ----------------------------------- Function Prototypes */
92 static int delete_strm(struct strm_object *stream_obj);
93
94 /*
95  *  ======== strm_allocate_buffer ========
96  *  Purpose:
97  *      Allocates buffers for a stream.
98  */
99 int 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
143 func_end:
144         return status;
145 }
146
147 /*
148  *  ======== strm_close ========
149  *  Purpose:
150  *      Close a stream opened with strm_open().
151  */
152 int 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);
183 func_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  */
197 int 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  */
240 void 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  */
253 void 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  */
267 int 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  */
301 int 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         }
360 func_end:
361         return status;
362 }
363
364 /*
365  *  ======== strm_idle ========
366  *  Purpose:
367  *      Idles a particular stream.
368  */
369 int 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  */
396 bool 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  */
415 int 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  */
459 int 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         }
555 func_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  */
615 int 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         }
682 func_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  */
699 int 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  */
741 int 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         }
812 func_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  */
826 static 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 }