Esempio n. 1
0
MHI_STATUS parse_cmd_event(mhi_device_ctxt *mhi_dev_ctxt, mhi_event_pkt *ev_pkt)
{
	MHI_STATUS ret_val = MHI_STATUS_SUCCESS;
	mhi_cmd_pkt *cmd_pkt = NULL;
	uintptr_t phy_trb_loc = 0;
	if (NULL != ev_pkt)
		phy_trb_loc = (uintptr_t)MHI_EV_READ_PTR(EV_PTR,
							ev_pkt);
	else
		return MHI_STATUS_ERROR;

	cmd_pkt = (mhi_cmd_pkt *)mhi_p2v_addr(mhi_dev_ctxt->mhi_ctrl_seg_info,
							phy_trb_loc);
	mhi_log(MHI_MSG_INFO, "Received CMD completion event\n");
	switch (MHI_EV_READ_CODE(EV_TRB_CODE, ev_pkt)) {
		/* Command completion was successful */
	case MHI_EVENT_CC_SUCCESS:
	{
		u32 chan;
		MHI_TRB_GET_INFO(CMD_TRB_CHID, cmd_pkt, chan);
		switch (MHI_TRB_READ_INFO(CMD_TRB_TYPE, cmd_pkt)) {
		case MHI_PKT_TYPE_NOOP_CMD:
			mhi_log(MHI_MSG_INFO, "Processed NOOP cmd event\n");
			break;
		case MHI_PKT_TYPE_RESET_CHAN_CMD:
			if (MHI_STATUS_SUCCESS != reset_chan_cmd(mhi_dev_ctxt,
								cmd_pkt))
				mhi_log(MHI_MSG_INFO,
					"Failed to process reset cmd\n");
		break;
		case MHI_PKT_TYPE_STOP_CHAN_CMD:
		{

			mhi_log(MHI_MSG_INFO, "Processed cmd stop event\n");
			if (MHI_STATUS_SUCCESS != ret_val) {
				mhi_log(MHI_MSG_INFO,
						"Failed to set chan state\n");
				return MHI_STATUS_ERROR;
			}
			break;
		}
		case MHI_PKT_TYPE_START_CHAN_CMD:
		{
			if (MHI_STATUS_SUCCESS != start_chan_cmd(mhi_dev_ctxt,
								cmd_pkt))
				mhi_log(MHI_MSG_INFO,
					"Failed to process reset cmd\n");
			atomic_dec(&mhi_dev_ctxt->start_cmd_pending_ack);
			wake_up_interruptible(mhi_dev_ctxt->chan_start_complete);
			break;
		}
		default:
			mhi_log(MHI_MSG_INFO,
				"Bad cmd type 0x%x\n",
				MHI_TRB_READ_INFO(CMD_TRB_TYPE, cmd_pkt));
			break;
		}
		mhi_log(MHI_MSG_INFO, "CMD completion indicated successful\n");
		mhi_dev_ctxt->mhi_chan_pend_cmd_ack[chan] = MHI_CMD_NOT_PENDING;
		break;
	}
	default:
		mhi_log(MHI_MSG_INFO, "Unhandled mhi completion code\n");
		break;
	}
	mhi_log(MHI_MSG_INFO, "Recycling cmd event\n");
	ctxt_del_element(mhi_dev_ctxt->mhi_local_cmd_ctxt, NULL);
	return MHI_STATUS_SUCCESS;
}
MHI_STATUS mhi_process_event_ring(mhi_device_ctxt *mhi_dev_ctxt,
		u32 ev_index,
		u32 event_quota)
{
	mhi_event_pkt *local_rp = NULL;
	mhi_event_pkt *device_rp = NULL;
	mhi_event_pkt event_to_process;
	mhi_event_ctxt *ev_ctxt = NULL;
	mhi_ring *local_ev_ctxt =
		&mhi_dev_ctxt->mhi_local_event_ctxt[ev_index];

	ev_ctxt = &mhi_dev_ctxt->mhi_ctrl_seg->mhi_ec_list[ev_index];

	device_rp =
		(mhi_event_pkt *)mhi_p2v_addr(mhi_dev_ctxt->mhi_ctrl_seg_info,
				ev_ctxt->mhi_event_read_ptr);
	local_rp = (mhi_event_pkt *)local_ev_ctxt->rp;


	if (unlikely(MHI_STATUS_SUCCESS != validate_ev_el_addr(local_ev_ctxt,
					(uintptr_t)device_rp)))
		mhi_log(MHI_MSG_ERROR,
				"Failed to validate event ring element 0x%p\n",
				device_rp);


	while ((local_rp != device_rp) && (event_quota > 0) &&
			(device_rp != NULL) && (local_rp != NULL)) {
		event_to_process = *local_rp;
		if (unlikely(MHI_STATUS_SUCCESS != recycle_trb_and_ring(mhi_dev_ctxt,
						local_ev_ctxt,
						MHI_RING_TYPE_EVENT_RING,
						ev_index)))
			mhi_log(MHI_MSG_ERROR, "Failed to recycle ev pkt\n");
		switch (MHI_TRB_READ_INFO(EV_TRB_TYPE, (&event_to_process))) {
			case MHI_PKT_TYPE_CMD_COMPLETION_EVENT:
				mhi_log(MHI_MSG_INFO,
						"MHI CCE received ring 0x%x\n",
						ev_index);
				__pm_stay_awake(&mhi_dev_ctxt->wake_lock);
				__pm_relax(&mhi_dev_ctxt->wake_lock);
				parse_cmd_event(mhi_dev_ctxt,
						&event_to_process);
				break;
			case MHI_PKT_TYPE_TX_EVENT:
				{
					u32 chan = MHI_EV_READ_CHID(EV_CHID, &event_to_process);

					if (((MHI_EV_READ_CODE(EV_TRB_CODE, &event_to_process) ==
									MHI_EVENT_CC_OOB) ||
						(MHI_EV_READ_CODE(EV_TRB_CODE, &event_to_process) ==
									 MHI_EVENT_CC_DB_MODE)) &&
							(chan == MHI_CLIENT_IP_HW_0_OUT) &&
							(mhi_dev_ctxt->mhi_local_chan_ctxt[chan].rp ==
							 mhi_dev_ctxt->mhi_local_chan_ctxt[chan].wp))
					{
						mhi_log(MHI_MSG_VERBOSE, "Empty OOB chan %d\n", chan);
						parse_xfer_event(mhi_dev_ctxt, &event_to_process);
					} else {
				                __pm_stay_awake(&mhi_dev_ctxt->wake_lock);
				                parse_xfer_event(mhi_dev_ctxt, &event_to_process);
			                   	__pm_relax(&mhi_dev_ctxt->wake_lock);
					}
				}
				break;
			case MHI_PKT_TYPE_STATE_CHANGE_EVENT:
				{
					STATE_TRANSITION new_state;
					new_state = MHI_READ_STATE(&event_to_process);
					mhi_log(MHI_MSG_INFO,
							"MHI STE received ring 0x%x\n",
							ev_index);
					mhi_init_state_transition(mhi_dev_ctxt, new_state);
					break;
				}
			case MHI_PKT_TYPE_EE_EVENT:
				{
					STATE_TRANSITION new_state;
					mhi_log(MHI_MSG_INFO,
							"MHI EEE received ring 0x%x\n",
							ev_index);
					__pm_stay_awake(&mhi_dev_ctxt->wake_lock);
					__pm_relax(&mhi_dev_ctxt->wake_lock);
					switch(MHI_READ_EXEC_ENV(&event_to_process)) {
						case MHI_EXEC_ENV_SBL:
							new_state = STATE_TRANSITION_SBL;
							mhi_init_state_transition(mhi_dev_ctxt,
									new_state);
							break;
						case MHI_EXEC_ENV_AMSS:
							new_state = STATE_TRANSITION_AMSS;
							mhi_init_state_transition(mhi_dev_ctxt,
									new_state);
							break;
					}
					break;
				}
			default:
				mhi_log(MHI_MSG_ERROR,
						"Unsupported packet type code 0x%x\n",
						MHI_TRB_READ_INFO(EV_TRB_TYPE,
							&event_to_process));
				break;
		}
		local_rp = (mhi_event_pkt *)local_ev_ctxt->rp;
		device_rp = (mhi_event_pkt *)mhi_p2v_addr(
				mhi_dev_ctxt->mhi_ctrl_seg_info,
				(u64)ev_ctxt->mhi_event_read_ptr);
		--event_quota;
	}
	return MHI_STATUS_SUCCESS;
}
Esempio n. 3
0
/**
 * @brief Thread which handles inbound data for MHI clients.
 * This thread will invoke thecallback for the mhi clients to
 * inform thme of data availability.
 *
 * The thread monitors the MHI state variable to know if it should
 * continue processing, * or stop.
 *
 * @param ctxt void pointer to a device context
 */
