]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dmaengine: sh: setup_xref error handling
authorThomas Andreatta <thomasandreatta2000@gmail.com>
Wed, 27 Aug 2025 15:24:43 +0000 (17:24 +0200)
committerVinod Koul <vkoul@kernel.org>
Tue, 2 Sep 2025 06:59:36 +0000 (12:29 +0530)
This patch modifies the type of setup_xref from void to int and handles
errors since the function can fail.

`setup_xref` now returns the (eventual) error from
`dmae_set_dmars`|`dmae_set_chcr`, while `shdma_tx_submit` handles the
result, removing the chunks from the queue and marking PM as idle in
case of an error.

Signed-off-by: Thomas Andreatta <thomas.andreatta2000@gmail.com>
Link: https://lore.kernel.org/r/20250827152442.90962-1-thomas.andreatta2000@gmail.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/sh/shdma-base.c
drivers/dma/sh/shdmac.c
include/linux/shdma-base.h

index 6b4fce453c85c3b734566a7a59d7e67b4d121283..834741adadaade097260e48906fe429bc6cb01b2 100644 (file)
@@ -129,12 +129,25 @@ static dma_cookie_t shdma_tx_submit(struct dma_async_tx_descriptor *tx)
                        const struct shdma_ops *ops = sdev->ops;
                        dev_dbg(schan->dev, "Bring up channel %d\n",
                                schan->id);
-                       /*
-                        * TODO: .xfer_setup() might fail on some platforms.
-                        * Make it int then, on error remove chunks from the
-                        * queue again
-                        */
-                       ops->setup_xfer(schan, schan->slave_id);
+
+                       ret = ops->setup_xfer(schan, schan->slave_id);
+                       if (ret < 0) {
+                               dev_err(schan->dev, "setup_xfer failed: %d\n", ret);
+
+                               /* Remove chunks from the queue and mark them as idle */
+                               list_for_each_entry_safe(chunk, c, &schan->ld_queue, node) {
+                                       if (chunk->cookie == cookie) {
+                                               chunk->mark = DESC_IDLE;
+                                               list_move(&chunk->node, &schan->ld_free);
+                                       }
+                               }
+
+                               schan->pm_state = SHDMA_PM_ESTABLISHED;
+                               ret = pm_runtime_put(schan->dev);
+
+                               spin_unlock_irq(&schan->chan_lock);
+                               return ret;
+                       }
 
                        if (schan->pm_state == SHDMA_PM_PENDING)
                                shdma_chan_xfer_ld_queue(schan);
index 093e449e19eeeb5a190b4e53a500cf061d054784..603e15102e45ef005f74f78755d78e28493a3c92 100644 (file)
@@ -300,21 +300,30 @@ static bool sh_dmae_channel_busy(struct shdma_chan *schan)
        return dmae_is_busy(sh_chan);
 }
 
-static void sh_dmae_setup_xfer(struct shdma_chan *schan,
-                              int slave_id)
+static int sh_dmae_setup_xfer(struct shdma_chan *schan, int slave_id)
 {
        struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
                                                    shdma_chan);
 
+       int ret = 0;
        if (slave_id >= 0) {
                const struct sh_dmae_slave_config *cfg =
                        sh_chan->config;
 
-               dmae_set_dmars(sh_chan, cfg->mid_rid);
-               dmae_set_chcr(sh_chan, cfg->chcr);
+               ret = dmae_set_dmars(sh_chan, cfg->mid_rid);
+               if (ret < 0)
+                       goto END;
+
+               ret = dmae_set_chcr(sh_chan, cfg->chcr);
+               if (ret < 0)
+                       goto END;
+
        } else {
                dmae_init(sh_chan);
        }
+
+END:
+       return ret;
 }
 
 /*
index 6dfd05ef5c2d9f0d5b6b496909ab25a12e639c5e..03ba4dab2ef731b83c997afcfd06e21fb12e057a 100644 (file)
@@ -96,7 +96,7 @@ struct shdma_ops {
        int (*desc_setup)(struct shdma_chan *, struct shdma_desc *,
                          dma_addr_t, dma_addr_t, size_t *);
        int (*set_slave)(struct shdma_chan *, int, dma_addr_t, bool);
-       void (*setup_xfer)(struct shdma_chan *, int);
+       int (*setup_xfer)(struct shdma_chan *, int);
        void (*start_xfer)(struct shdma_chan *, struct shdma_desc *);
        struct shdma_desc *(*embedded_desc)(void *, int);
        bool (*chan_irq)(struct shdma_chan *, int);