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

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

Merge "msm: mhi: Send Ch cmd ack in async fashion"

parents 1d93666c 98e95994
Loading
Loading
Loading
Loading
+181 −28
Original line number Original line Diff line number Diff line
@@ -87,6 +87,10 @@ static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi,
static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi,
static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi,
		struct event_req *ereq);
		struct event_req *ereq);
static void mhi_dev_event_msi_cb(void *req);
static void mhi_dev_event_msi_cb(void *req);
static void mhi_dev_cmd_event_msi_cb(void *req);

static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi);



static struct mhi_dev_uevent_info channel_state_info[MHI_MAX_CHANNELS];
static struct mhi_dev_uevent_info channel_state_info[MHI_MAX_CHANNELS];
static DECLARE_COMPLETION(read_from_host);
static DECLARE_COMPLETION(read_from_host);
@@ -262,7 +266,7 @@ static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq)
{
{
	struct ep_pcie_msi_config cfg;
	struct ep_pcie_msi_config cfg;
	struct mhi_addr msi_addr;
	struct mhi_addr msi_addr;
	struct mhi_dev_channel *ch = ereq->context;
	struct mhi_dev_channel *ch;
	uint64_t evnt_ring_idx = mhi->ev_ring_start + ereq->event_ring;
	uint64_t evnt_ring_idx = mhi->ev_ring_start + ereq->event_ring;
	struct mhi_dev_ring *ring = &mhi->ring[evnt_ring_idx];
	struct mhi_dev_ring *ring = &mhi->ring[evnt_ring_idx];
	union mhi_dev_ring_ctx *ctx;
	union mhi_dev_ring_ctx *ctx;
@@ -283,14 +287,23 @@ static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq)
	msi_addr.phy_addr = ring->msi_buf_dma_handle;
	msi_addr.phy_addr = ring->msi_buf_dma_handle;


	ereq->event_type = SEND_MSI;
	ereq->event_type = SEND_MSI;
	if (!ereq->is_cmd_cpl) {
		ch = ereq->context;
		ereq->msi_cb = mhi_dev_event_msi_cb;
		ereq->msi_cb = mhi_dev_event_msi_cb;

		ch->msi_cnt++;
		ch->msi_cnt++;

		mhi_log(MHI_MSG_VERBOSE,
		mhi_log(MHI_MSG_VERBOSE,
			"Sending MSI %d to 0x%llx as data = 0x%x for ch %d msi_count %d, ereq flush_num %d\n",
			"Sending MSI %d to 0x%llx as data = 0x%x for ch %d msi_count %d, ereq flush_num %d\n",
		ctx->ev.msivec, msi_addr.host_pa, *ring->msi_buf, ch->ch_id,
			ctx->ev.msivec, msi_addr.host_pa,
			*ring->msi_buf, ch->ch_id,
			ch->msi_cnt, ereq->flush_num);
			ch->msi_cnt, ereq->flush_num);
	} else {
		ereq->msi_cb = mhi_dev_cmd_event_msi_cb;
		mhi_log(MHI_MSG_VERBOSE,
			"Sending MSI %d to 0x%llx as data = 0x%x for cmd ack, ereq flush_num %d\n",
			ctx->ev.msivec, msi_addr.host_pa, *ring->msi_buf,
			ereq->flush_num);
	}

	mhi_ctx->write_to_host(mhi, &msi_addr, ereq, MHI_DEV_DMA_ASYNC);
	mhi_ctx->write_to_host(mhi, &msi_addr, ereq, MHI_DEV_DMA_ASYNC);


	return 0;
	return 0;
@@ -314,6 +327,27 @@ static void mhi_dev_event_rd_offset_completion_cb(void *req)
		sizeof(uint64_t), DMA_TO_DEVICE);
		sizeof(uint64_t), DMA_TO_DEVICE);
}
}


static void mhi_dev_cmd_event_msi_cb(void *req)
{
	struct mhi_cmd_cmpl_ctx *cmd_ctx;
	struct mhi_dev *mhi;
	struct event_req *ereq = req;
	unsigned long flags;

	mhi_log(MHI_MSG_VERBOSE, "MSI completed for flush req %d\n",
		ereq->flush_num);

	/*Cmd completion handling*/
	mhi = ereq->context;
	cmd_ctx = mhi->cmd_ctx;
	cmd_ctx->cmd_buf_wp += ereq->num_events;
	if (cmd_ctx->cmd_buf_wp == NUM_CMD_EVENTS_DEFAULT)
		cmd_ctx->cmd_buf_wp = 0;
	spin_lock_irqsave(&mhi->lock, flags);
	list_add_tail(&ereq->list, &cmd_ctx->cmd_req_buffers);
	spin_unlock_irqrestore(&mhi->lock, flags);
}

static void mhi_dev_event_msi_cb(void *req)
static void mhi_dev_event_msi_cb(void *req)
{
{
	struct event_req *ereq = req;
	struct event_req *ereq = req;
@@ -401,7 +435,8 @@ static int mhi_trigger_msi_edma(struct mhi_dev_ring *ring, u32 idx)
}
}


static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
		struct event_req *ereq, uint32_t evt_len)
		struct event_req *ereq, uint32_t evt_len,
		enum mhi_dev_tr_compl_evt_type event_type)
{
{
	int rc = 0;
	int rc = 0;
	uint64_t evnt_ring_idx = mhi->ev_ring_start + evnt_ring;
	uint64_t evnt_ring_idx = mhi->ev_ring_start + evnt_ring;
@@ -430,25 +465,25 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
			return rc;
			return rc;
		}
		}
	}
	}
	ch = ereq->context;

	/* Check the limits of the buffer to be flushed */
	if (ereq->tr_events < ch->tr_events ||
		(ereq->tr_events + ereq->num_events) >
		(ch->tr_events + ch->evt_buf_size)) {
		pr_err("%s: Invalid completion event buffer!\n", __func__);
		mhi_log(MHI_MSG_ERROR,
			"Invalid cmpl evt buf - start %pK, end %pK\n",
			ereq->tr_events, ereq->tr_events + ereq->num_events);
		return -EINVAL;
	}


	mutex_lock(&ring->event_lock);
	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 */
	/* add the events */
	ereq->client_cb = mhi_dev_event_buf_completion_cb;
	ereq->client_cb = mhi_dev_event_buf_completion_cb;
	ereq->is_cmd_cpl = (event_type == SEND_CMD_CMP) ? true:false;
	ereq->event_type = SEND_EVENT_BUFFER;
	ereq->event_type = SEND_EVENT_BUFFER;


	if (!ereq->is_cmd_cpl) {
		ch = ereq->context;
		mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of ch %d\n",
				ereq->num_events, ch->ch_id);
	} else {
		mhi_log(MHI_MSG_VERBOSE,
			"Flushing %d cmpl events of cmd ring\n",
			ereq->num_events);
	}

	rc = mhi_dev_add_element(ring, ereq->tr_events, ereq, evt_len);
	rc = mhi_dev_add_element(ring, ereq->tr_events, ereq, evt_len);
	if (rc) {
	if (rc) {
		pr_err("%s(): error in adding element rc %d\n", __func__, rc);
		pr_err("%s(): error in adding element rc %d\n", __func__, rc);
@@ -506,6 +541,55 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
	return rc;
	return rc;
}
}


static int mhi_dev_flush_cmd_completion_events(struct mhi_dev *mhi,
		union mhi_dev_ring_element_type *el)
{
	struct mhi_cmd_cmpl_ctx *cmd_ctx = mhi->cmd_ctx;
	unsigned long flags;
	struct event_req *flush_ereq;
	union mhi_dev_ring_element_type *compl_ev;
	int rc = 0;

