spi: Fixes for v5.11
A couple of core fixes here, both to do with handling of drivers which don't report their maximum speed since we factored some of the handling for transfer speeds out into the core in the previous release. There's also some driver specific fixes, including a relatively large set for some races around timeouts in spi-geni-qcom. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAl/3NqwACgkQJNaLcl1U h9C04gf8DHM+rGA6XsQfxjlqPmu0KOq+QVfDEYvXEbpWIQ1YWyB3kK3H6ftvFMJz bWW1xBjJL6nav9pZwRllLu2P1hkXek0MpZFFRp00MrUbUW06ct103xiIGVmVPUMQ A4w44nt7WJj/k9fRyvAjrAp1LQ8pGl0H1m6kifZLpNm8GlUMrCyFz7kfWs6ojHOo uBfru37WFiSfgQeDVTBd9v0A7Nu/dEnMlHCbikifpwsB/Q0GTfs8GG4pIo+QehwQ VhOCi/x+p7JW3Tksp4DM6jawzpBCoTRt5EzNzbprIyPde3vzUj4rjiqkcAxgW3hu oiwkkjM5e3/0oVHebSkmRVuG2qlT8w== =hP9t -----END PGP SIGNATURE----- Merge tag 'spi-fix-v5.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull spi fixes from Mark Brown: "A couple of core fixes here, both to do with handling of drivers which don't report their maximum speed since we factored some of the handling for transfer speeds out into the core in the previous release. There's also some driver specific fixes, including a relatively large set for some races around timeouts in spi-geni-qcom" * tag 'spi-fix-v5.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: spi: fix the divide by 0 error when calculating xfer waiting time spi: Fix the clamping of spi->max_speed_hz spi: altera: fix return value for altera_spi_txrx() spi: stm32: FIFO threshold level - fix align packet size spi: spi-geni-qcom: Print an error when we timeout setting the CS spi: spi-geni-qcom: Don't try to set CS if an xfer is pending spi: spi-geni-qcom: Fail new xfers if xfer/cancel/abort pending spi: spi-geni-qcom: Fix geni_spi_isr() NULL dereference in timeout case
This commit is contained in:
Коммит
f5e6c33025
|
@ -189,24 +189,26 @@ static int altera_spi_txrx(struct spi_master *master,
|
|||
|
||||
/* send the first byte */
|
||||
altera_spi_tx_word(hw);
|
||||
} else {
|
||||
while (hw->count < hw->len) {
|
||||
altera_spi_tx_word(hw);
|
||||
|
||||
for (;;) {
|
||||
altr_spi_readl(hw, ALTERA_SPI_STATUS, &val);
|
||||
if (val & ALTERA_SPI_STATUS_RRDY_MSK)
|
||||
break;
|
||||
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
altera_spi_rx_word(hw);
|
||||
}
|
||||
spi_finalize_current_transfer(master);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return t->len;
|
||||
while (hw->count < hw->len) {
|
||||
altera_spi_tx_word(hw);
|
||||
|
||||
for (;;) {
|
||||
altr_spi_readl(hw, ALTERA_SPI_STATUS, &val);
|
||||
if (val & ALTERA_SPI_STATUS_RRDY_MSK)
|
||||
break;
|
||||
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
altera_spi_rx_word(hw);
|
||||
}
|
||||
spi_finalize_current_transfer(master);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t altera_spi_irq(int irq, void *dev)
|
||||
|
|
|
@ -83,6 +83,7 @@ struct spi_geni_master {
|
|||
spinlock_t lock;
|
||||
int irq;
|
||||
bool cs_flag;
|
||||
bool abort_failed;
|
||||
};
|
||||
|
||||
static int get_spi_clk_cfg(unsigned int speed_hz,
|
||||
|
@ -141,8 +142,49 @@ static void handle_fifo_timeout(struct spi_master *spi,
|
|||
spin_unlock_irq(&mas->lock);
|
||||
|
||||
time_left = wait_for_completion_timeout(&mas->abort_done, HZ);
|
||||
if (!time_left)
|
||||
if (!time_left) {
|
||||
dev_err(mas->dev, "Failed to cancel/abort m_cmd\n");
|
||||
|
||||
/*
|
||||
* No need for a lock since SPI core has a lock and we never
|
||||
* access this from an interrupt.
|
||||
*/
|
||||
mas->abort_failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool spi_geni_is_abort_still_pending(struct spi_geni_master *mas)
|
||||
{
|
||||
struct geni_se *se = &mas->se;
|
||||
u32 m_irq, m_irq_en;
|
||||
|
||||
if (!mas->abort_failed)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* The only known case where a transfer times out and then a cancel
|
||||
* times out then an abort times out is if something is blocking our
|
||||
* interrupt handler from running. Avoid starting any new transfers
|
||||
* until that sorts itself out.
|
||||
*/
|
||||
spin_lock_irq(&mas->lock);
|
||||
m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS);
|
||||
m_irq_en = readl(se->base + SE_GENI_M_IRQ_EN);
|
||||
spin_unlock_irq(&mas->lock);
|
||||
|
||||
if (m_irq & m_irq_en) {
|
||||
dev_err(mas->dev, "Interrupts pending after abort: %#010x\n",
|
||||
m_irq & m_irq_en);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're here the problem resolved itself so no need to check more
|
||||
* on future transfers.
|
||||
*/
|
||||
mas->abort_failed = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
|
||||
|
@ -158,10 +200,21 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
|
|||
if (set_flag == mas->cs_flag)
|
||||
return;
|
||||
|
||||
mas->cs_flag = set_flag;
|
||||
|
||||
pm_runtime_get_sync(mas->dev);
|
||||
|
||||
if (spi_geni_is_abort_still_pending(mas)) {
|
||||
dev_err(mas->dev, "Can't set chip select\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
spin_lock_irq(&mas->lock);
|
||||
if (mas->cur_xfer) {
|
||||
dev_err(mas->dev, "Can't set CS when prev xfer running\n");
|
||||
spin_unlock_irq(&mas->lock);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mas->cs_flag = set_flag;
|
||||
reinit_completion(&mas->cs_done);
|
||||
if (set_flag)
|
||||
geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0);
|
||||
|
@ -170,9 +223,12 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
|
|||
spin_unlock_irq(&mas->lock);
|
||||
|
||||
time_left = wait_for_completion_timeout(&mas->cs_done, HZ);
|
||||
if (!time_left)
|
||||
if (!time_left) {
|
||||
dev_warn(mas->dev, "Timeout setting chip select\n");
|
||||
handle_fifo_timeout(spi, NULL);
|
||||
}
|
||||
|
||||
exit:
|
||||
pm_runtime_put(mas->dev);
|
||||
}
|
||||
|
||||
|
@ -280,6 +336,9 @@ static int spi_geni_prepare_message(struct spi_master *spi,
|
|||
int ret;
|
||||
struct spi_geni_master *mas = spi_master_get_devdata(spi);
|
||||
|
||||
if (spi_geni_is_abort_still_pending(mas))
|
||||
return -EBUSY;
|
||||
|
||||
ret = setup_fifo_params(spi_msg->spi, spi);
|
||||
if (ret)
|
||||
dev_err(mas->dev, "Couldn't select mode %d\n", ret);
|
||||
|
@ -354,6 +413,12 @@ static bool geni_spi_handle_tx(struct spi_geni_master *mas)
|
|||
unsigned int bytes_per_fifo_word = geni_byte_per_fifo_word(mas);
|
||||
unsigned int i = 0;
|
||||
|
||||
/* Stop the watermark IRQ if nothing to send */
|
||||
if (!mas->cur_xfer) {
|
||||
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
|
||||
return false;
|
||||
}
|
||||
|
||||
max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * bytes_per_fifo_word;
|
||||
if (mas->tx_rem_bytes < max_bytes)
|
||||
max_bytes = mas->tx_rem_bytes;
|
||||
|
@ -396,6 +461,14 @@ static void geni_spi_handle_rx(struct spi_geni_master *mas)
|
|||
if (rx_last_byte_valid && rx_last_byte_valid < 4)
|
||||
rx_bytes -= bytes_per_fifo_word - rx_last_byte_valid;
|
||||
}
|
||||
|
||||
/* Clear out the FIFO and bail if nowhere to put it */
|
||||
if (!mas->cur_xfer) {
|
||||
for (i = 0; i < DIV_ROUND_UP(rx_bytes, bytes_per_fifo_word); i++)
|
||||
readl(se->base + SE_GENI_RX_FIFOn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mas->rx_rem_bytes < rx_bytes)
|
||||
rx_bytes = mas->rx_rem_bytes;
|
||||
|
||||
|
@ -495,6 +568,9 @@ static int spi_geni_transfer_one(struct spi_master *spi,
|
|||
{
|
||||
struct spi_geni_master *mas = spi_master_get_devdata(spi);
|
||||
|
||||
if (spi_geni_is_abort_still_pending(mas))
|
||||
return -EBUSY;
|
||||
|
||||
/* Terminate and return success for 0 byte length transfer */
|
||||
if (!xfer->len)
|
||||
return 0;
|
||||
|
|
|
@ -493,9 +493,9 @@ static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi, u32 xfer_len)
|
|||
|
||||
/* align packet size with data registers access */
|
||||
if (spi->cur_bpw > 8)
|
||||
fthlv -= (fthlv % 2); /* multiple of 2 */
|
||||
fthlv += (fthlv % 2) ? 1 : 0;
|
||||
else
|
||||
fthlv -= (fthlv % 4); /* multiple of 4 */
|
||||
fthlv += (fthlv % 4) ? (4 - (fthlv % 4)) : 0;
|
||||
|
||||
if (!fthlv)
|
||||
fthlv = 1;
|
||||
|
|
|
@ -1108,6 +1108,7 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
|
|||
{
|
||||
struct spi_statistics *statm = &ctlr->statistics;
|
||||
struct spi_statistics *stats = &msg->spi->statistics;
|
||||
u32 speed_hz = xfer->speed_hz;
|
||||
unsigned long long ms;
|
||||
|
||||
if (spi_controller_is_slave(ctlr)) {
|
||||
|
@ -1116,8 +1117,11 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
|
|||
return -EINTR;
|
||||
}
|
||||
} else {
|
||||
if (!speed_hz)
|
||||
speed_hz = 100000;
|
||||
|
||||
ms = 8LL * 1000LL * xfer->len;
|
||||
do_div(ms, xfer->speed_hz);
|
||||
do_div(ms, speed_hz);
|
||||
ms += ms + 200; /* some tolerance */
|
||||
|
||||
if (ms > UINT_MAX)
|
||||
|
@ -3378,8 +3382,9 @@ int spi_setup(struct spi_device *spi)
|
|||
if (status)
|
||||
return status;
|
||||
|
||||
if (!spi->max_speed_hz ||
|
||||
spi->max_speed_hz > spi->controller->max_speed_hz)
|
||||
if (spi->controller->max_speed_hz &&
|
||||
(!spi->max_speed_hz ||
|
||||
spi->max_speed_hz > spi->controller->max_speed_hz))
|
||||
spi->max_speed_hz = spi->controller->max_speed_hz;
|
||||
|
||||
mutex_lock(&spi->controller->io_mutex);
|
||||
|
|
Загрузка…
Ссылка в новой задаче