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

Commit c3635c78 authored by Linus Walleij's avatar Linus Walleij Committed by Dan Williams
Browse files

DMAENGINE: generic slave control v2



Convert the device_terminate_all() operation on the
DMA engine to a generic device_control() operation
which can now optionally support also pausing and
resuming DMA on a certain channel. Implemented for the
COH 901 318 DMAC as an example.

[dan.j.williams@intel.com: update for timberdale]
Signed-off-by: default avatarLinus Walleij <linus.walleij@stericsson.com>
Acked-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
Cc: Maciej Sosnowski <maciej.sosnowski@intel.com>
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Li Yang <leoli@freescale.com>
Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
Cc: Magnus Damm <damm@opensource.se>
Cc: Liam Girdwood <lrg@slimlogic.co.uk>
Cc: Joe Perches <joe@perches.com>
Cc: Roland Dreier <rdreier@cisco.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 0f65169b
Loading
Loading
Loading
Loading
+0 −14
Original line number Diff line number Diff line
@@ -109,20 +109,6 @@ struct coh901318_platform {
 */
u32 coh901318_get_bytes_left(struct dma_chan *chan);

/**
 * coh901318_stop() - Stops dma transfer
 * @chan: dma channel handle
 * return 0 on success otherwise negative value
 */
void coh901318_stop(struct dma_chan *chan);

/**
 * coh901318_continue() - Resumes a stopped dma transfer
 * @chan: dma channel handle
 * return 0 on success otherwise negative value
 */
void coh901318_continue(struct dma_chan *chan);

/**
 * coh901318_filter_id() - DMA channel filter function
 * @chan: dma channel handle
+8 −2
Original line number Diff line number Diff line
@@ -759,13 +759,17 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
	return NULL;
}

static void atc_terminate_all(struct dma_chan *chan)
static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd)
{
	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
	struct at_dma		*atdma = to_at_dma(chan->device);
	struct at_desc		*desc, *_desc;
	LIST_HEAD(list);

	/* Only supports DMA_TERMINATE_ALL */
	if (cmd != DMA_TERMINATE_ALL)
		return -ENXIO;

	/*
	 * This is only called when something went wrong elsewhere, so
	 * we don't really care about the data. Just disable the
@@ -789,6 +793,8 @@ static void atc_terminate_all(struct dma_chan *chan)
	/* Flush all pending and queued descriptors */
	list_for_each_entry_safe(desc, _desc, &list, desc_node)
		atc_chain_complete(atchan, desc);

	return 0;
}

/**
@@ -1091,7 +1097,7 @@ static int __init at_dma_probe(struct platform_device *pdev)

	if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) {
		atdma->dma_common.device_prep_slave_sg = atc_prep_slave_sg;
		atdma->dma_common.device_terminate_all = atc_terminate_all;
		atdma->dma_common.device_control = atc_control;
	}

	dma_writel(atdma, EN, AT_DMA_ENABLE);
+28 −14
Original line number Diff line number Diff line
@@ -506,10 +506,11 @@ u32 coh901318_get_bytes_left(struct dma_chan *chan)
EXPORT_SYMBOL(coh901318_get_bytes_left);


/* Stops a transfer without losing data. Enables power save.
   Use this function in conjunction with coh901318_continue(..)
/*
 * Pauses a transfer without losing data. Enables power save.
 * Use this function in conjunction with coh901318_resume.
 */
void coh901318_stop(struct dma_chan *chan)
static void coh901318_pause(struct dma_chan *chan)
{
	u32 val;
	unsigned long flags;
@@ -550,12 +551,11 @@ void coh901318_stop(struct dma_chan *chan)

	spin_unlock_irqrestore(&cohc->lock, flags);
}
EXPORT_SYMBOL(coh901318_stop);

/* Continues a transfer that has been stopped via 300_dma_stop(..).
/* Resumes a transfer that has been stopped via 300_dma_stop(..).
   Power save is handled.
*/
void coh901318_continue(struct dma_chan *chan)
static void coh901318_resume(struct dma_chan *chan)
{
	u32 val;
	unsigned long flags;
@@ -581,7 +581,6 @@ void coh901318_continue(struct dma_chan *chan)

	spin_unlock_irqrestore(&cohc->lock, flags);
}
EXPORT_SYMBOL(coh901318_continue);

bool coh901318_filter_id(struct dma_chan *chan, void *chan_id)
{
@@ -945,7 +944,7 @@ coh901318_free_chan_resources(struct dma_chan *chan)

	spin_unlock_irqrestore(&cohc->lock, flags);

	chan->device->device_terminate_all(chan);
	chan->device->device_control(chan, DMA_TERMINATE_ALL);
}


