Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aa4e78e6 authored by Ravit Katzav's avatar Ravit Katzav
Browse files

msm: ipa: fix TAG process timeout



In case of timeout in TAG process, completion object was referenced
after it got free. This commit adds reference count to the completion
object to avoid this condition.

Change-Id: I059813fe26b39b3fe60adadd9fa90397304219bc
Acked-by: default avatarAdy Abraham <adya@qti.qualcomm.com>
Signed-off-by: default avatarRavit Katzav <rkatzav@codeaurora.org>
parent d2d9cb96
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -1741,7 +1741,7 @@ begin:
			BUG();
		}
		if (status->status_mask & IPA_HW_PKT_STATUS_MASK_TAG_VALID) {
			struct completion *comp;
			struct ipa_tag_completion *comp;
			IPADBG("TAG packet arrived\n");
			if (status->tag_f_2 == IPA_COOKIE) {
				skb_pull(skb, IPA_PKT_STATUS_SIZE);
@@ -1751,7 +1751,9 @@ begin:
				}
				memcpy(&comp, skb->data, sizeof(comp));
				skb_pull(skb, sizeof(comp));
				complete(comp);
				complete(&comp->comp);
				if (atomic_dec_return(&comp->cnt) == 0)
					kfree(comp);
				continue;
			} else {
				IPADBG("ignoring TAG with wrong cookie\n");
+5 −0
Original line number Diff line number Diff line
@@ -643,6 +643,11 @@ struct ipa_active_clients {
	int cnt;
};

struct ipa_tag_completion {
	struct completion comp;
	atomic_t cnt;
};

struct ipa_controller;

struct ipa_wdi_ctx {
+21 −6
Original line number Diff line number Diff line
@@ -3436,8 +3436,7 @@ int ipa_tag_process(struct ipa_desc desc[],
	int i;
	struct sk_buff *dummy_skb;
	int res;
	DECLARE_COMPLETION_ONSTACK(comp);
	void *comp_ptr = &comp;
	struct ipa_tag_completion *comp;

	/* Not enough room for the required descriptors for the tag process */
	if (IPA_TAG_MAX_DESC - descs_num < REQUIRED_TAG_PROCESS_DESCRIPTORS) {
@@ -3517,16 +3516,26 @@ int ipa_tag_process(struct ipa_desc desc[],
		sizeof(struct ipa_desc));
	desc_idx += descs_num;

	comp = kzalloc(sizeof(*comp), GFP_KERNEL);
	if (!comp) {
		IPAERR("no mem\n");
		res = -ENOMEM;
		goto fail_free_desc;
	}
	init_completion(&comp->comp);

	/* completion needs to be released from both here and rx handler */
	atomic_set(&comp->cnt, 2);

	/* dummy packet to send to IPA. packet payload is a completion object */
	dummy_skb = alloc_skb(sizeof(comp), GFP_KERNEL);
	if (!dummy_skb) {
		IPAERR("failed to allocate memory\n");
		res = -ENOMEM;
		goto fail_free_desc;
		goto fail_free_skb;
	}

	memcpy(skb_put(dummy_skb, sizeof(comp_ptr)), &comp_ptr,
		sizeof(comp_ptr));
	memcpy(skb_put(dummy_skb, sizeof(comp)), &comp, sizeof(comp));

	tag_desc[desc_idx].pyld = dummy_skb->data;
	tag_desc[desc_idx].len = dummy_skb->len;
@@ -3546,14 +3555,18 @@ int ipa_tag_process(struct ipa_desc desc[],
	tag_desc = NULL;

	IPADBG("waiting for TAG response\n");
	res = wait_for_completion_timeout(&comp, timeout);
	res = wait_for_completion_timeout(&comp->comp, timeout);
	if (res == 0) {
		IPAERR("timeout for waiting for TAG response\n");
		WARN_ON(1);
		if (atomic_dec_return(&comp->cnt) == 0)
			kfree(comp);
		return -ETIME;
	}

	IPADBG("TAG response arrived!\n");
	if (atomic_dec_return(&comp->cnt) == 0)
		kfree(comp);

	/* sleep for short period to ensure IPA wrote all packets to BAM */
	usleep_range(IPA_TAG_SLEEP_MIN_USEC, IPA_TAG_SLEEP_MAX_USEC);
@@ -3563,6 +3576,8 @@ int ipa_tag_process(struct ipa_desc desc[],
fail_send:
	dev_kfree_skb_any(dummy_skb);
	desc_idx--;
fail_free_skb:
	kfree(comp);
fail_free_desc:
	/*
	 * Free only the first descriptors allocated here.