Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f8975224 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull slave dmaengine fixes from Vinod Koul:
 "Four fixes for dw, pl08x, imx-sdma and at_hdmac driver.  Nothing
  unusual here, simple fixes to these drivers"

* 'fixes' of git://git.infradead.org/users/vkoul/slave-dma:
  dmaengine: pl08x: Define capabilities for generic capabilities reporting
  dmaengine: dw: append MODULE_ALIAS for platform driver
  dmaengine: imx-sdma: switch to dynamic context mode after script loaded
  dmaengine: at_hdmac: Fix calculation of the residual bytes
parents 3d7a6db5 ea524c7e
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -97,6 +97,12 @@

#define DRIVER_NAME	"pl08xdmac"

#define PL80X_DMA_BUSWIDTHS \
	BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \
	BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
	BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
	BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)

static struct amba_driver pl08x_amba_driver;
struct pl08x_driver_data;

@@ -2070,6 +2076,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
	pl08x->memcpy.device_pause = pl08x_pause;
	pl08x->memcpy.device_resume = pl08x_resume;
	pl08x->memcpy.device_terminate_all = pl08x_terminate_all;
	pl08x->memcpy.src_addr_widths = PL80X_DMA_BUSWIDTHS;
	pl08x->memcpy.dst_addr_widths = PL80X_DMA_BUSWIDTHS;
	pl08x->memcpy.directions = BIT(DMA_MEM_TO_MEM);
	pl08x->memcpy.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;

	/* Initialize slave engine */
	dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
@@ -2086,6 +2096,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
	pl08x->slave.device_pause = pl08x_pause;
	pl08x->slave.device_resume = pl08x_resume;
	pl08x->slave.device_terminate_all = pl08x_terminate_all;
	pl08x->slave.src_addr_widths = PL80X_DMA_BUSWIDTHS;
	pl08x->slave.dst_addr_widths = PL80X_DMA_BUSWIDTHS;
	pl08x->slave.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
	pl08x->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;

	/* Get the platform data */
	pl08x->pd = dev_get_platdata(&adev->dev);
+112 −72
Original line number Diff line number Diff line
@@ -238,93 +238,126 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
}

/*
 * atc_get_current_descriptors -
 * locate the descriptor which equal to physical address in DSCR
 * @atchan: the channel we want to start
 * @dscr_addr: physical descriptor address in DSCR
 * atc_get_desc_by_cookie - get the descriptor of a cookie
 * @atchan: the DMA channel
 * @cookie: the cookie to get the descriptor for
 */
static struct at_desc *atc_get_current_descriptors(struct at_dma_chan *atchan,
							u32 dscr_addr)
