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

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

Merge "msm: mhi_dev: Wait for pending writes to complete"

parents 9c10bf7d 0f82ea3b
Loading
Loading
Loading
Loading
+59 −7
Original line number Original line Diff line number Diff line
@@ -63,6 +63,10 @@
#define TR_RING_ELEMENT_SZ	sizeof(struct mhi_dev_transfer_ring_element)
#define TR_RING_ELEMENT_SZ	sizeof(struct mhi_dev_transfer_ring_element)
#define RING_ELEMENT_TYPE_SZ	sizeof(union mhi_dev_ring_element_type)
#define RING_ELEMENT_TYPE_SZ	sizeof(union mhi_dev_ring_element_type)


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

uint32_t bhi_imgtxdb;
uint32_t bhi_imgtxdb;
enum mhi_msg_level mhi_msg_lvl = MHI_MSG_ERROR;
enum mhi_msg_level mhi_msg_lvl = MHI_MSG_ERROR;
enum mhi_msg_level mhi_ipc_msg_lvl = MHI_MSG_VERBOSE;
enum mhi_msg_level mhi_ipc_msg_lvl = MHI_MSG_VERBOSE;
@@ -913,7 +917,7 @@ static int mhi_dev_process_stop_cmd(struct mhi_dev_ring *ring, uint32_t ch_id,
		return 0;
		return 0;
	} else if (mhi->ch_ctx_cache[ch_id].ch_type ==
	} else if (mhi->ch_ctx_cache[ch_id].ch_type ==
			MHI_DEV_CH_TYPE_INBOUND_CHANNEL &&
			MHI_DEV_CH_TYPE_INBOUND_CHANNEL &&
			mhi->ch[ch_id].wr_request_active) {
			(mhi->ch[ch_id].pend_wr_count > 0)) {
		mhi_log(MHI_MSG_INFO, "Pending inbound transaction\n");
		mhi_log(MHI_MSG_INFO, "Pending inbound transaction\n");
		return 0;
		return 0;
	}
	}
@@ -1453,9 +1457,23 @@ static void mhi_dev_transfer_completion_cb(void *mreq)
	rd_offset = req->rd_offset;
	rd_offset = req->rd_offset;
	ch->curr_ereq->context = ch;
	ch->curr_ereq->context = ch;


	if (mhi->ch_ctx_cache[ch->ch_id].ch_type ==
			MHI_DEV_CH_TYPE_INBOUND_CHANNEL)
		ch->pend_wr_count--;

	dma_unmap_single(&mhi_ctx->pdev->dev, req->dma,
	dma_unmap_single(&mhi_ctx->pdev->dev, req->dma,
			req->len, DMA_FROM_DEVICE);
			req->len, DMA_FROM_DEVICE);


	/*
	 * Channel got closed with transfers pending
	 * Do not trigger callback or send cmpl to host
	 */
	if (ch->state == MHI_DEV_CH_CLOSED) {
		mhi_log(MHI_MSG_DBG, "Ch %d closed with %d writes pending\n",
				ch->ch_id, ch->pend_wr_count + 1);
		return;
	}

	/* Trigger client call back */
	/* Trigger client call back */
	req->client_cb(req);
	req->client_cb(req);


@@ -2009,18 +2027,49 @@ int mhi_dev_channel_isempty(struct mhi_dev_client *handle)
}
}
EXPORT_SYMBOL(mhi_dev_channel_isempty);
EXPORT_SYMBOL(mhi_dev_channel_isempty);


bool mhi_dev_channel_has_pending_write(struct mhi_dev_client *handle)
{
	struct mhi_dev_channel *ch;

	if (!handle) {
		mhi_log(MHI_MSG_ERROR, "Invalid channel access\n");
		return -EINVAL;
	}

	ch = handle->channel;
	if (!ch)
		return -EINVAL;

	return ch->pend_wr_count ? true : false;
}
EXPORT_SYMBOL(mhi_dev_channel_has_pending_write);

