From d402048facfa4dc17e11230bc893907ca314316c Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Fri, 28 Oct 2016 14:22:59 -0700 Subject: [PATCH] msm: ipa3: fix send_cmd_timeout logic When sending commands to IPA with timeout, the completion object needs to be allocated on heap to make sure memory is still available when EOT is received for this command. Change-Id: I0228967ca3b33a56489a80833c0565ba2dfe8c2a CRs-Fixed: 1082708 Acked-by: Ady Abraham Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 127 ++++++++++++++++++----- 1 file changed, 102 insertions(+), 25 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 09c7c1b0fd05..cc1cb456ab8a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -766,6 +766,30 @@ static void ipa3_transport_irq_cmd_ack(void *user1, int user2) complete(&desc->xfer_done); } +/** + * ipa3_transport_irq_cmd_ack_free - callback function which will be + * called by SPS/GSI driver after an immediate command is complete. + * This function will also free the completion object once it is done. + * @tag_comp: pointer to the completion object + * @ignored: parameter not used + * + * Complete the immediate commands completion object, this will release the + * thread which waits on this completion object (ipa3_send_cmd()) + */ +static void ipa3_transport_irq_cmd_ack_free(void *tag_comp, int ignored) +{ + struct ipa3_tag_completion *comp = tag_comp; + + if (!comp) { + IPAERR("comp is NULL\n"); + return; + } + + complete(&comp->comp); + if (atomic_dec_return(&comp->cnt) == 0) + kfree(comp); +} + /** * ipa3_send_cmd - send immediate commands * @num_desc: number of descriptors within the desc struct @@ -778,7 +802,58 @@ static void ipa3_transport_irq_cmd_ack(void *user1, int user2) */ int ipa3_send_cmd(u16 num_desc, struct ipa3_desc *descr) { - return ipa3_send_cmd_timeout(num_desc, descr, 0); + struct ipa3_desc *desc; + int i, result = 0; + struct ipa3_sys_context *sys; + int ep_idx; + + for (i = 0; i < num_desc; i++) + IPADBG("sending imm cmd %d\n", descr[i].opcode); + + ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_CMD_PROD); + if (-1 == ep_idx) { + IPAERR("Client %u is not mapped\n", + IPA_CLIENT_APPS_CMD_PROD); + return -EFAULT; + } + + sys = ipa3_ctx->ep[ep_idx].sys; + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + + if (num_desc == 1) { + init_completion(&descr->xfer_done); + + if (descr->callback || descr->user1) + WARN_ON(1); + + descr->callback = ipa3_transport_irq_cmd_ack; + descr->user1 = descr; + if (ipa3_send_one(sys, descr, true)) { + IPAERR("fail to send immediate command\n"); + result = -EFAULT; + goto bail; + } + wait_for_completion(&descr->xfer_done); + } else { + desc = &descr[num_desc - 1]; + init_completion(&desc->xfer_done); + + if (desc->callback || desc->user1) + WARN_ON(1); + + desc->callback = ipa3_transport_irq_cmd_ack; + desc->user1 = desc; + if (ipa3_send(sys, num_desc, descr, true)) { + IPAERR("fail to send multiple immediate command set\n"); + result = -EFAULT; + goto bail; + } + wait_for_completion(&desc->xfer_done); + } + +bail: + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return result; } /** @@ -800,6 +875,7 @@ int ipa3_send_cmd_timeout(u16 num_desc, struct ipa3_desc *descr, u32 timeout) struct ipa3_sys_context *sys; int ep_idx; int completed; + struct ipa3_tag_completion *comp; for (i = 0; i < num_desc; i++) IPADBG("sending imm cmd %d\n", descr[i].opcode); @@ -810,55 +886,56 @@ int ipa3_send_cmd_timeout(u16 num_desc, struct ipa3_desc *descr, u32 timeout) IPA_CLIENT_APPS_CMD_PROD); return -EFAULT; } + + comp = kzalloc(sizeof(*comp), GFP_ATOMIC); + if (!comp) { + IPAERR("no mem\n"); + return -ENOMEM; + } + init_completion(&comp->comp); + + /* completion needs to be released from both here and in ack callback */ + atomic_set(&comp->cnt, 2); + sys = ipa3_ctx->ep[ep_idx].sys; IPA_ACTIVE_CLIENTS_INC_SIMPLE(); if (num_desc == 1) { - init_completion(&descr->xfer_done); - if (descr->callback || descr->user1) WARN_ON(1); - descr->callback = ipa3_transport_irq_cmd_ack; - descr->user1 = descr; + descr->callback = ipa3_transport_irq_cmd_ack_free; + descr->user1 = comp; if (ipa3_send_one(sys, descr, true)) { IPAERR("fail to send immediate command\n"); + kfree(comp); result = -EFAULT; goto bail; } - if (timeout) { - completed = wait_for_completion_timeout( - &descr->xfer_done, msecs_to_jiffies(timeout)); - if (!completed) - IPADBG("timeout waiting for imm-cmd ACK\n"); - } else { - wait_for_completion(&descr->xfer_done); - } } else { desc = &descr[num_desc - 1]; - init_completion(&desc->xfer_done); if (desc->callback || desc->user1) WARN_ON(1); - desc->callback = ipa3_transport_irq_cmd_ack; - desc->user1 = desc; + desc->callback = ipa3_transport_irq_cmd_ack_free; + desc->user1 = comp; if (ipa3_send(sys, num_desc, descr, true)) { IPAERR("fail to send multiple immediate command set\n"); + kfree(comp); result = -EFAULT; goto bail; } - if (timeout) { - completed = wait_for_completion_timeout( - &desc->xfer_done, msecs_to_jiffies(timeout)); - if (!completed) - IPADBG("timeout waiting for imm-cmd ACK\n"); - } else { - wait_for_completion(&desc->xfer_done); - } - } + completed = wait_for_completion_timeout( + &comp->comp, msecs_to_jiffies(timeout)); + if (!completed) + IPADBG("timeout waiting for imm-cmd ACK\n"); + + if (atomic_dec_return(&comp->cnt) == 0) + kfree(comp); + bail: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return result;