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 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; }
enum MHI_STATUS mhi_init_mmio(struct mhi_device_ctxt *mhi_dev_ctxt) { u64 pcie_dword_val = 0; u32 pcie_word_val = 0; u32 i = 0; enum MHI_STATUS ret_val; mhi_log(MHI_MSG_INFO, "~~~ Initializing MMIO ~~~\n"); mhi_dev_ctxt->mmio_addr = mhi_dev_ctxt->dev_props->bar0_base; mhi_log(MHI_MSG_INFO, "Bar 0 address is at: 0x%p\n", mhi_dev_ctxt->mmio_addr); mhi_dev_ctxt->mmio_len = mhi_reg_read(mhi_dev_ctxt->mmio_addr, MHIREGLEN); if (0 == mhi_dev_ctxt->mmio_len) { mhi_log(MHI_MSG_ERROR, "Received mmio length as zero\n"); return MHI_STATUS_ERROR; } mhi_log(MHI_MSG_INFO, "Testing MHI Ver\n"); mhi_dev_ctxt->dev_props->mhi_ver = mhi_reg_read( mhi_dev_ctxt->mmio_addr, MHIVER); if (MHI_VERSION != mhi_dev_ctxt->dev_props->mhi_ver) { mhi_log(MHI_MSG_CRITICAL, "Bad MMIO version, 0x%x\n", mhi_dev_ctxt->dev_props->mhi_ver); if (mhi_dev_ctxt->dev_props->mhi_ver == 0xFFFFFFFF) ret_val = mhi_wait_for_mdm(mhi_dev_ctxt); if (ret_val) return MHI_STATUS_ERROR; } /* Enable the channels */ for (i = 0; i < MHI_MAX_CHANNELS; ++i) { struct mhi_chan_ctxt *chan_ctxt = &mhi_dev_ctxt->mhi_ctrl_seg->mhi_cc_list[i]; if (VALID_CHAN_NR(i)) chan_ctxt->mhi_chan_state = MHI_CHAN_STATE_ENABLED; else chan_ctxt->mhi_chan_state = MHI_CHAN_STATE_DISABLED; } mhi_log(MHI_MSG_INFO, "Read back MMIO Ready bit successfully. Moving on..\n"); mhi_log(MHI_MSG_INFO, "Reading channel doorbell offset\n"); mhi_dev_ctxt->channel_db_addr = mhi_dev_ctxt->mmio_addr; mhi_dev_ctxt->event_db_addr = mhi_dev_ctxt->mmio_addr; mhi_dev_ctxt->channel_db_addr += mhi_reg_read_field( mhi_dev_ctxt->mmio_addr, CHDBOFF, CHDBOFF_CHDBOFF_MASK, CHDBOFF_CHDBOFF_SHIFT); mhi_log(MHI_MSG_INFO, "Reading event doorbell offset\n"); mhi_dev_ctxt->event_db_addr += mhi_reg_read_field( mhi_dev_ctxt->mmio_addr, ERDBOFF, ERDBOFF_ERDBOFF_MASK, ERDBOFF_ERDBOFF_SHIFT); mhi_log(MHI_MSG_INFO, "Setting all MMIO values.\n"); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, MHICFG, MHICFG_NER_MASK, MHICFG_NER_SHIFT, MHI_MAX_CHANNELS); pcie_dword_val = mhi_v2p_addr(mhi_dev_ctxt->mhi_ctrl_seg_info, (uintptr_t)mhi_dev_ctxt->mhi_ctrl_seg->mhi_cc_list); pcie_word_val = HIGH_WORD(pcie_dword_val); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, CCABAP_HIGHER, CCABAP_HIGHER_CCABAP_HIGHER_MASK, CCABAP_HIGHER_CCABAP_HIGHER_SHIFT, pcie_word_val); pcie_word_val = LOW_WORD(pcie_dword_val); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, CCABAP_LOWER, CCABAP_LOWER_CCABAP_LOWER_MASK, CCABAP_LOWER_CCABAP_LOWER_SHIFT, pcie_word_val); /* Write the Event Context Base Address Register High and Low parts */ pcie_dword_val = mhi_v2p_addr(mhi_dev_ctxt->mhi_ctrl_seg_info, (uintptr_t)mhi_dev_ctxt->mhi_ctrl_seg->mhi_ec_list); pcie_word_val = HIGH_WORD(pcie_dword_val); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, ECABAP_HIGHER, ECABAP_HIGHER_ECABAP_HIGHER_MASK, ECABAP_HIGHER_ECABAP_HIGHER_SHIFT, pcie_word_val); pcie_word_val = LOW_WORD(pcie_dword_val); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, ECABAP_LOWER, ECABAP_LOWER_ECABAP_LOWER_MASK, ECABAP_LOWER_ECABAP_LOWER_SHIFT, pcie_word_val); /* Write the Command Ring Control Register High and Low parts */ pcie_dword_val = mhi_v2p_addr(mhi_dev_ctxt->mhi_ctrl_seg_info, (uintptr_t)mhi_dev_ctxt->mhi_ctrl_seg->mhi_cmd_ctxt_list); pcie_word_val = HIGH_WORD(pcie_dword_val); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, CRCBAP_HIGHER, CRCBAP_HIGHER_CRCBAP_HIGHER_MASK, CRCBAP_HIGHER_CRCBAP_HIGHER_SHIFT, pcie_word_val); pcie_word_val = LOW_WORD(pcie_dword_val); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, CRCBAP_LOWER, CRCBAP_LOWER_CRCBAP_LOWER_MASK, CRCBAP_LOWER_CRCBAP_LOWER_SHIFT, pcie_word_val); mhi_dev_ctxt->cmd_db_addr = mhi_dev_ctxt->mmio_addr + CRDB_LOWER; /* Set the control segment in the MMIO */ pcie_dword_val = mhi_v2p_addr(mhi_dev_ctxt->mhi_ctrl_seg_info, (uintptr_t)mhi_dev_ctxt->mhi_ctrl_seg); pcie_word_val = HIGH_WORD(pcie_dword_val); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, MHICTRLBASE_HIGHER, MHICTRLBASE_HIGHER_MHICTRLBASE_HIGHER_MASK, MHICTRLBASE_HIGHER_MHICTRLBASE_HIGHER_SHIFT, pcie_word_val); pcie_word_val = LOW_WORD(pcie_dword_val); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, MHICTRLBASE_LOWER, MHICTRLBASE_LOWER_MHICTRLBASE_LOWER_MASK, MHICTRLBASE_LOWER_MHICTRLBASE_LOWER_SHIFT, pcie_word_val); pcie_dword_val = mhi_v2p_addr(mhi_dev_ctxt->mhi_ctrl_seg_info, (uintptr_t)mhi_dev_ctxt->mhi_ctrl_seg) + mhi_get_memregion_len(mhi_dev_ctxt->mhi_ctrl_seg_info) - 1; pcie_word_val = HIGH_WORD(pcie_dword_val); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, MHICTRLLIMIT_HIGHER, MHICTRLLIMIT_HIGHER_MHICTRLLIMIT_HIGHER_MASK, MHICTRLLIMIT_HIGHER_MHICTRLLIMIT_HIGHER_SHIFT, pcie_word_val); pcie_word_val = LOW_WORD(pcie_dword_val); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, MHICTRLLIMIT_LOWER, MHICTRLLIMIT_LOWER_MHICTRLLIMIT_LOWER_MASK, MHICTRLLIMIT_LOWER_MHICTRLLIMIT_LOWER_SHIFT, pcie_word_val); /* Set the data segment in the MMIO */ pcie_dword_val = MHI_DATA_SEG_WINDOW_START_ADDR; pcie_word_val = HIGH_WORD(pcie_dword_val); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, MHIDATABASE_HIGHER, MHIDATABASE_HIGHER_MHIDATABASE_HIGHER_MASK, MHIDATABASE_HIGHER_MHIDATABASE_HIGHER_SHIFT, pcie_word_val); pcie_word_val = LOW_WORD(pcie_dword_val); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, MHIDATABASE_LOWER, MHIDATABASE_LOWER_MHIDATABASE_LOWER_MASK, MHIDATABASE_LOWER_MHIDATABASE_LOWER_SHIFT, pcie_word_val); pcie_dword_val = MHI_DATA_SEG_WINDOW_END_ADDR; pcie_word_val = HIGH_WORD(pcie_dword_val); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, MHIDATALIMIT_HIGHER, MHIDATALIMIT_HIGHER_MHIDATALIMIT_HIGHER_MASK, MHIDATALIMIT_HIGHER_MHIDATALIMIT_HIGHER_SHIFT, pcie_word_val); pcie_word_val = LOW_WORD(pcie_dword_val); mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_addr, MHIDATALIMIT_LOWER, MHIDATALIMIT_LOWER_MHIDATALIMIT_LOWER_MASK, MHIDATALIMIT_LOWER_MHIDATALIMIT_LOWER_SHIFT, pcie_word_val); mhi_log(MHI_MSG_INFO, "Done..\n"); return MHI_STATUS_SUCCESS; }