Commit d9a3e992 authored by Thomas Andreatta's avatar Thomas Andreatta Committed by Vinod Koul
Browse files

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: default avatarThomas Andreatta <thomas.andreatta2000@gmail.com>
Link: https://lore.kernel.org/r/20250827152442.90962-1-thomas.andreatta2000@gmail.com


Signed-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent 981d4978
Loading
Loading
Loading
Loading
+19 −6
Original line number Diff line number Diff line
@@ -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);
+13 −4
Original line number Diff line number Diff line
@@ -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;
}

/*
+1 −1
Original line number Diff line number Diff line
@@ -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);