Пример #1
0
enum MHI_STATUS start_chan_sync(struct mhi_client_handle *client_handle)
{
	enum MHI_STATUS ret_val = MHI_STATUS_SUCCESS;
	int chan = client_handle->chan_info.chan_nr;
	int r = 0;

	init_completion(&client_handle->chan_open_complete);
	ret_val = mhi_send_cmd(client_handle->mhi_dev_ctxt,
			       MHI_COMMAND_START_CHAN,
			       chan);
	if (ret_val != MHI_STATUS_SUCCESS) {
		mhi_log(MHI_MSG_ERROR,
			"Failed to send start command for chan %d ret %d\n",
			chan, ret_val);
		return ret_val;
	}
	r = wait_for_completion_timeout(
			&client_handle->chan_open_complete,
			msecs_to_jiffies(MHI_MAX_CMD_TIMEOUT));
	if (!r) {
		mhi_log(MHI_MSG_ERROR,
			   "Timed out waiting for chan %d start completion\n",
			    chan);
		ret_val = MHI_STATUS_ERROR;
	}
	return ret_val;
}
Пример #2
0
MHI_STATUS parse_inbound(mhi_device_ctxt *mhi_dev_ctxt, u32 chan,
			mhi_xfer_pkt *local_ev_trb_loc, u16 xfer_len)
{
	mhi_client_handle *client_handle;
	mhi_ring *local_chan_ctxt;
	mhi_result *result;
	mhi_cb_info cb_info;

	client_handle = mhi_dev_ctxt->client_handle_list[chan];
	local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan];

	if (unlikely(mhi_dev_ctxt->mhi_local_chan_ctxt[chan].rp ==
	    mhi_dev_ctxt->mhi_local_chan_ctxt[chan].wp)) {
		mhi_dev_ctxt->mhi_chan_cntr[chan].empty_ring_removal++;
		mhi_wait_for_mdm(mhi_dev_ctxt);
		return mhi_send_cmd(mhi_dev_ctxt,
				    MHI_COMMAND_RESET_CHAN,
				    chan);
	}

	if (NULL != mhi_dev_ctxt->client_handle_list[chan])
		result = &mhi_dev_ctxt->client_handle_list[chan]->result;

	/* If a client is registered */
	if (unlikely(IS_SOFTWARE_CHANNEL(chan))) {
		MHI_TX_TRB_SET_LEN(TX_TRB_LEN,
		local_ev_trb_loc,
		xfer_len);
		ctxt_del_element(local_chan_ctxt, NULL);
		if (NULL != client_handle->client_info.mhi_client_cb &&
		   (0 == (client_handle->pkt_count % client_handle->cb_mod))) {
			cb_info.cb_reason = MHI_CB_XFER_SUCCESS;
			cb_info.result = &client_handle->result;
			cb_info.result->transaction_status =
					MHI_STATUS_SUCCESS;
			client_handle->client_info.mhi_client_cb(&cb_info);
		}
	} else  {
		/* IN Hardware channel with no client
		 * registered, we are done with this TRB*/
		if (likely(NULL != client_handle)) {
			ctxt_del_element(local_chan_ctxt, NULL);
		/* A client is not registred for this IN channel */
		} else  {/* Hardware Channel, no client registerered,
				drop data */
			recycle_trb_and_ring(mhi_dev_ctxt,
				 &mhi_dev_ctxt->mhi_local_chan_ctxt[chan],
				 MHI_RING_TYPE_XFER_RING,
				 chan);
		}
	}
	return MHI_STATUS_SUCCESS;
}
Пример #3
0
MHI_STATUS reset_chan_cmd(mhi_device_ctxt *mhi_dev_ctxt, mhi_cmd_pkt *cmd_pkt)
{
	u32 chan  = 0;
	MHI_STATUS ret_val = MHI_STATUS_SUCCESS;
	mhi_ring *local_chan_ctxt;
	mhi_chan_ctxt *chan_ctxt;
	mhi_client_handle *client_handle = NULL;
	struct mutex *chan_mutex;

	MHI_TRB_GET_INFO(CMD_TRB_CHID, cmd_pkt, chan);

	if (!VALID_CHAN_NR(chan)) {
		mhi_log(MHI_MSG_ERROR,
			"Bad channel number for CCE\n");
		return MHI_STATUS_ERROR;
	}

	chan_mutex = &mhi_dev_ctxt->mhi_chan_mutex[chan];
	mutex_lock(chan_mutex);
	client_handle = mhi_dev_ctxt->client_handle_list[chan];
	local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
	chan_ctxt = &mhi_dev_ctxt->mhi_ctrl_seg->mhi_cc_list[chan];
	mhi_log(MHI_MSG_INFO, "Processed cmd reset event\n");

	/* Reset the local channel context */
	local_chan_ctxt->rp = local_chan_ctxt->base;
	local_chan_ctxt->wp = local_chan_ctxt->base;
	local_chan_ctxt->ack_rp = local_chan_ctxt->base;

	/* Reset the mhi channel context */
	chan_ctxt->mhi_chan_state = MHI_CHAN_STATE_ENABLED;
	chan_ctxt->mhi_trb_read_ptr = chan_ctxt->mhi_trb_ring_base_addr;
	chan_ctxt->mhi_trb_write_ptr = chan_ctxt->mhi_trb_ring_base_addr;

	mhi_dev_ctxt->mhi_chan_pend_cmd_ack[chan] = MHI_CMD_NOT_PENDING;
	mutex_unlock(chan_mutex);
	mhi_log(MHI_MSG_INFO, "Reset complete starting channel back up.\n");
	if (MHI_STATUS_SUCCESS != mhi_send_cmd(mhi_dev_ctxt,
						MHI_COMMAND_START_CHAN,
						chan))
		mhi_log(MHI_MSG_CRITICAL, "Failed to restart channel.\n");
	if (NULL != client_handle)
		complete(&client_handle->chan_close_complete);
	return ret_val;
}
Пример #4
0
MHI_STATUS parse_outbound(mhi_device_ctxt *mhi_dev_ctxt, u32 chan,
			mhi_xfer_pkt *local_ev_trb_loc, u16 xfer_len)
{
	mhi_result *result = NULL;
	MHI_STATUS ret_val = 0;
	mhi_client_handle *client_handle = NULL;
	mhi_ring *local_chan_ctxt = NULL;
	mhi_cb_info cb_info;
	local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
	client_handle = mhi_dev_ctxt->client_handle_list[chan];

	/* If ring is empty */
	if (mhi_dev_ctxt->mhi_local_chan_ctxt[chan].rp ==
	    mhi_dev_ctxt->mhi_local_chan_ctxt[chan].wp) {
		mhi_dev_ctxt->mhi_chan_cntr[chan].empty_ring_removal++;
		mhi_wait_for_mdm(mhi_dev_ctxt);
		return mhi_send_cmd(mhi_dev_ctxt,
					MHI_COMMAND_RESET_CHAN,
					chan);
	}

	if (NULL != client_handle) {
		result = &mhi_dev_ctxt->client_handle_list[chan]->result;

		if (NULL != (&client_handle->client_info.mhi_client_cb) &&
		   (0 == (client_handle->pkt_count % client_handle->cb_mod))) {
			cb_info.cb_reason = MHI_CB_XFER_SUCCESS;
			cb_info.result = &client_handle->result;
			cb_info.result->transaction_status =
					MHI_STATUS_SUCCESS;
			client_handle->client_info.mhi_client_cb(&cb_info);
		}
	}
	ret_val = ctxt_del_element(&mhi_dev_ctxt->mhi_local_chan_ctxt[chan],
						NULL);
	atomic_dec(&mhi_dev_ctxt->counters.outbound_acks);
	mhi_log(MHI_MSG_VERBOSE,
		"Processed outbound ack chan %d Pending acks %d.\n",
		chan, atomic_read(&mhi_dev_ctxt->counters.outbound_acks));
	return MHI_STATUS_SUCCESS;
}
Пример #5
0
MHI_STATUS process_SBL_transition(mhi_device_ctxt *mhi_dev_ctxt,
		STATE_TRANSITION cur_work_item)
{
	MHI_STATUS ret_val;
	u32 chan;
	mhi_chan_ctxt *chan_ctxt;
	mhi_log(MHI_MSG_INFO, "Processing SBL state transition\n");
	for (chan = 0; chan <= MHI_CLIENT_SAHARA_IN; ++chan)
	{
		chan_ctxt =
			&mhi_dev_ctxt->mhi_ctrl_seg->mhi_cc_list[chan];
		if (MHI_CHAN_STATE_ENABLED == chan_ctxt->mhi_chan_state ) {
			ret_val = mhi_send_cmd(mhi_dev_ctxt,
						MHI_COMMAND_START_CHAN,
						chan);
			if (MHI_STATUS_SUCCESS != ret_val) {
				mhi_log(MHI_MSG_VERBOSE,
					"Starting Channel 0x%x \n", chan);
				mhi_log(MHI_MSG_CRITICAL,
					"Failed to start chan0x%x, ret 0x%x\n",
					chan, ret_val);
				return MHI_STATUS_ERROR;
			} else {
					atomic_inc(
					&mhi_dev_ctxt->start_cmd_pending_ack);
			}
		}
		wait_event_interruptible(*mhi_dev_ctxt->chan_start_complete,
		atomic_read(&mhi_dev_ctxt->start_cmd_pending_ack) == 0);
	}

	if (!mhi_dev_ctxt->flags.mhi_clients_probed) {
		ret_val = probe_clients(mhi_dev_ctxt, cur_work_item);
	}

	return MHI_STATUS_SUCCESS;
}
Пример #6
0
MHI_STATUS process_AMSS_transition(mhi_device_ctxt *mhi_dev_ctxt,
				STATE_TRANSITION cur_work_item)
{
	MHI_STATUS ret_val;
	u32 chan;
	unsigned long flags;
	mhi_chan_ctxt *chan_ctxt;
	mhi_log(MHI_MSG_INFO, "Processing AMSS state transition\n");
	write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags);
	atomic_inc(&mhi_dev_ctxt->flags.data_pending);
	mhi_assert_device_wake(mhi_dev_ctxt);

	write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags);
	ret_val = mhi_add_elements_to_event_rings(mhi_dev_ctxt,
			cur_work_item);
	if (MHI_STATUS_SUCCESS != ret_val)
		return MHI_STATUS_ERROR;
	for (chan = 0; chan <= MHI_MAX_CHANNELS; ++chan) {
		if (VALID_CHAN_NR(chan)) {
			chan_ctxt =
				&mhi_dev_ctxt->mhi_ctrl_seg->mhi_cc_list[chan];
			if (MHI_CHAN_STATE_ENABLED ==
						chan_ctxt->mhi_chan_state) {
				mhi_log(MHI_MSG_INFO,
					"Starting Channel 0x%x \n", chan);
				ret_val = mhi_send_cmd(mhi_dev_ctxt,
						MHI_COMMAND_START_CHAN,
						chan);
				if (MHI_STATUS_SUCCESS != ret_val) {
					mhi_log(MHI_MSG_CRITICAL,
							"Failed to start chan0x%x,0x%x\n",
							chan, ret_val);
					return MHI_STATUS_ERROR;
				} else {
					atomic_inc(
							&mhi_dev_ctxt->start_cmd_pending_ack);
				}
			}
		}
	}
	mhi_log(MHI_MSG_INFO, "Waiting for cmd completions\n");
	wait_event_interruptible(*mhi_dev_ctxt->chan_start_complete,
			atomic_read(&mhi_dev_ctxt->start_cmd_pending_ack) == 0);
	if (0 == mhi_dev_ctxt->flags.mhi_initialized) {

		mhi_dev_ctxt->flags.mhi_initialized = 1;
		ret_val = mhi_set_state_of_all_channels(mhi_dev_ctxt,
				MHI_CHAN_STATE_RUNNING);
		if (MHI_STATUS_SUCCESS != ret_val)
			mhi_log(MHI_MSG_CRITICAL,
					"Failed to set local chan state\n");
		if (!mhi_dev_ctxt->flags.mhi_clients_probed) {
			ret_val = probe_clients(mhi_dev_ctxt, cur_work_item);
			if (ret_val != MHI_STATUS_SUCCESS)
				mhi_log(MHI_MSG_CRITICAL,
						"Failed to probe MHI CORE clients.\n");
			mhi_dev_ctxt->flags.mhi_clients_probed = 1;

			ring_all_ev_dbs(mhi_dev_ctxt);
			ring_all_chan_dbs(mhi_dev_ctxt);
			ring_all_cmd_dbs(mhi_dev_ctxt);

		} else {
			ring_all_chan_dbs(mhi_dev_ctxt);
			mhi_log(MHI_MSG_CRITICAL,
					"Notifying clients that MHI is enabled\n");
			mhi_notify_clients(mhi_dev_ctxt,
					MHI_CB_MHI_ENABLED);
		}
		if (ret_val != MHI_STATUS_SUCCESS)
			mhi_log(MHI_MSG_CRITICAL,
					"Failed to probe MHI CORE clients, ret 0x%x \n",
					ret_val);
	}
	atomic_dec(&mhi_dev_ctxt->flags.data_pending);
	mhi_log(MHI_MSG_INFO, "Exited\n");
	return MHI_STATUS_SUCCESS;
}