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

Commit e3461f89 authored by Girish Mahadevan's avatar Girish Mahadevan
Browse files

spi: spi_qsd: Separate rx and tx completion objects



Use a dedicated completion for rx and tx instead of a common completion
object for both.
Currently a single completion object is used for both streams but the
driver does a wait only once, however the DMA driver will signal
completion twice. This could be problematic in DMA related
transfers involving big buffers where you need to send more than one
buffer for a SPI transfer as the driver does an init_completion() on the
completion object again. This could cause a race between the DMA driver's
ISR setting the completion object and the SPI driver calling init on the
same object.
To work around this potential race condition, use dedicated completion
object for each stream and don't call init_completion() API during the
same transfer (it is called once per transfer)

Change-Id: Ib061b614bbc9036411d97ad964ed4c2f56880eae
Signed-off-by: default avatarGirish Mahadevan <girishm@codeaurora.org>
parent 8ca03863
Loading
Loading
Loading
Loading
+22 −6
Original line number Diff line number Diff line
@@ -785,9 +785,13 @@ static int msm_spi_bam_pipe_connect(struct msm_spi *dd,
	struct sps_register_event event  = {
		.mode      = SPS_TRIGGER_WAIT,
		.options   = SPS_O_EOT,
		.xfer_done = &dd->transfer_complete,
	};

	if (pipe == &dd->bam.prod)
		event.xfer_done = &dd->rx_transfer_complete;
	else if (pipe == &dd->bam.cons)
		event.xfer_done = &dd->tx_transfer_complete;

	ret = sps_connect(pipe->handle, config);
	if (ret) {
		dev_err(dd->dev, "%s: sps_connect(%s:0x%p):%d",
@@ -988,7 +992,6 @@ msm_spi_bam_next_transfer(struct msm_spi *dd)
		return 0;

	if (dd->tx_bytes_remaining > 0) {
		init_completion(&dd->transfer_complete);
		if (msm_spi_set_state(dd, SPI_OP_STATE_RESET))
			return 0;
		if ((msm_spi_bam_begin_transfer(dd)) < 0) {
@@ -1058,7 +1061,8 @@ static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id)
	}

	if (dd->done) {
		complete(&dd->transfer_complete);
		complete(&dd->rx_transfer_complete);
		complete(&dd->tx_transfer_complete);
		dd->done = 0;
	}
	return ret;
@@ -1421,7 +1425,8 @@ static int msm_spi_process_transfer(struct msm_spi *dd)
	dd->rx_bytes_remaining = dd->cur_msg_len;
	dd->read_buf           = dd->cur_transfer->rx_buf;
	dd->write_buf          = dd->cur_transfer->tx_buf;
	init_completion(&dd->transfer_complete);
	init_completion(&dd->tx_transfer_complete);
	init_completion(&dd->rx_transfer_complete);
	if (dd->cur_transfer->bits_per_word)
		bpw = dd->cur_transfer->bits_per_word;
	else
@@ -1497,10 +1502,21 @@ static int msm_spi_process_transfer(struct msm_spi *dd)

	/* Assume success, this might change later upon transaction result */
	do {
		if (!wait_for_completion_timeout(&dd->transfer_complete,
		if (dd->write_buf &&
			!wait_for_completion_timeout(&dd->tx_transfer_complete,
						 timeout)) {
				dev_err(dd->dev,
					"%s: SPI Tx transaction timeout\n",
					__func__);
				status = -EIO;
				break;
		}

		if (dd->read_buf &&
			!wait_for_completion_timeout(&dd->rx_transfer_complete,
						 timeout)) {
				dev_err(dd->dev,
					"%s: SPI transaction timeout\n",
					"%s: SPI Rx transaction timeout\n",
					__func__);
				status = -EIO;
				break;
+2 −1
Original line number Diff line number Diff line
@@ -308,7 +308,8 @@ struct msm_spi {
	struct mutex             core_lock;
	struct spi_device       *spi;
	struct spi_transfer     *cur_transfer;
	struct completion        transfer_complete;
	struct completion        tx_transfer_complete;
	struct completion        rx_transfer_complete;
	struct clk              *clk;    /* core clock */
	struct clk              *pclk;   /* interface clock */
	struct qup_i2c_clk_path_vote clk_path_vote;