Loading drivers/platform/msm/mhi_dev/mhi.c +181 −28 Original line number Original line Diff line number Diff line Loading @@ -87,6 +87,10 @@ static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi, static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq); struct event_req *ereq); static void mhi_dev_event_msi_cb(void *req); static void mhi_dev_event_msi_cb(void *req); static void mhi_dev_cmd_event_msi_cb(void *req); static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi); static struct mhi_dev_uevent_info channel_state_info[MHI_MAX_CHANNELS]; static struct mhi_dev_uevent_info channel_state_info[MHI_MAX_CHANNELS]; static DECLARE_COMPLETION(read_from_host); static DECLARE_COMPLETION(read_from_host); Loading Loading @@ -262,7 +266,7 @@ static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq) { { struct ep_pcie_msi_config cfg; struct ep_pcie_msi_config cfg; struct mhi_addr msi_addr; struct mhi_addr msi_addr; struct mhi_dev_channel *ch = ereq->context; struct mhi_dev_channel *ch; uint64_t evnt_ring_idx = mhi->ev_ring_start + ereq->event_ring; uint64_t evnt_ring_idx = mhi->ev_ring_start + ereq->event_ring; struct mhi_dev_ring *ring = &mhi->ring[evnt_ring_idx]; struct mhi_dev_ring *ring = &mhi->ring[evnt_ring_idx]; union mhi_dev_ring_ctx *ctx; union mhi_dev_ring_ctx *ctx; Loading @@ -283,14 +287,23 @@ static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq) msi_addr.phy_addr = ring->msi_buf_dma_handle; msi_addr.phy_addr = ring->msi_buf_dma_handle; ereq->event_type = SEND_MSI; ereq->event_type = SEND_MSI; if (!ereq->is_cmd_cpl) { ch = ereq->context; ereq->msi_cb = mhi_dev_event_msi_cb; ereq->msi_cb = mhi_dev_event_msi_cb; ch->msi_cnt++; ch->msi_cnt++; mhi_log(MHI_MSG_VERBOSE, mhi_log(MHI_MSG_VERBOSE, "Sending MSI %d to 0x%llx as data = 0x%x for ch %d msi_count %d, ereq flush_num %d\n", "Sending MSI %d to 0x%llx as data = 0x%x for ch %d msi_count %d, ereq flush_num %d\n", ctx->ev.msivec, msi_addr.host_pa, *ring->msi_buf, ch->ch_id, ctx->ev.msivec, msi_addr.host_pa, *ring->msi_buf, ch->ch_id, ch->msi_cnt, ereq->flush_num); ch->msi_cnt, ereq->flush_num); } else { ereq->msi_cb = mhi_dev_cmd_event_msi_cb; mhi_log(MHI_MSG_VERBOSE, "Sending MSI %d to 0x%llx as data = 0x%x for cmd ack, ereq flush_num %d\n", ctx->ev.msivec, msi_addr.host_pa, *ring->msi_buf, ereq->flush_num); } mhi_ctx->write_to_host(mhi, &msi_addr, ereq, MHI_DEV_DMA_ASYNC); mhi_ctx->write_to_host(mhi, &msi_addr, ereq, MHI_DEV_DMA_ASYNC); return 0; return 0; Loading @@ -314,6 +327,27 @@ static void mhi_dev_event_rd_offset_completion_cb(void *req) sizeof(uint64_t), DMA_TO_DEVICE); sizeof(uint64_t), DMA_TO_DEVICE); } } static void mhi_dev_cmd_event_msi_cb(void *req) { struct mhi_cmd_cmpl_ctx *cmd_ctx; struct mhi_dev *mhi; struct event_req *ereq = req; unsigned long flags; mhi_log(MHI_MSG_VERBOSE, "MSI completed for flush req %d\n", ereq->flush_num); /*Cmd completion handling*/ mhi = ereq->context; cmd_ctx = mhi->cmd_ctx; cmd_ctx->cmd_buf_wp += ereq->num_events; if (cmd_ctx->cmd_buf_wp == NUM_CMD_EVENTS_DEFAULT) cmd_ctx->cmd_buf_wp = 0; spin_lock_irqsave(&mhi->lock, flags); list_add_tail(&ereq->list, &cmd_ctx->cmd_req_buffers); spin_unlock_irqrestore(&mhi->lock, flags); } static void mhi_dev_event_msi_cb(void *req) static void mhi_dev_event_msi_cb(void *req) { { struct event_req *ereq = req; struct event_req *ereq = req; Loading Loading @@ -401,7 +435,8 @@ static int mhi_trigger_msi_edma(struct mhi_dev_ring *ring, u32 idx) } } static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring, static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring, struct event_req *ereq, uint32_t evt_len) struct event_req *ereq, uint32_t evt_len, enum mhi_dev_tr_compl_evt_type event_type) { { int rc = 0; int rc = 0; uint64_t evnt_ring_idx = mhi->ev_ring_start + evnt_ring; uint64_t evnt_ring_idx = mhi->ev_ring_start + evnt_ring; Loading Loading @@ -430,25 +465,25 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring, return rc; return rc; } } } } ch = ereq->context; /* Check the limits of the buffer to be flushed */ if (ereq->tr_events < ch->tr_events || (ereq->tr_events + ereq->num_events) > (ch->tr_events + ch->evt_buf_size)) { pr_err("%s: Invalid completion event buffer!\n", __func__); mhi_log(MHI_MSG_ERROR, "Invalid cmpl evt buf - start %pK, end %pK\n", ereq->tr_events, ereq->tr_events + ereq->num_events); return -EINVAL; } mutex_lock(&ring->event_lock); mutex_lock(&ring->event_lock); mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of ch %d\n", ereq->num_events, ch->ch_id); /* add the events */ /* add the events */ ereq->client_cb = mhi_dev_event_buf_completion_cb; ereq->client_cb = mhi_dev_event_buf_completion_cb; ereq->is_cmd_cpl = (event_type == SEND_CMD_CMP) ? true:false; ereq->event_type = SEND_EVENT_BUFFER; ereq->event_type = SEND_EVENT_BUFFER; if (!ereq->is_cmd_cpl) { ch = ereq->context; mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of ch %d\n", ereq->num_events, ch->ch_id); } else { mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of cmd ring\n", ereq->num_events); } rc = mhi_dev_add_element(ring, ereq->tr_events, ereq, evt_len); rc = mhi_dev_add_element(ring, ereq->tr_events, ereq, evt_len); if (rc) { if (rc) { pr_err("%s(): error in adding element rc %d\n", __func__, rc); pr_err("%s(): error in adding element rc %d\n", __func__, rc); Loading Loading @@ -506,6 +541,55 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring, return rc; return rc; } } static int mhi_dev_flush_cmd_completion_events(struct mhi_dev *mhi, union mhi_dev_ring_element_type *el) { struct mhi_cmd_cmpl_ctx *cmd_ctx = mhi->cmd_ctx; unsigned long flags; struct event_req *flush_ereq; union mhi_dev_ring_element_type *compl_ev; int rc = 0; /*cmd completions are sent on event ring 0 always*/ if (!mhi->cmd_ctx) { if (mhi_dev_alloc_cmd_ack_buf_req(mhi)) { mhi_log(MHI_MSG_ERROR, "Alloc cmd ack buff failed"); return -ENOMEM; } } cmd_ctx = mhi->cmd_ctx; if (list_empty(&cmd_ctx->cmd_req_buffers)) { mhi_log(MHI_MSG_ERROR, "cmd req buff list is empty"); return -ENOMEM; } spin_lock_irqsave(&mhi->lock, flags); flush_ereq = container_of(cmd_ctx->cmd_req_buffers.next, struct event_req, list); list_del_init(&flush_ereq->list); flush_ereq->context = mhi; spin_unlock_irqrestore(&mhi->lock, flags); compl_ev = cmd_ctx->cmd_events + cmd_ctx->cmd_buf_rp; memcpy(compl_ev, el, sizeof(union mhi_dev_ring_element_type)); cmd_ctx->cmd_buf_rp++; if (cmd_ctx->cmd_buf_rp == NUM_CMD_EVENTS_DEFAULT) cmd_ctx->cmd_buf_rp = 0; flush_ereq->tr_events = compl_ev; rc = mhi_dev_send_multiple_tr_events(mhi, 0, flush_ereq, (1 * sizeof(union mhi_dev_ring_element_type)), SEND_CMD_CMP); if (rc) { mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n"); return rc; } return rc; } static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi, static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi, struct mhi_dev_channel *ch) struct mhi_dev_channel *ch) { { Loading Loading @@ -539,11 +623,25 @@ static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi, flush_ereq->flush_num = ch->flush_req_cnt; flush_ereq->flush_num = ch->flush_req_cnt; mhi_log(MHI_MSG_DBG, "Flush num %d called for ch %d\n", mhi_log(MHI_MSG_DBG, "Flush num %d called for ch %d\n", ch->flush_req_cnt, ch->ch_id); ch->flush_req_cnt, ch->ch_id); /* Check the limits of the buffer to be flushed */ if (flush_ereq->tr_events < ch->tr_events || (flush_ereq->tr_events + flush_ereq->num_events) > (ch->tr_events + ch->evt_buf_size)) { pr_err("%s: Invalid completion event buffer!\n", __func__); mhi_log(MHI_MSG_ERROR, "Invalid cmpl evt buf - start %pK, end %pK\n", flush_ereq->tr_events, flush_ereq->tr_events + flush_ereq->num_events); return -EINVAL; } rc = mhi_dev_send_multiple_tr_events(mhi, rc = mhi_dev_send_multiple_tr_events(mhi, mhi->ch_ctx_cache[ch->ch_id].err_indx, mhi->ch_ctx_cache[ch->ch_id].err_indx, flush_ereq, flush_ereq, (flush_ereq->num_events * (flush_ereq->num_events * sizeof(union mhi_dev_ring_element_type))); sizeof(union mhi_dev_ring_element_type)), SEND_EVENT_BUFFER); if (rc) { if (rc) { mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n"); mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n"); break; break; Loading Loading @@ -1608,7 +1706,7 @@ int mhi_dev_send_state_change_event(struct mhi_dev *mhi, event.evt_state_change.type = MHI_DEV_RING_EL_MHI_STATE_CHG; event.evt_state_change.type = MHI_DEV_RING_EL_MHI_STATE_CHG; event.evt_state_change.mhistate = state; event.evt_state_change.mhistate = state; return mhi_dev_send_event(mhi, 0, &event); return mhi_dev_flush_cmd_completion_events(mhi, &event); } } EXPORT_SYMBOL(mhi_dev_send_state_change_event); EXPORT_SYMBOL(mhi_dev_send_state_change_event); Loading @@ -1619,7 +1717,7 @@ int mhi_dev_send_ee_event(struct mhi_dev *mhi, enum mhi_dev_execenv exec_env) event.evt_ee_state.type = MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY; event.evt_ee_state.type = MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY; event.evt_ee_state.execenv = exec_env; event.evt_ee_state.execenv = exec_env; return mhi_dev_send_event(mhi, 0, &event); return mhi_dev_flush_cmd_completion_events(mhi, &event); } } EXPORT_SYMBOL(mhi_dev_send_ee_event); EXPORT_SYMBOL(mhi_dev_send_ee_event); Loading Loading @@ -1669,7 +1767,7 @@ static int mhi_dev_send_cmd_comp_event(struct mhi_dev *mhi, (size_t) event.evt_cmd_comp.ptr); (size_t) event.evt_cmd_comp.ptr); event.evt_cmd_comp.type = MHI_DEV_RING_EL_CMD_COMPLETION_EVT; event.evt_cmd_comp.type = MHI_DEV_RING_EL_CMD_COMPLETION_EVT; event.evt_cmd_comp.code = code; event.evt_cmd_comp.code = code; return mhi_dev_send_event(mhi, 0, &event); return mhi_dev_flush_cmd_completion_events(mhi, &event); } } static int mhi_dev_process_stop_cmd(struct mhi_dev_ring *ring, uint32_t ch_id, static int mhi_dev_process_stop_cmd(struct mhi_dev_ring *ring, uint32_t ch_id, Loading Loading @@ -1852,7 +1950,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, event.evt_cmd_comp.code = event.evt_cmd_comp.code = MHI_CMD_COMPL_CODE_UNDEFINED; MHI_CMD_COMPL_CODE_UNDEFINED; rc = mhi_dev_send_event(mhi, 0, &event); rc = mhi_dev_flush_cmd_completion_events(mhi, &event); if (rc) { if (rc) { pr_err("stop event send failed\n"); pr_err("stop event send failed\n"); return; return; Loading Loading @@ -1912,7 +2010,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, event.evt_cmd_comp.code = event.evt_cmd_comp.code = MHI_CMD_COMPL_CODE_UNDEFINED; MHI_CMD_COMPL_CODE_UNDEFINED; rc = mhi_dev_send_event(mhi, 0, &event); rc = mhi_dev_flush_cmd_completion_events(mhi, &event); if (rc) { if (rc) { pr_err("stop event send failed\n"); pr_err("stop event send failed\n"); return; return; Loading Loading @@ -2723,6 +2821,61 @@ static uint32_t mhi_dev_get_evt_ring_size(struct mhi_dev *mhi, uint32_t ch_id) mhi->ch_ctx_cache[ch_id].err_indx].ring_size; mhi->ch_ctx_cache[ch_id].err_indx].ring_size; } } static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi) { int rc = 0; uint32_t i; struct mhi_cmd_cmpl_ctx *cmd_ctx; union mhi_dev_ring_element_type *cmd_events; mhi->cmd_ctx = kmalloc(sizeof(struct mhi_cmd_cmpl_ctx), GFP_KERNEL); if (!mhi->cmd_ctx) return -ENOMEM; cmd_ctx = mhi->cmd_ctx; /* Allocate event requests */ cmd_ctx->ereqs = kcalloc(NUM_CMD_EVENTS_DEFAULT, sizeof(*cmd_ctx->ereqs), GFP_KERNEL); if (!cmd_ctx->ereqs) { goto free_ereqs; return -ENOMEM; } /* Allocate buffers to queue transfer completion events */ cmd_ctx->cmd_events = kcalloc(NUM_CMD_EVENTS_DEFAULT, sizeof(*cmd_events), GFP_KERNEL); if (!cmd_ctx->cmd_events) { rc = -ENOMEM; goto free_ereqs; } /* Organize event flush requests into a linked list */ INIT_LIST_HEAD(&cmd_ctx->cmd_req_buffers); for (i = 0; i < NUM_CMD_EVENTS_DEFAULT; ++i) { list_add_tail(&cmd_ctx->ereqs[i].list, &cmd_ctx->cmd_req_buffers); } /* * Initialize cmpl event buffer indexes - cmd_buf_rp and * cmd_buf_wp point to the first and last free index available. */ cmd_ctx->cmd_buf_rp = 0; cmd_ctx->cmd_buf_wp = NUM_CMD_EVENTS_DEFAULT - 1; return 0; free_ereqs: kfree(mhi->cmd_ctx); kfree(cmd_ctx->ereqs); cmd_ctx->ereqs = NULL; mhi->cmd_ctx = NULL; return rc; } static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi, static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi, struct mhi_dev_channel *ch, struct mhi_dev_ring *evt_ring) struct mhi_dev_channel *ch, struct mhi_dev_ring *evt_ring) { { Loading drivers/platform/msm/mhi_dev/mhi.h +17 −1 Original line number Original line Diff line number Diff line Loading @@ -271,6 +271,8 @@ struct mhi_config { /* maximum transfer completion events buffer */ /* maximum transfer completion events buffer */ #define NUM_TR_EVENTS_DEFAULT 128 #define NUM_TR_EVENTS_DEFAULT 128 #define NUM_CMD_EVENTS_DEFAULT 20 /* Set flush threshold to 80% of event buf size */ /* Set flush threshold to 80% of event buf size */ #define MHI_CMPL_EVT_FLUSH_THRSHLD(n) ((n * 8) / 10) #define MHI_CMPL_EVT_FLUSH_THRSHLD(n) ((n * 8) / 10) Loading Loading @@ -354,7 +356,8 @@ enum mhi_dev_ch_operation { enum mhi_dev_tr_compl_evt_type { enum mhi_dev_tr_compl_evt_type { SEND_EVENT_BUFFER, SEND_EVENT_BUFFER, SEND_EVENT_RD_OFFSET, SEND_EVENT_RD_OFFSET, SEND_MSI SEND_MSI, SEND_CMD_CMP, }; }; enum mhi_dev_transfer_type { enum mhi_dev_transfer_type { Loading Loading @@ -448,6 +451,18 @@ struct event_req { void (*msi_cb)(void *req); void (*msi_cb)(void *req); struct list_head list; struct list_head list; u32 flush_num; u32 flush_num; bool is_cmd_cpl; }; struct mhi_cmd_cmpl_ctx { /* Indices for completion event buffer */ uint32_t cmd_buf_rp; uint32_t cmd_buf_wp; uint32_t cmd_buf_size; bool mem_allocated; struct list_head cmd_req_buffers; struct event_req *ereqs; union mhi_dev_ring_element_type *cmd_events; }; }; struct mhi_dev_channel { struct mhi_dev_channel { Loading Loading @@ -531,6 +546,7 @@ struct mhi_dev { struct mhi_dev_ring *ring; struct mhi_dev_ring *ring; int mhi_irq; int mhi_irq; struct mhi_dev_channel *ch; struct mhi_dev_channel *ch; struct mhi_cmd_cmpl_ctx *cmd_ctx; int ctrl_int; int ctrl_int; int cmd_int; int cmd_int; Loading Loading
drivers/platform/msm/mhi_dev/mhi.c +181 −28 Original line number Original line Diff line number Diff line Loading @@ -87,6 +87,10 @@ static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi, static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq); struct event_req *ereq); static void mhi_dev_event_msi_cb(void *req); static void mhi_dev_event_msi_cb(void *req); static void mhi_dev_cmd_event_msi_cb(void *req); static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi); static struct mhi_dev_uevent_info channel_state_info[MHI_MAX_CHANNELS]; static struct mhi_dev_uevent_info channel_state_info[MHI_MAX_CHANNELS]; static DECLARE_COMPLETION(read_from_host); static DECLARE_COMPLETION(read_from_host); Loading Loading @@ -262,7 +266,7 @@ static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq) { { struct ep_pcie_msi_config cfg; struct ep_pcie_msi_config cfg; struct mhi_addr msi_addr; struct mhi_addr msi_addr; struct mhi_dev_channel *ch = ereq->context; struct mhi_dev_channel *ch; uint64_t evnt_ring_idx = mhi->ev_ring_start + ereq->event_ring; uint64_t evnt_ring_idx = mhi->ev_ring_start + ereq->event_ring; struct mhi_dev_ring *ring = &mhi->ring[evnt_ring_idx]; struct mhi_dev_ring *ring = &mhi->ring[evnt_ring_idx]; union mhi_dev_ring_ctx *ctx; union mhi_dev_ring_ctx *ctx; Loading @@ -283,14 +287,23 @@ static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq) msi_addr.phy_addr = ring->msi_buf_dma_handle; msi_addr.phy_addr = ring->msi_buf_dma_handle; ereq->event_type = SEND_MSI; ereq->event_type = SEND_MSI; if (!ereq->is_cmd_cpl) { ch = ereq->context; ereq->msi_cb = mhi_dev_event_msi_cb; ereq->msi_cb = mhi_dev_event_msi_cb; ch->msi_cnt++; ch->msi_cnt++; mhi_log(MHI_MSG_VERBOSE, mhi_log(MHI_MSG_VERBOSE, "Sending MSI %d to 0x%llx as data = 0x%x for ch %d msi_count %d, ereq flush_num %d\n", "Sending MSI %d to 0x%llx as data = 0x%x for ch %d msi_count %d, ereq flush_num %d\n", ctx->ev.msivec, msi_addr.host_pa, *ring->msi_buf, ch->ch_id, ctx->ev.msivec, msi_addr.host_pa, *ring->msi_buf, ch->ch_id, ch->msi_cnt, ereq->flush_num); ch->msi_cnt, ereq->flush_num); } else { ereq->msi_cb = mhi_dev_cmd_event_msi_cb; mhi_log(MHI_MSG_VERBOSE, "Sending MSI %d to 0x%llx as data = 0x%x for cmd ack, ereq flush_num %d\n", ctx->ev.msivec, msi_addr.host_pa, *ring->msi_buf, ereq->flush_num); } mhi_ctx->write_to_host(mhi, &msi_addr, ereq, MHI_DEV_DMA_ASYNC); mhi_ctx->write_to_host(mhi, &msi_addr, ereq, MHI_DEV_DMA_ASYNC); return 0; return 0; Loading @@ -314,6 +327,27 @@ static void mhi_dev_event_rd_offset_completion_cb(void *req) sizeof(uint64_t), DMA_TO_DEVICE); sizeof(uint64_t), DMA_TO_DEVICE); } } static void mhi_dev_cmd_event_msi_cb(void *req) { struct mhi_cmd_cmpl_ctx *cmd_ctx; struct mhi_dev *mhi; struct event_req *ereq = req; unsigned long flags; mhi_log(MHI_MSG_VERBOSE, "MSI completed for flush req %d\n", ereq->flush_num); /*Cmd completion handling*/ mhi = ereq->context; cmd_ctx = mhi->cmd_ctx; cmd_ctx->cmd_buf_wp += ereq->num_events; if (cmd_ctx->cmd_buf_wp == NUM_CMD_EVENTS_DEFAULT) cmd_ctx->cmd_buf_wp = 0; spin_lock_irqsave(&mhi->lock, flags); list_add_tail(&ereq->list, &cmd_ctx->cmd_req_buffers); spin_unlock_irqrestore(&mhi->lock, flags); } static void mhi_dev_event_msi_cb(void *req) static void mhi_dev_event_msi_cb(void *req) { { struct event_req *ereq = req; struct event_req *ereq = req; Loading Loading @@ -401,7 +435,8 @@ static int mhi_trigger_msi_edma(struct mhi_dev_ring *ring, u32 idx) } } static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring, static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring, struct event_req *ereq, uint32_t evt_len) struct event_req *ereq, uint32_t evt_len, enum mhi_dev_tr_compl_evt_type event_type) { { int rc = 0; int rc = 0; uint64_t evnt_ring_idx = mhi->ev_ring_start + evnt_ring; uint64_t evnt_ring_idx = mhi->ev_ring_start + evnt_ring; Loading Loading @@ -430,25 +465,25 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring, return rc; return rc; } } } } ch = ereq->context; /* Check the limits of the buffer to be flushed */ if (ereq->tr_events < ch->tr_events || (ereq->tr_events + ereq->num_events) > (ch->tr_events + ch->evt_buf_size)) { pr_err("%s: Invalid completion event buffer!\n", __func__); mhi_log(MHI_MSG_ERROR, "Invalid cmpl evt buf - start %pK, end %pK\n", ereq->tr_events, ereq->tr_events + ereq->num_events); return -EINVAL; } mutex_lock(&ring->event_lock); mutex_lock(&ring->event_lock); mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of ch %d\n", ereq->num_events, ch->ch_id); /* add the events */ /* add the events */ ereq->client_cb = mhi_dev_event_buf_completion_cb; ereq->client_cb = mhi_dev_event_buf_completion_cb; ereq->is_cmd_cpl = (event_type == SEND_CMD_CMP) ? true:false; ereq->event_type = SEND_EVENT_BUFFER; ereq->event_type = SEND_EVENT_BUFFER; if (!ereq->is_cmd_cpl) { ch = ereq->context; mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of ch %d\n", ereq->num_events, ch->ch_id); } else { mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of cmd ring\n", ereq->num_events); } rc = mhi_dev_add_element(ring, ereq->tr_events, ereq, evt_len); rc = mhi_dev_add_element(ring, ereq->tr_events, ereq, evt_len); if (rc) { if (rc) { pr_err("%s(): error in adding element rc %d\n", __func__, rc); pr_err("%s(): error in adding element rc %d\n", __func__, rc); Loading Loading @@ -506,6 +541,55 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring, return rc; return rc; } } static int mhi_dev_flush_cmd_completion_events(struct mhi_dev *mhi, union mhi_dev_ring_element_type *el) { struct mhi_cmd_cmpl_ctx *cmd_ctx = mhi->cmd_ctx; unsigned long flags; struct event_req *flush_ereq; union mhi_dev_ring_element_type *compl_ev; int rc = 0; /*cmd completions are sent on event ring 0 always*/ if (!mhi->cmd_ctx) { if (mhi_dev_alloc_cmd_ack_buf_req(mhi)) { mhi_log(MHI_MSG_ERROR, "Alloc cmd ack buff failed"); return -ENOMEM; } } cmd_ctx = mhi->cmd_ctx; if (list_empty(&cmd_ctx->cmd_req_buffers)) { mhi_log(MHI_MSG_ERROR, "cmd req buff list is empty"); return -ENOMEM; } spin_lock_irqsave(&mhi->lock, flags); flush_ereq = container_of(cmd_ctx->cmd_req_buffers.next, struct event_req, list); list_del_init(&flush_ereq->list); flush_ereq->context = mhi; spin_unlock_irqrestore(&mhi->lock, flags); compl_ev = cmd_ctx->cmd_events + cmd_ctx->cmd_buf_rp; memcpy(compl_ev, el, sizeof(union mhi_dev_ring_element_type)); cmd_ctx->cmd_buf_rp++; if (cmd_ctx->cmd_buf_rp == NUM_CMD_EVENTS_DEFAULT) cmd_ctx->cmd_buf_rp = 0; flush_ereq->tr_events = compl_ev; rc = mhi_dev_send_multiple_tr_events(mhi, 0, flush_ereq, (1 * sizeof(union mhi_dev_ring_element_type)), SEND_CMD_CMP); if (rc) { mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n"); return rc; } return rc; } static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi, static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi, struct mhi_dev_channel *ch) struct mhi_dev_channel *ch) { { Loading Loading @@ -539,11 +623,25 @@ static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi, flush_ereq->flush_num = ch->flush_req_cnt; flush_ereq->flush_num = ch->flush_req_cnt; mhi_log(MHI_MSG_DBG, "Flush num %d called for ch %d\n", mhi_log(MHI_MSG_DBG, "Flush num %d called for ch %d\n", ch->flush_req_cnt, ch->ch_id); ch->flush_req_cnt, ch->ch_id); /* Check the limits of the buffer to be flushed */ if (flush_ereq->tr_events < ch->tr_events || (flush_ereq->tr_events + flush_ereq->num_events) > (ch->tr_events + ch->evt_buf_size)) { pr_err("%s: Invalid completion event buffer!\n", __func__); mhi_log(MHI_MSG_ERROR, "Invalid cmpl evt buf - start %pK, end %pK\n", flush_ereq->tr_events, flush_ereq->tr_events + flush_ereq->num_events); return -EINVAL; } rc = mhi_dev_send_multiple_tr_events(mhi, rc = mhi_dev_send_multiple_tr_events(mhi, mhi->ch_ctx_cache[ch->ch_id].err_indx, mhi->ch_ctx_cache[ch->ch_id].err_indx, flush_ereq, flush_ereq, (flush_ereq->num_events * (flush_ereq->num_events * sizeof(union mhi_dev_ring_element_type))); sizeof(union mhi_dev_ring_element_type)), SEND_EVENT_BUFFER); if (rc) { if (rc) { mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n"); mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n"); break; break; Loading Loading @@ -1608,7 +1706,7 @@ int mhi_dev_send_state_change_event(struct mhi_dev *mhi, event.evt_state_change.type = MHI_DEV_RING_EL_MHI_STATE_CHG; event.evt_state_change.type = MHI_DEV_RING_EL_MHI_STATE_CHG; event.evt_state_change.mhistate = state; event.evt_state_change.mhistate = state; return mhi_dev_send_event(mhi, 0, &event); return mhi_dev_flush_cmd_completion_events(mhi, &event); } } EXPORT_SYMBOL(mhi_dev_send_state_change_event); EXPORT_SYMBOL(mhi_dev_send_state_change_event); Loading @@ -1619,7 +1717,7 @@ int mhi_dev_send_ee_event(struct mhi_dev *mhi, enum mhi_dev_execenv exec_env) event.evt_ee_state.type = MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY; event.evt_ee_state.type = MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY; event.evt_ee_state.execenv = exec_env; event.evt_ee_state.execenv = exec_env; return mhi_dev_send_event(mhi, 0, &event); return mhi_dev_flush_cmd_completion_events(mhi, &event); } } EXPORT_SYMBOL(mhi_dev_send_ee_event); EXPORT_SYMBOL(mhi_dev_send_ee_event); Loading Loading @@ -1669,7 +1767,7 @@ static int mhi_dev_send_cmd_comp_event(struct mhi_dev *mhi, (size_t) event.evt_cmd_comp.ptr); (size_t) event.evt_cmd_comp.ptr); event.evt_cmd_comp.type = MHI_DEV_RING_EL_CMD_COMPLETION_EVT; event.evt_cmd_comp.type = MHI_DEV_RING_EL_CMD_COMPLETION_EVT; event.evt_cmd_comp.code = code; event.evt_cmd_comp.code = code; return mhi_dev_send_event(mhi, 0, &event); return mhi_dev_flush_cmd_completion_events(mhi, &event); } } static int mhi_dev_process_stop_cmd(struct mhi_dev_ring *ring, uint32_t ch_id, static int mhi_dev_process_stop_cmd(struct mhi_dev_ring *ring, uint32_t ch_id, Loading Loading @@ -1852,7 +1950,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, event.evt_cmd_comp.code = event.evt_cmd_comp.code = MHI_CMD_COMPL_CODE_UNDEFINED; MHI_CMD_COMPL_CODE_UNDEFINED; rc = mhi_dev_send_event(mhi, 0, &event); rc = mhi_dev_flush_cmd_completion_events(mhi, &event); if (rc) { if (rc) { pr_err("stop event send failed\n"); pr_err("stop event send failed\n"); return; return; Loading Loading @@ -1912,7 +2010,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi, event.evt_cmd_comp.code = event.evt_cmd_comp.code = MHI_CMD_COMPL_CODE_UNDEFINED; MHI_CMD_COMPL_CODE_UNDEFINED; rc = mhi_dev_send_event(mhi, 0, &event); rc = mhi_dev_flush_cmd_completion_events(mhi, &event); if (rc) { if (rc) { pr_err("stop event send failed\n"); pr_err("stop event send failed\n"); return; return; Loading Loading @@ -2723,6 +2821,61 @@ static uint32_t mhi_dev_get_evt_ring_size(struct mhi_dev *mhi, uint32_t ch_id) mhi->ch_ctx_cache[ch_id].err_indx].ring_size; mhi->ch_ctx_cache[ch_id].err_indx].ring_size; } } static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi) { int rc = 0; uint32_t i; struct mhi_cmd_cmpl_ctx *cmd_ctx; union mhi_dev_ring_element_type *cmd_events; mhi->cmd_ctx = kmalloc(sizeof(struct mhi_cmd_cmpl_ctx), GFP_KERNEL); if (!mhi->cmd_ctx) return -ENOMEM; cmd_ctx = mhi->cmd_ctx; /* Allocate event requests */ cmd_ctx->ereqs = kcalloc(NUM_CMD_EVENTS_DEFAULT, sizeof(*cmd_ctx->ereqs), GFP_KERNEL); if (!cmd_ctx->ereqs) { goto free_ereqs; return -ENOMEM; } /* Allocate buffers to queue transfer completion events */ cmd_ctx->cmd_events = kcalloc(NUM_CMD_EVENTS_DEFAULT, sizeof(*cmd_events), GFP_KERNEL); if (!cmd_ctx->cmd_events) { rc = -ENOMEM; goto free_ereqs; } /* Organize event flush requests into a linked list */ INIT_LIST_HEAD(&cmd_ctx->cmd_req_buffers); for (i = 0; i < NUM_CMD_EVENTS_DEFAULT; ++i) { list_add_tail(&cmd_ctx->ereqs[i].list, &cmd_ctx->cmd_req_buffers); } /* * Initialize cmpl event buffer indexes - cmd_buf_rp and * cmd_buf_wp point to the first and last free index available. */ cmd_ctx->cmd_buf_rp = 0; cmd_ctx->cmd_buf_wp = NUM_CMD_EVENTS_DEFAULT - 1; return 0; free_ereqs: kfree(mhi->cmd_ctx); kfree(cmd_ctx->ereqs); cmd_ctx->ereqs = NULL; mhi->cmd_ctx = NULL; return rc; } static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi, static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi, struct mhi_dev_channel *ch, struct mhi_dev_ring *evt_ring) struct mhi_dev_channel *ch, struct mhi_dev_ring *evt_ring) { { Loading
drivers/platform/msm/mhi_dev/mhi.h +17 −1 Original line number Original line Diff line number Diff line Loading @@ -271,6 +271,8 @@ struct mhi_config { /* maximum transfer completion events buffer */ /* maximum transfer completion events buffer */ #define NUM_TR_EVENTS_DEFAULT 128 #define NUM_TR_EVENTS_DEFAULT 128 #define NUM_CMD_EVENTS_DEFAULT 20 /* Set flush threshold to 80% of event buf size */ /* Set flush threshold to 80% of event buf size */ #define MHI_CMPL_EVT_FLUSH_THRSHLD(n) ((n * 8) / 10) #define MHI_CMPL_EVT_FLUSH_THRSHLD(n) ((n * 8) / 10) Loading Loading @@ -354,7 +356,8 @@ enum mhi_dev_ch_operation { enum mhi_dev_tr_compl_evt_type { enum mhi_dev_tr_compl_evt_type { SEND_EVENT_BUFFER, SEND_EVENT_BUFFER, SEND_EVENT_RD_OFFSET, SEND_EVENT_RD_OFFSET, SEND_MSI SEND_MSI, SEND_CMD_CMP, }; }; enum mhi_dev_transfer_type { enum mhi_dev_transfer_type { Loading Loading @@ -448,6 +451,18 @@ struct event_req { void (*msi_cb)(void *req); void (*msi_cb)(void *req); struct list_head list; struct list_head list; u32 flush_num; u32 flush_num; bool is_cmd_cpl; }; struct mhi_cmd_cmpl_ctx { /* Indices for completion event buffer */ uint32_t cmd_buf_rp; uint32_t cmd_buf_wp; uint32_t cmd_buf_size; bool mem_allocated; struct list_head cmd_req_buffers; struct event_req *ereqs; union mhi_dev_ring_element_type *cmd_events; }; }; struct mhi_dev_channel { struct mhi_dev_channel { Loading Loading @@ -531,6 +546,7 @@ struct mhi_dev { struct mhi_dev_ring *ring; struct mhi_dev_ring *ring; int mhi_irq; int mhi_irq; struct mhi_dev_channel *ch; struct mhi_dev_channel *ch; struct mhi_cmd_cmpl_ctx *cmd_ctx; int ctrl_int; int ctrl_int; int cmd_int; int cmd_int; Loading