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

Commit b863c80e authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge changes I2ac035f6,I2e100892,Ie0e829bd into msm-4.14

* changes:
  mhi_bus: core: notify clients when dropping queued packets
  mhi_bus: core: add support for pre-allocating buffers for DL channels
  mhi: core: add support for collecting device ram dump during panic
parents 11747c5d 924b28ab
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -52,6 +52,9 @@ Main node properties:
		the data pipe. Not involved in active data transfer.
		BIT(2) : Must switch to doorbell mode whenever MHI M0 state
		transition happens.
		BIT(3) : MHI bus driver pre-allocate buffer for this channel.
		If set, clients not allowed to queue buffers. Valid only for DL
		direction.

- mhi,chan-names
  Usage: required
+95 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
 */

#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
@@ -42,6 +43,97 @@ static void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl,
	}
}

/* collect rddm during kernel panic */
static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl)
{
	int ret;
	struct mhi_buf *mhi_buf;
	u32 sequence_id;
	u32 rx_status;
	enum MHI_EE ee;
	struct image_info *rddm_image = mhi_cntrl->rddm_image;
	const u32 delayus = 100;
	u32 retry = (mhi_cntrl->timeout_ms * 1000) / delayus;
	void __iomem *base = mhi_cntrl->bhi;

	MHI_LOG("Entered with pm_state:%s dev_state:%s ee:%s\n",
		to_mhi_pm_state_str(mhi_cntrl->pm_state),
		TO_MHI_STATE_STR(mhi_cntrl->dev_state),
		TO_MHI_EXEC_STR(mhi_cntrl->ee));

	/*
	 * This should only be executing during a kernel panic, we expect all
	 * other cores to shutdown while we're collecting rddm buffer. After
	 * returning from this function, we expect device to reset.
	 *
	 * Normaly, we would read/write pm_state only after grabbing
	 * pm_lock, since we're in a panic, skipping it.
	 */

	if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
		return -EIO;

	/*
	 * There is no gurantee this state change would take effect since
	 * we're setting it w/o grabbing pmlock, it's best effort
	 */
	mhi_cntrl->pm_state = MHI_PM_LD_ERR_FATAL_DETECT;
	/* update should take the effect immediately */
	smp_wmb();

	/* setup the RX vector table */
	mhi_rddm_prepare(mhi_cntrl, rddm_image);
	mhi_buf = &rddm_image->mhi_buf[rddm_image->entries - 1];

	MHI_LOG("Starting BHIe programming for RDDM\n");

	mhi_write_reg(mhi_cntrl, base, BHIE_RXVECADDR_HIGH_OFFS,
		      upper_32_bits(mhi_buf->dma_addr));

	mhi_write_reg(mhi_cntrl, base, BHIE_RXVECADDR_LOW_OFFS,
		      lower_32_bits(mhi_buf->dma_addr));

	mhi_write_reg(mhi_cntrl, base, BHIE_RXVECSIZE_OFFS, mhi_buf->len);
	sequence_id = prandom_u32() & BHIE_RXVECSTATUS_SEQNUM_BMSK;

	if (unlikely(!sequence_id))
		sequence_id = 1;


	mhi_write_reg_field(mhi_cntrl, base, BHIE_RXVECDB_OFFS,
			    BHIE_RXVECDB_SEQNUM_BMSK, BHIE_RXVECDB_SEQNUM_SHFT,
			    sequence_id);

	MHI_LOG("Trigger device into RDDM mode\n");
	mhi_set_mhi_state(mhi_cntrl, MHI_STATE_SYS_ERR);

	MHI_LOG("Waiting for image download completion\n");
	while (retry--) {
		ret = mhi_read_reg_field(mhi_cntrl, base, BHIE_RXVECSTATUS_OFFS,
					 BHIE_RXVECSTATUS_STATUS_BMSK,
					 BHIE_RXVECSTATUS_STATUS_SHFT,
					 &rx_status);
		if (ret)
			return -EIO;

		if (rx_status == BHIE_RXVECSTATUS_STATUS_XFER_COMPL) {
			MHI_LOG("RDDM successfully collected\n");
			return 0;
		}

		udelay(delayus);
	}

	ee = mhi_get_exec_env(mhi_cntrl);
	ret = mhi_read_reg(mhi_cntrl, base, BHIE_RXVECSTATUS_OFFS, &rx_status);

	MHI_ERR("Did not complete RDDM transfer\n");
	MHI_ERR("Current EE:%s\n", TO_MHI_EXEC_STR(ee));
	MHI_ERR("RXVEC_STATUS:0x%x, ret:%d\n", rx_status, ret);

	return -EIO;
}

/* download ramdump image from device */
int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic)
{
@@ -56,6 +148,9 @@ int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic)
	if (!rddm_image)
		return -ENOMEM;

	if (in_panic)
		return __mhi_download_rddm_in_panic(mhi_cntrl);

	MHI_LOG("Waiting for device to enter RDDM state from EE:%s\n",
		TO_MHI_EXEC_STR(mhi_cntrl->ee));

+10 −0
Original line number Diff line number Diff line
@@ -823,6 +823,16 @@ static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl,
		mhi_chan->offload_ch = !!(bit_cfg & MHI_CH_CFG_BIT_OFFLOAD_CH);
		mhi_chan->db_cfg.reset_req =
			!!(bit_cfg & MHI_CH_CFG_BIT_DBMODE_RESET_CH);
		mhi_chan->pre_alloc = !!(bit_cfg & MHI_CH_CFG_BIT_PRE_ALLOC);

		if (mhi_chan->pre_alloc &&
		    (mhi_chan->dir != DMA_FROM_DEVICE ||
		     mhi_chan->xfer_type != MHI_XFER_BUFFER))
			goto error_chan_cfg;

		/* if mhi host allocate the buffers then client cannot queue */
		if (mhi_chan->pre_alloc)
			mhi_chan->queue_xfer = mhi_queue_nop;

		ret = of_property_read_string_index(of_node, "mhi,chan-names",
						    i, &mhi_chan->name);
