/* * ======== strm_get_info ======== * Purpose: * Retrieves information about a stream. */ int strm_get_info(struct strm_object *stream_obj, struct stream_info *stream_info, u32 stream_info_size) { struct bridge_drv_interface *intf_fxns; struct chnl_info chnl_info_obj; int status = 0; void *virt_base = NULL; /* NULL if no SM used */ if (!stream_obj) { status = -EFAULT; } else { if (stream_info_size < sizeof(struct stream_info)) { /* size of users info */ status = -EINVAL; } } if (status) goto func_end; intf_fxns = stream_obj->strm_mgr_obj->intf_fxns; status = (*intf_fxns->chnl_get_info) (stream_obj->chnl_obj, &chnl_info_obj); if (status) goto func_end; if (stream_obj->xlator) { /* We have a translator */ cmm_xlator_info(stream_obj->xlator, (u8 **) &virt_base, 0, stream_obj->segment_id, false); } stream_info->segment_id = stream_obj->segment_id; stream_info->strm_mode = stream_obj->strm_mode; stream_info->virt_base = virt_base; stream_info->user_strm->number_bufs_allowed = stream_obj->num_bufs; stream_info->user_strm->number_bufs_in_stream = chnl_info_obj.cio_cs + chnl_info_obj.cio_reqs; /* # of bytes transferred since last call to DSPStream_Idle() */ stream_info->user_strm->number_bytes = chnl_info_obj.bytes_tx; stream_info->user_strm->sync_object_handle = chnl_info_obj.event_obj; /* Determine stream state based on channel state and info */ if (chnl_info_obj.state & CHNL_STATEEOS) { stream_info->user_strm->ss_stream_state = STREAM_DONE; } else { if (chnl_info_obj.cio_cs > 0) stream_info->user_strm->ss_stream_state = STREAM_READY; else if (chnl_info_obj.cio_reqs > 0) stream_info->user_strm->ss_stream_state = STREAM_PENDING; else stream_info->user_strm->ss_stream_state = STREAM_IDLE; } func_end: return status; }
/* * ======== strm_open ======== * Purpose: * Open a stream for sending/receiving data buffers to/from a task or * XDAIS socket node on the DSP. */ int strm_open(struct node_object *hnode, u32 dir, u32 index, struct strm_attr *pattr, struct strm_res_object **strmres, struct process_context *pr_ctxt) { struct strm_mgr *strm_mgr_obj; struct bridge_drv_interface *intf_fxns; u32 ul_chnl_id; struct strm_object *strm_obj = NULL; s8 chnl_mode; struct chnl_attr chnl_attr_obj; int status = 0; struct cmm_object *hcmm_mgr = NULL; /* Shared memory manager hndl */ void *stream_res; DBC_REQUIRE(refs > 0); DBC_REQUIRE(strmres != NULL); DBC_REQUIRE(pattr != NULL); *strmres = NULL; if (dir != DSP_TONODE && dir != DSP_FROMNODE) { status = -EPERM; } else { /* Get the channel id from the node (set in node_connect()) */ status = node_get_channel_id(hnode, dir, index, &ul_chnl_id); } if (!status) status = node_get_strm_mgr(hnode, &strm_mgr_obj); if (!status) { strm_obj = kzalloc(sizeof(struct strm_object), GFP_KERNEL); if (strm_obj == NULL) { status = -ENOMEM; } else { strm_obj->strm_mgr_obj = strm_mgr_obj; strm_obj->dir = dir; strm_obj->strm_state = STREAM_IDLE; strm_obj->user_event = pattr->user_event; if (pattr->stream_attr_in != NULL) { strm_obj->timeout = pattr->stream_attr_in->timeout; strm_obj->num_bufs = pattr->stream_attr_in->num_bufs; strm_obj->strm_mode = pattr->stream_attr_in->strm_mode; strm_obj->segment_id = pattr->stream_attr_in->segment_id; strm_obj->buf_alignment = pattr->stream_attr_in->buf_alignment; strm_obj->dma_chnl_id = pattr->stream_attr_in->dma_chnl_id; strm_obj->dma_priority = pattr->stream_attr_in->dma_priority; chnl_attr_obj.uio_reqs = pattr->stream_attr_in->num_bufs; } else { strm_obj->timeout = DEFAULTTIMEOUT; strm_obj->num_bufs = DEFAULTNUMBUFS; strm_obj->strm_mode = STRMMODE_PROCCOPY; strm_obj->segment_id = 0; /* local mem */ strm_obj->buf_alignment = 0; strm_obj->dma_chnl_id = 0; strm_obj->dma_priority = 0; chnl_attr_obj.uio_reqs = DEFAULTNUMBUFS; } chnl_attr_obj.reserved1 = NULL; /* DMA chnl flush timeout */ chnl_attr_obj.reserved2 = strm_obj->timeout; chnl_attr_obj.event_obj = NULL; if (pattr->user_event != NULL) chnl_attr_obj.event_obj = pattr->user_event; } } if (status) goto func_cont; if ((pattr->virt_base == NULL) || !(pattr->virt_size > 0)) goto func_cont; /* No System DMA */ DBC_ASSERT(strm_obj->strm_mode != STRMMODE_LDMA); /* Get the shared mem mgr for this streams dev object */ status = dev_get_cmm_mgr(strm_mgr_obj->dev_obj, &hcmm_mgr); if (!status) { /*Allocate a SM addr translator for this strm. */ status = cmm_xlator_create(&strm_obj->xlator, hcmm_mgr, NULL); if (!status) { DBC_ASSERT(strm_obj->segment_id > 0); /* Set translators Virt Addr attributes */ status = cmm_xlator_info(strm_obj->xlator, (u8 **) &pattr->virt_base, pattr->virt_size, strm_obj->segment_id, true); } } func_cont: if (!status) { /* Open channel */ chnl_mode = (dir == DSP_TONODE) ? CHNL_MODETODSP : CHNL_MODEFROMDSP; intf_fxns = strm_mgr_obj->intf_fxns; status = (*intf_fxns->chnl_open) (&(strm_obj->chnl_obj), strm_mgr_obj->chnl_mgr, chnl_mode, ul_chnl_id, &chnl_attr_obj); if (status) { /* * over-ride non-returnable status codes so we return * something documented */ if (status != -ENOMEM && status != -EINVAL && status != -EPERM) { /* * We got a status that's not return-able. * Assert that we got something we were * expecting (-EFAULT isn't acceptable, * strm_mgr_obj->chnl_mgr better be valid or we * assert here), and then return -EPERM. */ DBC_ASSERT(status == -ENOSR || status == -ECHRNG || status == -EALREADY || status == -EIO); status = -EPERM; } } } if (!status) { status = drv_proc_insert_strm_res_element(strm_obj, &stream_res, pr_ctxt); if (status) delete_strm(strm_obj); else *strmres = (struct strm_res_object *)stream_res; } else { (void)delete_strm(strm_obj); } /* ensure we return a documented error code */ DBC_ENSURE((!status && strm_obj) || (*strmres == NULL && (status == -EFAULT || status == -EPERM || status == -EINVAL))); dev_dbg(bridge, "%s: hnode: %p dir: 0x%x index: 0x%x pattr: %p " "strmres: %p status: 0x%x\n", __func__, hnode, dir, index, pattr, strmres, status); return status; }
/* * ======== node_alloc_msg_buf ======== * Purpose: * Allocates buffer for zero copy messaging. */ DBAPI node_alloc_msg_buf(struct node_object *hnode, u32 usize, struct dsp_bufferattr *pattr, u8 **pbuffer) { struct node_object *pnode = (struct node_object *)hnode; int status = 0; bool va_flag = false; bool set_info; u32 proc_id; DBC_REQUIRE(refs > 0); DBC_REQUIRE(pbuffer != NULL); DBC_REQUIRE(usize > 0); if (!pnode) status = -EFAULT; else if (node_get_type(pnode) == NODE_DEVICE) status = -EPERM; if (status) goto func_end; if (pattr == NULL) pattr = &node_dfltbufattrs; /* set defaults */ status = proc_get_processor_id(pnode->hprocessor, &proc_id); if (proc_id != DSP_UNIT) { DBC_ASSERT(NULL); goto func_end; } /* If segment ID includes MEM_SETVIRTUALSEGID then pbuffer is a * virt address, so set this info in this node's translator * object for future ref. If MEM_GETVIRTUALSEGID then retrieve * virtual address from node's translator. */ if ((pattr->segment_id & MEM_SETVIRTUALSEGID) || (pattr->segment_id & MEM_GETVIRTUALSEGID)) { va_flag = true; set_info = (pattr->segment_id & MEM_SETVIRTUALSEGID) ? true : false; /* Clear mask bits */ pattr->segment_id &= ~MEM_MASKVIRTUALSEGID; /* Set/get this node's translators virtual address base/size */ status = cmm_xlator_info(pnode->xlator, pbuffer, usize, pattr->segment_id, set_info); } if (!status && (!va_flag)) { if (pattr->segment_id != 1) { /* Node supports single SM segment only. */ status = -EBADR; } /* Arbitrary SM buffer alignment not supported for host side * allocs, but guaranteed for the following alignment * values. */ switch (pattr->buf_alignment) { case 0: case 1: case 2: case 4: break; default: /* alignment value not suportted */ status = -EPERM; break; } if (!status) { /* allocate physical buffer from seg_id in node's * translator */ (void)cmm_xlator_alloc_buf(pnode->xlator, pbuffer, usize); if (*pbuffer == NULL) { pr_err("%s: error - Out of shared memory\n", __func__); status = -ENOMEM; } } } func_end: return status; }