	/*cmd completions are sent on event ring 0 always*/
	if (!mhi->cmd_ctx) {
		if (mhi_dev_alloc_cmd_ack_buf_req(mhi)) {
			mhi_log(MHI_MSG_ERROR, "Alloc cmd ack buff failed");
			return -ENOMEM;
		}
	}
	cmd_ctx = mhi->cmd_ctx;
	if (list_empty(&cmd_ctx->cmd_req_buffers)) {
		mhi_log(MHI_MSG_ERROR, "cmd req buff list is empty");
		return -ENOMEM;
	}

	spin_lock_irqsave(&mhi->lock, flags);
	flush_ereq = container_of(cmd_ctx->cmd_req_buffers.next,
					struct event_req, list);
	list_del_init(&flush_ereq->list);
	flush_ereq->context = mhi;
	spin_unlock_irqrestore(&mhi->lock, flags);

	compl_ev = cmd_ctx->cmd_events + cmd_ctx->cmd_buf_rp;
	memcpy(compl_ev, el, sizeof(union mhi_dev_ring_element_type));
	cmd_ctx->cmd_buf_rp++;
	if (cmd_ctx->cmd_buf_rp == NUM_CMD_EVENTS_DEFAULT)
		cmd_ctx->cmd_buf_rp = 0;
	flush_ereq->tr_events = compl_ev;
	rc = mhi_dev_send_multiple_tr_events(mhi,
				0,
				flush_ereq,
				(1 *
				sizeof(union mhi_dev_ring_element_type)),
				SEND_CMD_CMP);
	if (rc) {
		mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n");
		return rc;
	}

	return rc;
}

static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi,
static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi,
		struct mhi_dev_channel *ch)
		struct mhi_dev_channel *ch)
{
{
@@ -539,11 +623,25 @@ static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi,
		flush_ereq->flush_num = ch->flush_req_cnt;
		flush_ereq->flush_num = ch->flush_req_cnt;
		mhi_log(MHI_MSG_DBG, "Flush num %d called for ch %d\n",
		mhi_log(MHI_MSG_DBG, "Flush num %d called for ch %d\n",
			ch->flush_req_cnt, ch->ch_id);
			ch->flush_req_cnt, ch->ch_id);

		/* Check the limits of the buffer to be flushed */
		if (flush_ereq->tr_events < ch->tr_events ||
			(flush_ereq->tr_events + flush_ereq->num_events) >
			(ch->tr_events + ch->evt_buf_size)) {
			pr_err("%s: Invalid completion event buffer!\n",
				__func__);
			mhi_log(MHI_MSG_ERROR,
				"Invalid cmpl evt buf - start %pK, end %pK\n",
				flush_ereq->tr_events,
				flush_ereq->tr_events + flush_ereq->num_events);
			return -EINVAL;
		}
		rc = mhi_dev_send_multiple_tr_events(mhi,
		rc = mhi_dev_send_multiple_tr_events(mhi,
				mhi->ch_ctx_cache[ch->ch_id].err_indx,
				mhi->ch_ctx_cache[ch->ch_id].err_indx,
				flush_ereq,
				flush_ereq,
				(flush_ereq->num_events *
				(flush_ereq->num_events *
				sizeof(union mhi_dev_ring_element_type)));
				sizeof(union mhi_dev_ring_element_type)),
				SEND_EVENT_BUFFER);
		if (rc) {
		if (rc) {
			mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n");
			mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n");
			break;
			break;
@@ -1608,7 +1706,7 @@ int mhi_dev_send_state_change_event(struct mhi_dev *mhi,
	event.evt_state_change.type = MHI_DEV_RING_EL_MHI_STATE_CHG;
	event.evt_state_change.type = MHI_DEV_RING_EL_MHI_STATE_CHG;
	event.evt_state_change.mhistate = state;
	event.evt_state_change.mhistate = state;


	return mhi_dev_send_event(mhi, 0, &event);
	return mhi_dev_flush_cmd_completion_events(mhi, &event);
}
}
EXPORT_SYMBOL(mhi_dev_send_state_change_event);
EXPORT_SYMBOL(mhi_dev_send_state_change_event);


@@ -1619,7 +1717,7 @@ int mhi_dev_send_ee_event(struct mhi_dev *mhi, enum mhi_dev_execenv exec_env)
	event.evt_ee_state.type = MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY;
	event.evt_ee_state.type = MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY;
	event.evt_ee_state.execenv = exec_env;
	event.evt_ee_state.execenv = exec_env;


	return mhi_dev_send_event(mhi, 0, &event);
	return mhi_dev_flush_cmd_completion_events(mhi, &event);
}
}
EXPORT_SYMBOL(mhi_dev_send_ee_event);
EXPORT_SYMBOL(mhi_dev_send_ee_event);


@@ -1669,7 +1767,7 @@ static int mhi_dev_send_cmd_comp_event(struct mhi_dev *mhi,
			(size_t) event.evt_cmd_comp.ptr);
			(size_t) event.evt_cmd_comp.ptr);
	event.evt_cmd_comp.type = MHI_DEV_RING_EL_CMD_COMPLETION_EVT;
	event.evt_cmd_comp.type = MHI_DEV_RING_EL_CMD_COMPLETION_EVT;
	event.evt_cmd_comp.code = code;
	event.evt_cmd_comp.code = code;
	return mhi_dev_send_event(mhi, 0, &event);
	return mhi_dev_flush_cmd_completion_events(mhi, &event);
}
}


