dmaengine: sh: setup_xref error handling

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>
This commit is contained in:
Thomas Andreatta 2025-08-27 17:24:43 +02:00 committed by Vinod Koul
parent 981d4978ff
commit d9a3e99294
3 changed files with 33 additions and 11 deletions

View 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);

View 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;
}
/*

View 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);