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; }
/** * @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; }