MHI_STATUS parse_xfer_event(mhi_device_ctxt *ctxt, mhi_event_pkt *event)
{
	mhi_device_ctxt *mhi_dev_ctxt = (mhi_device_ctxt *)ctxt;
	mhi_result *result;
	u32 chan = MHI_MAX_CHANNELS;
	u16 xfer_len;
	uintptr_t phy_ev_trb_loc;
	mhi_xfer_pkt *local_ev_trb_loc;
	mhi_client_handle *client_handle;
	mhi_xfer_pkt *local_trb_loc;
	mhi_chan_ctxt *chan_ctxt;
	u32 nr_trb_to_parse;
	u32 i = 0;

	switch (MHI_EV_READ_CODE(EV_TRB_CODE, event)) {
	case MHI_EVENT_CC_EOB:
		mhi_log(MHI_MSG_VERBOSE, "IEOB condition detected\n");
	case MHI_EVENT_CC_OVERFLOW:
		mhi_log(MHI_MSG_VERBOSE, "Overflow condition detected\n");
	case MHI_EVENT_CC_EOT:
	{
		void *trb_data_loc;
		u32 ieot_flag;
		MHI_STATUS ret_val;
		mhi_ring *local_chan_ctxt;

		chan = MHI_EV_READ_CHID(EV_CHID, event);
		local_chan_ctxt =
			&mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
		phy_ev_trb_loc = MHI_EV_READ_PTR(EV_PTR, event);

		if (unlikely(!VALID_CHAN_NR(chan))) {
			mhi_log(MHI_MSG_ERROR, "Bad ring id.\n");
			break;
		}
		chan_ctxt = &mhi_dev_ctxt->mhi_ctrl_seg->mhi_cc_list[chan];
		ret_val = validate_xfer_el_addr(chan_ctxt,
						phy_ev_trb_loc);

		if (unlikely(MHI_STATUS_SUCCESS != ret_val)) {
			mhi_log(MHI_MSG_ERROR, "Bad event trb ptr.\n");
			break;
		}

		/* Get the TRB this event points to*/
		local_ev_trb_loc =
			(mhi_xfer_pkt *)mhi_p2v_addr(
					mhi_dev_ctxt->mhi_ctrl_seg_info,
							phy_ev_trb_loc);
		local_trb_loc = (mhi_xfer_pkt *)local_chan_ctxt->rp;

		ret_val = get_nr_enclosed_el(local_chan_ctxt,
				      local_trb_loc,
				      local_ev_trb_loc,
				      &nr_trb_to_parse);
		if (unlikely(MHI_STATUS_SUCCESS != ret_val)) {
			mhi_log(MHI_MSG_CRITICAL,
				"Failed to get nr available trbs ret: %d.\n",
				ret_val);
			return MHI_STATUS_ERROR;
		}
		do {
			u64 phy_buf_loc;
			MHI_TRB_GET_INFO(TX_TRB_IEOT, local_trb_loc, ieot_flag);
			phy_buf_loc = local_trb_loc->data_tx_pkt.buffer_ptr;
			trb_data_loc = (void *)(uintptr_t)phy_buf_loc;
			if (chan % 2)
				xfer_len = MHI_EV_READ_LEN(EV_LEN, event);
			else
				xfer_len = MHI_TX_TRB_GET_LEN(TX_TRB_LEN,
							local_trb_loc);

			if (!VALID_BUF(trb_data_loc, xfer_len)) {
				mhi_log(MHI_MSG_CRITICAL,
					"Bad buffer ptr: %p.\n",
					trb_data_loc);
				return MHI_STATUS_ERROR;
			}

			client_handle = mhi_dev_ctxt->client_handle_list[chan];
			if (NULL != client_handle) {
				client_handle->pkt_count++;
				result = &client_handle->result;
				result->payload_buf = trb_data_loc;
				result->bytes_xferd = xfer_len;
				result->user_data = client_handle->user_data;
			}
			if (chan % 2) {
				parse_inbound(mhi_dev_ctxt, chan,
						local_ev_trb_loc, xfer_len);
			} else {
				parse_outbound(mhi_dev_ctxt, chan,
						local_ev_trb_loc, xfer_len);
			}
			mhi_dev_ctxt->mhi_chan_cntr[chan].pkts_xferd++;
			if (local_trb_loc ==
				(mhi_xfer_pkt *)local_chan_ctxt->rp) {
				mhi_log(MHI_MSG_CRITICAL,
					"Done. Processed until: %p.\n",
					trb_data_loc);
				break;
			} else {
				local_trb_loc =
					(mhi_xfer_pkt *)local_chan_ctxt->rp;
			}
			i++;
		} while (i <= nr_trb_to_parse);
		break;
	} /* CC_EOT */
	case MHI_EVENT_CC_OOB:
	case MHI_EVENT_CC_DB_MODE:
	{
		mhi_ring *chan_ctxt = NULL;
		u64 db_value = 0;
		mhi_dev_ctxt->uldl_enabled = 1;
		chan = MHI_EV_READ_CHID(EV_CHID, event);
		mhi_dev_ctxt->db_mode[chan] = 1;
		chan_ctxt =
			&mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
		mhi_log(MHI_MSG_INFO, "OOB Detected chan %d.\n", chan);
		if (chan_ctxt->wp != chan_ctxt->rp) {
			db_value = mhi_v2p_addr(mhi_dev_ctxt->mhi_ctrl_seg_info,
							(uintptr_t)chan_ctxt->wp);
			MHI_WRITE_DB(mhi_dev_ctxt, mhi_dev_ctxt->channel_db_addr, chan,
				db_value);
		}
		client_handle = mhi_dev_ctxt->client_handle_list[chan];
			if (NULL != client_handle) {
				result->transaction_status = MHI_STATUS_DEVICE_NOT_READY;
			}
		break;
	}
	default:
		{
			mhi_log(MHI_MSG_ERROR,
				"Unknown TX completion.\n");
			break;
		}
	} /*switch(MHI_EV_READ_CODE(EV_TRB_CODE,event)) */
	return 0;
}