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

Commit 687c08a4 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mhi_dev: Avoid race in event ring updates"

parents abd094f1 271d8476
Loading
Loading
Loading
Loading
+44 −10
Original line number Diff line number Diff line
@@ -323,6 +323,7 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
		return -EINVAL;
	}

	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 */
@@ -331,6 +332,7 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
	rc = mhi_dev_add_element(ring, ereq->tr_events, ereq, evt_len);
	if (rc) {
		pr_err("%s(): error in adding element rc %d\n", __func__, rc);
		mutex_unlock(&ring->event_lock);
		return rc;
	}
	ring->ring_ctx_shadow->ev.rp = (ring->rd_offset *
@@ -366,6 +368,7 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
	ereq->client_cb = mhi_dev_event_rd_offset_completion_cb;
	ereq->event_ring = evnt_ring;
	mhi_ctx->write_to_host(mhi, &transfer_addr, ereq, MHI_DEV_DMA_ASYNC);
	mutex_unlock(&ring->event_lock);
	return rc;
}

@@ -1393,6 +1396,37 @@ int mhi_dev_send_event(struct mhi_dev *mhi, int evnt_ring,
	return ep_pcie_trigger_msi(mhi_ctx->phandle, ctx->ev.msivec);
}

static int mhi_dev_send_completion_event_async(struct mhi_dev_channel *ch,
			size_t rd_ofst, uint32_t len,
			enum mhi_dev_cmd_completion_code code,
			struct mhi_req *mreq)
{
	int rc;
	struct mhi_dev *mhi = ch->ring->mhi_dev;

	mhi_log(MHI_MSG_VERBOSE, "Ch %d\n", ch->ch_id);

	/* Queue the completion event for the current transfer */
	mreq->snd_cmpl = 1;
	rc = mhi_dev_queue_transfer_completion(mreq, NULL);
	if (rc) {
		mhi_log(MHI_MSG_ERROR,
			"Failed to queue completion for ch %d, rc %d\n",
			ch->ch_id, rc);
		return rc;
	}

	mhi_log(MHI_MSG_VERBOSE, "Calling flush for ch %d\n", ch->ch_id);
	rc = mhi_dev_flush_transfer_completion_events(mhi, ch);
	if (rc) {
		mhi_log(MHI_MSG_ERROR,
			"Failed to flush read completions to host\n");
		return rc;
	}

	return 0;
}

static int mhi_dev_send_completion_event(struct mhi_dev_channel *ch,
			size_t rd_ofst, uint32_t len,
			enum mhi_dev_cmd_completion_code code)
@@ -2699,7 +2733,7 @@ EXPORT_SYMBOL(mhi_dev_close_channel);

static int mhi_dev_check_tre_bytes_left(struct mhi_dev_channel *ch,
		struct mhi_dev_ring *ring, union mhi_dev_ring_element_type *el,
		uint32_t *chain)
		struct mhi_req *mreq)
{
	uint32_t td_done = 0;

@@ -2710,17 +2744,17 @@ static int mhi_dev_check_tre_bytes_left(struct mhi_dev_channel *ch,
	if (ch->tre_bytes_left == 0) {
		if (el->tre.chain) {
			if (el->tre.ieob)
				mhi_dev_send_completion_event(ch,
				mhi_dev_send_completion_event_async(ch,
				ring->rd_offset, el->tre.len,
					MHI_CMD_COMPL_CODE_EOB);
			*chain = 1;
				MHI_CMD_COMPL_CODE_EOB, mreq);
			mreq->chain = 1;
		} else {
			if (el->tre.ieot)
				mhi_dev_send_completion_event(
				mhi_dev_send_completion_event_async(
				ch, ring->rd_offset, el->tre.len,
					MHI_CMD_COMPL_CODE_EOT);
				MHI_CMD_COMPL_CODE_EOT, mreq);
			td_done = 1;
			*chain = 0;
			mreq->chain = 0;
		}
		mhi_dev_ring_inc_index(ring, ring->rd_offset);
		ch->tre_bytes_left = 0;
@@ -2831,7 +2865,7 @@ int mhi_dev_read_channel(struct mhi_req *mreq)
			goto exit;
		} else {
			td_done = mhi_dev_check_tre_bytes_left(ch, ring,
					el, &mreq->chain);
					el, mreq);
		}
	} while (usr_buf_remaining  && !td_done);
	if (td_done && ch->state == MHI_DEV_CH_PENDING_STOP) {
+5 −1
Original line number Diff line number Diff line
@@ -382,7 +382,11 @@ struct mhi_dev_ring {

	enum mhi_dev_ring_type			type;
	enum mhi_dev_ring_state			state;

	/*
	 * Lock to prevent race in updating event ring
	 * which is shared by multiple channels
	 */
	struct mutex	event_lock;
	/* device virtual address location of the cached host ring ctx data */
	union mhi_dev_ring_element_type		*ring_cache;
	/* Physical address of the cached ring copy on the device side */
+2 −1
Original line number Diff line number Diff line
/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -453,6 +453,7 @@ void mhi_ring_init(struct mhi_dev_ring *ring, enum mhi_dev_ring_type type,
	ring->state = RING_STATE_UINT;
	ring->ring_cb = NULL;
	ring->type = type;
	mutex_init(&ring->event_lock);
}
EXPORT_SYMBOL(mhi_ring_init);