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