Skip to content

Commit b39ef93

Browse files
Alain Volmatbroonie
authored andcommitted
spi: stm32: perform small transfer in polling mode
In case of interrupt based transfer, when the transfer is very small, relying on interrupts leads to lower performances than if the transfer were done using polling on the registers. Add a module parameter "polling_limit_us" to indicate the threshold in us from which a transfer would be done polling the registers rather than relying on interrupts. Signed-off-by: Alain Volmat <alain.volmat@foss.st.com> Link: https://patch.msgid.link/20251218-stm32-spi-enhancements-v2-3-3b69901ca9fe@foss.st.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 1ac3be2 commit b39ef93

1 file changed

Lines changed: 77 additions & 0 deletions

File tree

drivers/spi/spi-stm32.c

Lines changed: 77 additions & 0 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
@@ -2026,6 +2081,24 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
20262081
return ret;
20272082
}
20282083

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+
20292102
/**
20302103
* stm32_spi_transfer_one - transfer a single spi_transfer
20312104
* @ctrl: controller interface
@@ -2058,6 +2131,8 @@ static int stm32_spi_transfer_one(struct spi_controller *ctrl,
20582131

20592132
if (spi->cur_usedma)
20602133
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);
20612136
else
20622137
return spi->cfg->transfer_one_irq(spi);
20632138
}
@@ -2216,6 +2291,7 @@ static const struct stm32_spi_cfg stm32h7_spi_cfg = {
22162291
* SPI access hence handling is performed within the SPI interrupt
22172292
*/
22182293
.transfer_one_irq = stm32h7_spi_transfer_one_irq,
2294+
.transfer_one_poll = stm32h7_spi_transfer_one_poll,
22192295
.irq_handler_thread = stm32h7_spi_irq_thread,
22202296
.baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN,
22212297
.baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX,
@@ -2245,6 +2321,7 @@ static const struct stm32_spi_cfg stm32mp25_spi_cfg = {
22452321
* SPI access hence handling is performed within the SPI interrupt
22462322
*/
22472323
.transfer_one_irq = stm32h7_spi_transfer_one_irq,
2324+
.transfer_one_poll = stm32h7_spi_transfer_one_poll,
22482325
.irq_handler_thread = stm32h7_spi_irq_thread,
22492326
.baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN,
22502327
.baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX,

0 commit comments

Comments
 (0)