static int mhi_dev_process_stop_cmd(struct mhi_dev_ring *ring, uint32_t ch_id,
static int mhi_dev_process_stop_cmd(struct mhi_dev_ring *ring, uint32_t ch_id,
@@ -1852,7 +1950,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi,
				event.evt_cmd_comp.code =
				event.evt_cmd_comp.code =
					MHI_CMD_COMPL_CODE_UNDEFINED;
					MHI_CMD_COMPL_CODE_UNDEFINED;


			rc = mhi_dev_send_event(mhi, 0, &event);
			rc = mhi_dev_flush_cmd_completion_events(mhi, &event);
			if (rc) {
			if (rc) {
				pr_err("stop event send failed\n");
				pr_err("stop event send failed\n");
				return;
				return;
@@ -1912,7 +2010,7 @@ static void mhi_dev_process_cmd_ring(struct mhi_dev *mhi,
				event.evt_cmd_comp.code =
				event.evt_cmd_comp.code =
					MHI_CMD_COMPL_CODE_UNDEFINED;
					MHI_CMD_COMPL_CODE_UNDEFINED;


			rc = mhi_dev_send_event(mhi, 0, &event);
			rc = mhi_dev_flush_cmd_completion_events(mhi, &event);
			if (rc) {
			if (rc) {
				pr_err("stop event send failed\n");
				pr_err("stop event send failed\n");
				return;
				return;
@@ -2723,6 +2821,61 @@ static uint32_t mhi_dev_get_evt_ring_size(struct mhi_dev *mhi, uint32_t ch_id)
		mhi->ch_ctx_cache[ch_id].err_indx].ring_size;
		mhi->ch_ctx_cache[ch_id].err_indx].ring_size;
}
}


static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi)
{
	int rc = 0;
	uint32_t i;
	struct mhi_cmd_cmpl_ctx *cmd_ctx;
	union mhi_dev_ring_element_type *cmd_events;

	mhi->cmd_ctx = kmalloc(sizeof(struct mhi_cmd_cmpl_ctx),
					GFP_KERNEL);
	if (!mhi->cmd_ctx)
		return -ENOMEM;

	cmd_ctx = mhi->cmd_ctx;
	/* Allocate event requests */
	cmd_ctx->ereqs = kcalloc(NUM_CMD_EVENTS_DEFAULT,
						sizeof(*cmd_ctx->ereqs),
						GFP_KERNEL);
	if (!cmd_ctx->ereqs) {
		goto free_ereqs;
		return -ENOMEM;
	}

	/* Allocate buffers to queue transfer completion events */
	cmd_ctx->cmd_events = kcalloc(NUM_CMD_EVENTS_DEFAULT,
							sizeof(*cmd_events),
							GFP_KERNEL);
	if (!cmd_ctx->cmd_events) {
		rc = -ENOMEM;
		goto free_ereqs;
	}

	/* Organize event flush requests into a linked list */
	INIT_LIST_HEAD(&cmd_ctx->cmd_req_buffers);

	for (i = 0; i < NUM_CMD_EVENTS_DEFAULT; ++i) {
		list_add_tail(&cmd_ctx->ereqs[i].list,
					&cmd_ctx->cmd_req_buffers);
	}

	/*
	 * Initialize cmpl event buffer indexes - cmd_buf_rp and
	 * cmd_buf_wp point to the first and last free index available.
	 */
	cmd_ctx->cmd_buf_rp = 0;
	cmd_ctx->cmd_buf_wp = NUM_CMD_EVENTS_DEFAULT - 1;

	return 0;
free_ereqs:
		kfree(mhi->cmd_ctx);
		kfree(cmd_ctx->ereqs);
		cmd_ctx->ereqs = NULL;
		mhi->cmd_ctx = NULL;
		return rc;
}

static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi,
static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi,
		struct mhi_dev_channel *ch, struct mhi_dev_ring *evt_ring)
		struct mhi_dev_channel *ch, struct mhi_dev_ring *evt_ring)
{
{
+17 −1
Original line number Original line Diff line number Diff line
@@ -271,6 +271,8 @@ struct mhi_config {


/* maximum transfer completion events buffer */
/* maximum transfer completion events buffer */
#define NUM_TR_EVENTS_DEFAULT			128
#define NUM_TR_EVENTS_DEFAULT			128
#define NUM_CMD_EVENTS_DEFAULT			20



/* Set flush threshold to 80% of event buf size */
/* Set flush threshold to 80% of event buf size */
#define MHI_CMPL_EVT_FLUSH_THRSHLD(n) ((n * 8) / 10)
#define MHI_CMPL_EVT_FLUSH_THRSHLD(n) ((n * 8) / 10)
@@ -354,7 +356,8 @@ enum mhi_dev_ch_operation {
enum mhi_dev_tr_compl_evt_type {
enum mhi_dev_tr_compl_evt_type {
	SEND_EVENT_BUFFER,
	SEND_EVENT_BUFFER,
	SEND_EVENT_RD_OFFSET,
	SEND_EVENT_RD_OFFSET,
	SEND_MSI
	SEND_MSI,
	SEND_CMD_CMP,
};
};


enum mhi_dev_transfer_type {
enum mhi_dev_transfer_type {
@@ -448,6 +451,18 @@ struct event_req {
	void			(*msi_cb)(void *req);
	void			(*msi_cb)(void *req);
	struct list_head	list;
	struct list_head	list;
	u32			flush_num;
	u32			flush_num;
	bool		is_cmd_cpl;
};

struct mhi_cmd_cmpl_ctx {
	/* Indices for completion event buffer */
	uint32_t			cmd_buf_rp;
	uint32_t			cmd_buf_wp;
	uint32_t			cmd_buf_size;
	bool				mem_allocated;
	struct list_head	cmd_req_buffers;
	struct event_req		*ereqs;
	union mhi_dev_ring_element_type *cmd_events;
};
};


struct mhi_dev_channel {
struct mhi_dev_channel {
@@ -531,6 +546,7 @@ struct mhi_dev {
	struct mhi_dev_ring		*ring;
	struct mhi_dev_ring		*ring;
	int				mhi_irq;
	int				mhi_irq;
	struct mhi_dev_channel		*ch;
	struct mhi_dev_channel		*ch;
	struct mhi_cmd_cmpl_ctx			*cmd_ctx;


	int				ctrl_int;
	int				ctrl_int;
	int				cmd_int;
	int				cmd_int;