/**
 * crystalhd_create_dioq - Create Generic DIO queue
 * @adp: Adapter instance
 * @dioq_hnd: Handle to the dio queue created
 * @cb	: Optional - Call back To free the element.
 * @cbctx: Context to pass to callback.
 *
 * Return:
 *  status
 *
 * Initialize Generic DIO queue to hold any data. Callback
 * will be used to free elements while deleting the queue.
 */
BC_STATUS crystalhd_create_dioq(struct crystalhd_adp *adp,
                                crystalhd_dioq_t **dioq_hnd,
                                crystalhd_data_free_cb cb, void *cbctx)
{
    crystalhd_dioq_t *dioq = NULL;

    if (!adp || !dioq_hnd) {
        printk(KERN_ERR "%s: Invalid arg\n", __func__);
        return BC_STS_INV_ARG;
    }
#ifndef __APPLE__
    dioq = kzalloc(sizeof(*dioq), GFP_KERNEL);
#else
    dioq = (crystalhd_dioq_t*)kzalloc(sizeof(*dioq), GFP_KERNEL);
#endif
    if (!dioq)
        return BC_STS_INSUFF_RES;

    spin_lock_init(&dioq->lock);
    dioq->sig = BC_LINK_DIOQ_SIG;
    dioq->head = (crystalhd_elem_t *)&dioq->head;
    dioq->tail = (crystalhd_elem_t *)&dioq->head;
    crystalhd_create_event(&dioq->event);
    dioq->adp = adp;
    dioq->data_rel_cb = cb;
    dioq->cb_context = cbctx;
    *dioq_hnd = dioq;

    return BC_STS_SUCCESS;
}
static enum BC_STATUS bc_cproc_codein_sleep(struct crystalhd_cmd *ctx)
{
	wait_queue_head_t sleep_ev;
	int rc = 0;

	if (ctx->state & BC_LINK_SUSPEND)
		return BC_STS_IO_USER_ABORT;

	if (ctx->cin_wait_exit) {
		ctx->cin_wait_exit = 0;
		return BC_STS_CMD_CANCELLED;
	}
	crystalhd_create_event(&sleep_ev);
	crystalhd_wait_on_event(&sleep_ev, 0, 100, rc, 0);
	if (rc == -EINTR)
		return BC_STS_IO_USER_ABORT;

	return BC_STS_SUCCESS;
}
static enum BC_STATUS bc_cproc_hw_txdma(struct crystalhd_cmd *ctx,
				   struct crystalhd_ioctl_data *idata,
				   struct crystalhd_dio_req *dio)
{
	uint32_t tx_listid = 0;
	enum BC_STATUS sts = BC_STS_SUCCESS;
	wait_queue_head_t event;
	int rc = 0;

	if (!ctx || !idata || !dio) {
		BCMLOG_ERR("Invalid Arg!!\n");
		return BC_STS_INV_ARG;
	}

	crystalhd_create_event(&event);

	ctx->tx_list_id = 0;
	/* msleep_interruptible(2000); */
	sts = crystalhd_hw_post_tx(&ctx->hw_ctx, dio, bc_proc_in_completion,
				 &event, &tx_listid,
				 idata->udata.u.ProcInput.Encrypted);

	while (sts == BC_STS_BUSY) {
		sts = bc_cproc_codein_sleep(ctx);
		if (sts != BC_STS_SUCCESS)
			break;
		sts = crystalhd_hw_post_tx(&ctx->hw_ctx, dio,
					 bc_proc_in_completion,
					 &event, &tx_listid,
					 idata->udata.u.ProcInput.Encrypted);
	}
	if (sts != BC_STS_SUCCESS) {
		BCMLOG(BCMLOG_DBG, "_hw_txdma returning sts:%d\n", sts);
		return sts;
	}
	if (ctx->cin_wait_exit)
		ctx->cin_wait_exit = 0;

	ctx->tx_list_id = tx_listid;

	/* _post() succeeded.. wait for the completion. */
	crystalhd_wait_on_event(&event, (dio->uinfo.ev_sts), 3000, rc, 0);
	ctx->tx_list_id = 0;
	if (!rc) {
		return dio->uinfo.comp_sts;
	} else if (rc == -EBUSY) {
		BCMLOG(BCMLOG_DBG, "_tx_post() T/O\n");
		sts = BC_STS_TIMEOUT;
	} else if (rc == -EINTR) {
		BCMLOG(BCMLOG_DBG, "Tx Wait Signal int.\n");
		sts = BC_STS_IO_USER_ABORT;
	} else {
		sts = BC_STS_IO_ERROR;
	}

	/* We are cancelling the IO from the same context as the _post().
	 * so no need to wait on the event again.. the return itself
	 * ensures the release of our resources.
	 */
	crystalhd_hw_cancel_tx(&ctx->hw_ctx, tx_listid);

	return sts;
}