Skip to content

Commit

Permalink
Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git…
Browse files Browse the repository at this point in the history
…/djbw/async_tx

* 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx: (21 commits)
  dmaengine: add slave-dma maintainer
  dma: ipu_idmac: do not lose valid received data in the irq handler
  dmaengine: imx-sdma: fix up param for the last BD in sdma_prep_slave_sg()
  dmaengine: imx-sdma: correct sdmac->status in sdma_handle_channel_loop()
  dmaengine: imx-sdma: return sdmac->status in sdma_tx_status()
  dmaengine: imx-sdma: set sdmac->status to DMA_ERROR in err_out of sdma_prep_slave_sg()
  dmaengine: imx-sdma: remove IMX_DMA_SG_LOOP handling in sdma_prep_slave_sg()
  dmaengine i.MX dma: initialize dma capabilities outside channel loop
  dmaengine i.MX DMA: do not initialize chan_id field
  dmaengine i.MX dma: check sg entries for valid addresses and lengths
  dmaengine i.MX dma: set maximum segment size for our device
  dmaengine i.MX SDMA: reserve channel 0 by not registering it
  dmaengine i.MX SDMA: initialize dma capabilities outside channel loop
  dmaengine i.MX SDMA: do not initialize chan_id field
  dmaengine i.MX sdma: check sg entries for valid addresses and lengths
  dmaengine i.MX sdma: set maximum segment size for our device
  DMA: PL08x: fix channel pausing to timeout rather than lockup
  DMA: PL08x: fix infinite wait when terminating transfers
  dmaengine: imx-sdma: fix inconsistent naming in sdma_assign_cookie()
  dmaengine: imx-sdma: propagate error in sdma_probe() instead of returning 0
  ...
  • Loading branch information
Linus Torvalds committed Feb 15, 2011
2 parents f60c153 + 4abed0a commit b45bbf0
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 115 deletions.
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -2126,6 +2126,7 @@ S: Supported
F: fs/dlm/

DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
M: Vinod Koul <vinod.koul@intel.com>
M: Dan Williams <dan.j.williams@intel.com>
S: Supported
F: drivers/dma/
Expand Down
53 changes: 33 additions & 20 deletions drivers/dma/amba-pl08x.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/dmapool.h>
#include <linux/dmaengine.h>
#include <linux/amba/bus.h>
Expand Down Expand Up @@ -235,25 +236,33 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan,
}

/*
* Overall DMAC remains enabled always.
* Pause the channel by setting the HALT bit.
*
* Disabling individual channels could lose data.
* For M->P transfers, pause the DMAC first and then stop the peripheral -
* the FIFO can only drain if the peripheral is still requesting data.
* (note: this can still timeout if the DMAC FIFO never drains of data.)
*
* Disable the peripheral DMA after disabling the DMAC in order to allow
* the DMAC FIFO to drain, and hence allow the channel to show inactive
* For P->M transfers, disable the peripheral first to stop it filling
* the DMAC FIFO, and then pause the DMAC.
*/
static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch)
{
u32 val;
int timeout;

/* Set the HALT bit and wait for the FIFO to drain */
val = readl(ch->base + PL080_CH_CONFIG);
val |= PL080_CONFIG_HALT;
writel(val, ch->base + PL080_CH_CONFIG);

/* Wait for channel inactive */
while (pl08x_phy_channel_busy(ch))
cpu_relax();
for (timeout = 1000; timeout; timeout--) {
if (!pl08x_phy_channel_busy(ch))
break;
udelay(1);
}
if (pl08x_phy_channel_busy(ch))
pr_err("pl08x: channel%u timeout waiting for pause\n", ch->id);
}

static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
Expand All @@ -267,19 +276,24 @@ static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
}


