diff options
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/Makefile | 4 | ||||
-rw-r--r-- | drivers/dma/at_hdmac.c | 2 | ||||
-rw-r--r-- | drivers/dma/fsldma.c | 6 | ||||
-rw-r--r-- | drivers/dma/fsldma.h | 9 | ||||
-rw-r--r-- | drivers/dma/imx-dma.c | 2 | ||||
-rw-r--r-- | drivers/dma/imx-sdma.c | 178 | ||||
-rw-r--r-- | drivers/dma/intel_mid_dma.c | 8 | ||||
-rw-r--r-- | drivers/dma/ioat/Makefile | 2 | ||||
-rw-r--r-- | drivers/dma/mv_xor.c | 2 | ||||
-rw-r--r-- | drivers/dma/pch_dma.c | 15 | ||||
-rw-r--r-- | drivers/dma/ppc4xx/adma.c | 5 | ||||
-rw-r--r-- | drivers/dma/shdma.c | 133 | ||||
-rw-r--r-- | drivers/dma/shdma.h | 1 |
13 files changed, 227 insertions, 140 deletions
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index a8a84f4587f2..64b21f5cd740 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -1,8 +1,8 @@ ifeq ($(CONFIG_DMADEVICES_DEBUG),y) - EXTRA_CFLAGS += -DDEBUG + ccflags-y += -DDEBUG endif ifeq ($(CONFIG_DMADEVICES_VDEBUG),y) - EXTRA_CFLAGS += -DVERBOSE_DEBUG + ccflags-y += -DVERBOSE_DEBUG endif obj-$(CONFIG_DMA_ENGINE) += dmaengine.o diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index a0f3e6a06e06..ea0ee81cff53 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -722,7 +722,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, desc->lli.daddr = mem; desc->lli.ctrla = ctrla | ATC_DST_WIDTH(mem_width) - | len >> mem_width; + | len >> reg_width; desc->lli.ctrlb = ctrlb; if (!first) { diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 286c3ac6bdcc..e5e172d21692 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -50,9 +50,11 @@ static void dma_init(struct fsldma_chan *chan) * EIE - Error interrupt enable * EOSIE - End of segments interrupt enable (basic mode) * EOLNIE - End of links interrupt enable + * BWC - Bandwidth sharing among channels */ - DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EIE - | FSL_DMA_MR_EOLNIE | FSL_DMA_MR_EOSIE, 32); + DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC + | FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE + | FSL_DMA_MR_EOSIE, 32); break; case FSL_DMA_IP_83XX: /* Set the channel to below modes: diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h index cb4d6ff51597..ba9f403c0fbe 100644 --- a/drivers/dma/fsldma.h +++ b/drivers/dma/fsldma.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (C) 2007-2010 Freescale Semiconductor, Inc. All rights reserved. * * Author: * Zhang Wei <wei.zhang@freescale.com>, Jul 2007 @@ -36,6 +36,13 @@ #define FSL_DMA_MR_DAHE 0x00002000 #define FSL_DMA_MR_SAHE 0x00001000 +/* + * Bandwidth/pause control determines how many bytes a given + * channel is allowed to transfer before the DMA engine pauses + * the current channel and switches to the next channel + */ +#define FSL_DMA_MR_BWC 0x08000000 + /* Special MR definition for MPC8349 */ #define FSL_DMA_MR_EOTIE 0x00000080 #define FSL_DMA_MR_PRC_RM 0x00000800 diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index f629e4961af5..e53d438142bb 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -379,7 +379,7 @@ static int __init imxdma_probe(struct platform_device *pdev) return 0; err_init: - while (i-- >= 0) { + while (--i >= 0) { struct imxdma_channel *imxdmac = &imxdma->channel[i]; imx_dma_free(imxdmac->imxdma_channel); } diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 0834323a0599..d5a5d4d9c19b 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -273,50 +273,6 @@ struct sdma_channel { #define MXC_SDMA_MIN_PRIORITY 1 #define MXC_SDMA_MAX_PRIORITY 7 -/** - * struct sdma_script_start_addrs - SDMA script start pointers - * - * start addresses of the different functions in the physical - * address space of the SDMA engine. - */ -struct sdma_script_start_addrs { - u32 ap_2_ap_addr; - u32 ap_2_bp_addr; - u32 ap_2_ap_fixed_addr; - u32 bp_2_ap_addr; - u32 loopback_on_dsp_side_addr; - u32 mcu_interrupt_only_addr; - u32 firi_2_per_addr; - u32 firi_2_mcu_addr; - u32 per_2_firi_addr; - u32 mcu_2_firi_addr; - u32 uart_2_per_addr; - u32 uart_2_mcu_addr; - u32 per_2_app_addr; - u32 mcu_2_app_addr; - u32 per_2_per_addr; - u32 uartsh_2_per_addr; - u32 uartsh_2_mcu_addr; - u32 per_2_shp_addr; - u32 mcu_2_shp_addr; - u32 ata_2_mcu_addr; - u32 mcu_2_ata_addr; - u32 app_2_per_addr; - u32 app_2_mcu_addr; - u32 shp_2_per_addr; - u32 shp_2_mcu_addr; - u32 mshc_2_mcu_addr; - u32 mcu_2_mshc_addr; - u32 spdif_2_mcu_addr; - u32 mcu_2_spdif_addr; - u32 asrc_2_mcu_addr; - u32 ext_mem_2_ipu_addr; - u32 descrambler_addr; - u32 dptc_dvfs_addr; - u32 utra_addr; - u32 ram_code_start_addr; -}; - #define SDMA_FIRMWARE_MAGIC 0x414d4453 /** @@ -951,7 +907,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg( struct sdma_buffer_descriptor *bd = &sdmac->bd[i]; int param; - bd->buffer_addr = sgl->dma_address; + bd->buffer_addr = sg->dma_address; count = sg->length; @@ -1127,8 +1083,74 @@ static void sdma_issue_pending(struct dma_chan *chan) */ } -static int __init sdma_init(struct sdma_engine *sdma, - void *ram_code, int ram_code_size) +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34 + +static void sdma_add_scripts(struct sdma_engine *sdma, + const struct sdma_script_start_addrs *addr) +{ + s32 *addr_arr = (u32 *)addr; + s32 *saddr_arr = (u32 *)sdma->script_addrs; + int i; + + for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++) + if (addr_arr[i] > 0) + saddr_arr[i] = addr_arr[i]; +} + +static int __init sdma_get_firmware(struct sdma_engine *sdma, + const char *cpu_name, int to_version) +{ + const struct firmware *fw; + char *fwname; + const struct sdma_firmware_header *header; + int ret; + const struct sdma_script_start_addrs *addr; + unsigned short *ram_code; + + fwname = kasprintf(GFP_KERNEL, "sdma-%s-to%d.bin", cpu_name, to_version); + if (!fwname) + return -ENOMEM; + + ret = request_firmware(&fw, fwname, sdma->dev); + if (ret) { + kfree(fwname); + return ret; + } + kfree(fwname); + + if (fw->size < sizeof(*header)) + goto err_firmware; + + header = (struct sdma_firmware_header *)fw->data; + + if (header->magic != SDMA_FIRMWARE_MAGIC) + goto err_firmware; + if (header->ram_code_start + header->ram_code_size > fw->size) + goto err_firmware; + + addr = (void *)header + header->script_addrs_start; + ram_code = (void *)header + header->ram_code_start; + + clk_enable(sdma->clk); + /* download the RAM image for SDMA */ + sdma_load_script(sdma, ram_code, + header->ram_code_size, + sdma->script_addrs->ram_code_start_addr); + clk_disable(sdma->clk); + + sdma_add_scripts(sdma, addr); + + dev_info(sdma->dev, "loaded firmware %d.%d\n", + header->version_major, + header->version_minor); + +err_firmware: + release_firmware(fw); + + return ret; +} + +static int __init sdma_init(struct sdma_engine *sdma) { int i, ret; dma_addr_t ccb_phys; @@ -1192,11 +1214,6 @@ static int __init sdma_init(struct sdma_engine *sdma, __raw_writel(ccb_phys, sdma->regs + SDMA_H_C0PTR); - /* download the RAM image for SDMA */ - sdma_load_script(sdma, ram_code, - ram_code_size, - sdma->script_addrs->ram_code_start_addr); - /* Set bits of CONFIG register with given context switching mode */ __raw_writel(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG); @@ -1216,14 +1233,9 @@ err_dma_alloc: static int __init sdma_probe(struct platform_device *pdev) { int ret; - const struct firmware *fw; - const struct sdma_firmware_header *header; - const struct sdma_script_start_addrs *addr; int irq; - unsigned short *ram_code; struct resource *iores; struct sdma_platform_data *pdata = pdev->dev.platform_data; - char *fwname; int i; dma_cap_mask_t mask; struct sdma_engine *sdma; @@ -1262,38 +1274,9 @@ static int __init sdma_probe(struct platform_device *pdev) if (ret) goto err_request_irq; - fwname = kasprintf(GFP_KERNEL, "sdma-%s-to%d.bin", - pdata->cpu_name, pdata->to_version); - if (!fwname) { - ret = -ENOMEM; - goto err_cputype; - } - - ret = request_firmware(&fw, fwname, &pdev->dev); - if (ret) { - dev_err(&pdev->dev, "request firmware \"%s\" failed with %d\n", - fwname, ret); - kfree(fwname); - goto err_cputype; - } - kfree(fwname); - - if (fw->size < sizeof(*header)) - goto err_firmware; - - header = (struct sdma_firmware_header *)fw->data; - - if (header->magic != SDMA_FIRMWARE_MAGIC) - goto err_firmware; - if (header->ram_code_start + header->ram_code_size > fw->size) - goto err_firmware; - - addr = (void *)header + header->script_addrs_start; - ram_code = (void *)header + header->ram_code_start; - sdma->script_addrs = kmalloc(sizeof(*addr), GFP_KERNEL); + sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL); if (!sdma->script_addrs) - goto err_firmware; - memcpy(sdma->script_addrs, addr, sizeof(*addr)); + goto err_alloc; sdma->version = pdata->sdma_version; @@ -1316,10 +1299,15 @@ static int __init sdma_probe(struct platform_device *pdev) list_add_tail(&sdmac->chan.device_node, &sdma->dma_device.channels); } - ret = sdma_init(sdma, ram_code, header->ram_code_size); + ret = sdma_init(sdma); if (ret) goto err_init; + if (pdata->script_addrs) + sdma_add_scripts(sdma, pdata->script_addrs); + + sdma_get_firmware(sdma, pdata->cpu_name, pdata->to_version); + sdma->dma_device.dev = &pdev->dev; sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources; @@ -1336,10 +1324,6 @@ static int __init sdma_probe(struct platform_device *pdev) goto err_init; } - dev_info(&pdev->dev, "initialized (firmware %d.%d)\n", - header->version_major, - header->version_minor); - /* request channel 0. This is an internal control channel * to the SDMA engine and not available to clients. */ @@ -1347,15 +1331,13 @@ static int __init sdma_probe(struct platform_device *pdev) dma_cap_set(DMA_SLAVE, mask); dma_request_channel(mask, NULL, NULL); - release_firmware(fw); + dev_info(sdma->dev, "initialized\n"); return 0; err_init: kfree(sdma->script_addrs); -err_firmware: - release_firmware(fw); -err_cputype: +err_alloc: free_irq(irq, sdma); err_request_irq: iounmap(sdma->regs); @@ -1385,7 +1367,7 @@ static int __init sdma_module_init(void) { return platform_driver_probe(&sdma_driver, sdma_probe); } -subsys_initcall(sdma_module_init); +module_init(sdma_module_init); MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>"); MODULE_DESCRIPTION("i.MX SDMA driver"); diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index 338bc4eed1f3..3109bd94bc4f 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c @@ -1075,7 +1075,6 @@ static int mid_setup_dma(struct pci_dev *pdev) if (NULL == dma->dma_pool) { pr_err("ERR_MDMA:pci_pool_create failed\n"); err = -ENOMEM; - kfree(dma); goto err_dma_pool; } @@ -1186,7 +1185,6 @@ err_engine: free_irq(pdev->irq, dma); err_irq: pci_pool_destroy(dma->dma_pool); - kfree(dma); err_dma_pool: pr_err("ERR_MDMA:setup_dma failed: %d\n", err); return err; @@ -1413,7 +1411,7 @@ static const struct dev_pm_ops intel_mid_dma_pm = { .runtime_idle = dma_runtime_idle, }; -static struct pci_driver intel_mid_dma_pci = { +static struct pci_driver intel_mid_dma_pci_driver = { .name = "Intel MID DMA", .id_table = intel_mid_dma_ids, .probe = intel_mid_dma_probe, @@ -1431,13 +1429,13 @@ static int __init intel_mid_dma_init(void) { pr_debug("INFO_MDMA: LNW DMA Driver Version %s\n", INTEL_MID_DMA_DRIVER_VERSION); - return pci_register_driver(&intel_mid_dma_pci); + return pci_register_driver(&intel_mid_dma_pci_driver); } fs_initcall(intel_mid_dma_init); static void __exit intel_mid_dma_exit(void) { - pci_unregister_driver(&intel_mid_dma_pci); + pci_unregister_driver(&intel_mid_dma_pci_driver); } module_exit(intel_mid_dma_exit); diff --git a/drivers/dma/ioat/Makefile b/drivers/dma/ioat/Makefile index 8997d3fb9051..0ff7270af25b 100644 --- a/drivers/dma/ioat/Makefile +++ b/drivers/dma/ioat/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o -ioatdma-objs := pci.o dma.o dma_v2.o dma_v3.o dca.o +ioatdma-y := pci.o dma.o dma_v2.o dma_v3.o dca.o diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 411d5bf50fc4..a25f5f61e0e0 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -449,7 +449,7 @@ mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan) static void mv_xor_tasklet(unsigned long data) { struct mv_xor_chan *chan = (struct mv_xor_chan *) data; - __mv_xor_slot_cleanup(chan); + mv_xor_slot_cleanup(chan); } static struct mv_xor_desc_slot * diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index 92b679024fed..c064c89420d0 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -259,11 +259,6 @@ static void pdc_dostart(struct pch_dma_chan *pd_chan, struct pch_dma_desc* desc) return; } - channel_writel(pd_chan, DEV_ADDR, desc->regs.dev_addr); - channel_writel(pd_chan, MEM_ADDR, desc->regs.mem_addr); - channel_writel(pd_chan, SIZE, desc->regs.size); - channel_writel(pd_chan, NEXT, desc->regs.next); - dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> dev_addr: %x\n", pd_chan->chan.chan_id, desc->regs.dev_addr); dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> mem_addr: %x\n", @@ -273,10 +268,16 @@ static void pdc_dostart(struct pch_dma_chan *pd_chan, struct pch_dma_desc* desc) dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> next: %x\n", pd_chan->chan.chan_id, desc->regs.next); - if (list_empty(&desc->tx_list)) + if (list_empty(&desc->tx_list)) { + channel_writel(pd_chan, DEV_ADDR, desc->regs.dev_addr); + channel_writel(pd_chan, MEM_ADDR, desc->regs.mem_addr); + channel_writel(pd_chan, SIZE, desc->regs.size); + channel_writel(pd_chan, NEXT, desc->regs.next); pdc_set_mode(&pd_chan->chan, DMA_CTL0_ONESHOT); - else + } else { + channel_writel(pd_chan, NEXT, desc->txd.phys); pdc_set_mode(&pd_chan->chan, DMA_CTL0_SG); + } val = dma_readl(pd, CTL2); val |= 1 << (DMA_CTL2_START_SHIFT_BITS + pd_chan->chan.chan_id); diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c index 0d58a4a4487f..cef584533ee8 100644 --- a/drivers/dma/ppc4xx/adma.c +++ b/drivers/dma/ppc4xx/adma.c @@ -4449,9 +4449,8 @@ static int __devinit ppc440spe_adma_probe(struct platform_device *ofdev, if (!request_mem_region(res.start, resource_size(&res), dev_driver_string(&ofdev->dev))) { - dev_err(&ofdev->dev, "failed to request memory region " - "(0x%016llx-0x%016llx)\n", - (u64)res.start, (u64)res.end); + dev_err(&ofdev->dev, "failed to request memory region %pR\n", + &res); initcode = PPC_ADMA_INIT_MEMREG; ret = -EBUSY; goto out; diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index eb6b54dbb806..a0069c171518 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -27,7 +27,10 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/sh_dma.h> - +#include <linux/notifier.h> +#include <linux/kdebug.h> +#include <linux/spinlock.h> +#include <linux/rculist.h> #include "shdma.h" /* DMA descriptor control */ @@ -43,6 +46,13 @@ enum sh_dmae_desc_status { /* Default MEMCPY transfer size = 2^2 = 4 bytes */ #define LOG2_DEFAULT_XFER_SIZE 2 +/* + * Used for write-side mutual exclusion for the global device list, + * read-side synchronization by way of RCU. + */ +static DEFINE_SPINLOCK(sh_dmae_lock); +static LIST_HEAD(sh_dmae_devices); + /* A bitmask with bits enough for enum sh_dmae_slave_chan_id */ static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SH_DMA_SLAVE_NUMBER)]; @@ -817,10 +827,9 @@ static irqreturn_t sh_dmae_interrupt(int irq, void *data) return ret; } -#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) -static irqreturn_t sh_dmae_err(int irq, void *data) +static unsigned int sh_dmae_reset(struct sh_dmae_device *shdev) { - struct sh_dmae_device *shdev = (struct sh_dmae_device *)data; + unsigned int handled = 0; int i; /* halt the dma controller */ @@ -829,25 +838,35 @@ static irqreturn_t sh_dmae_err(int irq, void *data) /* We cannot detect, which channel caused the error, have to reset all */ for (i = 0; i < SH_DMAC_MAX_CHANNELS; i++) { struct sh_dmae_chan *sh_chan = shdev->chan[i]; - if (sh_chan) { - struct sh_desc *desc; - /* Stop the channel */ - dmae_halt(sh_chan); - /* Complete all */ - list_for_each_entry(desc, &sh_chan->ld_queue, 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); + struct sh_desc *desc; + + if (!sh_chan) + continue; + + /* Stop the channel */ + dmae_halt(sh_chan); + + /* Complete all */ + list_for_each_entry(desc, &sh_chan->ld_queue, 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); + handled++; } + sh_dmae_rst(shdev); - return IRQ_HANDLED; + return !!handled; +} + +static irqreturn_t sh_dmae_err(int irq, void *data) +{ + return IRQ_RETVAL(sh_dmae_reset(data)); } -#endif static void dmae_do_tasklet(unsigned long data) { @@ -876,6 +895,60 @@ static void dmae_do_tasklet(unsigned long data) sh_dmae_chan_ld_cleanup(sh_chan, false); } +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; +} + +static int sh_dmae_nmi_handler(struct notifier_block *self, + unsigned long cmd, void *data) +{ + struct sh_dmae_device *shdev; + int ret = NOTIFY_DONE; + bool triggered; + + /* + * Only concern ourselves with NMI events. + * + * Normally we would check the die chain value, but as this needs + * to be architecture independent, check for NMI context instead. + */ + if (!in_nmi()) + return NOTIFY_DONE; + + rcu_read_lock(); + list_for_each_entry_rcu(shdev, &sh_dmae_devices, node) { + /* + * Only stop if one of the controllers has NMIF asserted, + * we do not want to interfere with regular address error + * handling or NMI events that don't concern the DMACs. + */ + triggered = sh_dmae_nmi_notify(shdev); + if (triggered == true) + ret = NOTIFY_OK; + } + rcu_read_unlock(); + + return ret; +} + +static struct notifier_block sh_dmae_nmi_notifier __read_mostly = { + .notifier_call = sh_dmae_nmi_handler, + + /* Run before NMI debug handler and KGDB */ + .priority = 1, +}; + static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id, int irq, unsigned long flags) { @@ -967,6 +1040,7 @@ 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; struct sh_dmae_device *shdev; @@ -1032,6 +1106,15 @@ 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); + list_add_tail_rcu(&shdev->node, &sh_dmae_devices); + spin_unlock_irqrestore(&sh_dmae_lock, flags); + + /* Wire up NMI handling before bringing the controller online */ + err = register_die_notifier(&sh_dmae_nmi_notifier); + if (err) + goto notifier_err; + /* reset dma controller */ err = sh_dmae_rst(shdev); if (err) @@ -1135,6 +1218,12 @@ eirqres: eirq_err: #endif rst_err: + unregister_die_notifier(&sh_dmae_nmi_notifier); +notifier_err: + spin_lock_irqsave(&sh_dmae_lock, flags); + list_del_rcu(&shdev->node); + spin_unlock_irqrestore(&sh_dmae_lock, flags); + pm_runtime_put(&pdev->dev); if (dmars) iounmap(shdev->dmars); @@ -1155,6 +1244,7 @@ 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); @@ -1162,6 +1252,12 @@ static int __exit sh_dmae_remove(struct platform_device *pdev) if (errirq > 0) free_irq(errirq, shdev); + unregister_die_notifier(&sh_dmae_nmi_notifier); + + spin_lock_irqsave(&sh_dmae_lock, flags); + list_del_rcu(&shdev->node); + spin_unlock_irqrestore(&sh_dmae_lock, flags); + /* channel data remove */ sh_dmae_chan_remove(shdev); @@ -1213,3 +1309,4 @@ module_exit(sh_dmae_exit); MODULE_AUTHOR("Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>"); MODULE_DESCRIPTION("Renesas SH DMA Engine driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sh-dma-engine"); diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h index 4021275a0a43..52e4fb173805 100644 --- a/drivers/dma/shdma.h +++ b/drivers/dma/shdma.h @@ -43,6 +43,7 @@ struct sh_dmae_device { struct dma_device common; struct sh_dmae_chan *chan[SH_DMAC_MAX_CHANNELS]; struct sh_dmae_pdata *pdata; + struct list_head node; u32 __iomem *chan_reg; u16 __iomem *dmars; }; |