summaryrefslogtreecommitdiff
path: root/drivers/dma
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/at_hdmac.c2
-rw-r--r--drivers/dma/coh901318.c2
-rw-r--r--drivers/dma/dmatest.c6
-rw-r--r--drivers/dma/dw_dmac.c2
-rw-r--r--drivers/dma/fsldma.c2
-rw-r--r--drivers/dma/intel_mid_dma.c8
-rw-r--r--drivers/dma/intel_mid_dma_regs.h4
-rw-r--r--drivers/dma/ioat/dma.c1
-rw-r--r--drivers/dma/ioat/dma_v2.c1
-rw-r--r--drivers/dma/ioat/dma_v3.c1
-rw-r--r--drivers/dma/mpc512x_dma.c2
-rw-r--r--drivers/dma/shdma.c231
-rw-r--r--drivers/dma/shdma.h3
-rw-r--r--drivers/dma/ste_dma40.c4
-rw-r--r--drivers/dma/timb_dma.c3
15 files changed, 200 insertions, 72 deletions
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 3134003eec8b..36144f88d718 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -190,7 +190,7 @@ static void atc_desc_chain(struct at_desc **first, struct at_desc **prev,
/**
* atc_assign_cookie - compute and assign new cookie
* @atchan: channel we work on
- * @desc: descriptor to asign cookie for
+ * @desc: descriptor to assign cookie for
*
* Called with atchan->lock held and bh disabled
*/
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index b5a318916d05..af8c0b5ed70f 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -529,7 +529,7 @@ static void coh901318_pause(struct dma_chan *chan)
val = readl(virtbase + COH901318_CX_CFG +
COH901318_CX_CFG_SPACING * channel);
- /* Stopping infinit transfer */
+ /* Stopping infinite transfer */
if ((val & COH901318_CX_CTRL_TC_ENABLE) == 0 &&
(val & COH901318_CX_CFG_CH_ENABLE))
cohc->stopped = 1;
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index e0888cb538d4..b4f5c32b6a47 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -56,8 +56,8 @@ MODULE_PARM_DESC(pq_sources,
static int timeout = 3000;
module_param(timeout, uint, S_IRUGO);
-MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), \
- Pass -1 for infinite timeout");
+MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), "
+ "Pass -1 for infinite timeout");
/*
* Initialization patterns. All bytes in the source buffer has bit 7
@@ -634,5 +634,5 @@ static void __exit dmatest_exit(void)
}
module_exit(dmatest_exit);
-MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index efd836dfb65a..4d180ca9a1d8 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -1575,5 +1575,5 @@ module_exit(dw_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller driver");
-MODULE_AUTHOR("Haavard Skinnemoen <haavard.skinnemoen@atmel.com>");
+MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 6b396759e7f5..8a781540590c 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -1448,7 +1448,7 @@ static const struct of_device_id fsldma_of_ids[] = {
{}
};
-static struct of_platform_driver fsldma_of_driver = {
+static struct platform_driver fsldma_of_driver = {
.driver = {
.name = "fsl-elo-dma",
.owner = THIS_MODULE,
diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c
index f153adfcaceb..f653517ef744 100644
--- a/drivers/dma/intel_mid_dma.c
+++ b/drivers/dma/intel_mid_dma.c
@@ -911,8 +911,8 @@ static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
/**
* midc_handle_error - Handle DMA txn error
- * @mid: controller where error occured
- * @midc: chan where error occured
+ * @mid: controller where error occurred
+ * @midc: chan where error occurred
*
* Scan the descriptor for error
*/
@@ -1099,7 +1099,7 @@ static int mid_setup_dma(struct pci_dev *pdev)
dma->mask_reg = ioremap(LNW_PERIPHRAL_MASK_BASE,
LNW_PERIPHRAL_MASK_SIZE);
if (dma->mask_reg == NULL) {
- pr_err("ERR_MDMA:Cant map periphral intr space !!\n");
+ pr_err("ERR_MDMA:Can't map periphral intr space !!\n");
return -ENOMEM;
}
} else
@@ -1375,7 +1375,7 @@ int dma_resume(struct pci_dev *pci)
pci_restore_state(pci);
ret = pci_enable_device(pci);
if (ret) {
- pr_err("MDMA: device cant be enabled for %x\n", pci->device);
+ pr_err("MDMA: device can't be enabled for %x\n", pci->device);
return ret;
}
device->state = RUNNING;
diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h
index 709fecbdde79..aea5ee88ce03 100644
--- a/drivers/dma/intel_mid_dma_regs.h
+++ b/drivers/dma/intel_mid_dma_regs.h
@@ -174,8 +174,8 @@ union intel_mid_dma_cfg_hi {
* @dma: dma device struture pointer
* @busy: bool representing if ch is busy (active txn) or not
* @in_use: bool representing if ch is in use or not
- * @raw_tfr: raw trf interrupt recieved
- * @raw_block: raw block interrupt recieved
+ * @raw_tfr: raw trf interrupt received
+ * @raw_block: raw block interrupt received
*/
struct intel_mid_dma_chan {
struct dma_chan chan;
diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
index c9213ead4a26..a4d6cb0c0343 100644
--- a/drivers/dma/ioat/dma.c
+++ b/drivers/dma/ioat/dma.c
@@ -34,6 +34,7 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/workqueue.h>
+#include <linux/prefetch.h>
#include <linux/i7300_idle.h>
#include "dma.h"
#include "registers.h"
diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c
index 54d1a3c24e9c..5d65f8377971 100644
--- a/drivers/dma/ioat/dma_v2.c
+++ b/drivers/dma/ioat/dma_v2.c
@@ -34,6 +34,7 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/workqueue.h>
+#include <linux/prefetch.h>
#include <linux/i7300_idle.h>
#include "dma.h"
#include "dma_v2.h"
diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c
index d0f499098479..d845dc4b7103 100644
--- a/drivers/dma/ioat/dma_v3.c
+++ b/drivers/dma/ioat/dma_v3.c
@@ -60,6 +60,7 @@
#include <linux/gfp.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/prefetch.h>
#include "registers.h"
#include "hw.h"
#include "dma.h"
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 4f95d31f5a20..b9bae94f2015 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -328,7 +328,7 @@ static irqreturn_t mpc_dma_irq(int irq, void *data)
return IRQ_HANDLED;
}
-/* proccess completed descriptors */
+/* process completed descriptors */
static void mpc_dma_process_completed(struct mpc_dma *mdma)
{
dma_cookie_t last_cookie = 0;
diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
index 6451b581a70b..636e40925b16 100644
--- a/drivers/dma/shdma.c
+++ b/drivers/dma/shdma.c
@@ -48,7 +48,7 @@ enum sh_dmae_desc_status {
/*
* Used for write-side mutual exclusion for the global device list,
- * read-side synchronization by way of RCU.
+ * read-side synchronization by way of RCU, and per-controller data.
*/
static DEFINE_SPINLOCK(sh_dmae_lock);
static LIST_HEAD(sh_dmae_devices);
@@ -85,22 +85,35 @@ static void dmaor_write(struct sh_dmae_device *shdev, u16 data)
*/
static void sh_dmae_ctl_stop(struct sh_dmae_device *shdev)
{
- unsigned short dmaor = dmaor_read(shdev);
+ unsigned short dmaor;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sh_dmae_lock, flags);
+ dmaor = dmaor_read(shdev);
dmaor_write(shdev, dmaor & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME));
+
+ spin_unlock_irqrestore(&sh_dmae_lock, flags);
}
static int sh_dmae_rst(struct sh_dmae_device *shdev)
{
unsigned short dmaor;
+ unsigned long flags;
- sh_dmae_ctl_stop(shdev);
- dmaor = dmaor_read(shdev) | shdev->pdata->dmaor_init;
+ spin_lock_irqsave(&sh_dmae_lock, flags);
- dmaor_write(shdev, dmaor);
- if (dmaor_read(shdev) & (DMAOR_AE | DMAOR_NMIF)) {
- pr_warning("dma-sh: Can't initialize DMAOR.\n");
- return -EINVAL;
+ dmaor = dmaor_read(shdev) & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME);
+
+ dmaor_write(shdev, dmaor | shdev->pdata->dmaor_init);
+
+ dmaor = dmaor_read(shdev);
+
+ spin_unlock_irqrestore(&sh_dmae_lock, flags);
+
+ if (dmaor & (DMAOR_AE | DMAOR_NMIF)) {
+ dev_warn(shdev->common.dev, "Can't initialize DMAOR.\n");
+ return -EIO;
}
return 0;
}
@@ -184,7 +197,7 @@ static void dmae_init(struct sh_dmae_chan *sh_chan)
static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val)
{
- /* When DMA was working, can not set data to CHCR */
+ /* If DMA is active, cannot set CHCR. TODO: remove this superfluous check */
if (dmae_is_busy(sh_chan))
return -EBUSY;
@@ -200,12 +213,17 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
struct sh_dmae_device, common);
struct sh_dmae_pdata *pdata = shdev->pdata;
const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->id];
- u16 __iomem *addr = shdev->dmars + chan_pdata->dmars / sizeof(u16);
+ u16 __iomem *addr = shdev->dmars;
int shift = chan_pdata->dmars_bit;
if (dmae_is_busy(sh_chan))
return -EBUSY;
+ /* in the case of a missing DMARS resource use first memory window */
+ if (!addr)
+ addr = (u16 __iomem *)shdev->chan_reg;
+ addr += chan_pdata->dmars / sizeof(u16);
+
__raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift),
addr);
@@ -374,7 +392,12 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
LIST_HEAD(list);
int descs = sh_chan->descs_allocated;
+ /* Protect against ISR */
+ spin_lock_irq(&sh_chan->desc_lock);
dmae_halt(sh_chan);
+ spin_unlock_irq(&sh_chan->desc_lock);
+
+ /* Now no new interrupts will occur */
/* Prepared and not submitted descriptors can still be on the queue */
if (!list_empty(&sh_chan->ld_queue))
@@ -384,6 +407,7 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
/* The caller is holding dma_list_mutex */
struct sh_dmae_slave *param = chan->private;
clear_bit(param->slave_id, sh_dmae_slave_used);
+ chan->private = NULL;
}
spin_lock_bh(&sh_chan->desc_lock);
@@ -563,8 +587,6 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy(
if (!chan || !len)
return NULL;
- chan->private = NULL;
-
sh_chan = to_sh_chan(chan);
sg_init_table(&sg, 1);
@@ -620,9 +642,9 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
if (!chan)
return -EINVAL;
+ spin_lock_bh(&sh_chan->desc_lock);
dmae_halt(sh_chan);
- spin_lock_bh(&sh_chan->desc_lock);
if (!list_empty(&sh_chan->ld_queue)) {
/* Record partial transfer */
struct sh_desc *desc = list_entry(sh_chan->ld_queue.next,
@@ -716,6 +738,14 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all
list_move(&desc->node, &sh_chan->ld_free);
}
}
+
+ if (all && !callback)
+ /*
+ * Terminating and the loop completed normally: forgive
+ * uncompleted cookies
+ */
+ sh_chan->completed_cookie = sh_chan->common.cookie;
+
spin_unlock_bh(&sh_chan->desc_lock);
if (callback)
@@ -733,10 +763,6 @@ static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all)
{
while (__ld_cleanup(sh_chan, all))
;
-
- if (all)
- /* Terminating - forgive uncompleted cookies */
- sh_chan->completed_cookie = sh_chan->common.cookie;
}
static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
@@ -782,8 +808,10 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan,
sh_dmae_chan_ld_cleanup(sh_chan, false);
- last_used = chan->cookie;
+ /* First read completed cookie to avoid a skew */
last_complete = sh_chan->completed_cookie;
+ rmb();
+ last_used = chan->cookie;
BUG_ON(last_complete < 0);
dma_set_tx_state(txstate, last_complete, last_used, 0);
@@ -813,8 +841,12 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan,
static irqreturn_t sh_dmae_interrupt(int irq, void *data)
{
irqreturn_t ret = IRQ_NONE;
- struct sh_dmae_chan *sh_chan = (struct sh_dmae_chan *)data;
- u32 chcr = sh_dmae_readl(sh_chan, CHCR);
+ struct sh_dmae_chan *sh_chan = data;
+ u32 chcr;
+
+ spin_lock(&sh_chan->desc_lock);
+
+ chcr = sh_dmae_readl(sh_chan, CHCR);
if (chcr & CHCR_TE) {
/* DMA stop */
@@ -824,10 +856,13 @@ static irqreturn_t sh_dmae_interrupt(int irq, void *data)
tasklet_schedule(&sh_chan->tasklet);
}
+ spin_unlock(&sh_chan->desc_lock);
+
return ret;
}
-static unsigned int sh_dmae_reset(struct sh_dmae_device *shdev)
+/* Called from error IRQ or NMI */
+static bool sh_dmae_reset(struct sh_dmae_device *shdev)
{
unsigned int handled = 0;
int i;
@@ -839,22 +874,32 @@ static unsigned int sh_dmae_reset(struct sh_dmae_device *shdev)
for (i = 0; i < SH_DMAC_MAX_CHANNELS; i++) {
struct sh_dmae_chan *sh_chan = shdev->chan[i];
struct sh_desc *desc;
+ LIST_HEAD(dl);
if (!sh_chan)
continue;
+ spin_lock(&sh_chan->desc_lock);
+
/* Stop the channel */
dmae_halt(sh_chan);
+ list_splice_init(&sh_chan->ld_queue, &dl);
+
+ spin_unlock(&sh_chan->desc_lock);
+
/* Complete all */
- list_for_each_entry(desc, &sh_chan->ld_queue, node) {
+ list_for_each_entry(desc, &dl, node) {
struct dma_async_tx_descriptor *tx = &desc->async_tx;
desc->mark = DESC_IDLE;
if (tx->callback)
tx->callback(tx->callback_param);
}
- list_splice_init(&sh_chan->ld_queue, &sh_chan->ld_free);
+ spin_lock(&sh_chan->desc_lock);
+ list_splice(&dl, &sh_chan->ld_free);
+ spin_unlock(&sh_chan->desc_lock);
+
handled++;
}
@@ -865,7 +910,13 @@ static unsigned int sh_dmae_reset(struct sh_dmae_device *shdev)
static irqreturn_t sh_dmae_err(int irq, void *data)
{
- return IRQ_RETVAL(sh_dmae_reset(data));
+ struct sh_dmae_device *shdev = data;
+
+ if (!(dmaor_read(shdev) & DMAOR_AE))
+ return IRQ_NONE;
+
+ sh_dmae_reset(data);
+ return IRQ_HANDLED;
}
static void dmae_do_tasklet(unsigned long data)
@@ -897,17 +948,11 @@ static void dmae_do_tasklet(unsigned long data)
static bool sh_dmae_nmi_notify(struct sh_dmae_device *shdev)
{
- unsigned int handled;
-
/* Fast path out if NMIF is not asserted for this controller */
if ((dmaor_read(shdev) & DMAOR_NMIF) == 0)
return false;
- handled = sh_dmae_reset(shdev);
- if (handled)
- return true;
-
- return false;
+ return sh_dmae_reset(shdev);
}
static int sh_dmae_nmi_handler(struct notifier_block *self,
@@ -977,9 +1022,6 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
tasklet_init(&new_sh_chan->tasklet, dmae_do_tasklet,
(unsigned long)new_sh_chan);
- /* Init the channel */
- dmae_init(new_sh_chan);
-
spin_lock_init(&new_sh_chan->desc_lock);
/* Init descripter manage list */
@@ -1040,9 +1082,8 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
struct sh_dmae_pdata *pdata = pdev->dev.platform_data;
unsigned long irqflags = IRQF_DISABLED,
chan_flag[SH_DMAC_MAX_CHANNELS] = {};
- unsigned long flags;
int errirq, chan_irq[SH_DMAC_MAX_CHANNELS];
- int err, i, irq_cnt = 0, irqres = 0;
+ int err, i, irq_cnt = 0, irqres = 0, irq_cap = 0;
struct sh_dmae_device *shdev;
struct resource *chan, *dmars, *errirq_res, *chanirq_res;
@@ -1051,7 +1092,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
return -ENODEV;
chan = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- /* DMARS area is optional, if absent, this controller cannot do slave DMA */
+ /* DMARS area is optional */
dmars = platform_get_resource(pdev, IORESOURCE_MEM, 1);
/*
* IRQ resources:
@@ -1106,11 +1147,11 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
- spin_lock_irqsave(&sh_dmae_lock, flags);
+ spin_lock_irq(&sh_dmae_lock);
list_add_tail_rcu(&shdev->node, &sh_dmae_devices);
- spin_unlock_irqrestore(&sh_dmae_lock, flags);
+ spin_unlock_irq(&sh_dmae_lock);
- /* reset dma controller */
+ /* reset dma controller - only needed as a test */
err = sh_dmae_rst(shdev);
if (err)
goto rst_err;
@@ -1118,7 +1159,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&shdev->common.channels);
dma_cap_set(DMA_MEMCPY, shdev->common.cap_mask);
- if (dmars)
+ if (pdata->slave && pdata->slave_num)
dma_cap_set(DMA_SLAVE, shdev->common.cap_mask);
shdev->common.device_alloc_chan_resources
@@ -1167,8 +1208,13 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
!platform_get_resource(pdev, IORESOURCE_IRQ, 1)) {
/* Special case - all multiplexed */
for (; irq_cnt < pdata->channel_num; irq_cnt++) {
- chan_irq[irq_cnt] = chanirq_res->start;
- chan_flag[irq_cnt] = IRQF_SHARED;
+ if (irq_cnt < SH_DMAC_MAX_CHANNELS) {
+ chan_irq[irq_cnt] = chanirq_res->start;
+ chan_flag[irq_cnt] = IRQF_SHARED;
+ } else {
+ irq_cap = 1;
+ break;
+ }
}
} else {
do {
@@ -1182,22 +1228,32 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
"Found IRQ %d for channel %d\n",
i, irq_cnt);
chan_irq[irq_cnt++] = i;
+
+ if (irq_cnt >= SH_DMAC_MAX_CHANNELS)
+ break;
+ }
+
+ if (irq_cnt >= SH_DMAC_MAX_CHANNELS) {
+ irq_cap = 1;
+ break;
}
chanirq_res = platform_get_resource(pdev,
IORESOURCE_IRQ, ++irqres);
} while (irq_cnt < pdata->channel_num && chanirq_res);
}
- if (irq_cnt < pdata->channel_num)
- goto eirqres;
-
/* Create DMA Channel */
- for (i = 0; i < pdata->channel_num; i++) {
+ for (i = 0; i < irq_cnt; i++) {
err = sh_dmae_chan_probe(shdev, i, chan_irq[i], chan_flag[i]);
if (err)
goto chan_probe_err;
}
+ if (irq_cap)
+ dev_notice(&pdev->dev, "Attempting to register %d DMA "
+ "channels when a maximum of %d are supported.\n",
+ pdata->channel_num, SH_DMAC_MAX_CHANNELS);
+
pm_runtime_put(&pdev->dev);
platform_set_drvdata(pdev, shdev);
@@ -1207,21 +1263,24 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
chan_probe_err:
sh_dmae_chan_remove(shdev);
-eirqres:
+
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
free_irq(errirq, shdev);
eirq_err:
#endif
rst_err:
- spin_lock_irqsave(&sh_dmae_lock, flags);
+ spin_lock_irq(&sh_dmae_lock);
list_del_rcu(&shdev->node);
- spin_unlock_irqrestore(&sh_dmae_lock, flags);
+ spin_unlock_irq(&sh_dmae_lock);
pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
if (dmars)
iounmap(shdev->dmars);
emapdmars:
iounmap(shdev->chan_reg);
+ synchronize_rcu();
emapchan:
kfree(shdev);
ealloc:
@@ -1237,7 +1296,6 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
{
struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
struct resource *res;
- unsigned long flags;
int errirq = platform_get_irq(pdev, 0);
dma_async_device_unregister(&shdev->common);
@@ -1245,9 +1303,9 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
if (errirq > 0)
free_irq(errirq, shdev);
- spin_lock_irqsave(&sh_dmae_lock, flags);
+ spin_lock_irq(&sh_dmae_lock);
list_del_rcu(&shdev->node);
- spin_unlock_irqrestore(&sh_dmae_lock, flags);
+ spin_unlock_irq(&sh_dmae_lock);
/* channel data remove */
sh_dmae_chan_remove(shdev);
@@ -1258,6 +1316,7 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
iounmap(shdev->dmars);
iounmap(shdev->chan_reg);
+ synchronize_rcu();
kfree(shdev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1276,12 +1335,78 @@ static void sh_dmae_shutdown(struct platform_device *pdev)
sh_dmae_ctl_stop(shdev);
}
+static int sh_dmae_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int sh_dmae_runtime_resume(struct device *dev)
+{
+ struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+
+ return sh_dmae_rst(shdev);
+}
+
+#ifdef CONFIG_PM
+static int sh_dmae_suspend(struct device *dev)
+{
+ struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < shdev->pdata->channel_num; i++) {
+ struct sh_dmae_chan *sh_chan = shdev->chan[i];
+ if (sh_chan->descs_allocated)
+ sh_chan->pm_error = pm_runtime_put_sync(dev);
+ }
+
+ return 0;
+}
+
+static int sh_dmae_resume(struct device *dev)
+{
+ struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < shdev->pdata->channel_num; i++) {
+ struct sh_dmae_chan *sh_chan = shdev->chan[i];
+ struct sh_dmae_slave *param = sh_chan->common.private;
+
+ if (!sh_chan->descs_allocated)
+ continue;
+
+ if (!sh_chan->pm_error)
+ pm_runtime_get_sync(dev);
+
+ if (param) {
+ const struct sh_dmae_slave_config *cfg = param->config;
+ dmae_set_dmars(sh_chan, cfg->mid_rid);
+ dmae_set_chcr(sh_chan, cfg->chcr);
+ } else {
+ dmae_init(sh_chan);
+ }
+ }
+
+ return 0;
+}
+#else
+#define sh_dmae_suspend NULL
+#define sh_dmae_resume NULL
+#endif
+
+const struct dev_pm_ops sh_dmae_pm = {
+ .suspend = sh_dmae_suspend,
+ .resume = sh_dmae_resume,
+ .runtime_suspend = sh_dmae_runtime_suspend,
+ .runtime_resume = sh_dmae_runtime_resume,
+};
+
static struct platform_driver sh_dmae_driver = {
.remove = __exit_p(sh_dmae_remove),
.shutdown = sh_dmae_shutdown,
.driver = {
.owner = THIS_MODULE,
.name = "sh-dma-engine",
+ .pm = &sh_dmae_pm,
},
};
diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h
index 52e4fb173805..5ae9fc512180 100644
--- a/drivers/dma/shdma.h
+++ b/drivers/dma/shdma.h
@@ -17,7 +17,7 @@
#include <linux/interrupt.h>
#include <linux/list.h>
-#define SH_DMAC_MAX_CHANNELS 6
+#define SH_DMAC_MAX_CHANNELS 20
#define SH_DMA_SLAVE_NUMBER 256
#define SH_DMA_TCR_MAX 0x00FFFFFF /* 16MB */
@@ -37,6 +37,7 @@ struct sh_dmae_chan {
int id; /* Raw id of this channel */
u32 __iomem *base;
char dev_id[16]; /* unique name per DMAC of channel */
+ int pm_error;
};
struct sh_dmae_device {
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 5d054bb908e5..8f222d4db7de 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -90,7 +90,7 @@ struct d40_lli_pool {
* @lli_log: Same as above but for logical channels.
* @lli_pool: The pool with two entries pre-allocated.
* @lli_len: Number of llis of current descriptor.
- * @lli_current: Number of transfered llis.
+ * @lli_current: Number of transferred llis.
* @lcla_alloc: Number of LCLA entries allocated.
* @txd: DMA engine struct. Used for among other things for communication
* during a transfer.
@@ -1214,7 +1214,7 @@ static void dma_tasklet(unsigned long data)
return;
err:
- /* Rescue manouver if receiving double interrupts */
+ /* Rescue manoeuvre if receiving double interrupts */
if (d40c->pending_tx > 0)
d40c->pending_tx--;
spin_unlock_irqrestore(&d40c->lock, flags);
diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c
index d2c75feff7df..f69f90a61873 100644
--- a/drivers/dma/timb_dma.c
+++ b/drivers/dma/timb_dma.c
@@ -27,7 +27,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/mfd/core.h>
#include <linux/slab.h>
#include <linux/timb_dma.h>
@@ -685,7 +684,7 @@ static irqreturn_t td_irq(int irq, void *devid)
static int __devinit td_probe(struct platform_device *pdev)
{
- struct timb_dma_platform_data *pdata = mfd_get_data(pdev);
+ struct timb_dma_platform_data *pdata = pdev->dev.platform_data;
struct timb_dma *td;
struct resource *iomem;
int irq;