Skip to content

Commit 458800e

Browse files
committed
spi: stm32: stability & performance enhancements
Merge series from Alain Volmat <alain.volmat@foss.st.com>: The series fixes a stability issue when dealing with <8bpw transfers, as well as enforce an error if the DMA information provided within the DT are incorrect. Performance enhancement is also provided by allowing a polling mode which is triggered when the transfer is so short that polling mode transfer would lead to faster transfer than if it was done in a interrupt driven manner.
2 parents 65ccce3 + b39ef93 commit 458800e

1 file changed

Lines changed: 94 additions & 12 deletions

File tree

drivers/spi/spi-stm32.c

Lines changed: 94 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@
202202
#define STM32_SPI_HOST_MODE(stm32_spi) (!(stm32_spi)->device_mode)
203203
#define STM32_SPI_DEVICE_MODE(stm32_spi) ((stm32_spi)->device_mode)
204204

205+
static unsigned int polling_limit_us = 30;
206+
module_param(polling_limit_us, uint, 0664);
207+
MODULE_PARM_DESC(polling_limit_us, "maximum time in us to run a transfer in polling mode\n");
208+
205209
/**
206210
* struct stm32_spi_reg - stm32 SPI register & bitfield desc
207211
* @reg: register offset
@@ -266,6 +270,7 @@ struct stm32_spi;
266270
* @dma_rx_cb: routine to call after DMA RX channel operation is complete
267271
* @dma_tx_cb: routine to call after DMA TX channel operation is complete
268272
* @transfer_one_irq: routine to configure interrupts for driver
273+
* @transfer_one_poll: routine to perform a transfer via register polling
269274
* @irq_handler_event: Interrupt handler for SPI controller events
270275
* @irq_handler_thread: thread of interrupt handler for SPI controller
271276
* @baud_rate_div_min: minimum baud rate divisor
@@ -291,6 +296,7 @@ struct stm32_spi_cfg {
291296
void (*dma_rx_cb)(void *data);
292297
void (*dma_tx_cb)(void *data);
293298
int (*transfer_one_irq)(struct stm32_spi *spi);
299+
int (*transfer_one_poll)(struct stm32_spi *spi);
294300
irqreturn_t (*irq_handler_event)(int irq, void *dev_id);
295301
irqreturn_t (*irq_handler_thread)(int irq, void *dev_id);
296302
unsigned int baud_rate_div_min;
@@ -1355,6 +1361,55 @@ static int stm32fx_spi_transfer_one_irq(struct stm32_spi *spi)
13551361
return 1;
13561362
}
13571363

1364+
/**
1365+
* stm32h7_spi_transfer_one_poll - transfer a single spi_transfer by direct
1366+
* register access without interrupt usage
1367+
* @spi: pointer to the spi controller data structure
1368+
*
1369+
* It must returns 0 if the transfer is finished or 1 if the transfer is still
1370+
* in progress.
1371+
*/
1372+
static int stm32h7_spi_transfer_one_poll(struct stm32_spi *spi)
1373+
{
1374+
unsigned long flags;
1375+
u32 sr;
1376+
1377+
spin_lock_irqsave(&spi->lock, flags);
1378+
1379+
stm32_spi_enable(spi);
1380+
1381+
/* Be sure to have data in fifo before starting data transfer */
1382+
if (spi->tx_buf)
1383+
stm32h7_spi_write_txfifo(spi);
1384+
1385+
if (STM32_SPI_HOST_MODE(spi))
1386+
stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART);
1387+
1388+
sr = readl_relaxed(spi->base + STM32H7_SPI_SR);
1389+
/* Keep writing / reading while waiting for the end of transfer */
1390+
while (spi->tx_len || spi->rx_len || !(sr & STM32H7_SPI_SR_EOT)) {
1391+
if (spi->rx_len && (sr & (STM32H7_SPI_SR_RXP | STM32H7_SPI_SR_RXWNE |
1392+
STM32H7_SPI_SR_RXPLVL)))
1393+
stm32h7_spi_read_rxfifo(spi);
1394+
1395+
if (spi->tx_len && (sr & STM32H7_SPI_SR_TXP))
1396+
stm32h7_spi_write_txfifo(spi);
1397+
1398+
sr = readl_relaxed(spi->base + STM32H7_SPI_SR);
1399+
1400+
/* Clear suspension bit if necessary */
1401+
if (sr & STM32H7_SPI_SR_SUSP)
1402+
writel_relaxed(sr & STM32H7_SPI_SR_SUSP, spi->base + STM32H7_SPI_IFCR);
1403+
}
1404+
1405+
spin_unlock_irqrestore(&spi->lock, flags);
1406+
1407+
stm32h7_spi_disable(spi);
1408+
spi_finalize_current_transfer(spi->ctrl);
1409+
1410+
return 0;
1411+
}
1412+
13581413
/**
13591414
* stm32h7_spi_transfer_one_irq - transfer a single spi_transfer using
13601415
* interrupts
@@ -1906,11 +1961,12 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, struct spi_transfer
19061961
cfg2_clrb |= STM32H7_SPI_CFG2_MIDI;
19071962
if ((len > 1) && (spi->cur_midi > 0)) {
19081963
u32 sck_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, spi->cur_speed);
1909-
u32 midi = min_t(u32,
1910-
DIV_ROUND_UP(spi->cur_midi, sck_period_ns),
1911-
FIELD_GET(STM32H7_SPI_CFG2_MIDI,
1912-
STM32H7_SPI_CFG2_MIDI));
1964+
u32 midi = DIV_ROUND_UP(spi->cur_midi, sck_period_ns);
19131965

1966+
if ((spi->cur_bpw + midi) < 8)
1967+
midi = 8 - spi->cur_bpw;
1968+
1969+
midi = min_t(u32, midi, FIELD_MAX(STM32H7_SPI_CFG2_MIDI));
19141970

19151971
dev_dbg(spi->dev, "period=%dns, midi=%d(=%dns)\n",
19161972
sck_period_ns, midi, midi * sck_period_ns);
@@ -2025,6 +2081,24 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
20252081
return ret;
20262082
}
20272083

2084+
/**
2085+
* stm32_spi_can_poll - detect if poll based transfer is appropriate
2086+
* @spi: pointer to the spi controller data structure
2087+
*
2088+
* Returns true is poll is more appropriate, false otherwise.
2089+
*/
2090+
static bool stm32_spi_can_poll(struct stm32_spi *spi)
2091+
{
2092+
unsigned long hz_per_byte, byte_limit;
2093+
2094+
/* Evaluate the transfer time and use polling if applicable */
2095+
hz_per_byte = polling_limit_us ?
2096+
DIV_ROUND_UP(8 * USEC_PER_SEC, polling_limit_us) : 0;
2097+
byte_limit = hz_per_byte ? spi->cur_speed / hz_per_byte : 1;
2098+
2099+
return (spi->cur_xferlen < byte_limit) ? true : false;
2100+
}
2101+
20282102
/**
20292103
* stm32_spi_transfer_one - transfer a single spi_transfer
20302104
* @ctrl: controller interface
@@ -2057,6 +2131,8 @@ static int stm32_spi_transfer_one(struct spi_controller *ctrl,
20572131

20582132
if (spi->cur_usedma)
20592133
return stm32_spi_transfer_one_dma(spi, transfer);
2134+
else if (spi->cfg->transfer_one_poll && stm32_spi_can_poll(spi))
2135+
return spi->cfg->transfer_one_poll(spi);
20602136
else
20612137
return spi->cfg->transfer_one_irq(spi);
20622138
}
@@ -2215,6 +2291,7 @@ static const struct stm32_spi_cfg stm32h7_spi_cfg = {
22152291
* SPI access hence handling is performed within the SPI interrupt
22162292
*/
22172293
.transfer_one_irq = stm32h7_spi_transfer_one_irq,
2294+
.transfer_one_poll = stm32h7_spi_transfer_one_poll,
22182295
.irq_handler_thread = stm32h7_spi_irq_thread,
22192296
.baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN,
22202297
.baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX,
@@ -2244,6 +2321,7 @@ static const struct stm32_spi_cfg stm32mp25_spi_cfg = {
22442321
* SPI access hence handling is performed within the SPI interrupt
22452322
*/
22462323
.transfer_one_irq = stm32h7_spi_transfer_one_irq,
2324+
.transfer_one_poll = stm32h7_spi_transfer_one_poll,
22472325
.irq_handler_thread = stm32h7_spi_irq_thread,
22482326
.baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN,
22492327
.baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX,
@@ -2406,23 +2484,27 @@ static int stm32_spi_probe(struct platform_device *pdev)
24062484
spi->dma_tx = dma_request_chan(spi->dev, "tx");
24072485
if (IS_ERR(spi->dma_tx)) {
24082486
ret = PTR_ERR(spi->dma_tx);
2409-
spi->dma_tx = NULL;
2410-
if (ret == -EPROBE_DEFER)
2487+
if (ret == -ENODEV) {
2488+
dev_info(&pdev->dev, "tx dma disabled\n");
2489+
spi->dma_tx = NULL;
2490+
} else {
2491+
dev_err_probe(&pdev->dev, ret, "failed to request tx dma channel\n");
24112492
goto err_clk_disable;
2412-
2413-
dev_warn(&pdev->dev, "failed to request tx dma channel\n");
2493+
}
24142494
} else {
24152495
ctrl->dma_tx = spi->dma_tx;
24162496
}
24172497

24182498
spi->dma_rx = dma_request_chan(spi->dev, "rx");
24192499
if (IS_ERR(spi->dma_rx)) {
24202500
ret = PTR_ERR(spi->dma_rx);
2421-
spi->dma_rx = NULL;
2422-
if (ret == -EPROBE_DEFER)
2501+
if (ret == -ENODEV) {
2502+
dev_info(&pdev->dev, "rx dma disabled\n");
2503+
spi->dma_rx = NULL;
2504+
} else {
2505+
dev_err_probe(&pdev->dev, ret, "failed to request rx dma channel\n");
24232506
goto err_dma_release;
2424-
2425-
dev_warn(&pdev->dev, "failed to request rx dma channel\n");
2507+
}
24262508
} else {
24272509
ctrl->dma_rx = spi->dma_rx;
24282510
}

0 commit comments

Comments
 (0)