summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-10-31 13:04:29 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2016-10-31 13:04:29 -0700
commit42721afa5c9c5ad874791cc7c73a095c66393205 (patch)
treeb22cfb06f6954923bdfb611d2e18bc8c87a8b57a
parent07b3f6b47321acb325cc39b7a15f87f2d8245c66 (diff)
parentd402048facfa4dc17e11230bc893907ca314316c (diff)
Merge "msm: ipa3: fix send_cmd_timeout logic"
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_dp.c127
1 files 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
@@ -767,6 +767,30 @@ static void ipa3_transport_irq_cmd_ack(void *user1, int user2)
}
/**
+ * 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
* @descr: descriptor structure
@@ -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;