static struct at_desc *atc_get_desc_by_cookie(struct at_dma_chan *atchan,
						dma_cookie_t cookie)
{
	struct at_desc  *desc, *_desc, *child, *desc_cur = NULL;
	struct at_desc *desc, *_desc;

	list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
		if (desc->lli.dscr == dscr_addr) {
			desc_cur = desc;
			break;
	list_for_each_entry_safe(desc, _desc, &atchan->queue, desc_node) {
		if (desc->txd.cookie == cookie)
			return desc;
	}

		list_for_each_entry(child, &desc->tx_list, desc_node) {
			if (child->lli.dscr == dscr_addr) {
				desc_cur = child;
				break;
	list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
		if (desc->txd.cookie == cookie)
			return desc;
	}

	return NULL;
}

/**
 * atc_calc_bytes_left - calculates the number of bytes left according to the
 * value read from CTRLA.
 *
 * @current_len: the number of bytes left before reading CTRLA
 * @ctrla: the value of CTRLA
 * @desc: the descriptor containing the transfer width
 */
static inline int atc_calc_bytes_left(int current_len, u32 ctrla,
					struct at_desc *desc)
{
	return current_len - ((ctrla & ATC_BTSIZE_MAX) << desc->tx_width);
}

	return desc_cur;
/**
 * atc_calc_bytes_left_from_reg - calculates the number of bytes left according
 * to the current value of CTRLA.
 *
 * @current_len: the number of bytes left before reading CTRLA
 * @atchan: the channel to read CTRLA for
 * @desc: the descriptor containing the transfer width
 */
static inline int atc_calc_bytes_left_from_reg(int current_len,
			struct at_dma_chan *atchan, struct at_desc *desc)
{
	u32 ctrla = channel_readl(atchan, CTRLA);

	return atc_calc_bytes_left(current_len, ctrla, desc);
}

/*
 * atc_get_bytes_left -
 * Get the number of bytes residue in dma buffer,
 * @chan: the channel we want to start
/**
 * atc_get_bytes_left - get the number of bytes residue for a cookie
 * @chan: DMA channel
 * @cookie: transaction identifier to check status of
 */
static int atc_get_bytes_left(struct dma_chan *chan)
static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
{
	struct at_dma_chan      *atchan = to_at_dma_chan(chan);
	struct at_dma           *atdma = to_at_dma(chan->device);
	int	chan_id = atchan->chan_common.chan_id;
	struct at_desc *desc_first = atc_first_active(atchan);
	struct at_desc *desc_cur;
	int ret = 0, count = 0;
	struct at_desc *desc;
	int ret;
	u32 ctrla, dscr;

	/*
	 * Initialize necessary values in the first time.
	 * remain_desc record remain desc length.
	 * If the cookie doesn't match to the currently running transfer then
	 * we can return the total length of the associated DMA transfer,
	 * because it is still queued.
	 */
	if (atchan->remain_desc == 0)
		/* First descriptor embedds the transaction length */
		atchan->remain_desc = desc_first->len;
	desc = atc_get_desc_by_cookie(atchan, cookie);
	if (desc == NULL)
		return -EINVAL;
	else if (desc != desc_first)
		return desc->total_len;

	/* cookie matches to the currently running transfer */
	ret = desc_first->total_len;

	if (desc_first->lli.dscr) {
		/* hardware linked list transfer */

		/*
	 * This happens when current descriptor transfer complete.
	 * The residual buffer size should reduce current descriptor length.
		 * Calculate the residue by removing the length of the child
		 * descriptors already transferred from the total length.
		 * To get the current child descriptor we can use the value of
		 * the channel's DSCR register and compare it against the value
		 * of the hardware linked list structure of each child
		 * descriptor.
		 */
	if (unlikely(test_bit(ATC_IS_BTC, &atchan->status))) {
		clear_bit(ATC_IS_BTC, &atchan->status);
		desc_cur = atc_get_current_descriptors(atchan,
						channel_readl(atchan, DSCR));
		if (!desc_cur) {
			ret = -EINVAL;
			goto out;
		}

		count = (desc_cur->lli.ctrla & ATC_BTSIZE_MAX)
			<< desc_first->tx_width;
		if (atchan->remain_desc < count) {
			ret = -EINVAL;
			goto out;
		ctrla = channel_readl(atchan, CTRLA);
		rmb(); /* ensure CTRLA is read before DSCR */
		dscr = channel_readl(atchan, DSCR);

		/* for the first descriptor we can be more accurate */
		if (desc_first->lli.dscr == dscr)
			return atc_calc_bytes_left(ret, ctrla, desc_first);

		ret -= desc_first->len;
		list_for_each_entry(desc, &desc_first->tx_list, desc_node) {
			if (desc->lli.dscr == dscr)
				break;

			ret -= desc->len;
		}

		atchan->remain_desc -= count;
		ret = atchan->remain_desc;
	} else {
		/*
		 * Get residual bytes when current
		 * descriptor transfer in progress.
		 * For the last descriptor in the chain we can calculate
		 * the remaining bytes using the channel's register.
		 * Note that the transfer width of the first and last
		 * descriptor may differ.
		 */
		count = (channel_readl(atchan, CTRLA) & ATC_BTSIZE_MAX)
				<< (desc_first->tx_width);
		ret = atchan->remain_desc - count;
		if (!desc->lli.dscr)
			ret = atc_calc_bytes_left_from_reg(ret, atchan, desc);
	} else {
		/* single transfer */
		ret = atc_calc_bytes_left_from_reg(ret, atchan, desc_first);
	}
	/*
	 * Check fifo empty.
	 */
	if (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id)))
		atc_issue_pending(chan);

out:
	return ret;
}

@@ -539,8 +572,6 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
					/* Give information to tasklet */
					set_bit(ATC_IS_ERROR, &atchan->status);
				}
				if (pending & AT_DMA_BTC(i))
					set_bit(ATC_IS_BTC, &atchan->status);
				tasklet_schedule(&atchan->tasklet);
				ret = IRQ_HANDLED;
			}
@@ -653,14 +684,18 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
		desc->lli.ctrlb = ctrlb;

		desc->txd.cookie = 0;
		desc->len = xfer_count << src_width;

		atc_desc_chain(&first, &prev, desc);
	}

	/* First descriptor of the chain embedds additional information */
	first->txd.cookie = -EBUSY;
	first->len = len;
	first->total_len = len;

	/* set transfer width for the calculation of the residue */
	first->tx_width = src_width;
	prev->tx_width = src_width;

	/* set end-of-link to the last link descriptor of list*/
	set_desc_eol(desc);
@@ -752,6 +787,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
					| ATC_SRC_WIDTH(mem_width)
					| len >> mem_width;
			desc->lli.ctrlb = ctrlb;
			desc->len = len;

			atc_desc_chain(&first, &prev, desc);
			total_len += len;
@@ -792,6 +828,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
					| ATC_DST_WIDTH(mem_width)
					| len >> reg_width;
			desc->lli.ctrlb = ctrlb;
			desc->len = len;

			atc_desc_chain(&first, &prev, desc);
			total_len += len;
