]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
spi: introduce fallback to pio
authorRobin Gong <yibin.gong@nxp.com>
Tue, 16 Jun 2020 22:42:08 +0000 (06:42 +0800)
committerMark Brown <broonie@kernel.org>
Tue, 23 Jun 2020 12:38:14 +0000 (13:38 +0100)
Add fallback to pio mode in case dma transfer failed with error status
SPI_TRANS_FAIL_NO_START.
If spi client driver want to enable this feature please set xfer->error in
the proper place such as dmaengine_prep_slave_sg() failure detect(but no
any data put into spi bus yet). Besides, add master->fallback checking in
its can_dma() so that spi core could switch to pio next time. Please refer
to spi-imx.c.

Signed-off-by: Robin Gong <yibin.gong@nxp.com>
Link: https://lore.kernel.org/r/1592347329-28363-2-git-send-email-yibin.gong@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi.c
include/linux/spi/spi.h

index 8158e281f35409ebbc19fa0cf04c539b5fd20e76..6fa56590bba2755bde8f3fc78a141ecd668d86f2 100644 (file)
@@ -982,6 +982,8 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg)
                spi_unmap_buf(ctlr, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
        }
 
+       ctlr->cur_msg_mapped = false;
+
        return 0;
 }
 #else /* !CONFIG_HAS_DMA */
@@ -1234,8 +1236,17 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
                if (xfer->tx_buf || xfer->rx_buf) {
                        reinit_completion(&ctlr->xfer_completion);
 
+fallback_pio:
                        ret = ctlr->transfer_one(ctlr, msg->spi, xfer);
                        if (ret < 0) {
+                               if (ctlr->cur_msg_mapped &&
+                                  (xfer->error & SPI_TRANS_FAIL_NO_START)) {
+                                       __spi_unmap_msg(ctlr, msg);
+                                       ctlr->fallback = true;
+                                       xfer->error &= ~SPI_TRANS_FAIL_NO_START;
+                                       goto fallback_pio;
+                               }
+
                                SPI_STATISTICS_INCREMENT_FIELD(statm,
                                                               errors);
                                SPI_STATISTICS_INCREMENT_FIELD(stats,
@@ -1693,6 +1704,7 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
        spin_lock_irqsave(&ctlr->queue_lock, flags);
        ctlr->cur_msg = NULL;
        ctlr->cur_msg_prepared = false;
+       ctlr->fallback = false;
        kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);
        spin_unlock_irqrestore(&ctlr->queue_lock, flags);
 
index aac57b5b7c21d1ada59e45779e728892bd746445..b4917df79637462ca788205cea6999ffb5467c22 100644 (file)
@@ -447,6 +447,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
  *     If the driver does not set this, the SPI core takes the snapshot as
  *     close to the driver hand-over as possible.
  * @irq_flags: Interrupt enable state during PTP system timestamping
+ * @fallback: fallback to pio if dma transfer return failure with
+ *     SPI_TRANS_FAIL_NO_START.
  *
  * Each SPI controller can communicate with one or more @spi_device
  * children.  These make a small bus, sharing MOSI, MISO and SCK signals
@@ -602,6 +604,7 @@ struct spi_controller {
        bool                            auto_runtime_pm;
        bool                            cur_msg_prepared;
        bool                            cur_msg_mapped;
+       bool                            fallback;
        struct completion               xfer_completion;
        size_t                          max_dma_len;
 
@@ -847,6 +850,7 @@ extern void spi_res_release(struct spi_controller *ctlr,
  *     back unset and they need the better resolution.
  * @timestamped_post: See above. The reason why both exist is that these
  *     booleans are also used to keep state in the core SPI logic.
+ * @error: Error status logged by spi controller driver.
  *
  * SPI transfers always write the same number of bytes as they read.
  * Protocol drivers should always provide @rx_buf and/or @tx_buf.
@@ -940,6 +944,9 @@ struct spi_transfer {
        bool            timestamped;
 
        struct list_head transfer_list;
+
+#define SPI_TRANS_FAIL_NO_START        BIT(0)
+       u16             error;
 };
 
 /**