spi: spi-geni-qcom: Don't keep a local state variable

The variable "cur_mcmd" kept track of our current state (idle, xfer,
cs, cancel).  We don't really need it, so get rid of it.  Instead:
* Use separate condition variables for "chip select done", "cancel
  done", and "abort done".  This is important so that if a "done"
  comes through (perhaps some previous interrupt finally came through)
  it can't confuse the cancel/abort function.
* Use the "done" interrupt only for when a chip select or transfer is
  done and we can tell the difference by looking at whether "cur_xfer"
  is NULL.

This is mostly a no-op change.  However, it is possible it could fix
an issue where a super delayed interrupt for a cancel command could
have confused our waiting for an abort command.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
Link: https://lore.kernel.org/r/20200618080459.v4.5.Ib1e6855405fc9c99916ab7c7dee84d73a8bf3d68@changeid
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Douglas Anderson 2020-06-18 08:06:26 -07:00 committed by Mark Brown
parent 902481a78e
commit 7ba9bdcb91
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0

View File

@ -63,13 +63,6 @@
#define TIMESTAMP_AFTER BIT(3)
#define POST_CMD_DELAY BIT(4)
enum spi_m_cmd_opcode {
CMD_NONE,
CMD_XFER,
CMD_CS,
CMD_CANCEL,
};
struct spi_geni_master {
struct geni_se se;
struct device *dev;
@ -81,10 +74,11 @@ struct spi_geni_master {
unsigned int tx_rem_bytes;
unsigned int rx_rem_bytes;
const struct spi_transfer *cur_xfer;
struct completion xfer_done;
struct completion cs_done;
struct completion cancel_done;
struct completion abort_done;
unsigned int oversampling;
spinlock_t lock;
enum spi_m_cmd_opcode cur_mcmd;
int irq;
};
@ -126,20 +120,23 @@ static void handle_fifo_timeout(struct spi_master *spi,
struct geni_se *se = &mas->se;
spin_lock_irq(&mas->lock);
reinit_completion(&mas->xfer_done);
mas->cur_mcmd = CMD_CANCEL;
geni_se_cancel_m_cmd(se);
reinit_completion(&mas->cancel_done);
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
mas->cur_xfer = NULL;
mas->tx_rem_bytes = mas->rx_rem_bytes = 0;
geni_se_cancel_m_cmd(se);
spin_unlock_irq(&mas->lock);
time_left = wait_for_completion_timeout(&mas->xfer_done, HZ);
time_left = wait_for_completion_timeout(&mas->cancel_done, HZ);
if (time_left)
return;
spin_lock_irq(&mas->lock);
reinit_completion(&mas->xfer_done);
reinit_completion(&mas->abort_done);
geni_se_abort_m_cmd(se);
spin_unlock_irq(&mas->lock);
time_left = wait_for_completion_timeout(&mas->xfer_done, HZ);
time_left = wait_for_completion_timeout(&mas->abort_done, HZ);
if (!time_left)
dev_err(mas->dev, "Failed to cancel/abort m_cmd\n");
}
@ -156,15 +153,14 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
set_flag = !set_flag;
spin_lock_irq(&mas->lock);
reinit_completion(&mas->xfer_done);
mas->cur_mcmd = CMD_CS;
reinit_completion(&mas->cs_done);
if (set_flag)
geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0);
else
geni_se_setup_m_cmd(se, SPI_CS_DEASSERT, 0);
spin_unlock_irq(&mas->lock);
time_left = wait_for_completion_timeout(&mas->xfer_done, HZ);
time_left = wait_for_completion_timeout(&mas->cs_done, HZ);
if (!time_left)
handle_fifo_timeout(spi, NULL);
@ -383,7 +379,6 @@ static void setup_fifo_xfer(struct spi_transfer *xfer,
mas->rx_rem_bytes = xfer->len;
}
writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG);
mas->cur_mcmd = CMD_XFER;
/*
* Lock around right before we start the transfer since our
@ -520,11 +515,13 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
geni_spi_handle_tx(mas);
if (m_irq & M_CMD_DONE_EN) {
if (mas->cur_mcmd == CMD_XFER)
if (mas->cur_xfer) {
spi_finalize_current_transfer(spi);
else if (mas->cur_mcmd == CMD_CS)
complete(&mas->xfer_done);
mas->cur_mcmd = CMD_NONE;
mas->cur_xfer = NULL;
} else {
complete(&mas->cs_done);
}
/*
* If this happens, then a CMD_DONE came before all the Tx
* buffer bytes were sent out. This is unusual, log this
@ -546,10 +543,10 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
mas->rx_rem_bytes, mas->cur_bits_per_word);
}
if ((m_irq & M_CMD_CANCEL_EN) || (m_irq & M_CMD_ABORT_EN)) {
mas->cur_mcmd = CMD_NONE;
complete(&mas->xfer_done);
}
if (m_irq & M_CMD_CANCEL_EN)
complete(&mas->cancel_done);
if (m_irq & M_CMD_ABORT_EN)
complete(&mas->abort_done);
/*
* It's safe or a good idea to Ack all of our our interrupts at the
@ -617,7 +614,9 @@ static int spi_geni_probe(struct platform_device *pdev)
spi->handle_err = handle_fifo_timeout;
spi->set_cs = spi_geni_set_cs;
init_completion(&mas->xfer_done);
init_completion(&mas->cs_done);
init_completion(&mas->cancel_done);
init_completion(&mas->abort_done);
spin_lock_init(&mas->lock);
pm_runtime_enable(dev);