@@ -806,8 +843,11 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,

	/* First descriptor of the chain embedds additional information */
	first->txd.cookie = -EBUSY;
	first->len = total_len;
	first->total_len = total_len;

	/* set transfer width for the calculation of the residue */
	first->tx_width = reg_width;
	prev->tx_width = reg_width;

	/* first link descriptor of list is responsible of flags */
	first->txd.flags = flags; /* client is in control of this ack */
@@ -872,6 +912,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
				| ATC_FC_MEM2PER
				| ATC_SIF(atchan->mem_if)
				| ATC_DIF(atchan->per_if);
		desc->len = period_len;
		break;

	case DMA_DEV_TO_MEM:
@@ -883,6 +924,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
				| ATC_FC_PER2MEM
				| ATC_SIF(atchan->per_if)
				| ATC_DIF(atchan->mem_if);
		desc->len = period_len;
		break;

	default:
@@ -964,7 +1006,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,

	/* First descriptor of the chain embedds additional information */
	first->txd.cookie = -EBUSY;
	first->len = buf_len;
	first->total_len = buf_len;
	first->tx_width = reg_width;

	return &first->txd;
@@ -1118,7 +1160,7 @@ atc_tx_status(struct dma_chan *chan,
	spin_lock_irqsave(&atchan->lock, flags);

	/*  Get number of bytes left in the active transactions */
	bytes = atc_get_bytes_left(chan);
	bytes = atc_get_bytes_left(chan, cookie);

	spin_unlock_irqrestore(&atchan->lock, flags);

@@ -1214,7 +1256,6 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)

	spin_lock_irqsave(&atchan->lock, flags);
	atchan->descs_allocated = i;
	atchan->remain_desc = 0;
	list_splice(&tmp_list, &atchan->free_list);
	dma_cookie_init(chan);
	spin_unlock_irqrestore(&atchan->lock, flags);
@@ -1257,7 +1298,6 @@ static void atc_free_chan_resources(struct dma_chan *chan)
	list_splice_init(&atchan->free_list, &list);
	atchan->descs_allocated = 0;
	atchan->status = 0;
	atchan->remain_desc = 0;

	dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
}
+3 −4
Original line number Diff line number Diff line
@@ -181,8 +181,9 @@ struct at_lli {
 * @at_lli: hardware lli structure
 * @txd: support for the async_tx api
 * @desc_node: node on the channed descriptors list
 * @len: total transaction bytecount
 * @len: descriptor byte count
 * @tx_width: transfer width
 * @total_len: total transaction byte count
 */
struct at_desc {
	/* FIRST values the hardware uses */
@@ -194,6 +195,7 @@ struct at_desc {
	struct list_head		desc_node;
	size_t				len;
	u32				tx_width;
	size_t				total_len;
};

static inline struct at_desc *
@@ -213,7 +215,6 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd)
enum atc_status {
	ATC_IS_ERROR = 0,
	ATC_IS_PAUSED = 1,
	ATC_IS_BTC = 2,
	ATC_IS_CYCLIC = 24,
};

@@ -231,7 +232,6 @@ enum atc_status {
 * @save_cfg: configuration register that is saved on suspend/resume cycle
 * @save_dscr: for cyclic operations, preserve next descriptor address in
 *             the cyclic list on suspend/resume cycle
 * @remain_desc: to save remain desc length
 * @dma_sconfig: configuration for slave transfers, passed via
 * .device_config
 * @lock: serializes enqueue/dequeue operations to descriptors lists
@@ -251,7 +251,6 @@ struct at_dma_chan {
	struct tasklet_struct	tasklet;
	u32			save_cfg;
	u32			save_dscr;
	u32			remain_desc;
	struct dma_slave_config dma_sconfig;

	spinlock_t		lock;
+4 −1
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@

#include "internal.h"

#define DRV_NAME	"dw_dmac"

static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
					struct of_dma *ofdma)
{
@@ -284,7 +286,7 @@ static struct platform_driver dw_driver = {
	.remove		= dw_remove,
	.shutdown       = dw_shutdown,
	.driver = {
		.name	= "dw_dmac",
		.name	= DRV_NAME,
		.pm	= &dw_dev_pm_ops,
		.of_match_table = of_match_ptr(dw_dma_of_id_table),
		.acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
@@ -305,3 +307,4 @@ module_exit(dw_exit);

MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver");
MODULE_ALIAS("platform:" DRV_NAME);
+4 −3
Original line number Diff line number Diff line
@@ -531,6 +531,10 @@ static int sdma_run_channel0(struct sdma_engine *sdma)
		dev_err(sdma->dev, "Timeout waiting for CH0 ready\n");
	}

	/* Set bits of CONFIG register with dynamic context switching */
	if (readl(sdma->regs + SDMA_H_CONFIG) == 0)
		writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);

	return ret ? 0 : -ETIMEDOUT;
}

@@ -1394,9 +1398,6 @@ static int sdma_init(struct sdma_engine *sdma)

	writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR);

	/* Set bits of CONFIG register with given context switching mode */
	writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);

	/* Initializes channel's priorities */
	sdma_set_channel_priority(&sdma->channel[0], 7);