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

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

Merge "mhi: core: Add range check for channel id received in event ring"

parents 890712ad 01919f9c
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -705,6 +705,9 @@ struct mhi_chan {
	struct completion completion;
	rwlock_t lock;
	struct list_head node;

	/* stats */
	u64 mode_change;
};

struct tsync_node {
+49 −24
Original line number Diff line number Diff line
@@ -568,9 +568,9 @@ int mhi_queue_dma(struct mhi_device *mhi_dev,
		mhi_tre->dword[1] = MHI_TRE_DATA_DWORD1(mhi_chan->bei, 1, 0, 0);
	}

	MHI_VERB("chan:%d WP:0x%llx TRE:0x%llx 0x%08x 0x%08x\n", mhi_chan->chan,
		 (u64)mhi_to_physical(tre_ring, mhi_tre), mhi_tre->ptr,
		 mhi_tre->dword[0], mhi_tre->dword[1]);
	MHI_VERB("chan:%d WP:0x%llx TRE:0x%llx 0x%08x 0x%08x rDB %d\n",
		mhi_chan->chan, (u64)mhi_to_physical(tre_ring, mhi_tre),
		mhi_tre->ptr, mhi_tre->dword[0], mhi_tre->dword[1], ring_db);

	/* increment WP */
	mhi_add_ring_element(mhi_cntrl, tre_ring);
@@ -982,6 +982,7 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
	unsigned long flags = 0;
	bool ring_db = true;
	int n_free_tre, n_queued_tre;
	unsigned long rflags;

	ev_code = MHI_TRE_GET_EV_CODE(event);
	buf_ring = &mhi_chan->buf_ring;
@@ -1071,12 +1072,8 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
		break;
	} /* CC_EOT */
	case MHI_EV_CC_OOB:
	case MHI_EV_CC_DB_MODE:
	{
		unsigned long flags;

		MHI_VERB("DB_MODE/OOB Detected chan %d.\n", mhi_chan->chan);
		mhi_chan->db_cfg.db_mode = 1;
		mhi_chan->db_cfg.db_mode = true;
		mhi_chan->mode_change++;

		/*
		 * on RSC channel IPA HW has a minimum credit requirement before
@@ -1090,14 +1087,27 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
				ring_db = false;
		}

		read_lock_irqsave(&mhi_cntrl->pm_lock, flags);
		MHI_VERB("OOB_MODE chan %d ring_db %d\n", mhi_chan->chan,
			ring_db);

		read_lock_irqsave(&mhi_cntrl->pm_lock, rflags);
		if (tre_ring->wp != tre_ring->rp &&
		    MHI_DB_ACCESS_VALID(mhi_cntrl) && ring_db) {
		    MHI_DB_ACCESS_VALID(mhi_cntrl) && ring_db)
			mhi_ring_chan_db(mhi_cntrl, mhi_chan);
		}
		read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags);
		read_unlock_irqrestore(&mhi_cntrl->pm_lock, rflags);
		break;
	case MHI_EV_CC_DB_MODE:
		MHI_VERB("DB_MODE chan %d.\n", mhi_chan->chan);
		mhi_chan->db_cfg.db_mode = true;
		mhi_chan->mode_change++;

		read_lock_irqsave(&mhi_cntrl->pm_lock, rflags);
		if (tre_ring->wp != tre_ring->rp &&
		    MHI_DB_ACCESS_VALID(mhi_cntrl))
			mhi_ring_chan_db(mhi_cntrl, mhi_chan);

		read_unlock_irqrestore(&mhi_cntrl->pm_lock, rflags);
		break;
	}
	case MHI_EV_CC_BAD_TRE:
		MHI_ASSERT(1, "Received BAD TRE event for ring");
		break;
@@ -1135,7 +1145,12 @@ static int parse_rsc_event(struct mhi_controller *mhi_cntrl,
	xfer_len = MHI_TRE_GET_EV_LEN(event);

	/* received out of bound cookie */
	MHI_ASSERT(cookie >= buf_ring->len, "Invalid Cookie\n");
	if (cookie >= buf_ring->len) {
		MHI_ERR("cookie 0x%08x bufring_len %zu", cookie, buf_ring->len);
		MHI_ERR("Processing Event:0x%llx 0x%08x 0x%08x\n",
			event->ptr, event->dword[0], event->dword[1]);
		panic("invalid cookie");
	}

	buf_info = buf_ring->base + cookie;

@@ -1385,6 +1400,10 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl,
			local_rp->ptr, local_rp->dword[0], local_rp->dword[1]);

		chan = MHI_TRE_GET_EV_CHID(local_rp);
		if (chan >= mhi_cntrl->max_chan) {
			MHI_ERR("invalid channel id %u\n", chan);
			continue;
		}
		mhi_chan = &mhi_cntrl->mhi_chan[chan];

		if (likely(type == MHI_PKT_TYPE_TX_EVENT)) {
@@ -1680,14 +1699,18 @@ irqreturn_t mhi_intvec_threaded_handlr(int irq_number, void *dev)
	MHI_VERB("Enter\n");

	write_lock_irq(&mhi_cntrl->pm_lock);
	if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
	if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
		write_unlock_irq(&mhi_cntrl->pm_lock);
		goto exit_intvec;
	}

	state = mhi_get_mhi_state(mhi_cntrl);
	ee = mhi_cntrl->ee;
	mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl);
		MHI_LOG("device ee:%s dev_state:%s\n",
	MHI_LOG("local ee: %s device ee:%s dev_state:%s\n",
		TO_MHI_EXEC_STR(ee),
		TO_MHI_EXEC_STR(mhi_cntrl->ee),
		TO_MHI_STATE_STR(state));
	}

	if (state == MHI_STATE_SYS_ERR) {
		MHI_ERR("MHI system error detected\n");
@@ -2205,12 +2228,14 @@ int mhi_debugfs_mhi_chan_show(struct seq_file *m, void *d)
				   chan_ctxt->pollcfg, chan_ctxt->chtype,
				   chan_ctxt->erindex);
			seq_printf(m,
				   " base:0x%llx len:0x%llx wp:0x%llx local_rp:0x%llx local_wp:0x%llx db:0x%llx\n",
				   " base:0x%llx len:0x%llx wp:0x%llx local_rp:0x%llx local_wp:0x%llx db:0x%llx mode_change:0x%llx\n",
				   chan_ctxt->rbase, chan_ctxt->rlen,
				   chan_ctxt->wp,
				   mhi_to_physical(ring, ring->rp),
				   mhi_to_physical(ring, ring->wp),
				   mhi_chan->db_cfg.db_val);
				   mhi_chan->db_cfg.db_val,
				   mhi_chan->mode_change);
			mhi_chan->mode_change = 0;
		}
	}

