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

Commit 1f3617ef authored by Gauri Joshi's avatar Gauri Joshi
Browse files

msm: mhi-dev: Flush ereqs from dev close to avoid OOS transfers



Currently there is a race condition where during the flushing of ereqs
the channel is closed from the client on the EP side, which is causing
the flush function to access null memory. To avoid that call the flush
from dev close which ensures all the pending ereqs are closed before
closing the channel and freeing the memory.

Change-Id: Id81d8cb8b326340d28f6cfe9d48dcd685a8038f9
Signed-off-by: default avatarGauri Joshi <gaurjosh@codeaurora.org>
parent 75c8d2fc
Loading
Loading
Loading
Loading
+19 −7
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <linux/vmalloc.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/limits.h>

#include "mhi.h"
#include "mhi_hwio.h"
@@ -65,7 +66,7 @@

#define MHI_DEV_CH_CLOSE_TIMEOUT_MIN	5000
#define MHI_DEV_CH_CLOSE_TIMEOUT_MAX	5100
#define MHI_DEV_CH_CLOSE_TIMEOUT_COUNT	30
#define MHI_DEV_CH_CLOSE_TIMEOUT_COUNT	200

uint32_t bhi_imgtxdb;
enum mhi_msg_level mhi_msg_lvl = MHI_MSG_ERROR;
@@ -363,6 +364,12 @@ static void mhi_dev_event_msi_cb(void *req)
	}

	ch = ereq->context;
	if (!ch) {
		mhi_log(MHI_MSG_ERROR, "Invalid ereq context, return\n");
		return;
	}
	if (ch->pend_flush_cnt++ >= U32_MAX)
		ch->pend_flush_cnt = 0;
	mhi = ch->ring->mhi_dev;

	mhi_log(MHI_MSG_VERBOSE, "MSI completed for flush req %d\n",
@@ -641,7 +648,8 @@ static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi,
		list_del_init(&flush_ereq->list);
		spin_unlock_irqrestore(&mhi->lock, flags);

		ch->flush_req_cnt++;
		if (ch->flush_req_cnt++ >= U32_MAX)
			ch->flush_req_cnt = 0;
		flush_ereq->flush_num = ch->flush_req_cnt;
		mhi_log(MHI_MSG_DBG, "Flush num %d called for ch %d\n",
			ch->flush_req_cnt, ch->ch_id);
@@ -3214,24 +3222,28 @@ void mhi_dev_close_channel(struct mhi_dev_client *handle)
{
	struct mhi_dev_channel *ch;
	int count = 0;

	int rc = 0;
	if (!handle) {
		mhi_log(MHI_MSG_ERROR, "Invalid channel access:%d\n", -ENODEV);
		return;
	}
	ch = handle->channel;

	mutex_lock(&ch->ch_lock);

	rc = mhi_dev_flush_transfer_completion_events(mhi_ctx, ch);
	if (rc) {
		mhi_log(MHI_MSG_ERROR,
			"Failed to flush read completions to host\n");
	}
	do {
		if (ch->pend_wr_count &&
			!list_empty(&ch->event_req_buffers)) {
		if (ch->flush_req_cnt != ch->pend_flush_cnt) {
			usleep_range(MHI_DEV_CH_CLOSE_TIMEOUT_MIN,
					MHI_DEV_CH_CLOSE_TIMEOUT_MAX);
		} else
			break;
	} while (++count < MHI_DEV_CH_CLOSE_TIMEOUT_COUNT);

	mutex_lock(&ch->ch_lock);

	if (ch->pend_wr_count)
		mhi_log(MHI_MSG_ERROR, "%d writes pending for channel %d\n",
			ch->pend_wr_count, ch->ch_id);
+1 −0
Original line number Diff line number Diff line
@@ -508,6 +508,7 @@ struct mhi_dev_channel {
	uint32_t			pend_wr_count;
	uint32_t			msi_cnt;
	uint32_t			flush_req_cnt;
	uint32_t			pend_flush_cnt;
	bool				skip_td;
	bool				db_pending;
	bool				reset_pending;