4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
6 * DSP/BIOS Bridge Stream Manager.
8 * Copyright (C) 2005-2006 Texas Instruments, Inc.
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.
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.
19 #include <linux/types.h>
21 /* ----------------------------------- Host OS */
22 #include <dspbridge/host_os.h>
24 /* ----------------------------------- DSP/BIOS Bridge */
25 #include <dspbridge/dbdefs.h>
27 /* ----------------------------------- Trace & Debug */
28 #include <dspbridge/dbc.h>
30 /* ----------------------------------- OS Adaptation Layer */
31 #include <dspbridge/sync.h>
33 /* ----------------------------------- Bridge Driver */
34 #include <dspbridge/dspdefs.h>
36 /* ----------------------------------- Resource Manager */
37 #include <dspbridge/nodepriv.h>
39 /* ----------------------------------- Others */
40 #include <dspbridge/cmm.h>
42 /* ----------------------------------- This */
43 #include <dspbridge/strm.h>
45 #include <dspbridge/resourcecleanup.h>
47 /* ----------------------------------- Defines, Data Structures, Typedefs */
48 #define DEFAULTTIMEOUT 10000
49 #define DEFAULTNUMBUFS 2
52 * ======== strm_mgr ========
53 * The strm_mgr contains device information needed to open the underlying
54 * channels of a stream.
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
;
64 * ======== strm_object ========
65 * This object is allocated in strm_open().
68 struct strm_mgr
*strm_mgr_obj
;
69 struct chnl_object
*chnl_obj
;
70 u32 dir
; /* DSP_TONODE or DSP_FROMNODE */
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
;
87 /* ----------------------------------- Globals */
88 static u32 refs
; /* module reference count */
90 /* ----------------------------------- Function Prototypes */
91 static int delete_strm(struct strm_object
*stream_obj
);
94 * ======== strm_allocate_buffer ========
96 * Allocates buffers for a stream.
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
)
105 struct strm_object
*stream_obj
= strmres
->stream
;
107 DBC_REQUIRE(refs
> 0);
108 DBC_REQUIRE(ap_buffer
!= NULL
);
112 * Allocate from segment specified at time of stream open.
124 for (i
= 0; i
< num_bufs
; i
++) {
125 DBC_ASSERT(stream_obj
->xlator
!= NULL
);
126 (void)cmm_xlator_alloc_buf(stream_obj
->xlator
, &ap_buffer
[i
],
128 if (ap_buffer
[i
] == NULL
) {
135 strm_free_buffer(strmres
, ap_buffer
, alloc_cnt
, pr_ctxt
);
140 drv_proc_update_strm_res(num_bufs
, strmres
);
147 * ======== strm_close ========
149 * Close a stream opened with strm_open().
151 int strm_close(struct strm_res_object
*strmres
,
152 struct process_context
*pr_ctxt
)
154 struct bridge_drv_interface
*intf_fxns
;
155 struct chnl_info chnl_info_obj
;
157 struct strm_object
*stream_obj
= strmres
->stream
;
159 DBC_REQUIRE(refs
> 0);
164 /* Have all buffers been reclaimed? If not, return
166 intf_fxns
= stream_obj
->strm_mgr_obj
->intf_fxns
;
168 (*intf_fxns
->chnl_get_info
) (stream_obj
->chnl_obj
,
172 if (chnl_info_obj
.cio_cs
> 0 || chnl_info_obj
.cio_reqs
> 0)
175 status
= delete_strm(stream_obj
);
181 idr_remove(pr_ctxt
->stream_id
, strmres
->id
);
183 DBC_ENSURE(status
== 0 || status
== -EFAULT
||
184 status
== -EPIPE
|| status
== -EPERM
);
186 dev_dbg(bridge
, "%s: stream_obj: %p, status 0x%x\n", __func__
,
192 * ======== strm_create ========
194 * Create a STRM manager object.
196 int strm_create(struct strm_mgr
**strm_man
,
197 struct dev_object
*dev_obj
)
199 struct strm_mgr
*strm_mgr_obj
;
202 DBC_REQUIRE(refs
> 0);
203 DBC_REQUIRE(strm_man
!= NULL
);
204 DBC_REQUIRE(dev_obj
!= NULL
);
207 /* Allocate STRM manager object */
208 strm_mgr_obj
= kzalloc(sizeof(struct strm_mgr
), GFP_KERNEL
);
209 if (strm_mgr_obj
== NULL
)
212 strm_mgr_obj
->dev_obj
= dev_obj
;
214 /* Get Channel manager and Bridge function interface */
216 status
= dev_get_chnl_mgr(dev_obj
, &(strm_mgr_obj
->chnl_mgr
));
218 (void)dev_get_intf_fxns(dev_obj
,
219 &(strm_mgr_obj
->intf_fxns
));
220 DBC_ASSERT(strm_mgr_obj
->intf_fxns
!= NULL
);
225 *strm_man
= strm_mgr_obj
;
229 DBC_ENSURE((!status
&& *strm_man
) || (status
&& *strm_man
== NULL
));
235 * ======== strm_delete ========
237 * Delete the STRM Manager Object.
239 void strm_delete(struct strm_mgr
*strm_mgr_obj
)
241 DBC_REQUIRE(refs
> 0);
242 DBC_REQUIRE(strm_mgr_obj
);
248 * ======== strm_exit ========
250 * Discontinue usage of STRM module.
254 DBC_REQUIRE(refs
> 0);
258 DBC_ENSURE(refs
>= 0);
262 * ======== strm_free_buffer ========
264 * Frees the buffers allocated for a stream.
266 int strm_free_buffer(struct strm_res_object
*strmres
, u8
** ap_buffer
,
267 u32 num_bufs
, struct process_context
*pr_ctxt
)
271 struct strm_object
*stream_obj
= strmres
->stream
;
273 DBC_REQUIRE(refs
> 0);
274 DBC_REQUIRE(ap_buffer
!= NULL
);
280 for (i
= 0; i
< num_bufs
; i
++) {
281 DBC_ASSERT(stream_obj
->xlator
!= NULL
);
283 cmm_xlator_free_buf(stream_obj
->xlator
,
290 drv_proc_update_strm_res(num_bufs
- i
, strmres
);
296 * ======== strm_get_info ========
298 * Retrieves information about a stream.
300 int strm_get_info(struct strm_object
*stream_obj
,
301 struct stream_info
*stream_info
,
302 u32 stream_info_size
)
304 struct bridge_drv_interface
*intf_fxns
;
305 struct chnl_info chnl_info_obj
;
307 void *virt_base
= NULL
; /* NULL if no SM used */
309 DBC_REQUIRE(refs
> 0);
310 DBC_REQUIRE(stream_info
!= NULL
);
311 DBC_REQUIRE(stream_info_size
>= sizeof(struct stream_info
));
316 if (stream_info_size
< sizeof(struct stream_info
)) {
317 /* size of users info */
324 intf_fxns
= stream_obj
->strm_mgr_obj
->intf_fxns
;
326 (*intf_fxns
->chnl_get_info
) (stream_obj
->chnl_obj
,
331 if (stream_obj
->xlator
) {
332 /* We have a translator */
333 DBC_ASSERT(stream_obj
->segment_id
> 0);
334 cmm_xlator_info(stream_obj
->xlator
, (u8
**) &virt_base
, 0,
335 stream_obj
->segment_id
, false);
337 stream_info
->segment_id
= stream_obj
->segment_id
;
338 stream_info
->strm_mode
= stream_obj
->strm_mode
;
339 stream_info
->virt_base
= virt_base
;
340 stream_info
->user_strm
->number_bufs_allowed
= stream_obj
->num_bufs
;
341 stream_info
->user_strm
->number_bufs_in_stream
= chnl_info_obj
.cio_cs
+
342 chnl_info_obj
.cio_reqs
;
343 /* # of bytes transferred since last call to DSPStream_Idle() */
344 stream_info
->user_strm
->number_bytes
= chnl_info_obj
.bytes_tx
;
345 stream_info
->user_strm
->sync_object_handle
= chnl_info_obj
.event_obj
;
346 /* Determine stream state based on channel state and info */
347 if (chnl_info_obj
.state
& CHNL_STATEEOS
) {
348 stream_info
->user_strm
->ss_stream_state
= STREAM_DONE
;
350 if (chnl_info_obj
.cio_cs
> 0)
351 stream_info
->user_strm
->ss_stream_state
= STREAM_READY
;
352 else if (chnl_info_obj
.cio_reqs
> 0)
353 stream_info
->user_strm
->ss_stream_state
=
356 stream_info
->user_strm
->ss_stream_state
= STREAM_IDLE
;
364 * ======== strm_idle ========
366 * Idles a particular stream.
368 int strm_idle(struct strm_object
*stream_obj
, bool flush_data
)
370 struct bridge_drv_interface
*intf_fxns
;
373 DBC_REQUIRE(refs
> 0);
378 intf_fxns
= stream_obj
->strm_mgr_obj
->intf_fxns
;
380 status
= (*intf_fxns
->chnl_idle
) (stream_obj
->chnl_obj
,
385 dev_dbg(bridge
, "%s: stream_obj: %p flush_data: 0x%x status: 0x%x\n",
386 __func__
, stream_obj
, flush_data
, status
);
391 * ======== strm_init ========
393 * Initialize the STRM module.
399 DBC_REQUIRE(refs
>= 0);
404 DBC_ENSURE((ret
&& (refs
> 0)) || (!ret
&& (refs
>= 0)));
410 * ======== strm_issue ========
412 * Issues a buffer on a stream
414 int strm_issue(struct strm_object
*stream_obj
, u8
*pbuf
, u32 ul_bytes
,
415 u32 ul_buf_size
, u32 dw_arg
)
417 struct bridge_drv_interface
*intf_fxns
;
419 void *tmp_buf
= NULL
;
421 DBC_REQUIRE(refs
> 0);
422 DBC_REQUIRE(pbuf
!= NULL
);
427 intf_fxns
= stream_obj
->strm_mgr_obj
->intf_fxns
;
429 if (stream_obj
->segment_id
!= 0) {
430 tmp_buf
= cmm_xlator_translate(stream_obj
->xlator
,
438 status
= (*intf_fxns
->chnl_add_io_req
)
439 (stream_obj
->chnl_obj
, pbuf
, ul_bytes
, ul_buf_size
,
440 (u32
) tmp_buf
, dw_arg
);
446 dev_dbg(bridge
, "%s: stream_obj: %p pbuf: %p ul_bytes: 0x%x dw_arg:"
447 " 0x%x status: 0x%x\n", __func__
, stream_obj
, pbuf
,
448 ul_bytes
, dw_arg
, status
);
453 * ======== strm_open ========
455 * Open a stream for sending/receiving data buffers to/from a task or
456 * XDAIS socket node on the DSP.
458 int strm_open(struct node_object
*hnode
, u32 dir
, u32 index
,
459 struct strm_attr
*pattr
,
460 struct strm_res_object
**strmres
,
461 struct process_context
*pr_ctxt
)
463 struct strm_mgr
*strm_mgr_obj
;
464 struct bridge_drv_interface
*intf_fxns
;
466 struct strm_object
*strm_obj
= NULL
;
468 struct chnl_attr chnl_attr_obj
;
470 struct cmm_object
*hcmm_mgr
= NULL
; /* Shared memory manager hndl */
474 DBC_REQUIRE(refs
> 0);
475 DBC_REQUIRE(strmres
!= NULL
);
476 DBC_REQUIRE(pattr
!= NULL
);
478 if (dir
!= DSP_TONODE
&& dir
!= DSP_FROMNODE
) {
481 /* Get the channel id from the node (set in node_connect()) */
482 status
= node_get_channel_id(hnode
, dir
, index
, &ul_chnl_id
);
485 status
= node_get_strm_mgr(hnode
, &strm_mgr_obj
);
488 strm_obj
= kzalloc(sizeof(struct strm_object
), GFP_KERNEL
);
489 if (strm_obj
== NULL
) {
492 strm_obj
->strm_mgr_obj
= strm_mgr_obj
;
494 strm_obj
->strm_state
= STREAM_IDLE
;
495 strm_obj
->user_event
= pattr
->user_event
;
496 if (pattr
->stream_attr_in
!= NULL
) {
498 pattr
->stream_attr_in
->timeout
;
500 pattr
->stream_attr_in
->num_bufs
;
501 strm_obj
->strm_mode
=
502 pattr
->stream_attr_in
->strm_mode
;
503 strm_obj
->segment_id
=
504 pattr
->stream_attr_in
->segment_id
;
505 strm_obj
->buf_alignment
=
506 pattr
->stream_attr_in
->buf_alignment
;
507 strm_obj
->dma_chnl_id
=
508 pattr
->stream_attr_in
->dma_chnl_id
;
509 strm_obj
->dma_priority
=
510 pattr
->stream_attr_in
->dma_priority
;
511 chnl_attr_obj
.uio_reqs
=
512 pattr
->stream_attr_in
->num_bufs
;
514 strm_obj
->timeout
= DEFAULTTIMEOUT
;
515 strm_obj
->num_bufs
= DEFAULTNUMBUFS
;
516 strm_obj
->strm_mode
= STRMMODE_PROCCOPY
;
517 strm_obj
->segment_id
= 0; /* local mem */
518 strm_obj
->buf_alignment
= 0;
519 strm_obj
->dma_chnl_id
= 0;
520 strm_obj
->dma_priority
= 0;
521 chnl_attr_obj
.uio_reqs
= DEFAULTNUMBUFS
;
523 chnl_attr_obj
.reserved1
= NULL
;
524 /* DMA chnl flush timeout */
525 chnl_attr_obj
.reserved2
= strm_obj
->timeout
;
526 chnl_attr_obj
.event_obj
= NULL
;
527 if (pattr
->user_event
!= NULL
)
528 chnl_attr_obj
.event_obj
= pattr
->user_event
;
535 if ((pattr
->virt_base
== NULL
) || !(pattr
->virt_size
> 0))
539 DBC_ASSERT(strm_obj
->strm_mode
!= STRMMODE_LDMA
);
540 /* Get the shared mem mgr for this streams dev object */
541 status
= dev_get_cmm_mgr(strm_mgr_obj
->dev_obj
, &hcmm_mgr
);
543 /*Allocate a SM addr translator for this strm. */
544 status
= cmm_xlator_create(&strm_obj
->xlator
, hcmm_mgr
, NULL
);
546 DBC_ASSERT(strm_obj
->segment_id
> 0);
547 /* Set translators Virt Addr attributes */
548 status
= cmm_xlator_info(strm_obj
->xlator
,
549 (u8
**) &pattr
->virt_base
,
551 strm_obj
->segment_id
, true);
557 chnl_mode
= (dir
== DSP_TONODE
) ?
558 CHNL_MODETODSP
: CHNL_MODEFROMDSP
;
559 intf_fxns
= strm_mgr_obj
->intf_fxns
;
560 status
= (*intf_fxns
->chnl_open
) (&(strm_obj
->chnl_obj
),
561 strm_mgr_obj
->chnl_mgr
,
562 chnl_mode
, ul_chnl_id
,
566 * over-ride non-returnable status codes so we return
567 * something documented
569 if (status
!= -ENOMEM
&& status
!=
570 -EINVAL
&& status
!= -EPERM
) {
572 * We got a status that's not return-able.
573 * Assert that we got something we were
574 * expecting (-EFAULT isn't acceptable,
575 * strm_mgr_obj->chnl_mgr better be valid or we
576 * assert here), and then return -EPERM.
578 DBC_ASSERT(status
== -ENOSR
||
580 status
== -EALREADY
||
587 status
= drv_proc_insert_strm_res_element(strm_obj
,
588 &stream_res
, pr_ctxt
);
590 delete_strm(strm_obj
);
592 *strmres
= (struct strm_res_object
*)stream_res
;
594 (void)delete_strm(strm_obj
);
597 /* ensure we return a documented error code */
598 DBC_ENSURE((!status
&& strm_obj
) ||
599 (*strmres
== NULL
&& (status
== -EFAULT
||
601 || status
== -EINVAL
)));
603 dev_dbg(bridge
, "%s: hnode: %p dir: 0x%x index: 0x%x pattr: %p "
604 "strmres: %p status: 0x%x\n", __func__
,
605 hnode
, dir
, index
, pattr
, strmres
, status
);
610 * ======== strm_reclaim ========
612 * Relcaims a buffer from a stream.
614 int strm_reclaim(struct strm_object
*stream_obj
, u8
** buf_ptr
,
615 u32
*nbytes
, u32
*buff_size
, u32
*pdw_arg
)
617 struct bridge_drv_interface
*intf_fxns
;
618 struct chnl_ioc chnl_ioc_obj
;
620 void *tmp_buf
= NULL
;
622 DBC_REQUIRE(refs
> 0);
623 DBC_REQUIRE(buf_ptr
!= NULL
);
624 DBC_REQUIRE(nbytes
!= NULL
);
625 DBC_REQUIRE(pdw_arg
!= NULL
);
631 intf_fxns
= stream_obj
->strm_mgr_obj
->intf_fxns
;
634 (*intf_fxns
->chnl_get_ioc
) (stream_obj
->chnl_obj
,
638 *nbytes
= chnl_ioc_obj
.byte_size
;
640 *buff_size
= chnl_ioc_obj
.buf_size
;
642 *pdw_arg
= chnl_ioc_obj
.arg
;
643 if (!CHNL_IS_IO_COMPLETE(chnl_ioc_obj
)) {
644 if (CHNL_IS_TIMED_OUT(chnl_ioc_obj
)) {
647 /* Allow reclaims after idle to succeed */
648 if (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj
))
653 /* Translate zerocopy buffer if channel not canceled. */
655 && (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj
))
656 && (stream_obj
->strm_mode
== STRMMODE_ZEROCOPY
)) {
658 * This is a zero-copy channel so chnl_ioc_obj.buf
659 * contains the DSP address of SM. We need to
660 * translate it to a virtual address for the user
662 * Note: Could add CMM_DSPPA2VA to CMM in the future.
664 tmp_buf
= cmm_xlator_translate(stream_obj
->xlator
,
667 if (tmp_buf
!= NULL
) {
668 /* now convert this GPP Pa to Va */
669 tmp_buf
= cmm_xlator_translate(stream_obj
->
677 chnl_ioc_obj
.buf
= tmp_buf
;
679 *buf_ptr
= chnl_ioc_obj
.buf
;
682 /* ensure we return a documented return code */
683 DBC_ENSURE(!status
|| status
== -EFAULT
||
684 status
== -ETIME
|| status
== -ESRCH
||
687 dev_dbg(bridge
, "%s: stream_obj: %p buf_ptr: %p nbytes: %p "
688 "pdw_arg: %p status 0x%x\n", __func__
, stream_obj
,
689 buf_ptr
, nbytes
, pdw_arg
, status
);
694 * ======== strm_register_notify ========
696 * Register to be notified on specific events for this stream.
698 int strm_register_notify(struct strm_object
*stream_obj
, u32 event_mask
,
699 u32 notify_type
, struct dsp_notification
702 struct bridge_drv_interface
*intf_fxns
;
705 DBC_REQUIRE(refs
> 0);
706 DBC_REQUIRE(hnotification
!= NULL
);
710 } else if ((event_mask
& ~((DSP_STREAMIOCOMPLETION
) |
711 DSP_STREAMDONE
)) != 0) {
714 if (notify_type
!= DSP_SIGNALEVENT
)
719 intf_fxns
= stream_obj
->strm_mgr_obj
->intf_fxns
;
722 (*intf_fxns
->chnl_register_notify
) (stream_obj
->
728 /* ensure we return a documented return code */
729 DBC_ENSURE(!status
|| status
== -EFAULT
||
730 status
== -ETIME
|| status
== -ESRCH
||
731 status
== -ENOSYS
|| status
== -EPERM
);
736 * ======== strm_select ========
738 * Selects a ready stream.
740 int strm_select(struct strm_object
**strm_tab
, u32 strms
,
741 u32
*pmask
, u32 utimeout
)
744 struct chnl_info chnl_info_obj
;
745 struct bridge_drv_interface
*intf_fxns
;
746 struct sync_object
**sync_events
= NULL
;
750 DBC_REQUIRE(refs
> 0);
751 DBC_REQUIRE(strm_tab
!= NULL
);
752 DBC_REQUIRE(pmask
!= NULL
);
753 DBC_REQUIRE(strms
> 0);
756 for (i
= 0; i
< strms
; i
++) {
765 /* Determine which channels have IO ready */
766 for (i
= 0; i
< strms
; i
++) {
767 intf_fxns
= strm_tab
[i
]->strm_mgr_obj
->intf_fxns
;
768 status
= (*intf_fxns
->chnl_get_info
) (strm_tab
[i
]->chnl_obj
,
773 if (chnl_info_obj
.cio_cs
> 0)
778 if (!status
&& utimeout
> 0 && *pmask
== 0) {
779 /* Non-zero timeout */
780 sync_events
= kmalloc(strms
* sizeof(struct sync_object
*),
783 if (sync_events
== NULL
) {
786 for (i
= 0; i
< strms
; i
++) {
788 strm_tab
[i
]->strm_mgr_obj
->intf_fxns
;
789 status
= (*intf_fxns
->chnl_get_info
)
790 (strm_tab
[i
]->chnl_obj
, &chnl_info_obj
);
795 chnl_info_obj
.sync_event
;
801 sync_wait_on_multiple_events(sync_events
, strms
,
804 /* Since we waited on the event, we have to
806 sync_set_event(sync_events
[index
]);
814 DBC_ENSURE((!status
&& (*pmask
!= 0 || utimeout
== 0)) ||
815 (status
&& *pmask
== 0));
821 * ======== delete_strm ========
823 * Frees the resources allocated for a stream.
825 static int delete_strm(struct strm_object
*stream_obj
)
827 struct bridge_drv_interface
*intf_fxns
;
831 if (stream_obj
->chnl_obj
) {
832 intf_fxns
= stream_obj
->strm_mgr_obj
->intf_fxns
;
833 /* Channel close can fail only if the channel handle
835 status
= (*intf_fxns
->chnl_close
)
836 (stream_obj
->chnl_obj
);
838 /* Free all SM address translator resources */
839 kfree(stream_obj
->xlator
);