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;
109 * Allocate from segment specified at time of stream open.
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],
125 if (ap_buffer[i] == NULL) {
132 strm_free_buffer(strmres, ap_buffer, alloc_cnt, pr_ctxt);
137 drv_proc_update_strm_res(num_bufs, strmres);
144 * ======== strm_close ========
146 * Close a stream opened with strm_open().
148 int strm_close(struct strm_res_object *strmres,
149 struct process_context *pr_ctxt)
151 struct bridge_drv_interface *intf_fxns;
152 struct chnl_info chnl_info_obj;
154 struct strm_object *stream_obj = strmres->stream;
159 /* Have all buffers been reclaimed? If not, return
161 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
163 (*intf_fxns->chnl_get_info) (stream_obj->chnl_obj,
167 if (chnl_info_obj.cio_cs > 0 || chnl_info_obj.cio_reqs > 0)
170 status = delete_strm(stream_obj);
176 idr_remove(pr_ctxt->stream_id, strmres->id);
178 dev_dbg(bridge, "%s: stream_obj: %p, status 0x%x\n", __func__,
184 * ======== strm_create ========
186 * Create a STRM manager object.
188 int strm_create(struct strm_mgr **strm_man,
189 struct dev_object *dev_obj)
191 struct strm_mgr *strm_mgr_obj;
195 /* Allocate STRM manager object */
196 strm_mgr_obj = kzalloc(sizeof(struct strm_mgr), GFP_KERNEL);
197 if (strm_mgr_obj == NULL)
200 strm_mgr_obj->dev_obj = dev_obj;
202 /* Get Channel manager and Bridge function interface */
204 status = dev_get_chnl_mgr(dev_obj, &(strm_mgr_obj->chnl_mgr));
206 (void)dev_get_intf_fxns(dev_obj,
207 &(strm_mgr_obj->intf_fxns));
208 DBC_ASSERT(strm_mgr_obj->intf_fxns != NULL);
213 *strm_man = strm_mgr_obj;
221 * ======== strm_delete ========
223 * Delete the STRM Manager Object.
225 void strm_delete(struct strm_mgr *strm_mgr_obj)
231 * ======== strm_exit ========
233 * Discontinue usage of STRM module.
241 * ======== strm_free_buffer ========
243 * Frees the buffers allocated for a stream.
245 int strm_free_buffer(struct strm_res_object *strmres, u8 ** ap_buffer,
246 u32 num_bufs, struct process_context *pr_ctxt)
250 struct strm_object *stream_obj = strmres->stream;
256 for (i = 0; i < num_bufs; i++) {
257 DBC_ASSERT(stream_obj->xlator != NULL);
259 cmm_xlator_free_buf(stream_obj->xlator,
266 drv_proc_update_strm_res(num_bufs - i, strmres);
272 * ======== strm_get_info ========
274 * Retrieves information about a stream.
276 int strm_get_info(struct strm_object *stream_obj,
277 struct stream_info *stream_info,
278 u32 stream_info_size)
280 struct bridge_drv_interface *intf_fxns;
281 struct chnl_info chnl_info_obj;
283 void *virt_base = NULL; /* NULL if no SM used */
288 if (stream_info_size < sizeof(struct stream_info)) {
289 /* size of users info */
296 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
298 (*intf_fxns->chnl_get_info) (stream_obj->chnl_obj,
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);
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;
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 =
328 stream_info->user_strm->ss_stream_state = STREAM_IDLE;
336 * ======== strm_idle ========
338 * Idles a particular stream.
340 int strm_idle(struct strm_object *stream_obj, bool flush_data)
342 struct bridge_drv_interface *intf_fxns;
348 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
350 status = (*intf_fxns->chnl_idle) (stream_obj->chnl_obj,
355 dev_dbg(bridge, "%s: stream_obj: %p flush_data: 0x%x status: 0x%x\n",
356 __func__, stream_obj, flush_data, status);
361 * ======== strm_init ========
363 * Initialize the STRM module.
376 * ======== strm_issue ========
378 * Issues a buffer on a stream
380 int strm_issue(struct strm_object *stream_obj, u8 *pbuf, u32 ul_bytes,
381 u32 ul_buf_size, u32 dw_arg)
383 struct bridge_drv_interface *intf_fxns;
385 void *tmp_buf = NULL;
390 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
392 if (stream_obj->segment_id != 0) {
393 tmp_buf = cmm_xlator_translate(stream_obj->xlator,
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);
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);
416 * ======== strm_open ========
418 * Open a stream for sending/receiving data buffers to/from a task or
419 * XDAIS socket node on the DSP.
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)
426 struct strm_mgr *strm_mgr_obj;
427 struct bridge_drv_interface *intf_fxns;
429 struct strm_object *strm_obj = NULL;
431 struct chnl_attr chnl_attr_obj;
433 struct cmm_object *hcmm_mgr = NULL; /* Shared memory manager hndl */
438 if (dir != DSP_TONODE && dir != DSP_FROMNODE) {
441 /* Get the channel id from the node (set in node_connect()) */
442 status = node_get_channel_id(hnode, dir, index, &ul_chnl_id);
445 status = node_get_strm_mgr(hnode, &strm_mgr_obj);
448 strm_obj = kzalloc(sizeof(struct strm_object), GFP_KERNEL);
449 if (strm_obj == NULL) {
452 strm_obj->strm_mgr_obj = strm_mgr_obj;
454 strm_obj->strm_state = STREAM_IDLE;
455 strm_obj->user_event = pattr->user_event;
456 if (pattr->stream_attr_in != NULL) {
458 pattr->stream_attr_in->timeout;
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;
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;
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;
495 if ((pattr->virt_base == NULL) || !(pattr->virt_size > 0))
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);
503 /*Allocate a SM addr translator for this strm. */
504 status = cmm_xlator_create(&strm_obj->xlator, hcmm_mgr, NULL);
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,
511 strm_obj->segment_id, true);
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,
526 * over-ride non-returnable status codes so we return
527 * something documented
529 if (status != -ENOMEM && status !=
530 -EINVAL && status != -EPERM) {
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.
538 DBC_ASSERT(status == -ENOSR ||
540 status == -EALREADY ||
547 status = drv_proc_insert_strm_res_element(strm_obj,
548 &stream_res, pr_ctxt);
550 delete_strm(strm_obj);
552 *strmres = (struct strm_res_object *)stream_res;
554 (void)delete_strm(strm_obj);
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);
564 * ======== strm_reclaim ========
566 * Relcaims a buffer from a stream.
568 int strm_reclaim(struct strm_object *stream_obj, u8 ** buf_ptr,
569 u32 *nbytes, u32 *buff_size, u32 *pdw_arg)
571 struct bridge_drv_interface *intf_fxns;
572 struct chnl_ioc chnl_ioc_obj;
574 void *tmp_buf = NULL;
580 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
583 (*intf_fxns->chnl_get_ioc) (stream_obj->chnl_obj,
587 *nbytes = chnl_ioc_obj.byte_size;
589 *buff_size = chnl_ioc_obj.buf_size;
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)) {
596 /* Allow reclaims after idle to succeed */
597 if (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj))
602 /* Translate zerocopy buffer if channel not canceled. */
604 && (!CHNL_IS_IO_CANCELLED(chnl_ioc_obj))
605 && (stream_obj->strm_mode == STRMMODE_ZEROCOPY)) {
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
611 * Note: Could add CMM_DSPPA2VA to CMM in the future.
613 tmp_buf = cmm_xlator_translate(stream_obj->xlator,
616 if (tmp_buf != NULL) {
617 /* now convert this GPP Pa to Va */
618 tmp_buf = cmm_xlator_translate(stream_obj->
626 chnl_ioc_obj.buf = tmp_buf;
628 *buf_ptr = chnl_ioc_obj.buf;
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);
638 * ======== strm_register_notify ========
640 * Register to be notified on specific events for this stream.
642 int strm_register_notify(struct strm_object *stream_obj, u32 event_mask,
643 u32 notify_type, struct dsp_notification
646 struct bridge_drv_interface *intf_fxns;
651 } else if ((event_mask & ~((DSP_STREAMIOCOMPLETION) |
652 DSP_STREAMDONE)) != 0) {
655 if (notify_type != DSP_SIGNALEVENT)
660 intf_fxns = stream_obj->strm_mgr_obj->intf_fxns;
663 (*intf_fxns->chnl_register_notify) (stream_obj->
674 * ======== strm_select ========
676 * Selects a ready stream.
678 int strm_select(struct strm_object **strm_tab, u32 strms,
679 u32 *pmask, u32 utimeout)
682 struct chnl_info chnl_info_obj;
683 struct bridge_drv_interface *intf_fxns;
684 struct sync_object **sync_events = NULL;
689 for (i = 0; i < strms; i++) {
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,
706 if (chnl_info_obj.cio_cs > 0)
711 if (!status && utimeout > 0 && *pmask == 0) {
712 /* Non-zero timeout */
713 sync_events = kmalloc(strms * sizeof(struct sync_object *),
716 if (sync_events == NULL) {
719 for (i = 0; i < strms; i++) {
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);
728 chnl_info_obj.sync_event;
734 sync_wait_on_multiple_events(sync_events, strms,
737 /* Since we waited on the event, we have to
739 sync_set_event(sync_events[index]);
751 * ======== delete_strm ========
753 * Frees the resources allocated for a stream.
755 static int delete_strm(struct strm_object *stream_obj)
757 struct bridge_drv_interface *intf_fxns;
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
765 status = (*intf_fxns->chnl_close)
766 (stream_obj->chnl_obj);
768 /* Free all SM address translator resources */
769 kfree(stream_obj->xlator);