+3 −0
Original line number Diff line number Diff line
@@ -339,6 +339,7 @@ enum MHI_CH_CFG {
#define MHI_CH_CFG_BIT_LPM_NOTIFY BIT(0) /* require LPM notification */
#define MHI_CH_CFG_BIT_OFFLOAD_CH BIT(1) /* satellite mhi devices */
#define MHI_CH_CFG_BIT_DBMODE_RESET_CH BIT(2) /* require db mode to reset */
#define MHI_CH_CFG_BIT_PRE_ALLOC BIT(3) /* host allocate buffers for DL */

enum MHI_EV_CFG {
	MHI_EV_CFG_ELEMENTS = 0,
@@ -565,6 +566,7 @@ struct mhi_chan {
	bool lpm_notify;
	bool configured;
	bool offload_ch;
	bool pre_alloc;
	/* functions that generate the transfer ring elements */
	int (*gen_tre)(struct mhi_controller *, struct mhi_chan *, void *,
		       void *, size_t, enum MHI_FLAGS);
@@ -654,6 +656,7 @@ void mhi_write_db(struct mhi_controller *mhi_cntrl, void __iomem *db_addr,
void mhi_ring_cmd_db(struct mhi_controller *mhi_cntrl, struct mhi_cmd *mhi_cmd);
void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl,
		      struct mhi_chan *mhi_chan);
void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, enum MHI_STATE state);

/* memory allocation methods */
static inline void *mhi_alloc_coherent(struct mhi_controller *mhi_cntrl,
+61 −0
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@
#include <linux/mhi.h>
#include "mhi_internal.h"

static void __mhi_unprepare_channel(struct mhi_controller *mhi_cntrl,
				    struct mhi_chan *mhi_chan);

int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl,
			      void __iomem *base,
			      u32 offset,
@@ -661,6 +664,22 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
				mhi_cntrl->wake_put(mhi_cntrl, false);
				read_unlock_bh(&mhi_cntrl->pm_lock);
			}

			/*
			 * recycle the buffer if buffer is pre-allocated,
			 * if there is error, not much we can do apart from
			 * dropping the packet
			 */
			if (mhi_chan->pre_alloc) {
				if (mhi_queue_buf(mhi_chan->mhi_dev, mhi_chan,
						  buf_info->cb_buf,
						  buf_info->len, MHI_EOT)) {
					MHI_ERR(
						"Error recycling buffer for chan:%d\n",
						mhi_chan->chan);
					kfree(buf_info->cb_buf);
				}
			}
		};
		break;
	} /* CC_EOT */
@@ -1086,6 +1105,32 @@ static int __mhi_prepare_channel(struct mhi_controller *mhi_cntrl,
	mhi_cntrl->wake_put(mhi_cntrl, false);
	read_unlock_bh(&mhi_cntrl->pm_lock);

	/* pre allocate buffer for xfer ring */
	if (mhi_chan->pre_alloc) {
		struct mhi_device *mhi_dev = mhi_chan->mhi_dev;
		int nr_el = get_nr_avail_ring_elements(mhi_cntrl,
						       &mhi_chan->tre_ring);

		while (nr_el--) {
			void *buf;

			buf = kmalloc(MHI_MAX_MTU, GFP_KERNEL);
			if (!buf) {
				ret = -ENOMEM;
				goto error_pre_alloc;
			}

			ret = mhi_queue_buf(mhi_dev, mhi_chan, buf, MHI_MAX_MTU,
					    MHI_EOT);
			if (ret) {
				MHI_ERR("Chan:%d error queue buffer\n",
					mhi_chan->chan);
				kfree(buf);
				goto error_pre_alloc;
			}
		}
	}

	mutex_unlock(&mhi_chan->mutex);

	MHI_LOG("Chan:%d successfully moved to start state\n", mhi_chan->chan);
@@ -1104,6 +1149,12 @@ static int __mhi_prepare_channel(struct mhi_controller *mhi_cntrl,
error_init_chan:
	mutex_unlock(&mhi_chan->mutex);

	return ret;

error_pre_alloc:
	mutex_unlock(&mhi_chan->mutex);
	__mhi_unprepare_channel(mhi_cntrl, mhi_chan);

	return ret;
}

@@ -1115,6 +1166,7 @@ void mhi_reset_chan(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan)
	struct mhi_ring *ev_ring, *buf_ring, *tre_ring;
	unsigned long flags;
	int chan = mhi_chan->chan;
	struct mhi_result result;

	/* nothing to reset, client don't queue buffers */
	if (mhi_chan->offload_ch)
@@ -1159,6 +1211,8 @@ void mhi_reset_chan(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan)
	/* reset any pending buffers */
	buf_ring = &mhi_chan->buf_ring;
	tre_ring = &mhi_chan->tre_ring;
	result.transaction_status = -ENOTCONN;
	result.bytes_xferd = 0;
	while (tre_ring->rp != tre_ring->wp) {
		struct mhi_buf_info *buf_info = buf_ring->rp;

@@ -1169,6 +1223,13 @@ void mhi_reset_chan(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan)
				 buf_info->len, buf_info->dir);
		mhi_del_ring_element(mhi_cntrl, buf_ring);
		mhi_del_ring_element(mhi_cntrl, tre_ring);

		if (mhi_chan->pre_alloc) {
			kfree(buf_info->cb_buf);
		} else {
			result.buf_addr = buf_info->cb_buf;
			mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
		}
	}

	read_unlock_bh(&mhi_cntrl->pm_lock);
Loading