/* Stops the channel */
static void pl08x_stop_phy_chan(struct pl08x_phy_chan *ch)
/*
* pl08x_terminate_phy_chan() stops the channel, clears the FIFO and
* clears any pending interrupt status. This should not be used for
* an on-going transfer, but as a method of shutting down a channel
* (eg, when it's no longer used) or terminating a transfer.
*/
static void pl08x_terminate_phy_chan(struct pl08x_driver_data *pl08x,
struct pl08x_phy_chan *ch)
{
u32 val;
u32 val = readl(ch->base + PL080_CH_CONFIG);

pl08x_pause_phy_chan(ch);
val &= ~(PL080_CONFIG_ENABLE | PL080_CONFIG_ERR_IRQ_MASK |
PL080_CONFIG_TC_IRQ_MASK);

/* Disable channel */
val = readl(ch->base + PL080_CH_CONFIG);
val &= ~PL080_CONFIG_ENABLE;
val &= ~PL080_CONFIG_ERR_IRQ_MASK;
val &= ~PL080_CONFIG_TC_IRQ_MASK;
writel(val, ch->base + PL080_CH_CONFIG);

writel(1 << ch->id, pl08x->base + PL080_ERR_CLEAR);
writel(1 << ch->id, pl08x->base + PL080_TC_CLEAR);
}

static inline u32 get_bytes_in_cctl(u32 cctl)
Expand Down Expand Up @@ -404,13 +418,12 @@ static inline void pl08x_put_phy_channel(struct pl08x_driver_data *pl08x,
{
unsigned long flags;

spin_lock_irqsave(&ch->lock, flags);

/* Stop the channel and clear its interrupts */
pl08x_stop_phy_chan(ch);
writel((1 << ch->id), pl08x->base + PL080_ERR_CLEAR);
writel((1 << ch->id), pl08x->base + PL080_TC_CLEAR);
pl08x_terminate_phy_chan(pl08x, ch);

/* Mark it as free */
spin_lock_irqsave(&ch->lock, flags);
ch->serving = NULL;
spin_unlock_irqrestore(&ch->lock, flags);
}
Expand Down Expand Up @@ -1449,7 +1462,7 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
plchan->state = PL08X_CHAN_IDLE;

if (plchan->phychan) {
pl08x_stop_phy_chan(plchan->phychan);
pl08x_terminate_phy_chan(pl08x, plchan->phychan);

/*
* Mark physical channel as free and free any slave
Expand Down
26 changes: 22 additions & 4 deletions drivers/dma/imx-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct imxdma_channel {

struct imxdma_engine {
struct device *dev;
struct device_dma_parameters dma_parms;
struct dma_device dma_device;
struct imxdma_channel channel[MAX_DMA_CHANNELS];
};
Expand Down Expand Up @@ -242,6 +243,21 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
else
dmamode = DMA_MODE_WRITE;

switch (imxdmac->word_size) {
case DMA_SLAVE_BUSWIDTH_4_BYTES:
if (sgl->length & 3 || sgl->dma_address & 3)
return NULL;
break;
case DMA_SLAVE_BUSWIDTH_2_BYTES:
if (sgl->length & 1 || sgl->dma_address & 1)
return NULL;
break;
case DMA_SLAVE_BUSWIDTH_1_BYTE:
break;
default:
return NULL;
}

ret = imx_dma_setup_sg(imxdmac->imxdma_channel, sgl, sg_len,
dma_length, imxdmac->per_address, dmamode);
if (ret)
Expand Down Expand Up @@ -329,6 +345,9 @@ static int __init imxdma_probe(struct platform_device *pdev)

INIT_LIST_HEAD(&imxdma->dma_device.channels);

dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask);
dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask);

/* Initialize channel parameters */
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
struct imxdma_channel *imxdmac = &imxdma->channel[i];
Expand All @@ -346,11 +365,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
imxdmac->imxdma = imxdma;
spin_lock_init(&imxdmac->lock);

dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask);
dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask);

imxdmac->chan.device = &imxdma->dma_device;
imxdmac->chan.chan_id = i;
imxdmac->channel = i;

/* Add the channel to the DMAC list */
Expand All @@ -370,6 +385,9 @@ static int __init imxdma_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, imxdma);

imxdma->dma_device.dev->dma_parms = &imxdma->dma_parms;
dma_set_max_seg_size(imxdma->dma_device.dev, 0xffffff);

ret = dma_async_device_register(&imxdma->dma_device);
if (ret) {
dev_err(&pdev->dev, "unable to register\n");
Expand Down
Loading

0 comments on commit b45bbf0

Please sign in to comment.