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; }
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; }
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; }
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; }
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; }
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; }