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 /* ----------------------------------- OS Adaptation Layer */
28 #include <dspbridge/sync.h>
30 /* ----------------------------------- Bridge Driver */
31 #include <dspbridge/dspdefs.h>
33 /* ----------------------------------- Resource Manager */
34 #include <dspbridge/nodepriv.h>
36 /* ----------------------------------- Others */
37 #include <dspbridge/cmm.h>
39 /* ----------------------------------- This */
40 #include <dspbridge/strm.h>
42 #include <dspbridge/resourcecleanup.h>
44 /* ----------------------------------- Defines, Data Structures, Typedefs */
45 #define DEFAULTTIMEOUT 10000
46 #define DEFAULTNUMBUFS 2
49 * ======== strm_mgr ========
50 * The strm_mgr contains device information needed to open the underlying
51 * channels of a stream.
54 struct dev_object
*dev_obj
; /* Device for this processor */
55 struct chnl_mgr
*chnl_mgr
; /* Channel manager */
56 /* Function interface to Bridge driver */
57 struct bridge_drv_interface
*intf_fxns
;
61 * ======== strm_object ========
62 * This object is allocated in strm_open().
65 struct strm_mgr
*strm_mgr_obj
;
66 struct chnl_object
*chnl_obj
;
67 u32 dir
; /* DSP_TONODE or DSP_FROMNODE */
69 u32 num_bufs
; /* Max # of bufs allowed in stream */
70 u32 bufs_in_strm
; /* Current # of bufs in stream */
71 u32 bytes
; /* bytes transferred since idled */
72 /* STREAM_IDLE, STREAM_READY, ... */
73 enum dsp_streamstate strm_state
;
74 void *user_event
; /* Saved for strm_get_info() */
75 enum dsp_strmmode strm_mode
; /* STRMMODE_[PROCCOPY][ZEROCOPY]... */
76 u32 dma_chnl_id
; /* DMA chnl id */
77 u32 dma_priority
; /* DMA priority:DMAPRI_[LOW][HIGH] */
78 u32 segment_id
; /* >0 is SM segment.=0 is local heap */
79 u32 buf_alignment
; /* Alignment for stream bufs */
80 /* Stream's SM address translator */
81 struct cmm_xlatorobject
*xlator
;
84 /* ----------------------------------- Function Prototypes */
85 static int delete_strm(struct strm_object
*stream_obj
);
88 * ======== strm_allocate_buffer ========
90 * Allocates buffers for a stream.
92 int strm_allocate_buffer(struct strm_res_object
*strmres
, u32 usize
,
93 u8
**ap_buffer
, u32 num_bufs
,
94 struct process_context
*pr_ctxt
)
99 struct strm_object
*stream_obj
= strmres
->stream
;
103 * Allocate from segment specified at time of stream open.
115 for (i
= 0; i
< num_bufs
; i
++) {
116 (void)cmm_xlator_alloc_buf(stream_obj
->xlator
, &ap_buffer
[i
],
118 if (ap_buffer
[i
] == NULL
) {
125 strm_free_buffer(strmres
, ap_buffer
, alloc_cnt
, pr_ctxt
);
130 drv_proc_update_strm_res(num_bufs
, strmres
);
137 * ======== strm_close ========
139 * Close a stream opened with strm_open().
141 int strm_close(struct strm_res_object
*strmres
,
142 struct process_context
*pr_ctxt
)
144 struct bridge_drv_interface
*intf_fxns
;
145 struct chnl_info chnl_info_obj
;
147 struct strm_object
*stream_obj
= strmres
->stream
;
152 /* Have all buffers been reclaimed? If not, return
154 intf_fxns
= stream_obj
->strm_mgr_obj
->intf_fxns
;
156 (*intf_fxns
->chnl_get_info
) (stream_obj
->chnl_obj
,
159 if (chnl_info_obj
.cio_cs
> 0 || chnl_info_obj
.cio_reqs
> 0)
162 status
= delete_strm(stream_obj
);
168 idr_remove(pr_ctxt
->stream_id
, strmres
->id
);
170 dev_dbg(bridge
, "%s: stream_obj: %p, status 0x%x\n", __func__
,
176 * ======== strm_create ========
178 * Create a STRM manager object.
180 int strm_create(struct strm_mgr
**strm_man
,
181 struct dev_object
*dev_obj
)
183 struct strm_mgr
*strm_mgr_obj
;
187 /* Allocate STRM manager object */
188 strm_mgr_obj
= kzalloc(sizeof(struct strm_mgr
), GFP_KERNEL
);
189 if (strm_mgr_obj
== NULL
)
192 strm_mgr_obj
->dev_obj
= dev_obj
;
194 /* Get Channel manager and Bridge function interface */
196 status
= dev_get_chnl_mgr(dev_obj
, &(strm_mgr_obj
->chnl_mgr
));
198 (void)dev_get_intf_fxns(dev_obj
,
199 &(strm_mgr_obj
->intf_fxns
));
204 *strm_man
= strm_mgr_obj
;
212 * ======== strm_delete ========
214 * Delete the STRM Manager Object.
216 void strm_delete(struct strm_mgr
*strm_mgr_obj
)
222 * ======== strm_free_buffer ========
224 * Frees the buffers allocated for a stream.
226 int strm_free_buffer(struct strm_res_object
*strmres
, u8
** ap_buffer
,
227 u32 num_bufs
, struct process_context
*pr_ctxt
)
231 struct strm_object
*stream_obj
= strmres
->stream
;
237 for (i
= 0; i
< num_bufs
; i
++) {
239 cmm_xlator_free_buf(stream_obj
->xlator
,
246 drv_proc_update_strm_res(num_bufs
- i
, strmres
);
252 * ======== strm_get_info ========
254 * Retrieves information about a stream.
256 int strm_get_info(struct strm_object
*stream_obj
,
257 struct stream_info
*stream_info
,
258 u32 stream_info_size
)
260 struct bridge_drv_interface
*intf_fxns
;
261 struct chnl_info chnl_info_obj
;
263 void *virt_base
= NULL
; /* NULL if no SM used */
268 if (stream_info_size
< sizeof(struct stream_info
)) {
269 /* size of users info */
276 intf_fxns
= stream_obj
->strm_mgr_obj
->intf_fxns
;
278 (*intf_fxns
->chnl_get_info
) (stream_obj
->chnl_obj
,
283 if (stream_obj
->xlator
) {
284 /* We have a translator */
285 cmm_xlator_info(stream_obj
->xlator
, (u8
**) &virt_base
, 0,
286 stream_obj
->segment_id
, false);
288 stream_info
->segment_id
= stream_obj
->segment_id
;
289 stream_info
->strm_mode
= stream_obj
->strm_mode
;
290 stream_info
->virt_base
= virt_base
;
291 stream_info
->user_strm
->number_bufs_allowed
= stream_obj
->num_bufs
;
292 stream_info
->user_strm
->number_bufs_in_stream
= chnl_info_obj
.cio_cs
+
293 chnl_info_obj
.cio_reqs
;
294 /* # of bytes transferred since last call to DSPStream_Idle() */
295 stream_info
->user_strm
->number_bytes
= chnl_info_obj
.bytes_tx
;
296 stream_info
->user_strm
->sync_object_handle
= chnl_info_obj
.event_obj
;
297 /* Determine stream state based on channel state and info */
298 if (chnl_info_obj
.state
& CHNL_STATEEOS
) {
299 stream_info
->user_strm
->ss_stream_state
= STREAM_DONE
;
301 if (chnl_info_obj
.cio_cs
> 0)
302 stream_info
->user_strm
->ss_stream_state
= STREAM_READY
;
303 else if (chnl_info_obj
.cio_reqs
> 0)
304 stream_info
->user_strm
->ss_stream_state
=
307 stream_info
->user_strm
->ss_stream_state
= STREAM_IDLE
;
315 * ======== strm_idle ========
317 * Idles a particular stream.
319 int strm_idle(struct strm_object
*stream_obj
, bool flush_data
)
321 struct bridge_drv_interface
*intf_fxns
;
327 intf_fxns
= stream_obj
->strm_mgr_obj
->intf_fxns
;
329 status
= (*intf_fxns
->chnl_idle
) (stream_obj
->chnl_obj
,
334 dev_dbg(bridge
, "%s: stream_obj: %p flush_data: 0x%x status: 0x%x\n",
335 __func__
, stream_obj
, flush_data
, status
);
340 * ======== strm_issue ========
342 * Issues a buffer on a stream
344 int strm_issue(struct strm_object
*stream_obj
, u8
*pbuf
, u32 ul_bytes
,
345 u32 ul_buf_size
, u32 dw_arg
)
347 struct bridge_drv_interface
*intf_fxns
;
349 void *tmp_buf
= NULL
;
354 intf_fxns
= stream_obj
->strm_mgr_obj
->intf_fxns
;
356 if (stream_obj
->segment_id
!= 0) {
357 tmp_buf
= cmm_xlator_translate(stream_obj
->xlator
,
365 status
= (*intf_fxns
->chnl_add_io_req
)
366 (stream_obj
->chnl_obj
, pbuf
, ul_bytes
, ul_buf_size
,
367 (u32
) tmp_buf
, dw_arg
);
373 dev_dbg(bridge
, "%s: stream_obj: %p pbuf: %p ul_bytes: 0x%x dw_arg:"
374 " 0x%x status: 0x%x\n", __func__
, stream_obj
, pbuf
,
375 ul_bytes
, dw_arg
, status
);
380 * ======== strm_open ========
382 * Open a stream for sending/receiving data buffers to/from a task or
383 * XDAIS socket node on the DSP.
385 int strm_open(struct node_object
*hnode
, u32 dir
, u32 index
,
386 struct strm_attr
*pattr
,
387 struct strm_res_object
**strmres
,
388 struct process_context
*pr_ctxt
)
390 struct strm_mgr
*strm_mgr_obj
;
391 struct bridge_drv_interface
*intf_fxns
;
393 struct strm_object
*strm_obj
= NULL
;
395 struct chnl_attr chnl_attr_obj
;
397 struct cmm_object
*hcmm_mgr
= NULL
; /* Shared memory manager hndl */
402 if (dir
!= DSP_TONODE
&& dir
!= DSP_FROMNODE
) {
405 /* Get the channel id from the node (set in node_connect()) */
406 status
= node_get_channel_id(hnode
, dir
, index
, &ul_chnl_id
);
409 status
= node_get_strm_mgr(hnode
, &strm_mgr_obj
);
412 strm_obj
= kzalloc(sizeof(struct strm_object
), GFP_KERNEL
);
413 if (strm_obj
== NULL
) {
416 strm_obj
->strm_mgr_obj
= strm_mgr_obj
;
418 strm_obj
->strm_state
= STREAM_IDLE
;
419 strm_obj
->user_event
= pattr
->user_event
;
420 if (pattr
->stream_attr_in
!= NULL
) {
422 pattr
->stream_attr_in
->timeout
;
424 pattr
->stream_attr_in
->num_bufs
;
425 strm_obj
->strm_mode
=
426 pattr
->stream_attr_in
->strm_mode
;
427 strm_obj
->segment_id
=
428 pattr
->stream_attr_in
->segment_id
;
429 strm_obj
->buf_alignment
=
430 pattr
->stream_attr_in
->buf_alignment
;
431 strm_obj
->dma_chnl_id
=
432 pattr
->stream_attr_in
->dma_chnl_id
;
433 strm_obj
->dma_priority
=
434 pattr
->stream_attr_in
->dma_priority
;
435 chnl_attr_obj
.uio_reqs
=
436 pattr
->stream_attr_in
->num_bufs
;
438 strm_obj
->timeout
= DEFAULTTIMEOUT
;
439 strm_obj
->num_bufs
= DEFAULTNUMBUFS
;
440 strm_obj
->strm_mode
= STRMMODE_PROCCOPY
;
441 strm_obj
->segment_id
= 0; /* local mem */
442 strm_obj
->buf_alignment
= 0;
443 strm_obj
->dma_chnl_id
= 0;
444 strm_obj
->dma_priority
= 0;
445 chnl_attr_obj
.uio_reqs
= DEFAULTNUMBUFS
;
447 chnl_attr_obj
.reserved1
= NULL
;
448 /* DMA chnl flush timeout */
449 chnl_attr_obj
.reserved2
= strm_obj
->timeout
;
450 chnl_attr_obj
.event_obj
= NULL
;
451 if (pattr
->user_event
!= NULL
)
452 chnl_attr_obj
.event_obj
= pattr
->user_event
;
459 if ((pattr
->virt_base
== NULL
) || !(pattr
->virt_size
> 0))
463 /* Get the shared mem mgr for this streams dev object */
464 status
= dev_get_cmm_mgr(strm_mgr_obj
->dev_obj
, &hcmm_mgr
);
466 /*Allocate a SM addr translator for this strm. */
467 status
= cmm_xlator_create(&strm_obj
->xlator
, hcmm_mgr
, NULL
);
469 /* Set translators Virt Addr attributes */
470 status
= cmm_xlator_info(strm_obj
->xlator
,
471 (u8
**) &pattr
->virt_base
,
473 strm_obj
->segment_id
, true);
479 chnl_mode
= (dir
== DSP_TONODE
) ?
480 CHNL_MODETODSP
: CHNL_MODEFROMDSP
;
481 intf_fxns
= strm_mgr_obj
->intf_fxns
;
482 status
= (*intf_fxns
->chnl_open
) (&(strm_obj
->chnl_obj
),
483 strm_mgr_obj
->chnl_mgr
,
484 chnl_mode
, ul_chnl_id
,
488 * over-ride non-returnable status codes so we return
489 * something documented
491 if (status
!= -ENOMEM
&& status
!=
492 -EINVAL
&& status
!= -EPERM
) {
494 * We got a status that's not return-able.
495 * Assert that we got something we were
496 * expecting (-EFAULT isn't acceptable,
497 * strm_mgr_obj->chnl_mgr better be valid or we
498 * assert here), and then return -EPERM.
505 status
= drv_proc_insert_strm_res_element(strm_obj
,
506 &stream_res
, pr_ctxt
);
508 delete_strm(strm_obj
);
510 *strmres
= (struct strm_res_object
*)stream_res
;
512 (void)delete_strm(strm_obj
);
515 dev_dbg(bridge
, "%s: hnode: %p dir: 0x%x index: 0x%x pattr: %p "
516 "strmres: %p status: 0x%x\n", __func__
,
517 hnode
, dir
, index
, pattr
, strmres
, status
);
522 * ======== strm_reclaim ========
524 * Relcaims a buffer from a stream.
526 int strm_reclaim(struct strm_object
*stream_obj
, u8
** buf_ptr
,
527 u32
*nbytes
, u32
*buff_size
, u32
*pdw_arg
)
529 struct bridge_drv_interface
*intf_fxns
;
530 struct chnl_ioc chnl_ioc_obj
;
532 void *tmp_buf
= NULL
;
538 intf_fxns
= stream_obj
->strm_mgr_obj
->intf_fxns
;
541 (*intf_fxns
->chnl_get_ioc
) (stream_obj
->chnl_obj
,
545 *nbytes
= chnl_ioc_obj
.byte_size
;
547 *buff_size
= chnl_ioc_obj
.buf_size
;
549 *pdw_arg
= chnl_ioc_obj
.arg
;
550 if (!CHNL_IS_IO_COMPLETE(chnl_ioc_obj
)) {
551 if (CHNL_IS_TIMED_OUT(chnl_ioc_obj
)) {
554 /* Allow reclaims after idle to succeed */
555 if (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj
))
560 /* Translate zerocopy buffer if channel not canceled. */
562 && (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj
))
563 && (stream_obj
->strm_mode
== STRMMODE_ZEROCOPY
)) {
565 * This is a zero-copy channel so chnl_ioc_obj.buf
566 * contains the DSP address of SM. We need to
567 * translate it to a virtual address for the user
569 * Note: Could add CMM_DSPPA2VA to CMM in the future.
571 tmp_buf
= cmm_xlator_translate(stream_obj
->xlator
,
574 if (tmp_buf
!= NULL
) {
575 /* now convert this GPP Pa to Va */
576 tmp_buf
= cmm_xlator_translate(stream_obj
->
584 chnl_ioc_obj
.buf
= tmp_buf
;
586 *buf_ptr
= chnl_ioc_obj
.buf
;
589 dev_dbg(bridge
, "%s: stream_obj: %p buf_ptr: %p nbytes: %p "
590 "pdw_arg: %p status 0x%x\n", __func__
, stream_obj
,
591 buf_ptr
, nbytes
, pdw_arg
, status
);
596 * ======== strm_register_notify ========
598 * Register to be notified on specific events for this stream.
600 int strm_register_notify(struct strm_object
*stream_obj
, u32 event_mask
,
601 u32 notify_type
, struct dsp_notification
604 struct bridge_drv_interface
*intf_fxns
;
609 } else if ((event_mask
& ~((DSP_STREAMIOCOMPLETION
) |
610 DSP_STREAMDONE
)) != 0) {
613 if (notify_type
!= DSP_SIGNALEVENT
)
618 intf_fxns
= stream_obj
->strm_mgr_obj
->intf_fxns
;
621 (*intf_fxns
->chnl_register_notify
) (stream_obj
->
632 * ======== strm_select ========
634 * Selects a ready stream.
636 int strm_select(struct strm_object
**strm_tab
, u32 strms
,
637 u32
*pmask
, u32 utimeout
)
640 struct chnl_info chnl_info_obj
;
641 struct bridge_drv_interface
*intf_fxns
;
642 struct sync_object
**sync_events
= NULL
;
647 for (i
= 0; i
< strms
; i
++) {
656 /* Determine which channels have IO ready */
657 for (i
= 0; i
< strms
; i
++) {
658 intf_fxns
= strm_tab
[i
]->strm_mgr_obj
->intf_fxns
;
659 status
= (*intf_fxns
->chnl_get_info
) (strm_tab
[i
]->chnl_obj
,
664 if (chnl_info_obj
.cio_cs
> 0)
669 if (!status
&& utimeout
> 0 && *pmask
== 0) {
670 /* Non-zero timeout */
671 sync_events
= kmalloc(strms
* sizeof(struct sync_object
*),
674 if (sync_events
== NULL
) {
677 for (i
= 0; i
< strms
; i
++) {
679 strm_tab
[i
]->strm_mgr_obj
->intf_fxns
;
680 status
= (*intf_fxns
->chnl_get_info
)
681 (strm_tab
[i
]->chnl_obj
, &chnl_info_obj
);
686 chnl_info_obj
.sync_event
;
692 sync_wait_on_multiple_events(sync_events
, strms
,
695 /* Since we waited on the event, we have to
697 sync_set_event(sync_events
[index
]);
709 * ======== delete_strm ========
711 * Frees the resources allocated for a stream.
713 static int delete_strm(struct strm_object
*stream_obj
)
715 struct bridge_drv_interface
*intf_fxns
;
719 if (stream_obj
->chnl_obj
) {
720 intf_fxns
= stream_obj
->strm_mgr_obj
->intf_fxns
;
721 /* Channel close can fail only if the channel handle
723 status
= (*intf_fxns
->chnl_close
)
724 (stream_obj
->chnl_obj
);
726 /* Free all SM address translator resources */
727 kfree(stream_obj
->xlator
);