+6 −0
Original line number Diff line number Diff line
@@ -1163,6 +1163,9 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl)
	write_unlock_irq(&mhi_cntrl->pm_lock);
	MHI_LOG("Wait for M3 completion\n");

	/* finish reg writes before D3 cold */
	mhi_force_reg_write(mhi_cntrl);

	ret = wait_event_timeout(mhi_cntrl->state_event,
				 mhi_cntrl->dev_state == MHI_STATE_M3 ||
				 MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
@@ -1274,6 +1277,9 @@ int mhi_pm_fast_suspend(struct mhi_controller *mhi_cntrl, bool notify_client)
	mhi_cntrl->M3_FAST++;
	write_unlock_irq(&mhi_cntrl->pm_lock);

	/* finish reg writes before DRV hand-off to avoid noc err */
	mhi_force_reg_write(mhi_cntrl);

	/* now safe to check ctrl event ring */
	tasklet_enable(&mhi_cntrl->mhi_event->task);
	mhi_msi_handlr(0, mhi_cntrl->mhi_event);
+9 −2
Original line number Diff line number Diff line
/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
/* Copyright (c) 2018-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
@@ -120,6 +120,7 @@ struct mhi_netdev {

	/* debug stats */
	u32 abuffers, kbuffers, rbuffers;
	bool napi_scheduled;
};

struct mhi_netdev_priv {
@@ -458,6 +459,7 @@ static int mhi_netdev_alloc_thread(void *data)

		/* replenish the ring */
		napi_schedule(mhi_netdev->napi);
		mhi_netdev->napi_scheduled = true;

		/* wait for buffers to run low or thread to stop */
		wait_event_interruptible(mhi_netdev->alloc_event,
@@ -497,6 +499,7 @@ static int mhi_netdev_poll(struct napi_struct *napi, int budget)
	if (rx_work < 0) {
		MSG_ERR("Error polling ret:%d\n", rx_work);
		napi_complete(napi);
		mhi_netdev->napi_scheduled = false;
		return 0;
	}

@@ -507,8 +510,10 @@ static int mhi_netdev_poll(struct napi_struct *napi, int budget)
		mhi_netdev_queue(mhi_netdev, rsc_dev->mhi_dev);

	/* complete work if # of packet processed less than allocated budget */
	if (rx_work < budget)
	if (rx_work < budget) {
		napi_complete(napi);
		mhi_netdev->napi_scheduled = false;
	}

	MSG_VERB("polled %d pkts\n", rx_work);

@@ -844,6 +849,7 @@ static void mhi_netdev_status_cb(struct mhi_device *mhi_dev, enum MHI_CB mhi_cb)
		return;

	napi_schedule(mhi_netdev->napi);
	mhi_netdev->napi_scheduled = true;
}

#ifdef CONFIG_DEBUG_FS
@@ -1104,6 +1110,7 @@ static int mhi_netdev_probe(struct mhi_device *mhi_dev,
	 * by triggering a napi_poll
	 */
	napi_schedule(mhi_netdev->napi);
	mhi_netdev->napi_scheduled = true;

	return 0;
}