@@ -1179,16 +1178,29 @@ coh901318_issue_pending(struct dma_chan *chan)
	spin_unlock_irqrestore(&cohc->lock, flags);
}

static void
coh901318_terminate_all(struct dma_chan *chan)
static int
coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd)
{
	unsigned long flags;
	struct coh901318_chan *cohc = to_coh901318_chan(chan);
	struct coh901318_desc *cohd;
	void __iomem *virtbase = cohc->base->virtbase;

	coh901318_stop(chan);
	if (cmd == DMA_PAUSE) {
		coh901318_pause(chan);
		return 0;
	}

	if (cmd == DMA_RESUME) {
		coh901318_resume(chan);
		return 0;
	}

	if (cmd != DMA_TERMINATE_ALL)
		return -ENXIO;

	/* The remainder of this function terminates the transfer */
	coh901318_pause(chan);
	spin_lock_irqsave(&cohc->lock, flags);

	/* Clear any pending BE or TC interrupt */
@@ -1227,6 +1239,8 @@ coh901318_terminate_all(struct dma_chan *chan)
	cohc->busy = 0;

	spin_unlock_irqrestore(&cohc->lock, flags);

	return 0;
}
void coh901318_base_init(struct dma_device *dma, const int *pick_chans,
			 struct coh901318_base *base)
@@ -1344,7 +1358,7 @@ static int __init coh901318_probe(struct platform_device *pdev)
	base->dma_slave.device_prep_slave_sg = coh901318_prep_slave_sg;
	base->dma_slave.device_is_tx_complete = coh901318_is_tx_complete;
	base->dma_slave.device_issue_pending = coh901318_issue_pending;
	base->dma_slave.device_terminate_all = coh901318_terminate_all;
	base->dma_slave.device_control = coh901318_control;
	base->dma_slave.dev = &pdev->dev;

	err = dma_async_device_register(&base->dma_slave);
@@ -1364,7 +1378,7 @@ static int __init coh901318_probe(struct platform_device *pdev)
	base->dma_memcpy.device_prep_dma_memcpy = coh901318_prep_memcpy;
	base->dma_memcpy.device_is_tx_complete = coh901318_is_tx_complete;
	base->dma_memcpy.device_issue_pending = coh901318_issue_pending;
	base->dma_memcpy.device_terminate_all = coh901318_terminate_all;
	base->dma_memcpy.device_control = coh901318_control;
	base->dma_memcpy.dev = &pdev->dev;
	/*
	 * This controller can only access address at even 32bit boundaries,
+1 −1
Original line number Diff line number Diff line
@@ -694,7 +694,7 @@ int dma_async_device_register(struct dma_device *device)
	BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
		!device->device_prep_slave_sg);
	BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
		!device->device_terminate_all);
		!device->device_control);

	BUG_ON(!device->device_alloc_chan_resources);
	BUG_ON(!device->device_free_chan_resources);
+8 −2
Original line number Diff line number Diff line
@@ -781,13 +781,17 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
	return NULL;
}

static void dwc_terminate_all(struct dma_chan *chan)
static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd)
{
	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
	struct dw_dma		*dw = to_dw_dma(chan->device);
	struct dw_desc		*desc, *_desc;
	LIST_HEAD(list);

	/* Only supports DMA_TERMINATE_ALL */
	if (cmd != DMA_TERMINATE_ALL)
		return -ENXIO;

	/*
	 * This is only called when something went wrong elsewhere, so
	 * we don't really care about the data. Just disable the
@@ -810,6 +814,8 @@ static void dwc_terminate_all(struct dma_chan *chan)
	/* Flush all pending and queued descriptors */
	list_for_each_entry_safe(desc, _desc, &list, desc_node)
		dwc_descriptor_complete(dwc, desc);

	return 0;
}

static enum dma_status
@@ -1338,7 +1344,7 @@ static int __init dw_probe(struct platform_device *pdev)
	dw->dma.device_prep_dma_memcpy = dwc_prep_dma_memcpy;

	dw->dma.device_prep_slave_sg = dwc_prep_slave_sg;
	dw->dma.device_terminate_all = dwc_terminate_all;
	dw->dma.device_control = dwc_control;

	dw->dma.device_is_tx_complete = dwc_is_tx_complete;
	dw->dma.device_issue_pending = dwc_issue_pending;
Loading