Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

spi: axi-spi-engine: move msg finalization out of irq handler

As a general principal, it is best to do as little as possible in an
interrupt handler. This patch reworks the AXI SPI Engine driver to move
timer_delete_sync() and spi_finalize_current_message() out of the
interrupt handler. Instead, spi_finalize_current_message() is moved to
the transfer_one_message function (similar to nearly all other SPI
controllers). A completion is now used to wait for the sync interrupt
that indicates that the message is complete. The watchdog timer is no
longer needed since we can use the wait_for_completion_timeout()
function to wait for the message to complete with the same effect.

As a bonus, these changes also improve throughput of the SPI controller.
For example, this was tested on a ZynqMP with a 80MHz SCLK reading 4
byte samples from an ADC. The max measured throughput increased from
26k to 28k samples per second.

Reviewed-by: Nuno Sa <nuno.sa@analog.com>
Signed-off-by: David Lechner <dlechner@baylibre.com>
Link: https://lore.kernel.org/r/20240207-axi-spi-engine-round-2-1-v2-2-40c0b4e85352@baylibre.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

David Lechner and committed by
Mark Brown
abb4b46c 531860e1

+15 -25
+15 -25
drivers/spi/spi-axi-spi-engine.c
··· 6 6 */ 7 7 8 8 #include <linux/clk.h> 9 + #include <linux/completion.h> 9 10 #include <linux/fpga/adi-axi-common.h> 10 11 #include <linux/interrupt.h> 11 12 #include <linux/io.h> ··· 14 13 #include <linux/module.h> 15 14 #include <linux/platform_device.h> 16 15 #include <linux/spi/spi.h> 17 - #include <linux/timer.h> 18 16 19 17 #define SPI_ENGINE_REG_RESET 0x40 20 18 ··· 109 109 spinlock_t lock; 110 110 111 111 void __iomem *base; 112 - struct timer_list watchdog_timer; 113 - struct spi_controller *controller; 114 - 112 + struct completion msg_complete; 115 113 unsigned int int_enable; 116 114 }; 117 115 ··· 481 483 482 484 if (pending & SPI_ENGINE_INT_SYNC && msg) { 483 485 if (completed_id == AXI_SPI_ENGINE_CUR_MSG_SYNC_ID) { 484 - if (timer_delete_sync(&spi_engine->watchdog_timer)) { 485 - msg->status = 0; 486 - msg->actual_length = msg->frame_length; 487 - spi_finalize_current_message(host); 488 - } 486 + msg->status = 0; 487 + msg->actual_length = msg->frame_length; 488 + complete(&spi_engine->msg_complete); 489 489 disable_int |= SPI_ENGINE_INT_SYNC; 490 490 } 491 491 } ··· 554 558 unsigned int int_enable = 0; 555 559 unsigned long flags; 556 560 557 - mod_timer(&spi_engine->watchdog_timer, jiffies + msecs_to_jiffies(5000)); 561 + reinit_completion(&spi_engine->msg_complete); 558 562 559 563 spin_lock_irqsave(&spi_engine->lock, flags); 560 564 ··· 576 580 spi_engine->int_enable = int_enable; 577 581 spin_unlock_irqrestore(&spi_engine->lock, flags); 578 582 579 - return 0; 580 - } 583 + if (!wait_for_completion_timeout(&spi_engine->msg_complete, 584 + msecs_to_jiffies(5000))) { 585 + dev_err(&host->dev, 586 + "Timeout occurred while waiting for transfer to complete. Hardware is probably broken.\n"); 587 + msg->status = -ETIMEDOUT; 588 + } 581 589 582 - static void spi_engine_timeout(struct timer_list *timer) 583 - { 584 - struct spi_engine *spi_engine = from_timer(spi_engine, timer, watchdog_timer); 585 - struct spi_controller *host = spi_engine->controller; 586 - 587 - if (WARN_ON(!host->cur_msg)) 588 - return; 589 - 590 - dev_err(&host->dev, 591 - "Timeout occurred while waiting for transfer to complete. Hardware is probably broken.\n"); 592 - host->cur_msg->status = -ETIMEDOUT; 593 590 spi_finalize_current_message(host); 591 + 592 + return msg->status; 594 593 } 595 594 596 595 static void spi_engine_release_hw(void *p) ··· 616 625 spi_engine = spi_controller_get_devdata(host); 617 626 618 627 spin_lock_init(&spi_engine->lock); 619 - timer_setup(&spi_engine->watchdog_timer, spi_engine_timeout, TIMER_IRQSAFE); 620 - spi_engine->controller = host; 628 + init_completion(&spi_engine->msg_complete); 621 629 622 630 spi_engine->clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk"); 623 631 if (IS_ERR(spi_engine->clk))