Skip to content

Commit

Permalink
Merge existing fixes from spi/for-5.11
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark Brown committed Dec 28, 2020
2 parents 5c8fe58 + a590370 commit a34d419
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 6 deletions.
84 changes: 80 additions & 4 deletions drivers/spi/spi-geni-qcom.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand All @@ -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);
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions drivers/spi/spi-stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit a34d419

Please sign in to comment.