int mhi_dev_close_channel(struct mhi_dev_client *handle)
int mhi_dev_close_channel(struct mhi_dev_client *handle)
{
{
	struct mhi_dev_channel *ch;
	struct mhi_dev_channel *ch;
	int count = 0;
	int rc = 0;
	int rc = 0;


	ch = handle->channel;
	ch = handle->channel;


	do {
		if (ch->pend_wr_count) {
			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);
	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);

	if (ch->state != MHI_DEV_CH_PENDING_START) {
	if (ch->state != MHI_DEV_CH_PENDING_START) {
		if (ch->ch_type == MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL &&
		if ((ch->ch_type == MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL &&
					!mhi_dev_channel_isempty(handle)) {
			!mhi_dev_channel_isempty(handle)) || ch->tre_loc) {
			mhi_log(MHI_MSG_ERROR,
			mhi_log(MHI_MSG_DBG,
				"Trying to close an active channel (%d)\n",
				"Trying to close an active channel (%d)\n",
				ch->ch_id);
				ch->ch_id);
			rc = -EAGAIN;
			rc = -EAGAIN;
@@ -2237,6 +2286,7 @@ int mhi_dev_write_channel(struct mhi_req *wreq)
	size_t bytes_to_write = 0;
	size_t bytes_to_write = 0;
	size_t bytes_written = 0;
	size_t bytes_written = 0;
	uint32_t tre_len = 0, suspend_wait_timeout = 0;
	uint32_t tre_len = 0, suspend_wait_timeout = 0;
	bool async_wr_sched = false;


	if (!wreq || !wreq->client || !wreq->buf) {
	if (!wreq || !wreq->client || !wreq->buf) {
		pr_err("%s: invalid parameters\n", __func__);
		pr_err("%s: invalid parameters\n", __func__);
@@ -2280,12 +2330,12 @@ int mhi_dev_write_channel(struct mhi_req *wreq)


	handle_client = wreq->client;
	handle_client = wreq->client;
	ch = handle_client->channel;
	ch = handle_client->channel;
	ch->wr_request_active = true;


	ring = ch->ring;
	ring = ch->ring;


	mutex_lock(&ch->ch_lock);
	mutex_lock(&ch->ch_lock);


	ch->pend_wr_count++;
	if (ch->state == MHI_DEV_CH_STOPPED) {
	if (ch->state == MHI_DEV_CH_STOPPED) {
		mhi_log(MHI_MSG_ERROR,
		mhi_log(MHI_MSG_ERROR,
			"channel %d already stopped\n", wreq->chan);
			"channel %d already stopped\n", wreq->chan);
@@ -2336,7 +2386,8 @@ int mhi_dev_write_channel(struct mhi_req *wreq)
					"Error while writing chan (%d) rc %d\n",
					"Error while writing chan (%d) rc %d\n",
					wreq->chan, rc);
					wreq->chan, rc);
			goto exit;
			goto exit;
		}
		} else if (wreq->mode == DMA_ASYNC)
			async_wr_sched = true;
		bytes_written += bytes_to_write;
		bytes_written += bytes_to_write;
		usr_buf_remaining -= bytes_to_write;
		usr_buf_remaining -= bytes_to_write;


@@ -2376,7 +2427,8 @@ int mhi_dev_write_channel(struct mhi_req *wreq)
		}
		}
	}
	}
exit:
exit:
	ch->wr_request_active = false;
	if (wreq->mode == DMA_SYNC || !async_wr_sched)
		ch->pend_wr_count--;
	mutex_unlock(&ch->ch_lock);
	mutex_unlock(&ch->ch_lock);
	mutex_unlock(&mhi_ctx->mhi_write_test);
	mutex_unlock(&mhi_ctx->mhi_write_test);
	return bytes_written;
	return bytes_written;
+1 −1
Original line number Original line Diff line number Diff line
@@ -461,7 +461,7 @@ struct mhi_dev_channel {
	uint32_t			tre_bytes_left;
	uint32_t			tre_bytes_left;
	/* td size being read/written from/to so far */
	/* td size being read/written from/to so far */
	uint32_t			td_size;
	uint32_t			td_size;
	bool				wr_request_active;
	uint32_t			pend_wr_count;
	bool				skip_td;
	bool				skip_td;
};
};


+46 −27
Original line number Original line Diff line number Diff line
@@ -47,6 +47,10 @@
#define MHI_UCI_AT_CTRL_READ_TIMEOUT	msecs_to_jiffies(1000)
#define MHI_UCI_AT_CTRL_READ_TIMEOUT	msecs_to_jiffies(1000)
#define MHI_UCI_WRITE_REQ_AVAIL_TIMEOUT msecs_to_jiffies(1000)
#define MHI_UCI_WRITE_REQ_AVAIL_TIMEOUT msecs_to_jiffies(1000)


#define MHI_UCI_RELEASE_TIMEOUT_MIN	5000
#define MHI_UCI_RELEASE_TIMEOUT_MAX	5100
#define MHI_UCI_RELEASE_TIMEOUT_COUNT	30

enum uci_dbg_level {
enum uci_dbg_level {
	UCI_DBG_VERBOSE = 0x0,
	UCI_DBG_VERBOSE = 0x0,
	UCI_DBG_INFO = 0x1,
	UCI_DBG_INFO = 0x1,
@@ -907,41 +911,56 @@ static int mhi_uci_client_release(struct inode *mhi_inode,
		struct file *file_handle)
		struct file *file_handle)
{
{
	struct uci_client *uci_handle = file_handle->private_data;
	struct uci_client *uci_handle = file_handle->private_data;
	int rc = 0;
	int count = 0;


	if (!uci_handle)
	if (!uci_handle)
		return -EINVAL;
		return -EINVAL;


	if (atomic_sub_return(1, &uci_handle->ref_count) == 0) {
	if (atomic_sub_return(1, &uci_handle->ref_count)) {
		uci_log(UCI_DBG_DBG, "Client close chan %d, ref count 0x%x\n",
			iminor(mhi_inode),
			atomic_read(&uci_handle->ref_count));
		return 0;
	}

	uci_log(UCI_DBG_DBG,
	uci_log(UCI_DBG_DBG,
			"Last client left, closing channel 0x%x\n",
			"Last client left, closing channel 0x%x\n",
			iminor(mhi_inode));
			iminor(mhi_inode));

	do {
		if (mhi_dev_channel_has_pending_write(uci_handle->out_handle))
			usleep_range(MHI_UCI_RELEASE_TIMEOUT_MIN,
				MHI_UCI_RELEASE_TIMEOUT_MAX);
		else
			break;
	} while (++count < MHI_UCI_RELEASE_TIMEOUT_COUNT);

	if (count == MHI_UCI_RELEASE_TIMEOUT_COUNT) {
		uci_log(UCI_DBG_DBG, "Channel %d has pending writes\n",
			iminor(mhi_inode));
	}

	if (atomic_read(&uci_handle->mhi_chans_open)) {
	if (atomic_read(&uci_handle->mhi_chans_open)) {
		atomic_set(&uci_handle->mhi_chans_open, 0);
		atomic_set(&uci_handle->mhi_chans_open, 0);


		if (!(uci_handle->f_flags & O_SYNC))
		if (!(uci_handle->f_flags & O_SYNC))
			kfree(uci_handle->wreqs);
			kfree(uci_handle->wreqs);
		mutex_lock(&uci_handle->out_chan_lock);
		mutex_lock(&uci_handle->out_chan_lock);
			rc = mhi_dev_close_channel(uci_handle->out_handle);
		mhi_dev_close_channel(uci_handle->out_handle);
		wake_up(&uci_handle->write_wq);
		wake_up(&uci_handle->write_wq);
		mutex_unlock(&uci_handle->out_chan_lock);
		mutex_unlock(&uci_handle->out_chan_lock);


		mutex_lock(&uci_handle->in_chan_lock);
		mutex_lock(&uci_handle->in_chan_lock);
			rc = mhi_dev_close_channel(uci_handle->in_handle);
		mhi_dev_close_channel(uci_handle->in_handle);
		wake_up(&uci_handle->read_wq);
		wake_up(&uci_handle->read_wq);
		mutex_unlock(&uci_handle->in_chan_lock);
		mutex_unlock(&uci_handle->in_chan_lock);

	}
	}

	atomic_set(&uci_handle->read_data_ready, 0);
	atomic_set(&uci_handle->read_data_ready, 0);
	atomic_set(&uci_handle->write_data_ready, 0);
	atomic_set(&uci_handle->write_data_ready, 0);
	file_handle->private_data = NULL;
	file_handle->private_data = NULL;
	} else {

		uci_log(UCI_DBG_DBG,
	return 0;
			"Client close chan %d, ref count 0x%x\n",
			iminor(mhi_inode),
			atomic_read(&uci_handle->ref_count));
	}
	return rc;
}
}


static void  mhi_parse_state(char *buf, int *nbytes, uint32_t info)
static void  mhi_parse_state(char *buf, int *nbytes, uint32_t info)
+15 −0
Original line number Original line Diff line number Diff line
@@ -18,6 +18,8 @@


#define IPA_DMA_SYNC                    1
#define IPA_DMA_SYNC                    1
#define IPA_DMA_ASYNC                   0
#define IPA_DMA_ASYNC                   0
#define DMA_SYNC                    1
#define DMA_ASYNC                   0


enum cb_reason {
enum cb_reason {
	MHI_DEV_TRE_AVAILABLE = 0,
	MHI_DEV_TRE_AVAILABLE = 0,
@@ -196,6 +198,13 @@ int mhi_dev_write_channel(struct mhi_req *wreq);
 */
 */
int mhi_dev_channel_isempty(struct mhi_dev_client *handle);
int mhi_dev_channel_isempty(struct mhi_dev_client *handle);


/**
* mhi_dev_channel_has_pending_write() - Checks if there are any pending writes
*					to be completed on inbound channel
* @handle_client:	Client Handle issued during mhi_dev_open_channel
*/
bool mhi_dev_channel_has_pending_write(struct mhi_dev_client *handle);

/**
/**
 * mhi_ctrl_state_info() - Provide MHI state info
 * mhi_ctrl_state_info() - Provide MHI state info
 *		@idx: Channel number idx. Look at channel_state_info and
 *		@idx: Channel number idx. Look at channel_state_info and
@@ -246,6 +255,12 @@ static inline int mhi_dev_channel_isempty(struct mhi_dev_client *handle)
	return -EINVAL;
	return -EINVAL;
};
};


static inline bool mhi_dev_channel_has_pending_write
	(struct mhi_dev_client *handle)
{
	return false;
}

static inline int mhi_ctrl_state_info(uint32_t idx, uint32_t *info)
static inline int mhi_ctrl_state_info(uint32_t idx, uint32_t *info)
{
{
	return -EINVAL;
	return -EINVAL;