/* * ======== bridge_msg_delete_queue ======== * Delete a msg_ctrl queue allocated in bridge_msg_create_queue. */ void bridge_msg_delete_queue(struct msg_queue *msg_queue_obj) { struct msg_mgr *hmsg_mgr; u32 io_msg_pend; if (!msg_queue_obj || !msg_queue_obj->hmsg_mgr) goto func_end; hmsg_mgr = msg_queue_obj->hmsg_mgr; msg_queue_obj->done = true; /* Unblock all threads blocked in MSG_Get() or MSG_Put(). */ io_msg_pend = msg_queue_obj->io_msg_pend; while (io_msg_pend) { /* Unblock thread */ sync_set_event(msg_queue_obj->sync_done); /* Wait for acknowledgement */ sync_wait_on_event(msg_queue_obj->sync_done_ack, SYNC_INFINITE); io_msg_pend = msg_queue_obj->io_msg_pend; } /* Remove message queue from hmsg_mgr->queue_list */ spin_lock_bh(&hmsg_mgr->msg_mgr_lock); lst_remove_elem(hmsg_mgr->queue_list, (struct list_head *)msg_queue_obj); /* Free the message queue object */ delete_msg_queue(msg_queue_obj, msg_queue_obj->max_msgs); if (!hmsg_mgr->msg_free_list) goto func_cont; if (LST_IS_EMPTY(hmsg_mgr->msg_free_list)) sync_reset_event(hmsg_mgr->sync_event); func_cont: spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); func_end: return; }
/* * ======== bridge_msg_delete_queue ======== * Delete a msg_ctrl queue allocated in bridge_msg_create_queue. */ void bridge_msg_delete_queue(struct msg_queue *msg_queue_obj) { struct msg_mgr *hmsg_mgr; u32 io_msg_pend; if (!msg_queue_obj || !msg_queue_obj->msg_mgr) return; hmsg_mgr = msg_queue_obj->msg_mgr; msg_queue_obj->done = true; /* Unblock all threads blocked in MSG_Get() or MSG_Put(). */ io_msg_pend = msg_queue_obj->io_msg_pend; while (io_msg_pend) { /* Unblock thread */ sync_set_event(msg_queue_obj->sync_done); /* Wait for acknowledgement */ sync_wait_on_event(msg_queue_obj->sync_done_ack, SYNC_INFINITE); io_msg_pend = msg_queue_obj->io_msg_pend; } /* Remove message queue from hmsg_mgr->queue_list */ spin_lock_bh(&hmsg_mgr->msg_mgr_lock); list_del(&msg_queue_obj->list_elem); /* Free the message queue object */ delete_msg_queue(msg_queue_obj, msg_queue_obj->max_msgs); if (list_empty(&hmsg_mgr->msg_free_list)) sync_reset_event(hmsg_mgr->sync_event); spin_unlock_bh(&hmsg_mgr->msg_mgr_lock); }
/* * ======== bridge_chnl_get_ioc ======== * Optionally wait for I/O completion on a channel. Dequeue an I/O * completion record, which contains information about the completed * I/O request. * Note: Ensures Channel Invariant (see notes above). */ int bridge_chnl_get_ioc(struct chnl_object *chnl_obj, u32 dwTimeOut, OUT struct chnl_ioc *pIOC) { int status = 0; struct chnl_object *pchnl = (struct chnl_object *)chnl_obj; struct chnl_irp *chnl_packet_obj; int stat_sync; bool dequeue_ioc = true; struct chnl_ioc ioc = { NULL, 0, 0, 0, 0 }; u8 *host_sys_buf = NULL; struct wmd_dev_context *dev_ctxt; struct dev_object *dev_obj; /* Check args: */ if (pIOC == NULL) { status = -EFAULT; } else if (!pchnl) { status = -EFAULT; } else if (dwTimeOut == CHNL_IOCNOWAIT) { if (LST_IS_EMPTY(pchnl->pio_completions)) status = -EREMOTEIO; } dev_obj = dev_get_first(); dev_get_wmd_context(dev_obj, &dev_ctxt); if (!dev_ctxt) status = -EFAULT; if (DSP_FAILED(status)) goto func_end; ioc.status = CHNL_IOCSTATCOMPLETE; if (dwTimeOut != CHNL_IOCNOWAIT && LST_IS_EMPTY(pchnl->pio_completions)) { if (dwTimeOut == CHNL_IOCINFINITE) dwTimeOut = SYNC_INFINITE; stat_sync = sync_wait_on_event(pchnl->sync_event, dwTimeOut); if (stat_sync == -ETIME) { /* No response from DSP */ ioc.status |= CHNL_IOCSTATTIMEOUT; dequeue_ioc = false; } else if (stat_sync == -EPERM) { /* This can occur when the user mode thread is * aborted (^C), or when _VWIN32_WaitSingleObject() * fails due to unkown causes. */ /* Even though Wait failed, there may be something in * the Q: */ if (LST_IS_EMPTY(pchnl->pio_completions)) { ioc.status |= CHNL_IOCSTATCANCEL; dequeue_ioc = false; } } } /* See comment in AddIOReq */ spin_lock_bh(&pchnl->chnl_mgr_obj->chnl_mgr_lock); omap_mbox_disable_irq(dev_ctxt->mbox, IRQ_RX); if (dequeue_ioc) { /* Dequeue IOC and set pIOC; */ DBC_ASSERT(!LST_IS_EMPTY(pchnl->pio_completions)); chnl_packet_obj = (struct chnl_irp *)lst_get_head(pchnl->pio_completions); /* Update pIOC from channel state and chirp: */ if (chnl_packet_obj) { pchnl->cio_cs--; /* If this is a zero-copy channel, then set IOC's pbuf * to the DSP's address. This DSP address will get * translated to user's virtual addr later. */ { host_sys_buf = chnl_packet_obj->host_sys_buf; ioc.pbuf = chnl_packet_obj->host_user_buf; } ioc.byte_size = chnl_packet_obj->byte_size; ioc.buf_size = chnl_packet_obj->buf_size; ioc.dw_arg = chnl_packet_obj->dw_arg; ioc.status |= chnl_packet_obj->status; /* Place the used chirp on the free list: */ lst_put_tail(pchnl->free_packets_list, (struct list_head *)chnl_packet_obj); } else { ioc.pbuf = NULL; ioc.byte_size = 0; } } else { ioc.pbuf = NULL; ioc.byte_size = 0; ioc.dw_arg = 0; ioc.buf_size = 0; } /* Ensure invariant: If any IOC's are queued for this channel... */ if (!LST_IS_EMPTY(pchnl->pio_completions)) { /* Since DSPStream_Reclaim() does not take a timeout * parameter, we pass the stream's timeout value to * bridge_chnl_get_ioc. We cannot determine whether or not * we have waited in User mode. Since the stream's timeout * value may be non-zero, we still have to set the event. * Therefore, this optimization is taken out. * * if (dwTimeOut == CHNL_IOCNOWAIT) { * ... ensure event is set.. * sync_set_event(pchnl->sync_event); * } */ sync_set_event(pchnl->sync_event); } else { /* else, if list is empty, ensure event is reset. */ sync_reset_event(pchnl->sync_event); } omap_mbox_enable_irq(dev_ctxt->mbox, IRQ_RX); spin_unlock_bh(&pchnl->chnl_mgr_obj->chnl_mgr_lock); if (dequeue_ioc && (pchnl->chnl_type == CHNL_PCPY && pchnl->chnl_id > 1)) { if (!(ioc.pbuf < (void *)USERMODE_ADDR)) goto func_cont; /* If the addr is in user mode, then copy it */ if (!host_sys_buf || !ioc.pbuf) { status = -EFAULT; goto func_cont; } if (!CHNL_IS_INPUT(pchnl->chnl_mode)) goto func_cont1; /*host_user_buf */ status = copy_to_user(ioc.pbuf, host_sys_buf, ioc.byte_size); if (status) { if (current->flags & PF_EXITING) status = 0; } if (status) status = -EFAULT; func_cont1: kfree(host_sys_buf); } func_cont: /* Update User's IOC block: */ *pIOC = ioc; func_end: return status; }