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:
Родитель
902481a78e
Коммит
7ba9bdcb91
|
@ -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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче