From 23e11811378259831777e8fdc8b9836faeaa72cd Mon Sep 17 00:00:00 2001 From: Vignesh Raman Date: Tue, 5 Aug 2014 18:39:41 +0530 Subject: dma: imx-sdma: use module_platform_driver for SDMA driver Currently there is no module_exit declared in SDMA driver, so that once sdma module is inserted, it's shown with permanent attribute by lsmod, and it can't be removed. Use module_platform_driver to register/unregister SDMA driver and modify SDMA's remove operation, to make SDMA driver possible to be removed. Signed-off-by: Jiada Wang Signed-off-by: Vinod Koul diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index f7626e3..40e65a4 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1603,6 +1603,8 @@ static int __init sdma_probe(struct platform_device *pdev) sdma->dma_device.dev->dma_parms = &sdma->dma_parms; dma_set_max_seg_size(sdma->dma_device.dev, 65535); + platform_set_drvdata(pdev, sdma); + ret = dma_async_device_register(&sdma->dma_device); if (ret) { dev_err(&pdev->dev, "unable to register\n"); @@ -1640,7 +1642,20 @@ err_irq: static int sdma_remove(struct platform_device *pdev) { - return -EBUSY; + struct sdma_engine *sdma = platform_get_drvdata(pdev); + struct resource *iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int irq = platform_get_irq(pdev, 0); + + dma_async_device_unregister(&sdma->dma_device); + kfree(sdma->script_addrs); + free_irq(irq, sdma); + iounmap(sdma->regs); + release_mem_region(iores->start, resource_size(iores)); + kfree(sdma); + + platform_set_drvdata(pdev, NULL); + dev_info(&pdev->dev, "Removed...\n"); + return 0; } static struct platform_driver sdma_driver = { @@ -1650,13 +1665,10 @@ static struct platform_driver sdma_driver = { }, .id_table = sdma_devtypes, .remove = sdma_remove, + .probe = sdma_probe, }; -static int __init sdma_module_init(void) -{ - return platform_driver_probe(&sdma_driver, sdma_probe); -} -module_init(sdma_module_init); +module_platform_driver(sdma_driver); MODULE_AUTHOR("Sascha Hauer, Pengutronix "); MODULE_DESCRIPTION("i.MX SDMA driver"); -- cgit v0.10.2 From c12fe49726cfebacb47dca5f2bb544c38aa09e6d Mon Sep 17 00:00:00 2001 From: Vignesh Raman Date: Tue, 5 Aug 2014 18:39:42 +0530 Subject: dma: imx-sdma: Adding tasklet_kill() in sdma_remove function. Several dma drivers calls tasklet_kill() in remove function. This is done because all running tasklets should be killed on remove. This is missing in imx sdma driver, so adding tasklet_kill() in sdma_remove function. Signed-off-by: Vignesh Raman Signed-off-by: Vinod Koul diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 40e65a4..c615e88 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1645,12 +1645,19 @@ static int sdma_remove(struct platform_device *pdev) struct sdma_engine *sdma = platform_get_drvdata(pdev); struct resource *iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); int irq = platform_get_irq(pdev, 0); + int i; dma_async_device_unregister(&sdma->dma_device); kfree(sdma->script_addrs); free_irq(irq, sdma); iounmap(sdma->regs); release_mem_region(iores->start, resource_size(iores)); + /* Kill the tasklet */ + for (i = 0; i < MAX_DMA_CHANNELS; i++) { + struct sdma_channel *sdmac = &sdma->channel[i]; + + tasklet_kill(&sdmac->tasklet); + } kfree(sdma); platform_set_drvdata(pdev, NULL); -- cgit v0.10.2 From ddc643630f5deb1995d191719086b64873c67a44 Mon Sep 17 00:00:00 2001 From: Srikanth Thokala Date: Mon, 28 Jul 2014 17:47:48 +0530 Subject: dma: Add Xilinx AXI DMA DT Binding Documentation Device-tree binding documentation of Xilinx DMA Engine Signed-off-by: Srikanth Thokala Acked-by: Arnd Bergmann Signed-off-by: Vinod Koul diff --git a/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt b/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt new file mode 100644 index 0000000..2291c40 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt @@ -0,0 +1,65 @@ +Xilinx AXI DMA engine, it does transfers between memory and AXI4 stream +target devices. It can be configured to have one channel or two channels. +If configured as two channels, one is to transmit to the device and another +is to receive from the device. + +Required properties: +- compatible: Should be "xlnx,axi-dma-1.00.a" +- #dma-cells: Should be <1>, see "dmas" property below +- reg: Should contain DMA registers location and length. +- dma-channel child node: Should have atleast one channel and can have upto + two channels per device. This node specifies the properties of each + DMA channel (see child node properties below). + +Optional properties: +- xlnx,include-sg: Tells whether configured for Scatter-mode in + the hardware. + +Required child node properties: +- compatible: It should be either "xlnx,axi-dma-mm2s-channel" or + "xlnx,axi-dma-s2mm-channel". +- interrupts: Should contain per channel DMA interrupts. +- xlnx,datawidth: Should contain the stream data width, take values + {32,64...1024}. + +Option child node properties: +- xlnx,include-dre: Tells whether hardware is configured for Data + Realignment Engine. + +Example: +++++++++ + +axi_dma_0: axidma@40400000 { + compatible = "xlnx,axi-dma-1.00.a"; + #dma_cells = <1>; + reg = < 0x40400000 0x10000 >; + dma-channel@40400000 { + compatible = "xlnx,axi-dma-mm2s-channel"; + interrupts = < 0 59 4 >; + xlnx,datawidth = <0x40>; + } ; + dma-channel@40400030 { + compatible = "xlnx,axi-dma-s2mm-channel"; + interrupts = < 0 58 4 >; + xlnx,datawidth = <0x40>; + } ; +} ; + + +* DMA client + +Required properties: +- dmas: a list of <[DMA device phandle] [Channel ID]> pairs, + where Channel ID is '0' for write/tx and '1' for read/rx + channel. +- dma-names: a list of DMA channel names, one per "dmas" entry + +Example: +++++++++ + +dmatest_0: dmatest@0 { + compatible ="xlnx,axi-dma-test-1.00.a"; + dmas = <&axi_dma_0 0 + &axi_dma_0 1>; + dma-names = "dma0", "dma1"; +} ; -- cgit v0.10.2 From 29a4bb1431035560b4be3fc5917c5ab8b8141204 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 13 Aug 2014 13:57:42 +0200 Subject: dma: xilinx: Remove .owner field for driver There is no need to init .owner field. Based on the patch from Peter Griffin "mmc: remove .owner field for drivers using module_platform_driver" This patch removes the superflous .owner field for drivers which use the module_platform_driver API, as this is overriden in platform_driver_register anyway." Signed-off-by: Michal Simek Reviewed-by: Levente Kurusa Signed-off-by: Vinod Koul diff --git a/drivers/dma/xilinx/xilinx_vdma.c b/drivers/dma/xilinx/xilinx_vdma.c index 42a13e8..a6e6476 100644 --- a/drivers/dma/xilinx/xilinx_vdma.c +++ b/drivers/dma/xilinx/xilinx_vdma.c @@ -1365,7 +1365,6 @@ static const struct of_device_id xilinx_vdma_of_ids[] = { static struct platform_driver xilinx_vdma_driver = { .driver = { .name = "xilinx-vdma", - .owner = THIS_MODULE, .of_match_table = xilinx_vdma_of_ids, }, .probe = xilinx_vdma_probe, -- cgit v0.10.2 From 58d06e989e1321b43c1e42bdf3846113e9e16ecd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 20 Aug 2014 15:18:44 +0200 Subject: dmaengine: Update documentation for inline wrapper Commit 16052827d98fbc13c31ebad560af4bd53e2b4dd5 ("dmaengine/dma_slave: introduce inline wrappers") introduced some wrappers, but there is still a reference to the old function. Update the documentation to use the wrapper, and add a missing "()" to a function name. Signed-off-by: Geert Uytterhoeven Signed-off-by: Vinod Koul diff --git a/Documentation/dmaengine.txt b/Documentation/dmaengine.txt index 573e28c..11fb87f 100644 --- a/Documentation/dmaengine.txt +++ b/Documentation/dmaengine.txt @@ -98,7 +98,7 @@ The slave DMA usage consists of following steps: unsigned long flags); The peripheral driver is expected to have mapped the scatterlist for - the DMA operation prior to calling device_prep_slave_sg, and must + the DMA operation prior to calling dmaengine_prep_slave_sg(), and must keep the scatterlist mapped until the DMA operation has completed. The scatterlist must be mapped using the DMA struct device. If a mapping needs to be synchronized later, dma_sync_*_for_*() must be @@ -195,5 +195,5 @@ Further APIs: Note: Not all DMA engine drivers can return reliable information for a running DMA channel. It is recommended that DMA engine users - pause or stop (via dmaengine_terminate_all) the channel before + pause or stop (via dmaengine_terminate_all()) the channel before using this API. -- cgit v0.10.2 From b19f40b8bf87bfc32b91260a90a7fa2cdebcd9bb Mon Sep 17 00:00:00 2001 From: Ryo Kataoka Date: Wed, 20 Aug 2014 17:53:03 -0700 Subject: dma: rcar-audmapp: Fix for no corresponding slave ID In case of no corresponding slave ID, the audmapp_set_slave() returns -ENXIO same as sh_dmae_set_slave() of shdmac.c. DMAEngine might return wrong channel without this patch Signed-off-by: Ryo Kataoka Signed-off-by: Jun Watanabe , Signed-off-by: Kuninori Morimoto Signed-off-by: Vinod Koul diff --git a/drivers/dma/sh/rcar-audmapp.c b/drivers/dma/sh/rcar-audmapp.c index dabbf0a..80fd2ae 100644 --- a/drivers/dma/sh/rcar-audmapp.c +++ b/drivers/dma/sh/rcar-audmapp.c @@ -117,7 +117,7 @@ static void audmapp_start_xfer(struct shdma_chan *schan, audmapp_write(auchan, chcr, PDMACHCR); } -static void audmapp_get_config(struct audmapp_chan *auchan, int slave_id, +static int audmapp_get_config(struct audmapp_chan *auchan, int slave_id, u32 *chcr, dma_addr_t *dst) { struct audmapp_device *audev = to_dev(auchan); @@ -131,20 +131,22 @@ static void audmapp_get_config(struct audmapp_chan *auchan, int slave_id, if (!pdata) { /* DT */ *chcr = ((u32)slave_id) << 16; auchan->shdma_chan.slave_id = (slave_id) >> 8; - return; + return 0; } /* non-DT */ if (slave_id >= AUDMAPP_SLAVE_NUMBER) - return; + return -ENXIO; for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++) if (cfg->slave_id == slave_id) { *chcr = cfg->chcr; *dst = cfg->dst; - break; + return 0; } + + return -ENXIO; } static int audmapp_set_slave(struct shdma_chan *schan, int slave_id, @@ -153,8 +155,11 @@ static int audmapp_set_slave(struct shdma_chan *schan, int slave_id, struct audmapp_chan *auchan = to_chan(schan); u32 chcr; dma_addr_t dst; + int ret; - audmapp_get_config(auchan, slave_id, &chcr, &dst); + ret = audmapp_get_config(auchan, slave_id, &chcr, &dst); + if (ret < 0) + return ret; if (try) return 0; -- cgit v0.10.2 From e34b731faa7d12d3681187968ef899747e4feb55 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Aug 2014 11:55:53 +0100 Subject: dma: imx-sdma: Remove spurious __init annotation on sdma_probe() We can't annotate probe functions as __init since binding can occur at any time, not just during kernel init. Signed-off-by: Mark Brown Acked-by: Shawn Guo Signed-off-by: Vinod Koul diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index c615e88..52ce1d2 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1448,7 +1448,7 @@ static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec, return dma_request_channel(mask, sdma_filter_fn, &data); } -static int __init sdma_probe(struct platform_device *pdev) +static int sdma_probe(struct platform_device *pdev) { const struct of_device_id *of_id = of_match_device(sdma_dt_ids, &pdev->dev); -- cgit v0.10.2 From e6222263124daae6be4b38b856af352667d95929 Mon Sep 17 00:00:00 2001 From: Qiao Zhou Date: Wed, 10 Sep 2014 16:40:48 +0800 Subject: dmaengine: mmp_tdma: add DMA_PREP_INTERRUPT flag support add DMA_PREP_INTERRUPT flag to support no_period_wakeup, in which user space app doesn't want audio interrupt to wake up audio threads. Signed-off-by: Qiao Zhou Signed-off-by: Vinod Koul diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index 6ad30e2..c6bd015 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -148,10 +148,16 @@ static void mmp_tdma_chan_set_desc(struct mmp_tdma_chan *tdmac, dma_addr_t phys) tdmac->reg_base + TDCR); } +static void mmp_tdma_enable_irq(struct mmp_tdma_chan *tdmac, bool enable) +{ + if (enable) + writel(TDIMR_COMP, tdmac->reg_base + TDIMR); + else + writel(0, tdmac->reg_base + TDIMR); +} + static void mmp_tdma_enable_chan(struct mmp_tdma_chan *tdmac) { - /* enable irq */ - writel(TDIMR_COMP, tdmac->reg_base + TDIMR); /* enable dma chan */ writel(readl(tdmac->reg_base + TDCR) | TDCR_CHANEN, tdmac->reg_base + TDCR); @@ -163,9 +169,6 @@ static void mmp_tdma_disable_chan(struct mmp_tdma_chan *tdmac) writel(readl(tdmac->reg_base + TDCR) & ~TDCR_CHANEN, tdmac->reg_base + TDCR); - /* disable irq */ - writel(0, tdmac->reg_base + TDIMR); - tdmac->status = DMA_COMPLETE; } @@ -434,6 +437,10 @@ static struct dma_async_tx_descriptor *mmp_tdma_prep_dma_cyclic( i++; } + /* enable interrupt */ + if (flags & DMA_PREP_INTERRUPT) + mmp_tdma_enable_irq(tdmac, true); + tdmac->buf_len = buf_len; tdmac->period_len = period_len; tdmac->pos = 0; @@ -455,6 +462,8 @@ static int mmp_tdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, switch (cmd) { case DMA_TERMINATE_ALL: mmp_tdma_disable_chan(tdmac); + /* disable interrupt */ + mmp_tdma_enable_irq(tdmac, false); break; case DMA_PAUSE: mmp_tdma_pause_chan(tdmac); -- cgit v0.10.2 From a22e292260079e781b66380eccdf4566cc3c95ed Mon Sep 17 00:00:00 2001 From: Qiao Zhou Date: Wed, 10 Sep 2014 16:40:49 +0800 Subject: ASoC: mmp-pcm: add NO_PERIOD_WAKEUP for PCM INFO add NO_PERIOD_WAKEUP to PCM INFO, which supports audio no IRQ mode Signed-off-by: Qiao Zhou Acked-by: Mark Brown Signed-off-by: Vinod Koul diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c index 5e8d813..64e8b94 100644 --- a/sound/soc/pxa/mmp-pcm.c +++ b/sound/soc/pxa/mmp-pcm.c @@ -34,7 +34,8 @@ struct mmp_dma_data { SNDRV_PCM_INFO_MMAP_VALID | \ SNDRV_PCM_INFO_INTERLEAVED | \ SNDRV_PCM_INFO_PAUSE | \ - SNDRV_PCM_INFO_RESUME) + SNDRV_PCM_INFO_RESUME | \ + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) static struct snd_pcm_hardware mmp_pcm_hardware[] = { { -- cgit v0.10.2 From 3d598f47e804a77208c6bb0a454123018e2f2281 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Aug 2014 20:29:12 +0300 Subject: dmaengine: dw: move dw_dmac.h to where it belongs to There is a common storage for platform data related structures and definitions inside kernel source tree. The patch moves file from include/linux to include/linux/platform_data and renames it acoordingly. The users are also updated. Signed-off-by: Andy Shevchenko Acked-by: Viresh Kumar [For the arch/avr32/.* and .*sound/atmel.*] Acked-by: Hans-Christian Egtvedt Signed-off-by: Vinod Koul diff --git a/MAINTAINERS b/MAINTAINERS index aefa948..a100729 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7875,7 +7875,7 @@ SYNOPSYS DESIGNWARE DMAC DRIVER M: Viresh Kumar M: Andy Shevchenko S: Maintained -F: include/linux/dw_dmac.h +F: include/linux/platform_data/dma-dw.h F: drivers/dma/dw/ SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index db85b5e..2a1aa71 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c @@ -7,7 +7,7 @@ */ #include #include -#include +#include #include #include #include diff --git a/arch/avr32/mach-at32ap/include/mach/atmel-mci.h b/arch/avr32/mach-at32ap/include/mach/atmel-mci.h index 4bba585..11d7f4b 100644 --- a/arch/avr32/mach-at32ap/include/mach/atmel-mci.h +++ b/arch/avr32/mach-at32ap/include/mach/atmel-mci.h @@ -1,7 +1,7 @@ #ifndef __MACH_ATMEL_MCI_H #define __MACH_ATMEL_MCI_H -#include +#include /** * struct mci_dma_data - DMA data for MCI interface diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h index 32667f9..43cc1df 100644 --- a/drivers/dma/dw/internal.h +++ b/drivers/dma/dw/internal.h @@ -12,7 +12,7 @@ #define _DW_DMAC_INTERNAL_H #include -#include +#include #include "regs.h" diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h index bb98d3e..af02439 100644 --- a/drivers/dma/dw/regs.h +++ b/drivers/dma/dw/regs.h @@ -11,7 +11,7 @@ #include #include -#include +#include #define DW_DMA_MAX_NR_CHANNELS 8 #define DW_DMA_MAX_NR_REQUESTS 16 @@ -161,7 +161,7 @@ struct dw_dma_regs { #define DWC_CTLH_DONE 0x00001000 #define DWC_CTLH_BLOCK_TS_MASK 0x00000fff -/* Bitfields in CFG_LO. Platform-configurable bits are in */ +/* Bitfields in CFG_LO. Platform-configurable bits are in */ #define DWC_CFGL_CH_PRIOR_MASK (0x7 << 5) /* priority mask */ #define DWC_CFGL_CH_PRIOR(x) ((x) << 5) /* priority */ #define DWC_CFGL_CH_SUSP (1 << 8) /* pause xfer */ @@ -172,7 +172,7 @@ struct dw_dma_regs { #define DWC_CFGL_RELOAD_SAR (1 << 30) #define DWC_CFGL_RELOAD_DAR (1 << 31) -/* Bitfields in CFG_HI. Platform-configurable bits are in */ +/* Bitfields in CFG_HI. Platform-configurable bits are in */ #define DWC_CFGH_DS_UPD_EN (1 << 5) #define DWC_CFGH_SS_UPD_EN (1 << 6) diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h deleted file mode 100644 index 68b4024..0000000 --- a/include/linux/dw_dmac.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Driver for the Synopsys DesignWare DMA Controller - * - * Copyright (C) 2007 Atmel Corporation - * Copyright (C) 2010-2011 ST Microelectronics - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef DW_DMAC_H -#define DW_DMAC_H - -#include - -/** - * struct dw_dma_slave - Controller-specific information about a slave - * - * @dma_dev: required DMA master device. Depricated. - * @bus_id: name of this device channel, not just a device name since - * devices may have more than one channel e.g. "foo_tx" - * @cfg_hi: Platform-specific initializer for the CFG_HI register - * @cfg_lo: Platform-specific initializer for the CFG_LO register - * @src_master: src master for transfers on allocated channel. - * @dst_master: dest master for transfers on allocated channel. - */ -struct dw_dma_slave { - struct device *dma_dev; - u32 cfg_hi; - u32 cfg_lo; - u8 src_master; - u8 dst_master; -}; - -/** - * struct dw_dma_platform_data - Controller configuration parameters - * @nr_channels: Number of channels supported by hardware (max 8) - * @is_private: The device channels should be marked as private and not for - * by the general purpose DMA channel allocator. - * @chan_allocation_order: Allocate channels starting from 0 or 7 - * @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0. - * @block_size: Maximum block size supported by the controller - * @nr_masters: Number of AHB masters supported by the controller - * @data_width: Maximum data width supported by hardware per AHB master - * (0 - 8bits, 1 - 16bits, ..., 5 - 256bits) - */ -struct dw_dma_platform_data { - unsigned int nr_channels; - bool is_private; -#define CHAN_ALLOCATION_ASCENDING 0 /* zero to seven */ -#define CHAN_ALLOCATION_DESCENDING 1 /* seven to zero */ - unsigned char chan_allocation_order; -#define CHAN_PRIORITY_ASCENDING 0 /* chan0 highest */ -#define CHAN_PRIORITY_DESCENDING 1 /* chan7 highest */ - unsigned char chan_priority; - unsigned short block_size; - unsigned char nr_masters; - unsigned char data_width[4]; -}; - -/* bursts size */ -enum dw_dma_msize { - DW_DMA_MSIZE_1, - DW_DMA_MSIZE_4, - DW_DMA_MSIZE_8, - DW_DMA_MSIZE_16, - DW_DMA_MSIZE_32, - DW_DMA_MSIZE_64, - DW_DMA_MSIZE_128, - DW_DMA_MSIZE_256, -}; - -/* Platform-configurable bits in CFG_HI */ -#define DWC_CFGH_FCMODE (1 << 0) -#define DWC_CFGH_FIFO_MODE (1 << 1) -#define DWC_CFGH_PROTCTL(x) ((x) << 2) -#define DWC_CFGH_SRC_PER(x) ((x) << 7) -#define DWC_CFGH_DST_PER(x) ((x) << 11) - -/* Platform-configurable bits in CFG_LO */ -#define DWC_CFGL_LOCK_CH_XFER (0 << 12) /* scope of LOCK_CH */ -#define DWC_CFGL_LOCK_CH_BLOCK (1 << 12) -#define DWC_CFGL_LOCK_CH_XACT (2 << 12) -#define DWC_CFGL_LOCK_BUS_XFER (0 << 14) /* scope of LOCK_BUS */ -#define DWC_CFGL_LOCK_BUS_BLOCK (1 << 14) -#define DWC_CFGL_LOCK_BUS_XACT (2 << 14) -#define DWC_CFGL_LOCK_CH (1 << 15) /* channel lockout */ -#define DWC_CFGL_LOCK_BUS (1 << 16) /* busmaster lockout */ -#define DWC_CFGL_HS_DST_POL (1 << 18) /* dst handshake active low */ -#define DWC_CFGL_HS_SRC_POL (1 << 19) /* src handshake active low */ - -/* DMA API extensions */ -struct dw_cyclic_desc { - struct dw_desc **desc; - unsigned long periods; - void (*period_callback)(void *param); - void *period_callback_param; -}; - -struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, - dma_addr_t buf_addr, size_t buf_len, size_t period_len, - enum dma_transfer_direction direction); -void dw_dma_cyclic_free(struct dma_chan *chan); -int dw_dma_cyclic_start(struct dma_chan *chan); -void dw_dma_cyclic_stop(struct dma_chan *chan); - -dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan); - -dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan); - -#endif /* DW_DMAC_H */ diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h new file mode 100644 index 0000000..68b4024 --- /dev/null +++ b/include/linux/platform_data/dma-dw.h @@ -0,0 +1,111 @@ +/* + * Driver for the Synopsys DesignWare DMA Controller + * + * Copyright (C) 2007 Atmel Corporation + * Copyright (C) 2010-2011 ST Microelectronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef DW_DMAC_H +#define DW_DMAC_H + +#include + +/** + * struct dw_dma_slave - Controller-specific information about a slave + * + * @dma_dev: required DMA master device. Depricated. + * @bus_id: name of this device channel, not just a device name since + * devices may have more than one channel e.g. "foo_tx" + * @cfg_hi: Platform-specific initializer for the CFG_HI register + * @cfg_lo: Platform-specific initializer for the CFG_LO register + * @src_master: src master for transfers on allocated channel. + * @dst_master: dest master for transfers on allocated channel. + */ +struct dw_dma_slave { + struct device *dma_dev; + u32 cfg_hi; + u32 cfg_lo; + u8 src_master; + u8 dst_master; +}; + +/** + * struct dw_dma_platform_data - Controller configuration parameters + * @nr_channels: Number of channels supported by hardware (max 8) + * @is_private: The device channels should be marked as private and not for + * by the general purpose DMA channel allocator. + * @chan_allocation_order: Allocate channels starting from 0 or 7 + * @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0. + * @block_size: Maximum block size supported by the controller + * @nr_masters: Number of AHB masters supported by the controller + * @data_width: Maximum data width supported by hardware per AHB master + * (0 - 8bits, 1 - 16bits, ..., 5 - 256bits) + */ +struct dw_dma_platform_data { + unsigned int nr_channels; + bool is_private; +#define CHAN_ALLOCATION_ASCENDING 0 /* zero to seven */ +#define CHAN_ALLOCATION_DESCENDING 1 /* seven to zero */ + unsigned char chan_allocation_order; +#define CHAN_PRIORITY_ASCENDING 0 /* chan0 highest */ +#define CHAN_PRIORITY_DESCENDING 1 /* chan7 highest */ + unsigned char chan_priority; + unsigned short block_size; + unsigned char nr_masters; + unsigned char data_width[4]; +}; + +/* bursts size */ +enum dw_dma_msize { + DW_DMA_MSIZE_1, + DW_DMA_MSIZE_4, + DW_DMA_MSIZE_8, + DW_DMA_MSIZE_16, + DW_DMA_MSIZE_32, + DW_DMA_MSIZE_64, + DW_DMA_MSIZE_128, + DW_DMA_MSIZE_256, +}; + +/* Platform-configurable bits in CFG_HI */ +#define DWC_CFGH_FCMODE (1 << 0) +#define DWC_CFGH_FIFO_MODE (1 << 1) +#define DWC_CFGH_PROTCTL(x) ((x) << 2) +#define DWC_CFGH_SRC_PER(x) ((x) << 7) +#define DWC_CFGH_DST_PER(x) ((x) << 11) + +/* Platform-configurable bits in CFG_LO */ +#define DWC_CFGL_LOCK_CH_XFER (0 << 12) /* scope of LOCK_CH */ +#define DWC_CFGL_LOCK_CH_BLOCK (1 << 12) +#define DWC_CFGL_LOCK_CH_XACT (2 << 12) +#define DWC_CFGL_LOCK_BUS_XFER (0 << 14) /* scope of LOCK_BUS */ +#define DWC_CFGL_LOCK_BUS_BLOCK (1 << 14) +#define DWC_CFGL_LOCK_BUS_XACT (2 << 14) +#define DWC_CFGL_LOCK_CH (1 << 15) /* channel lockout */ +#define DWC_CFGL_LOCK_BUS (1 << 16) /* busmaster lockout */ +#define DWC_CFGL_HS_DST_POL (1 << 18) /* dst handshake active low */ +#define DWC_CFGL_HS_SRC_POL (1 << 19) /* src handshake active low */ + +/* DMA API extensions */ +struct dw_cyclic_desc { + struct dw_desc **desc; + unsigned long periods; + void (*period_callback)(void *param); + void *period_callback_param; +}; + +struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, + dma_addr_t buf_addr, size_t buf_len, size_t period_len, + enum dma_transfer_direction direction); +void dw_dma_cyclic_free(struct dma_chan *chan); +int dw_dma_cyclic_start(struct dma_chan *chan); +void dw_dma_cyclic_stop(struct dma_chan *chan); + +dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan); + +dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan); + +#endif /* DW_DMAC_H */ diff --git a/include/sound/atmel-abdac.h b/include/sound/atmel-abdac.h index edff6a8..a8f735d 100644 --- a/include/sound/atmel-abdac.h +++ b/include/sound/atmel-abdac.h @@ -10,7 +10,7 @@ #ifndef __INCLUDE_SOUND_ATMEL_ABDAC_H #define __INCLUDE_SOUND_ATMEL_ABDAC_H -#include +#include /** * struct atmel_abdac_pdata - board specific ABDAC configuration diff --git a/include/sound/atmel-ac97c.h b/include/sound/atmel-ac97c.h index 00e6c289..f2a1cdc 100644 --- a/include/sound/atmel-ac97c.h +++ b/include/sound/atmel-ac97c.h @@ -10,7 +10,7 @@ #ifndef __INCLUDE_SOUND_ATMEL_AC97C_H #define __INCLUDE_SOUND_ATMEL_AC97C_H -#include +#include #define AC97C_CAPTURE 0x01 #define AC97C_PLAYBACK 0x02 diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c index edf2ca7..154a7c4 100644 --- a/sound/atmel/abdac.c +++ b/sound/atmel/abdac.c @@ -9,7 +9,7 @@ */ #include #include -#include +#include #include #include #include diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index a04d2317..1dfb35a 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include -- cgit v0.10.2 From 61c4319cb523a2346416cddaa7d4e2f9260c14d9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Aug 2014 20:29:13 +0300 Subject: avr32: at32ap700x: don't rely on default DMA masters In future we are going to remove the defaults of AHB masters from dw_dmac driver. It means each user have to supply proper source and destination masters by itself explicitly. Signed-off-by: Andy Shevchenko Acked-by: Hans-Christian Egtvedt Signed-off-by: Vinod Koul diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index 2a1aa71..ec7be28 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c @@ -1360,6 +1360,8 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data) | DWC_CFGH_DST_PER(1)); slave->sdata.cfg_lo &= ~(DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL); + slave->sdata.src_master = 1; + slave->sdata.dst_master = 0; data->dma_slave = slave; -- cgit v0.10.2 From 7e1e2f27c5508518e58e5cbb11e26cbb815f4c56 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Aug 2014 20:29:14 +0300 Subject: dmaengine: dw: convert dw_dma_slave to use explicit HS interfaces Instead of exposing the possibility to set DMA registers CFG_HI and CFG_LO strict user to provide handshake interfaces explicitly. Signed-off-by: Andy Shevchenko Acked-by: Hans-Christian Egtvedt Signed-off-by: Vinod Koul diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index ec7be28..37b7560 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c @@ -1356,10 +1356,8 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data) goto fail; slave->sdata.dma_dev = &dw_dmac0_device.dev; - slave->sdata.cfg_hi = (DWC_CFGH_SRC_PER(0) - | DWC_CFGH_DST_PER(1)); - slave->sdata.cfg_lo &= ~(DWC_CFGL_HS_DST_POL - | DWC_CFGL_HS_SRC_POL); + slave->sdata.src_id = 0; + slave->sdata.dst_id = 1; slave->sdata.src_master = 1; slave->sdata.dst_master = 0; @@ -2054,8 +2052,7 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data, /* Check if DMA slave interface for capture should be configured. */ if (flags & AC97C_CAPTURE) { rx_dws->dma_dev = &dw_dmac0_device.dev; - rx_dws->cfg_hi = DWC_CFGH_SRC_PER(3); - rx_dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL); + rx_dws->src_id = 3; rx_dws->src_master = 0; rx_dws->dst_master = 1; } @@ -2063,8 +2060,7 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data, /* Check if DMA slave interface for playback should be configured. */ if (flags & AC97C_PLAYBACK) { tx_dws->dma_dev = &dw_dmac0_device.dev; - tx_dws->cfg_hi = DWC_CFGH_DST_PER(4); - tx_dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL); + tx_dws->dst_id = 4; tx_dws->src_master = 0; tx_dws->dst_master = 1; } @@ -2136,8 +2132,7 @@ at32_add_device_abdac(unsigned int id, struct atmel_abdac_pdata *data) dws = &data->dws; dws->dma_dev = &dw_dmac0_device.dev; - dws->cfg_hi = DWC_CFGH_DST_PER(2); - dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL); + dws->dst_id = 2; dws->src_master = 0; dws->dst_master = 1; diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 1af731b..0a9c052 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -155,8 +155,8 @@ static void dwc_initialize(struct dw_dma_chan *dwc) */ BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev); - cfghi = dws->cfg_hi; - cfglo |= dws->cfg_lo & ~DWC_CFGL_CH_PRIOR_MASK; + cfghi |= DWC_CFGH_DST_PER(dws->dst_id); + cfghi |= DWC_CFGH_SRC_PER(dws->src_id); } else { if (dwc->direction == DMA_MEM_TO_DEV) cfghi = DWC_CFGH_DST_PER(dwc->request_line); diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h index 68b4024..bc411a1 100644 --- a/include/linux/platform_data/dma-dw.h +++ b/include/linux/platform_data/dma-dw.h @@ -17,17 +17,15 @@ * struct dw_dma_slave - Controller-specific information about a slave * * @dma_dev: required DMA master device. Depricated. - * @bus_id: name of this device channel, not just a device name since - * devices may have more than one channel e.g. "foo_tx" - * @cfg_hi: Platform-specific initializer for the CFG_HI register - * @cfg_lo: Platform-specific initializer for the CFG_LO register + * @src_id: src request line + * @dst_id: dst request line * @src_master: src master for transfers on allocated channel. * @dst_master: dest master for transfers on allocated channel. */ struct dw_dma_slave { struct device *dma_dev; - u32 cfg_hi; - u32 cfg_lo; + u8 src_id; + u8 dst_id; u8 src_master; u8 dst_master; }; -- cgit v0.10.2 From 8950052029874a6738552debb45077c596e90e6b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Aug 2014 20:29:15 +0300 Subject: dmaengine: dw: apply both HS interfaces and remove slave_id usage Instead of one request line member let's use both source and destination ones. Usually we have no such hardware except Atmel MMC controller found on AVR32 platform (see arch/avr32/mach-at32ap/at32ap700x.c and drivers/mmc/host/atmel-mci.c). This patch removes slave_id usage since it'll be removed from the generic structure in later. This breaks the non-ACPI / non-DT cases for the users of the driver, i.e. SPI and HSUART. However, these cases mean only PCI enumerated devices for now, which is anyway broken (considering more than one DMA controller in the system) and this patch series is intended to fix that eventually. The ACPI and DT cases shall be aware of the channel direction when setting request lines, but this is a minor problem that would be addressed in future. Suggested-by: Arnd Bergmann Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 0a9c052..1c45212 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -37,24 +37,6 @@ * support descriptor writeback. */ -static inline bool is_request_line_unset(struct dw_dma_chan *dwc) -{ - return dwc->request_line == (typeof(dwc->request_line))~0; -} - -static inline void dwc_set_masters(struct dw_dma_chan *dwc) -{ - struct dw_dma *dw = to_dw_dma(dwc->chan.device); - struct dw_dma_slave *dws = dwc->chan.private; - unsigned char mmax = dw->nr_masters - 1; - - if (!is_request_line_unset(dwc)) - return; - - dwc->src_master = min_t(unsigned char, mmax, dwc_get_sms(dws)); - dwc->dst_master = min_t(unsigned char, mmax, dwc_get_dms(dws)); -} - #define DWC_DEFAULT_CTLLO(_chan) ({ \ struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan); \ struct dma_slave_config *_sconfig = &_dwc->dma_sconfig; \ @@ -158,10 +140,8 @@ static void dwc_initialize(struct dw_dma_chan *dwc) cfghi |= DWC_CFGH_DST_PER(dws->dst_id); cfghi |= DWC_CFGH_SRC_PER(dws->src_id); } else { - if (dwc->direction == DMA_MEM_TO_DEV) - cfghi = DWC_CFGH_DST_PER(dwc->request_line); - else if (dwc->direction == DMA_DEV_TO_MEM) - cfghi = DWC_CFGH_SRC_PER(dwc->request_line); + cfghi |= DWC_CFGH_DST_PER(dwc->dst_id); + cfghi |= DWC_CFGH_SRC_PER(dwc->src_id); } channel_writel(dwc, CFG_LO, cfglo); @@ -967,10 +947,6 @@ set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig) memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig)); dwc->direction = sconfig->direction; - /* Take the request line from slave_id member */ - if (is_request_line_unset(dwc)) - dwc->request_line = sconfig->slave_id; - convert_burst(&dwc->dma_sconfig.src_maxburst); convert_burst(&dwc->dma_sconfig.dst_maxburst); @@ -1123,8 +1099,6 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan) * doesn't mean what you think it means), and status writeback. */ - dwc_set_masters(dwc); - spin_lock_irqsave(&dwc->lock, flags); i = dwc->descs_allocated; while (dwc->descs_allocated < NR_DESCS_PER_CHANNEL) { @@ -1182,7 +1156,6 @@ static void dwc_free_chan_resources(struct dma_chan *chan) list_splice_init(&dwc->free_list, &list); dwc->descs_allocated = 0; dwc->initialized = false; - dwc->request_line = ~0; /* Disable interrupts */ channel_clear_bit(dw, MASK.XFER, dwc->mask); @@ -1604,7 +1577,6 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata) channel_clear_bit(dw, CH_EN, dwc->mask); dwc->direction = DMA_TRANS_NONE; - dwc->request_line = ~0; /* Hardware configuration */ if (autocfg) { diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index c5b339a..7aa3cd3 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -41,7 +41,8 @@ static bool dw_dma_of_filter(struct dma_chan *chan, void *param) if (chan->device != &fargs->dw->dma) return false; - dwc->request_line = fargs->req; + dwc->src_id = fargs->req; + dwc->dst_id = fargs->req; dwc->src_master = fargs->src; dwc->dst_master = fargs->dst; @@ -86,7 +87,8 @@ static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param) chan->chan_id != dma_spec->chan_id) return false; - dwc->request_line = dma_spec->slave_id; + dwc->src_id = dma_spec->slave_id; + dwc->dst_id = dma_spec->slave_id; dwc->src_master = dwc_get_sms(NULL); dwc->dst_master = dwc_get_dms(NULL); diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h index af02439..0e82d99 100644 --- a/drivers/dma/dw/regs.h +++ b/drivers/dma/dw/regs.h @@ -221,9 +221,10 @@ struct dw_dma_chan { bool nollp; /* custom slave configuration */ - unsigned int request_line; - unsigned char src_master; - unsigned char dst_master; + u8 src_id; + u8 dst_id; + u8 src_master; + u8 dst_master; /* configuration passed via DMA_SLAVE_CONFIG */ struct dma_slave_config dma_sconfig; -- cgit v0.10.2 From 4d130de20c3f39fc1a1aecd3969b50d49ff2e358 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Aug 2014 20:29:16 +0300 Subject: dmaengine: dw: introduce generic filter function The introduced filter function would be reused in the ACPI and DT cases since in those cases we have to apply mandatory data to the requested channel. Thus, patch moves platform driver to use it in that case. The function unlikely can't be used by users of the driver due to an implicit dependency to the dw_dmac_core module. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 1c45212..10e43ea 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -919,6 +919,26 @@ err_desc_get: return NULL; } +bool dw_dma_filter(struct dma_chan *chan, void *param) +{ + struct dw_dma_chan *dwc = to_dw_dma_chan(chan); + struct dw_dma_slave *dws = param; + + if (!dws || dws->dma_dev != chan->device->dev) + return false; + + /* We have to copy data since dws can be temporary storage */ + + dwc->src_id = dws->src_id; + dwc->dst_id = dws->dst_id; + + dwc->src_master = dws->src_master; + dwc->dst_master = dws->dst_master; + + return true; +} +EXPORT_SYMBOL_GPL(dw_dma_filter); + /* * Fix sconfig's burst size according to dw_dmac. We need to convert them as: * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h index 43cc1df..2c8d02f 100644 --- a/drivers/dma/dw/internal.h +++ b/drivers/dma/dw/internal.h @@ -43,28 +43,6 @@ int dw_dma_resume(struct dw_dma_chip *chip); #endif /* CONFIG_PM_SLEEP */ -/** - * dwc_get_dms - get destination master - * @slave: pointer to the custom slave configuration - * - * Returns destination master in the custom slave configuration if defined, or - * default value otherwise. - */ -static inline unsigned int dwc_get_dms(struct dw_dma_slave *slave) -{ - return slave ? slave->dst_master : 0; -} - -/** - * dwc_get_sms - get source master - * @slave: pointer to the custom slave configuration - * - * Returns source master in the custom slave configuration if defined, or - * default value otherwise. - */ -static inline unsigned int dwc_get_sms(struct dw_dma_slave *slave) -{ - return slave ? slave->src_master : 1; -} +extern bool dw_dma_filter(struct dma_chan *chan, void *param); #endif /* _DW_DMAC_INTERNAL_H */ diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 7aa3cd3..860c9ac 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -25,74 +25,49 @@ #include "internal.h" -struct dw_dma_of_filter_args { - struct dw_dma *dw; - unsigned int req; - unsigned int src; - unsigned int dst; -}; - -static bool dw_dma_of_filter(struct dma_chan *chan, void *param) -{ - struct dw_dma_chan *dwc = to_dw_dma_chan(chan); - struct dw_dma_of_filter_args *fargs = param; - - /* Ensure the device matches our channel */ - if (chan->device != &fargs->dw->dma) - return false; - - dwc->src_id = fargs->req; - dwc->dst_id = fargs->req; - dwc->src_master = fargs->src; - dwc->dst_master = fargs->dst; - - return true; -} - static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec, struct of_dma *ofdma) { struct dw_dma *dw = ofdma->of_dma_data; - struct dw_dma_of_filter_args fargs = { - .dw = dw, + struct dw_dma_slave slave = { + .dma_dev = dw->dma.dev, }; dma_cap_mask_t cap; if (dma_spec->args_count != 3) return NULL; - fargs.req = dma_spec->args[0]; - fargs.src = dma_spec->args[1]; - fargs.dst = dma_spec->args[2]; + slave.src_id = dma_spec->args[0]; + slave.dst_id = dma_spec->args[0]; + slave.src_master = dma_spec->args[1]; + slave.dst_master = dma_spec->args[2]; - if (WARN_ON(fargs.req >= DW_DMA_MAX_NR_REQUESTS || - fargs.src >= dw->nr_masters || - fargs.dst >= dw->nr_masters)) + if (WARN_ON(slave.src_id >= DW_DMA_MAX_NR_REQUESTS || + slave.dst_id >= DW_DMA_MAX_NR_REQUESTS || + slave.src_master >= dw->nr_masters || + slave.dst_master >= dw->nr_masters)) return NULL; dma_cap_zero(cap); dma_cap_set(DMA_SLAVE, cap); /* TODO: there should be a simpler way to do this */ - return dma_request_channel(cap, dw_dma_of_filter, &fargs); + return dma_request_channel(cap, dw_dma_filter, &slave); } #ifdef CONFIG_ACPI static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param) { - struct dw_dma_chan *dwc = to_dw_dma_chan(chan); struct acpi_dma_spec *dma_spec = param; + struct dw_dma_slave slave = { + .dma_dev = dma_spec->dev, + .src_id = dma_spec->slave_id, + .dst_id = dma_spec->slave_id, + .src_master = 1, + .dst_master = 0, + }; - if (chan->device->dev != dma_spec->dev || - chan->chan_id != dma_spec->chan_id) - return false; - - dwc->src_id = dma_spec->slave_id; - dwc->dst_id = dma_spec->slave_id; - dwc->src_master = dwc_get_sms(NULL); - dwc->dst_master = dwc_get_dms(NULL); - - return true; + return dw_dma_filter(chan, &slave); } static void dw_dma_acpi_controller_register(struct dw_dma *dw) -- cgit v0.10.2 From a15636e83eb0dedefcb1221be729023e4c281748 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Aug 2014 20:29:17 +0300 Subject: dmaengine: dw: move clock operations to platform.c On BayTrail platform DMA is not functional in the PCI mode, whereby it always failed and exit at the point when it tries to get a clock. It causes the PCI mode probe to exit with the error message: dw_dmac_pci: probe of 0000:00:1e.0 failed with error -2 This patch moves clock operations to where it belongs to. Thus, the clock is provided only in ACPI / non-PCI cases. Reported-by: Chew, Chiau Ee Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 10e43ea..9546b1f 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include @@ -1488,13 +1487,6 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata) dw->regs = chip->regs; chip->dw = dw; - dw->clk = devm_clk_get(chip->dev, "hclk"); - if (IS_ERR(dw->clk)) - return PTR_ERR(dw->clk); - err = clk_prepare_enable(dw->clk); - if (err) - return err; - dw_params = dma_read_byaddr(chip->regs, DW_PARAMS); autocfg = dw_params >> DW_PARAMS_EN & 0x1; @@ -1665,7 +1657,6 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata) err_dma_register: free_irq(chip->irq, dw); err_pdata: - clk_disable_unprepare(dw->clk); return err; } EXPORT_SYMBOL_GPL(dw_dma_probe); @@ -1687,8 +1678,6 @@ int dw_dma_remove(struct dw_dma_chip *chip) channel_clear_bit(dw, CH_EN, dwc->mask); } - clk_disable_unprepare(dw->clk); - return 0; } EXPORT_SYMBOL_GPL(dw_dma_remove); @@ -1698,7 +1687,6 @@ void dw_dma_shutdown(struct dw_dma_chip *chip) struct dw_dma *dw = chip->dw; dw_dma_off(dw); - clk_disable_unprepare(dw->clk); } EXPORT_SYMBOL_GPL(dw_dma_shutdown); @@ -1709,8 +1697,6 @@ int dw_dma_suspend(struct dw_dma_chip *chip) struct dw_dma *dw = chip->dw; dw_dma_off(dw); - clk_disable_unprepare(dw->clk); - return 0; } EXPORT_SYMBOL_GPL(dw_dma_suspend); @@ -1719,9 +1705,7 @@ int dw_dma_resume(struct dw_dma_chip *chip) { struct dw_dma *dw = chip->dw; - clk_prepare_enable(dw->clk); dma_writel(dw, CFG, DW_CFG_DMA_EN); - return 0; } EXPORT_SYMBOL_GPL(dw_dma_resume); diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h index 2c8d02f..82258a1 100644 --- a/drivers/dma/dw/internal.h +++ b/drivers/dma/dw/internal.h @@ -21,12 +21,14 @@ * @dev: struct device of the DMA controller * @irq: irq line * @regs: memory mapped I/O space + * @clk: hclk clock * @dw: struct dw_dma that is filed by dw_dma_probe() */ struct dw_dma_chip { struct device *dev; int irq; void __iomem *regs; + struct clk *clk; struct dw_dma *dw; }; diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 860c9ac..d50077e 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -178,10 +178,17 @@ static int dw_probe(struct platform_device *pdev) chip->dev = dev; - err = dw_dma_probe(chip, pdata); + chip->clk = devm_clk_get(chip->dev, "hclk"); + if (IS_ERR(chip->clk)) + return PTR_ERR(chip->clk); + err = clk_prepare_enable(chip->clk); if (err) return err; + err = dw_dma_probe(chip, pdata); + if (err) + goto err_dw_dma_probe; + platform_set_drvdata(pdev, chip); if (pdev->dev.of_node) { @@ -196,6 +203,10 @@ static int dw_probe(struct platform_device *pdev) dw_dma_acpi_controller_register(chip->dw); return 0; + +err_dw_dma_probe: + clk_disable_unprepare(chip->clk); + return err; } static int dw_remove(struct platform_device *pdev) @@ -205,7 +216,10 @@ static int dw_remove(struct platform_device *pdev) if (pdev->dev.of_node) of_dma_controller_free(pdev->dev.of_node); - return dw_dma_remove(chip); + dw_dma_remove(chip); + clk_disable_unprepare(chip->clk); + + return 0; } static void dw_shutdown(struct platform_device *pdev) @@ -213,6 +227,7 @@ static void dw_shutdown(struct platform_device *pdev) struct dw_dma_chip *chip = platform_get_drvdata(pdev); dw_dma_shutdown(chip); + clk_disable_unprepare(chip->clk); } #ifdef CONFIG_OF @@ -238,7 +253,10 @@ static int dw_suspend_late(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct dw_dma_chip *chip = platform_get_drvdata(pdev); - return dw_dma_suspend(chip); + dw_dma_suspend(chip); + clk_disable_unprepare(chip->clk); + + return 0; } static int dw_resume_early(struct device *dev) @@ -246,6 +264,7 @@ static int dw_resume_early(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct dw_dma_chip *chip = platform_get_drvdata(pdev); + clk_prepare_enable(chip->clk); return dw_dma_resume(chip); } diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h index 0e82d99..00d27a9 100644 --- a/drivers/dma/dw/regs.h +++ b/drivers/dma/dw/regs.h @@ -251,7 +251,6 @@ struct dw_dma { void __iomem *regs; struct dma_pool *desc_pool; struct tasklet_struct tasklet; - struct clk *clk; /* channels */ struct dw_dma_chan *chan; -- cgit v0.10.2 From b279c4922e9242b4b1a04da7fa5622f2323c85de Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Aug 2014 20:29:18 +0300 Subject: dmaengine: dw: add PCI IDs for Braswell DMAs Braswell SoC has two DMA controllers for LPSS. This patch adds them to supported list in the PCI driver. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c index 39e30c3..9c88828 100644 --- a/drivers/dma/dw/pci.c +++ b/drivers/dma/dw/pci.c @@ -108,6 +108,10 @@ static const struct pci_device_id dw_pci_id_table[] = { { PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_pci_pdata }, { PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_pci_pdata }, + /* Braswell */ + { PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_pci_pdata }, + { PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_pci_pdata }, + /* Haswell */ { PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_pci_pdata }, { } -- cgit v0.10.2 From 9a1870ce812e13091c21af36d4dc1cd29077966d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Aug 2014 20:29:22 +0300 Subject: serial: 8250: don't use slave_id of dma_slave_config That field has been deprecated in favour of getting the necessary information from ACPI or DT. However, we still need to deal systems that are PCI only (no ACPI to back up) like Intel Bay Trail. In order to support such systems, we explicitly bind setup() to the appropriate DMA filter function and its corresponding parameter. Then when serial8250_request_dma() doesn't find the channel via ACPI or DT, it falls back to use the given filter function. Signed-off-by: Andy Shevchenko Acked-by: Greg Kroah-Hartman Signed-off-by: Vinod Koul diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 1b08c91..c3c7091 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -16,13 +16,13 @@ #include struct uart_8250_dma { + /* Filter function */ dma_filter_fn fn; + + /* Parameter to the filter function */ void *rx_param; void *tx_param; - int rx_chan_id; - int tx_chan_id; - struct dma_slave_config rxconf; struct dma_slave_config txconf; diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 4db7987..6664de2 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -216,10 +216,7 @@ out: static bool dw8250_dma_filter(struct dma_chan *chan, void *param) { - struct dw8250_data *data = param; - - return chan->chan_id == data->dma.tx_chan_id || - chan->chan_id == data->dma.rx_chan_id; + return false; } static void dw8250_setup_port(struct uart_8250_port *up) @@ -399,8 +396,6 @@ static int dw8250_probe(struct platform_device *pdev) if (!IS_ERR(data->rst)) reset_control_deassert(data->rst); - data->dma.rx_chan_id = -1; - data->dma.tx_chan_id = -1; data->dma.rx_param = data; data->dma.tx_param = data; data->dma.fn = dw8250_dma_filter; diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 61830b1..a00c9de 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -25,6 +25,9 @@ #include #include +#include +#include + #include "8250.h" /* @@ -1427,7 +1430,13 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios, static bool byt_dma_filter(struct dma_chan *chan, void *param) { - return chan->chan_id == *(int *)param; + struct dw_dma_slave *dws = param; + + if (dws->dma_dev != chan->device->dev) + return false; + + chan->private = dws; + return true; } static int @@ -1435,35 +1444,55 @@ byt_serial_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + struct pci_dev *pdev = priv->dev; + struct device *dev = port->port.dev; struct uart_8250_dma *dma; + struct dw_dma_slave *tx_param, *rx_param; + struct pci_dev *dma_dev; int ret; - dma = devm_kzalloc(port->port.dev, sizeof(*dma), GFP_KERNEL); + dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); if (!dma) return -ENOMEM; - switch (priv->dev->device) { + tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL); + if (!tx_param) + return -ENOMEM; + + rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL); + if (!rx_param) + return -ENOMEM; + + switch (pdev->device) { case PCI_DEVICE_ID_INTEL_BYT_UART1: - dma->rx_chan_id = 3; - dma->tx_chan_id = 2; + rx_param->src_id = 3; + tx_param->dst_id = 2; break; case PCI_DEVICE_ID_INTEL_BYT_UART2: - dma->rx_chan_id = 5; - dma->tx_chan_id = 4; + rx_param->src_id = 5; + tx_param->dst_id = 4; break; default: return -EINVAL; } - dma->rxconf.slave_id = dma->rx_chan_id; + rx_param->src_master = 1; + rx_param->dst_master = 0; + dma->rxconf.src_maxburst = 16; - dma->txconf.slave_id = dma->tx_chan_id; + tx_param->src_master = 1; + tx_param->dst_master = 0; + dma->txconf.dst_maxburst = 16; + dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 0)); + rx_param->dma_dev = &dma_dev->dev; + tx_param->dma_dev = &dma_dev->dev; + dma->fn = byt_dma_filter; - dma->rx_param = &dma->rx_chan_id; - dma->tx_param = &dma->tx_chan_id; + dma->rx_param = rx_param; + dma->tx_param = tx_param; ret = pci_default_setup(priv, board, port, idx); port->port.iotype = UPIO_MEM; -- cgit v0.10.2 From 29897087d90109a7ed67e68dbbc6fb077301c7d1 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 19 Aug 2014 20:29:23 +0300 Subject: serial: 8250_pci: Add PCI IDs for Intel Braswell Add new PCI IDs to cover newer Intel SoCs such as Braswell. Signed-off-by: Alan Cox Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Acked-by: Greg Kroah-Hartman Signed-off-by: Vinod Koul diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index a00c9de..85a2eb9 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1352,6 +1352,9 @@ ce4100_serial_setup(struct serial_private *priv, #define PCI_DEVICE_ID_INTEL_BYT_UART1 0x0f0a #define PCI_DEVICE_ID_INTEL_BYT_UART2 0x0f0c +#define PCI_DEVICE_ID_INTEL_BSW_UART1 0x228a +#define PCI_DEVICE_ID_INTEL_BSW_UART2 0x228c + #define BYT_PRV_CLK 0x800 #define BYT_PRV_CLK_EN (1 << 0) #define BYT_PRV_CLK_M_VAL_SHIFT 1 @@ -1465,10 +1468,12 @@ byt_serial_setup(struct serial_private *priv, switch (pdev->device) { case PCI_DEVICE_ID_INTEL_BYT_UART1: + case PCI_DEVICE_ID_INTEL_BSW_UART1: rx_param->src_id = 3; tx_param->dst_id = 2; break; case PCI_DEVICE_ID_INTEL_BYT_UART2: + case PCI_DEVICE_ID_INTEL_BSW_UART2: rx_param->src_id = 5; tx_param->dst_id = 4; break; @@ -1927,6 +1932,20 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = byt_serial_setup, }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BSW_UART1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = byt_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BSW_UART2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = byt_serial_setup, + }, /* * ITE */ @@ -5219,6 +5238,14 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, pbn_byt }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW_UART1, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, + pbn_byt }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW_UART2, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, + pbn_byt }, /* * Cronyx Omega PCI -- cgit v0.10.2 From b729bf34535ed413667b397a2f59cfa81266facf Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 19 Aug 2014 20:29:19 +0300 Subject: spi/pxa2xx: Don't use slave_id of dma_slave_config That field has been deprecated in favour of getting the necessary information from ACPI/DT. However, we still need to deal systems that are PCI only (no ACPI to back up). In order to support such systems, we allow the DMA filter function and its corresponding parameter via pxa2xx_spi_master platform data. Then when the pxa2xx_spi_dma_setup() doesn't find the channel via ACPI, it falls back to use the given filter function. Suggested-by: Arnd Bergmann Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Acked-by: Mark Brown Signed-off-by: Vinod Koul diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index c41ff14..62a9297 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -157,7 +157,6 @@ static struct dma_async_tx_descriptor * pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, enum dma_transfer_direction dir) { - struct pxa2xx_spi_master *pdata = drv_data->master_info; struct chip_data *chip = drv_data->cur_chip; enum dma_slave_buswidth width; struct dma_slave_config cfg; @@ -184,7 +183,6 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, cfg.dst_addr = drv_data->ssdr_physical; cfg.dst_addr_width = width; cfg.dst_maxburst = chip->dma_burst_size; - cfg.slave_id = pdata->tx_slave_id; sgt = &drv_data->tx_sgt; nents = drv_data->tx_nents; @@ -193,7 +191,6 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, cfg.src_addr = drv_data->ssdr_physical; cfg.src_addr_width = width; cfg.src_maxburst = chip->dma_burst_size; - cfg.slave_id = pdata->rx_slave_id; sgt = &drv_data->rx_sgt; nents = drv_data->rx_nents; @@ -210,14 +207,6 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); } -static bool pxa2xx_spi_dma_filter(struct dma_chan *chan, void *param) -{ - const struct pxa2xx_spi_master *pdata = param; - - return chan->chan_id == pdata->tx_chan_id || - chan->chan_id == pdata->rx_chan_id; -} - bool pxa2xx_spi_dma_is_possible(size_t len) { return len <= MAX_DMA_LEN; @@ -321,12 +310,12 @@ int pxa2xx_spi_dma_setup(struct driver_data *drv_data) return -ENOMEM; drv_data->tx_chan = dma_request_slave_channel_compat(mask, - pxa2xx_spi_dma_filter, pdata, dev, "tx"); + pdata->dma_filter, pdata->tx_param, dev, "tx"); if (!drv_data->tx_chan) return -ENODEV; drv_data->rx_chan = dma_request_slave_channel_compat(mask, - pxa2xx_spi_dma_filter, pdata, dev, "rx"); + pdata->dma_filter, pdata->rx_param, dev, "rx"); if (!drv_data->rx_chan) { dma_release_channel(drv_data->tx_chan); drv_data->tx_chan = NULL; diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 20ebbc7..0424b67 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -10,6 +10,9 @@ #include #include +#include +#include + enum { PORT_CE4100, PORT_BYT, @@ -19,33 +22,41 @@ struct pxa_spi_info { enum pxa_ssp_type type; int port_id; int num_chipselect; - int tx_slave_id; - int tx_chan_id; - int rx_slave_id; - int rx_chan_id; unsigned long max_clk_rate; + + /* DMA channel request parameters */ + void *tx_param; + void *rx_param; }; +static struct dw_dma_slave byt_tx_param = { .dst_id = 0 }; +static struct dw_dma_slave byt_rx_param = { .src_id = 1 }; + +static bool lpss_dma_filter(struct dma_chan *chan, void *param) +{ + struct dw_dma_slave *dws = param; + + if (dws->dma_dev != chan->device->dev) + return false; + + chan->private = dws; + return true; +} + static struct pxa_spi_info spi_info_configs[] = { [PORT_CE4100] = { .type = PXA25x_SSP, .port_id = -1, .num_chipselect = -1, - .tx_slave_id = -1, - .tx_chan_id = -1, - .rx_slave_id = -1, - .rx_chan_id = -1, .max_clk_rate = 3686400, }, [PORT_BYT] = { .type = LPSS_SSP, .port_id = 0, .num_chipselect = 1, - .tx_slave_id = 0, - .tx_chan_id = 0, - .rx_slave_id = 1, - .rx_chan_id = 1, .max_clk_rate = 50000000, + .tx_param = &byt_tx_param, + .rx_param = &byt_rx_param, }, }; @@ -59,6 +70,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, struct ssp_device *ssp; struct pxa_spi_info *c; char buf[40]; + struct pci_dev *dma_dev; ret = pcim_enable_device(dev); if (ret) @@ -73,11 +85,29 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, memset(&spi_pdata, 0, sizeof(spi_pdata)); spi_pdata.num_chipselect = (c->num_chipselect > 0) ? c->num_chipselect : dev->devfn; - spi_pdata.tx_slave_id = c->tx_slave_id; - spi_pdata.tx_chan_id = c->tx_chan_id; - spi_pdata.rx_slave_id = c->rx_slave_id; - spi_pdata.rx_chan_id = c->rx_chan_id; - spi_pdata.enable_dma = c->rx_slave_id >= 0 && c->tx_slave_id >= 0; + + dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); + + if (c->tx_param) { + struct dw_dma_slave *slave = c->tx_param; + + slave->dma_dev = &dma_dev->dev; + slave->src_master = 1; + slave->dst_master = 0; + } + + if (c->rx_param) { + struct dw_dma_slave *slave = c->rx_param; + + slave->dma_dev = &dma_dev->dev; + slave->src_master = 1; + slave->dst_master = 0; + } + + spi_pdata.dma_filter = lpss_dma_filter; + spi_pdata.tx_param = c->tx_param; + spi_pdata.rx_param = c->rx_param; + spi_pdata.enable_dma = c->rx_param && c->tx_param; ssp = &spi_pdata.ssp; ssp->phys_base = pci_resource_start(dev, 0); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index fe79210..256c0ab 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1062,8 +1062,6 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) pdata->num_chipselect = 1; pdata->enable_dma = true; - pdata->tx_chan_id = -1; - pdata->rx_chan_id = -1; return pdata; } diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h index 82d5111..d5a3165 100644 --- a/include/linux/spi/pxa2xx_spi.h +++ b/include/linux/spi/pxa2xx_spi.h @@ -23,6 +23,8 @@ #define PXA2XX_CS_ASSERT (0x01) #define PXA2XX_CS_DEASSERT (0x02) +struct dma_chan; + /* device.platform_data for SSP controller devices */ struct pxa2xx_spi_master { u32 clock_enable; @@ -30,10 +32,9 @@ struct pxa2xx_spi_master { u8 enable_dma; /* DMA engine specific config */ - int rx_chan_id; - int tx_chan_id; - int rx_slave_id; - int tx_slave_id; + bool (*dma_filter)(struct dma_chan *chan, void *param); + void *tx_param; + void *rx_param; /* For non-PXA arches */ struct ssp_device ssp; -- cgit v0.10.2 From 39d36536d4e89461c0733a48d5ffc9b730751983 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 19 Aug 2014 20:29:21 +0300 Subject: spi/pxa2xx-pci: Add support for Intel Braswell Instead of one port we have 3 ports and all of them can take advantage of the shared DMA controller. Signed-off-by: Mika Westerberg Acked-by: Mark Brown Signed-off-by: Vinod Koul diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 0424b67..b285294 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -16,6 +16,9 @@ enum { PORT_CE4100, PORT_BYT, + PORT_BSW0, + PORT_BSW1, + PORT_BSW2, }; struct pxa_spi_info { @@ -32,6 +35,13 @@ struct pxa_spi_info { static struct dw_dma_slave byt_tx_param = { .dst_id = 0 }; static struct dw_dma_slave byt_rx_param = { .src_id = 1 }; +static struct dw_dma_slave bsw0_tx_param = { .dst_id = 0 }; +static struct dw_dma_slave bsw0_rx_param = { .src_id = 1 }; +static struct dw_dma_slave bsw1_tx_param = { .dst_id = 6 }; +static struct dw_dma_slave bsw1_rx_param = { .src_id = 7 }; +static struct dw_dma_slave bsw2_tx_param = { .dst_id = 8 }; +static struct dw_dma_slave bsw2_rx_param = { .src_id = 9 }; + static bool lpss_dma_filter(struct dma_chan *chan, void *param) { struct dw_dma_slave *dws = param; @@ -58,6 +68,30 @@ static struct pxa_spi_info spi_info_configs[] = { .tx_param = &byt_tx_param, .rx_param = &byt_rx_param, }, + [PORT_BSW0] = { + .type = LPSS_SSP, + .port_id = 0, + .num_chipselect = 1, + .max_clk_rate = 50000000, + .tx_param = &bsw0_tx_param, + .rx_param = &bsw0_rx_param, + }, + [PORT_BSW1] = { + .type = LPSS_SSP, + .port_id = 1, + .num_chipselect = 1, + .max_clk_rate = 50000000, + .tx_param = &bsw1_tx_param, + .rx_param = &bsw1_rx_param, + }, + [PORT_BSW2] = { + .type = LPSS_SSP, + .port_id = 2, + .num_chipselect = 1, + .max_clk_rate = 50000000, + .tx_param = &bsw2_tx_param, + .rx_param = &bsw2_rx_param, + }, }; static int pxa2xx_spi_pci_probe(struct pci_dev *dev, @@ -159,6 +193,9 @@ static void pxa2xx_spi_pci_remove(struct pci_dev *dev) static const struct pci_device_id pxa2xx_spi_pci_devices[] = { { PCI_VDEVICE(INTEL, 0x2e6a), PORT_CE4100 }, { PCI_VDEVICE(INTEL, 0x0f0e), PORT_BYT }, + { PCI_VDEVICE(INTEL, 0x228e), PORT_BSW0 }, + { PCI_VDEVICE(INTEL, 0x2290), PORT_BSW1 }, + { PCI_VDEVICE(INTEL, 0x22ac), PORT_BSW2 }, { }, }; MODULE_DEVICE_TABLE(pci, pxa2xx_spi_pci_devices); -- cgit v0.10.2 From a64efe15cf28f9d784f7a23cb0de2a4f656da7a4 Mon Sep 17 00:00:00 2001 From: Andy Gross Date: Wed, 10 Sep 2014 21:18:53 -0500 Subject: dmaengine: qcom_adm: Add device tree binding Add device tree binding support for the QCOM ADM DMA driver. Signed-off-by: Andy Gross Signed-off-by: Vinod Koul diff --git a/Documentation/devicetree/bindings/dma/qcom_adm.txt b/Documentation/devicetree/bindings/dma/qcom_adm.txt new file mode 100644 index 0000000..9bcab91 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/qcom_adm.txt @@ -0,0 +1,62 @@ +QCOM ADM DMA Controller + +Required properties: +- compatible: must contain "qcom,adm" for IPQ/APQ8064 and MSM8960 +- reg: Address range for DMA registers +- interrupts: Should contain one interrupt shared by all channels +- #dma-cells: must be <2>. First cell denotes the channel number. Second cell + denotes CRCI (client rate control interface) flow control assignment. +- clocks: Should contain the core clock and interface clock. +- clock-names: Must contain "core" for the core clock and "iface" for the + interface clock. +- resets: Must contain an entry for each entry in reset names. +- reset-names: Must include the following entries: + - clk + - c0 + - c1 + - c2 +- qcom,ee: indicates the security domain identifier used in the secure world. + +Example: + adm_dma: dma@18300000 { + compatible = "qcom,adm"; + reg = <0x18300000 0x100000>; + interrupts = <0 170 0>; + #dma-cells = <2>; + + clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>; + clock-names = "core", "iface"; + + resets = <&gcc ADM0_RESET>, + <&gcc ADM0_C0_RESET>, + <&gcc ADM0_C1_RESET>, + <&gcc ADM0_C2_RESET>; + reset-names = "clk", "c0", "c1", "c2"; + qcom,ee = <0>; + }; + +DMA clients must use the format descripted in the dma.txt file, using a three +cell specifier for each channel. + +Each dmas request consists of 3 cells: + 1. phandle pointing to the DMA controller + 2. channel number + 3. CRCI assignment, if applicable. If no CRCI flow control is required, use 0. + The CRCI is used for flow control. It identifies the peripheral device that + is the source/destination for the transferred data. + +Example: + + spi4: spi@1a280000 { + status = "ok"; + spi-max-frequency = <50000000>; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 0>; + + dmas = <&adm_dma 6 9>, + <&adm_dma 5 10>; + dma-names = "rx", "tx"; + }; -- cgit v0.10.2 From b8291ddeed581e57327d715d29ffc501b9d48c5f Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 27 Aug 2014 10:52:49 -0300 Subject: dma: mv_xor: Replace printk with dev_info This commit replaces a printk(KERN_INFO ...) call with a dev_info() call, which is prefered for drivers. Signed-off-by: Ezequiel Garcia Signed-off-by: Vinod Koul diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 394cbc5..7c38768 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -537,8 +537,9 @@ static int mv_xor_alloc_chan_resources(struct dma_chan *chan) while (idx < num_descs_in_pool) { slot = kzalloc(sizeof(*slot), GFP_KERNEL); if (!slot) { - printk(KERN_INFO "MV XOR Channel only initialized" - " %d descriptor slots", idx); + dev_info(mv_chan_to_devp(mv_chan), + "channel only initialized %d descriptor slots", + idx); break; } virt_desc = mv_chan->dma_desc_pool_virt; -- cgit v0.10.2 From 3e4f52e2da9f66ba9c19b9266fa9ffcaee2f3ecc Mon Sep 17 00:00:00 2001 From: Lior Amsalem Date: Wed, 27 Aug 2014 10:52:50 -0300 Subject: dma: mv_xor: Simplify the DMA_MEMCPY operation A memory copy operation can be expressed as an XOR operation with one source. This commit removes code duplication in the driver by reusing the XOR operation for the MEMCPY. As an added benefit, we can now put MEMCPY and XOR descriptors on the same chain, which improves performance. Signed-off-by: Lior Amsalem Signed-off-by: Ezequiel Garcia Signed-off-by: Vinod Koul diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 7c38768..1e43f18 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -82,13 +82,6 @@ static void mv_desc_set_dest_addr(struct mv_xor_desc_slot *desc, hw_desc->phy_dest_addr = addr; } -static int mv_chan_memset_slot_count(size_t len) -{ - return 1; -} - -#define mv_chan_memcpy_slot_count(c) mv_chan_memset_slot_count(c) - static void mv_desc_set_src_addr(struct mv_xor_desc_slot *desc, int index, dma_addr_t addr) { @@ -144,17 +137,6 @@ static void mv_xor_device_clear_err_status(struct mv_xor_chan *chan) writel_relaxed(val, XOR_INTR_CAUSE(chan)); } -static int mv_can_chain(struct mv_xor_desc_slot *desc) -{ - struct mv_xor_desc_slot *chain_old_tail = list_entry( - desc->chain_node.prev, struct mv_xor_desc_slot, chain_node); - - if (chain_old_tail->type != desc->type) - return 0; - - return 1; -} - static void mv_set_mode(struct mv_xor_chan *chan, enum dma_transaction_type type) { @@ -236,8 +218,6 @@ static void mv_xor_start_new_chain(struct mv_xor_chan *mv_chan, { dev_dbg(mv_chan_to_devp(mv_chan), "%s %d: sw_desc %p\n", __func__, __LINE__, sw_desc); - if (sw_desc->type != mv_chan->current_type) - mv_set_mode(mv_chan, sw_desc->type); /* set the hardware chain */ mv_chan_set_next_descriptor(mv_chan, sw_desc->async_tx.phys); @@ -492,9 +472,6 @@ mv_xor_tx_submit(struct dma_async_tx_descriptor *tx) list_splice_init(&grp_start->tx_list, &old_chain_tail->chain_node); - if (!mv_can_chain(grp_start)) - goto submit_done; - dev_dbg(mv_chan_to_devp(mv_chan), "Append to last desc %pa\n", &old_chain_tail->async_tx.phys); @@ -516,7 +493,6 @@ mv_xor_tx_submit(struct dma_async_tx_descriptor *tx) if (new_hw_chain) mv_xor_start_new_chain(mv_chan, grp_start); -submit_done: spin_unlock_bh(&mv_chan->lock); return cookie; @@ -573,45 +549,6 @@ static int mv_xor_alloc_chan_resources(struct dma_chan *chan) } static struct dma_async_tx_descriptor * -mv_xor_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, - size_t len, unsigned long flags) -{ - struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); - struct mv_xor_desc_slot *sw_desc, *grp_start; - int slot_cnt; - - dev_dbg(mv_chan_to_devp(mv_chan), - "%s dest: %pad src %pad len: %u flags: %ld\n", - __func__, &dest, &src, len, flags); - if (unlikely(len < MV_XOR_MIN_BYTE_COUNT)) - return NULL; - - BUG_ON(len > MV_XOR_MAX_BYTE_COUNT); - - spin_lock_bh(&mv_chan->lock); - slot_cnt = mv_chan_memcpy_slot_count(len); - sw_desc = mv_xor_alloc_slots(mv_chan, slot_cnt, 1); - if (sw_desc) { - sw_desc->type = DMA_MEMCPY; - sw_desc->async_tx.flags = flags; - grp_start = sw_desc->group_head; - mv_desc_init(grp_start, flags); - mv_desc_set_byte_count(grp_start, len); - mv_desc_set_dest_addr(sw_desc->group_head, dest); - mv_desc_set_src_addr(grp_start, 0, src); - sw_desc->unmap_src_cnt = 1; - sw_desc->unmap_len = len; - } - spin_unlock_bh(&mv_chan->lock); - - dev_dbg(mv_chan_to_devp(mv_chan), - "%s sw_desc %p async_tx %p\n", - __func__, sw_desc, sw_desc ? &sw_desc->async_tx : NULL); - - return sw_desc ? &sw_desc->async_tx : NULL; -} - -static struct dma_async_tx_descriptor * mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, unsigned int src_cnt, size_t len, unsigned long flags) { @@ -636,7 +573,6 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, sw_desc->async_tx.flags = flags; grp_start = sw_desc->group_head; mv_desc_init(grp_start, flags); - /* the byte count field is the same as in memcpy desc*/ mv_desc_set_byte_count(grp_start, len); mv_desc_set_dest_addr(sw_desc->group_head, dest); sw_desc->unmap_src_cnt = src_cnt; @@ -651,6 +587,17 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, return sw_desc ? &sw_desc->async_tx : NULL; } +static struct dma_async_tx_descriptor * +mv_xor_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, + size_t len, unsigned long flags) +{ + /* + * A MEMCPY operation is identical to an XOR operation with only + * a single source address. + */ + return mv_xor_prep_dma_xor(chan, dest, &src, 1, len, flags); +} + static void mv_xor_free_chan_resources(struct dma_chan *chan) { struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); @@ -1071,7 +1018,7 @@ mv_xor_channel_add(struct mv_xor_device *xordev, mv_chan_unmask_interrupts(mv_chan); - mv_set_mode(mv_chan, DMA_MEMCPY); + mv_set_mode(mv_chan, DMA_XOR); spin_lock_init(&mv_chan->lock); INIT_LIST_HEAD(&mv_chan->chain); -- cgit v0.10.2 From dfc97661bdeadb57d35458430612072119b1c72f Mon Sep 17 00:00:00 2001 From: Lior Amsalem Date: Wed, 27 Aug 2014 10:52:51 -0300 Subject: dma: mv_xor: Remove multi-slot support Although the driver supported multiple-slot allocation, only one slot was ever allocated for each transaction. So, given we have no users of the multi-slot support, we can remove it and greatly simplify the code. Signed-off-by: Lior Amsalem Signed-off-by: Ezequiel Garcia Signed-off-by: Vinod Koul diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 1e43f18..a30e221 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -45,19 +45,15 @@ static void mv_xor_issue_pending(struct dma_chan *chan); #define mv_chan_to_devp(chan) \ ((chan)->dmadev.dev) -static void mv_desc_init(struct mv_xor_desc_slot *desc, unsigned long flags) +static void mv_desc_init(struct mv_xor_desc_slot *desc, + dma_addr_t addr, u32 byte_count) { struct mv_xor_desc *hw_desc = desc->hw_desc; hw_desc->status = (1 << 31); hw_desc->phy_next_desc = 0; hw_desc->desc_command = (1 << 31); -} - -static void mv_desc_set_byte_count(struct mv_xor_desc_slot *desc, - u32 byte_count) -{ - struct mv_xor_desc *hw_desc = desc->hw_desc; + hw_desc->phy_dest_addr = addr; hw_desc->byte_count = byte_count; } @@ -75,13 +71,6 @@ static void mv_desc_clear_next_desc(struct mv_xor_desc_slot *desc) hw_desc->phy_next_desc = 0; } -static void mv_desc_set_dest_addr(struct mv_xor_desc_slot *desc, - dma_addr_t addr) -{ - struct mv_xor_desc *hw_desc = desc->hw_desc; - hw_desc->phy_dest_addr = addr; -} - static void mv_desc_set_src_addr(struct mv_xor_desc_slot *desc, int index, dma_addr_t addr) { @@ -188,11 +177,6 @@ static char mv_chan_is_busy(struct mv_xor_chan *chan) return (state == 1) ? 1 : 0; } -static int mv_chan_xor_slot_count(size_t len, int src_cnt) -{ - return 1; -} - /** * mv_xor_free_slots - flags descriptor slots for reuse * @slot: Slot to free @@ -204,7 +188,7 @@ static void mv_xor_free_slots(struct mv_xor_chan *mv_chan, dev_dbg(mv_chan_to_devp(mv_chan), "%s %d slot %p\n", __func__, __LINE__, slot); - slot->slots_per_op = 0; + slot->slot_used = 0; } @@ -222,7 +206,7 @@ static void mv_xor_start_new_chain(struct mv_xor_chan *mv_chan, /* set the hardware chain */ mv_chan_set_next_descriptor(mv_chan, sw_desc->async_tx.phys); - mv_chan->pending += sw_desc->slot_cnt; + mv_chan->pending++; mv_xor_issue_pending(&mv_chan->dmachan); } @@ -243,8 +227,6 @@ mv_xor_run_tx_complete_actions(struct mv_xor_desc_slot *desc, desc->async_tx.callback_param); dma_descriptor_unmap(&desc->async_tx); - if (desc->group_head) - desc->group_head = NULL; } /* run dependent operations */ @@ -361,19 +343,16 @@ static void mv_xor_tasklet(unsigned long data) } static struct mv_xor_desc_slot * -mv_xor_alloc_slots(struct mv_xor_chan *mv_chan, int num_slots, - int slots_per_op) +mv_xor_alloc_slot(struct mv_xor_chan *mv_chan) { - struct mv_xor_desc_slot *iter, *_iter, *alloc_start = NULL; - LIST_HEAD(chain); - int slots_found, retry = 0; + struct mv_xor_desc_slot *iter, *_iter; + int retry = 0; /* start search from the last allocated descrtiptor * if a contiguous allocation can not be found start searching * from the beginning of the list */ retry: - slots_found = 0; if (retry == 0) iter = mv_chan->last_used; else @@ -383,55 +362,29 @@ retry: list_for_each_entry_safe_continue( iter, _iter, &mv_chan->all_slots, slot_node) { + prefetch(_iter); prefetch(&_iter->async_tx); - if (iter->slots_per_op) { + if (iter->slot_used) { /* give up after finding the first busy slot * on the second pass through the list */ if (retry) break; - - slots_found = 0; continue; } - /* start the allocation if the slot is correctly aligned */ - if (!slots_found++) - alloc_start = iter; - - if (slots_found == num_slots) { - struct mv_xor_desc_slot *alloc_tail = NULL; - struct mv_xor_desc_slot *last_used = NULL; - iter = alloc_start; - while (num_slots) { - int i; - - /* pre-ack all but the last descriptor */ - async_tx_ack(&iter->async_tx); - - list_add_tail(&iter->chain_node, &chain); - alloc_tail = iter; - iter->async_tx.cookie = 0; - iter->slot_cnt = num_slots; - iter->xor_check_result = NULL; - for (i = 0; i < slots_per_op; i++) { - iter->slots_per_op = slots_per_op - i; - last_used = iter; - iter = list_entry(iter->slot_node.next, - struct mv_xor_desc_slot, - slot_node); - } - num_slots -= slots_per_op; - } - alloc_tail->group_head = alloc_start; - alloc_tail->async_tx.cookie = -EBUSY; - list_splice(&chain, &alloc_tail->tx_list); - mv_chan->last_used = last_used; - mv_desc_clear_next_desc(alloc_start); - mv_desc_clear_next_desc(alloc_tail); - return alloc_tail; - } + /* pre-ack descriptor */ + async_tx_ack(&iter->async_tx); + + iter->slot_used = 1; + INIT_LIST_HEAD(&iter->chain_node); + iter->async_tx.cookie = -EBUSY; + mv_chan->last_used = iter; + mv_desc_clear_next_desc(iter); + + return iter; + } if (!retry++) goto retry; @@ -448,7 +401,7 @@ mv_xor_tx_submit(struct dma_async_tx_descriptor *tx) { struct mv_xor_desc_slot *sw_desc = to_mv_xor_slot(tx); struct mv_xor_chan *mv_chan = to_mv_xor_chan(tx->chan); - struct mv_xor_desc_slot *grp_start, *old_chain_tail; + struct mv_xor_desc_slot *old_chain_tail; dma_cookie_t cookie; int new_hw_chain = 1; @@ -456,27 +409,24 @@ mv_xor_tx_submit(struct dma_async_tx_descriptor *tx) "%s sw_desc %p: async_tx %p\n", __func__, sw_desc, &sw_desc->async_tx); - grp_start = sw_desc->group_head; - spin_lock_bh(&mv_chan->lock); cookie = dma_cookie_assign(tx); if (list_empty(&mv_chan->chain)) - list_splice_init(&sw_desc->tx_list, &mv_chan->chain); + list_add_tail(&sw_desc->chain_node, &mv_chan->chain); else { new_hw_chain = 0; old_chain_tail = list_entry(mv_chan->chain.prev, struct mv_xor_desc_slot, chain_node); - list_splice_init(&grp_start->tx_list, - &old_chain_tail->chain_node); + list_add_tail(&sw_desc->chain_node, &mv_chan->chain); dev_dbg(mv_chan_to_devp(mv_chan), "Append to last desc %pa\n", &old_chain_tail->async_tx.phys); /* fix up the hardware chain */ - mv_desc_set_next_desc(old_chain_tail, grp_start->async_tx.phys); + mv_desc_set_next_desc(old_chain_tail, sw_desc->async_tx.phys); /* if the channel is not busy */ if (!mv_chan_is_busy(mv_chan)) { @@ -491,7 +441,7 @@ mv_xor_tx_submit(struct dma_async_tx_descriptor *tx) } if (new_hw_chain) - mv_xor_start_new_chain(mv_chan, grp_start); + mv_xor_start_new_chain(mv_chan, sw_desc); spin_unlock_bh(&mv_chan->lock); @@ -525,7 +475,6 @@ static int mv_xor_alloc_chan_resources(struct dma_chan *chan) slot->async_tx.tx_submit = mv_xor_tx_submit; INIT_LIST_HEAD(&slot->chain_node); INIT_LIST_HEAD(&slot->slot_node); - INIT_LIST_HEAD(&slot->tx_list); dma_desc = mv_chan->dma_desc_pool; slot->async_tx.phys = dma_desc + idx * MV_XOR_SLOT_SIZE; slot->idx = idx++; @@ -553,8 +502,7 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, unsigned int src_cnt, size_t len, unsigned long flags) { struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); - struct mv_xor_desc_slot *sw_desc, *grp_start; - int slot_cnt; + struct mv_xor_desc_slot *sw_desc; if (unlikely(len < MV_XOR_MIN_BYTE_COUNT)) return NULL; @@ -566,19 +514,15 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, __func__, src_cnt, len, &dest, flags); spin_lock_bh(&mv_chan->lock); - slot_cnt = mv_chan_xor_slot_count(len, src_cnt); - sw_desc = mv_xor_alloc_slots(mv_chan, slot_cnt, 1); + sw_desc = mv_xor_alloc_slot(mv_chan); if (sw_desc) { sw_desc->type = DMA_XOR; sw_desc->async_tx.flags = flags; - grp_start = sw_desc->group_head; - mv_desc_init(grp_start, flags); - mv_desc_set_byte_count(grp_start, len); - mv_desc_set_dest_addr(sw_desc->group_head, dest); + mv_desc_init(sw_desc, dest, len); sw_desc->unmap_src_cnt = src_cnt; sw_desc->unmap_len = len; while (src_cnt--) - mv_desc_set_src_addr(grp_start, src_cnt, src[src_cnt]); + mv_desc_set_src_addr(sw_desc, src_cnt, src[src_cnt]); } spin_unlock_bh(&mv_chan->lock); dev_dbg(mv_chan_to_devp(mv_chan), diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h index d074922..e03021e 100644 --- a/drivers/dma/mv_xor.h +++ b/drivers/dma/mv_xor.h @@ -110,9 +110,7 @@ struct mv_xor_chan { * @completed_node: node on the mv_xor_chan.completed_slots list * @hw_desc: virtual address of the hardware descriptor chain * @phys: hardware address of the hardware descriptor chain - * @group_head: first operation in a transaction - * @slot_cnt: total slots used in an transaction (group of operations) - * @slots_per_op: number of slots per operation + * @slot_used: slot in use or not * @idx: pool index * @unmap_src_cnt: number of xor sources * @unmap_len: transaction bytecount @@ -127,14 +125,11 @@ struct mv_xor_desc_slot { struct list_head completed_node; enum dma_transaction_type type; void *hw_desc; - struct mv_xor_desc_slot *group_head; - u16 slot_cnt; - u16 slots_per_op; + u16 slot_used; u16 idx; u16 unmap_src_cnt; u32 value; size_t unmap_len; - struct list_head tx_list; struct dma_async_tx_descriptor async_tx; union { u32 *xor_check_result; -- cgit v0.10.2 From 0e7488ed01235fdd24ce7f0295dbbea0d45311bb Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 27 Aug 2014 10:52:52 -0300 Subject: dma: mv_xor: Remove all interrupt magic numbers This commit replaces the current magic numbers in the interrupt handling with proper macros, which makes more readable and self-documenting. While here replace the BUG() with a noisy WARN_ON(). There's no reason to tear down the entire system for an DMA IRQ error. Signed-off-by: Ezequiel Garcia Signed-off-by: Vinod Koul diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index a30e221..4ee5bb1 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -50,9 +50,9 @@ static void mv_desc_init(struct mv_xor_desc_slot *desc, { struct mv_xor_desc *hw_desc = desc->hw_desc; - hw_desc->status = (1 << 31); + hw_desc->status = XOR_DESC_DMA_OWNED; hw_desc->phy_next_desc = 0; - hw_desc->desc_command = (1 << 31); + hw_desc->desc_command = XOR_DESC_EOD_INT_EN; hw_desc->phy_dest_addr = addr; hw_desc->byte_count = byte_count; } @@ -105,17 +105,9 @@ static u32 mv_chan_get_intr_cause(struct mv_xor_chan *chan) return intr_cause; } -static int mv_is_err_intr(u32 intr_cause) -{ - if (intr_cause & ((1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9))) - return 1; - - return 0; -} - static void mv_xor_device_clear_eoc_cause(struct mv_xor_chan *chan) { - u32 val = ~(1 << (chan->idx * 16)); + u32 val = ~(XOR_INT_END_OF_DESC << (chan->idx * 16)); dev_dbg(mv_chan_to_devp(chan), "%s, val 0x%08x\n", __func__, val); writel_relaxed(val, XOR_INTR_CAUSE(chan)); } @@ -627,18 +619,16 @@ static void mv_dump_xor_regs(struct mv_xor_chan *chan) static void mv_xor_err_interrupt_handler(struct mv_xor_chan *chan, u32 intr_cause) { - if (intr_cause & (1 << 4)) { - dev_dbg(mv_chan_to_devp(chan), - "ignore this error\n"); - return; + if (intr_cause & XOR_INT_ERR_DECODE) { + dev_dbg(mv_chan_to_devp(chan), "ignoring address decode error\n"); + return; } - dev_err(mv_chan_to_devp(chan), - "error on chan %d. intr cause 0x%08x\n", + dev_err(mv_chan_to_devp(chan), "error on chan %d. intr cause 0x%08x\n", chan->idx, intr_cause); mv_dump_xor_regs(chan); - BUG(); + WARN_ON(1); } static irqreturn_t mv_xor_interrupt_handler(int irq, void *data) @@ -648,7 +638,7 @@ static irqreturn_t mv_xor_interrupt_handler(int irq, void *data) dev_dbg(mv_chan_to_devp(chan), "intr cause %x\n", intr_cause); - if (mv_is_err_intr(intr_cause)) + if (intr_cause & XOR_INTR_ERRORS) mv_xor_err_interrupt_handler(chan, intr_cause); tasklet_schedule(&chan->irq_tasklet); diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h index e03021e..ae41c31 100644 --- a/drivers/dma/mv_xor.h +++ b/drivers/dma/mv_xor.h @@ -34,6 +34,9 @@ #define XOR_OPERATION_MODE_MEMCPY 2 #define XOR_DESCRIPTOR_SWAP BIT(14) +#define XOR_DESC_DMA_OWNED BIT(31) +#define XOR_DESC_EOD_INT_EN BIT(31) + #define XOR_CURR_DESC(chan) (chan->mmr_high_base + 0x10 + (chan->idx * 4)) #define XOR_NEXT_DESC(chan) (chan->mmr_high_base + 0x00 + (chan->idx * 4)) #define XOR_BYTE_COUNT(chan) (chan->mmr_high_base + 0x20 + (chan->idx * 4)) @@ -48,7 +51,24 @@ #define XOR_INTR_MASK(chan) (chan->mmr_base + 0x40) #define XOR_ERROR_CAUSE(chan) (chan->mmr_base + 0x50) #define XOR_ERROR_ADDR(chan) (chan->mmr_base + 0x60) -#define XOR_INTR_MASK_VALUE 0x3F5 + +#define XOR_INT_END_OF_DESC BIT(0) +#define XOR_INT_END_OF_CHAIN BIT(1) +#define XOR_INT_STOPPED BIT(2) +#define XOR_INT_PAUSED BIT(3) +#define XOR_INT_ERR_DECODE BIT(4) +#define XOR_INT_ERR_RDPROT BIT(5) +#define XOR_INT_ERR_WRPROT BIT(6) +#define XOR_INT_ERR_OWN BIT(7) +#define XOR_INT_ERR_PAR BIT(8) +#define XOR_INT_ERR_MBUS BIT(9) + +#define XOR_INTR_ERRORS (XOR_INT_ERR_DECODE | XOR_INT_ERR_RDPROT | \ + XOR_INT_ERR_WRPROT | XOR_INT_ERR_OWN | \ + XOR_INT_ERR_PAR | XOR_INT_ERR_MBUS) + +#define XOR_INTR_MASK_VALUE (XOR_INT_END_OF_DESC | \ + XOR_INT_STOPPED | XOR_INTR_ERRORS) #define WINDOW_BASE(w) (0x50 + ((w) << 2)) #define WINDOW_SIZE(w) (0x70 + ((w) << 2)) -- cgit v0.10.2 From ba87d13721b6fe4a2479871dc4f77c5bd8db3c32 Mon Sep 17 00:00:00 2001 From: Lior Amsalem Date: Wed, 27 Aug 2014 10:52:53 -0300 Subject: dma: mv_xor: Reduce interrupts by enabling EOD only when needed This commit unmasks the end-of-chain interrupt and removes the end-of-descriptor command setting on all transactions, except those explicitly flagged with DMA_PREP_INTERRUPT. This allows to raise an interrupt only on chain completion, instead of on each descriptor completion, which reduces interrupt count. Signed-off-by: Lior Amsalem Signed-off-by: Ezequiel Garcia Signed-off-by: Vinod Koul diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 4ee5bb1..cbc90e5 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -46,13 +46,16 @@ static void mv_xor_issue_pending(struct dma_chan *chan); ((chan)->dmadev.dev) static void mv_desc_init(struct mv_xor_desc_slot *desc, - dma_addr_t addr, u32 byte_count) + dma_addr_t addr, u32 byte_count, + enum dma_ctrl_flags flags) { struct mv_xor_desc *hw_desc = desc->hw_desc; hw_desc->status = XOR_DESC_DMA_OWNED; hw_desc->phy_next_desc = 0; - hw_desc->desc_command = XOR_DESC_EOD_INT_EN; + /* Enable end-of-descriptor interrupts only for DMA_PREP_INTERRUPT */ + hw_desc->desc_command = (flags & DMA_PREP_INTERRUPT) ? + XOR_DESC_EOD_INT_EN : 0; hw_desc->phy_dest_addr = addr; hw_desc->byte_count = byte_count; } @@ -107,7 +110,10 @@ static u32 mv_chan_get_intr_cause(struct mv_xor_chan *chan) static void mv_xor_device_clear_eoc_cause(struct mv_xor_chan *chan) { - u32 val = ~(XOR_INT_END_OF_DESC << (chan->idx * 16)); + u32 val; + + val = XOR_INT_END_OF_DESC | XOR_INT_END_OF_CHAIN | XOR_INT_STOPPED; + val = ~(val << (chan->idx * 16)); dev_dbg(mv_chan_to_devp(chan), "%s, val 0x%08x\n", __func__, val); writel_relaxed(val, XOR_INTR_CAUSE(chan)); } @@ -510,7 +516,7 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, if (sw_desc) { sw_desc->type = DMA_XOR; sw_desc->async_tx.flags = flags; - mv_desc_init(sw_desc, dest, len); + mv_desc_init(sw_desc, dest, len, flags); sw_desc->unmap_src_cnt = src_cnt; sw_desc->unmap_len = len; while (src_cnt--) diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h index ae41c31..21b0828 100644 --- a/drivers/dma/mv_xor.h +++ b/drivers/dma/mv_xor.h @@ -67,7 +67,7 @@ XOR_INT_ERR_WRPROT | XOR_INT_ERR_OWN | \ XOR_INT_ERR_PAR | XOR_INT_ERR_MBUS) -#define XOR_INTR_MASK_VALUE (XOR_INT_END_OF_DESC | \ +#define XOR_INTR_MASK_VALUE (XOR_INT_END_OF_DESC | XOR_INT_END_OF_CHAIN | \ XOR_INT_STOPPED | XOR_INTR_ERRORS) #define WINDOW_BASE(w) (0x50 + ((w) << 2)) -- cgit v0.10.2 From 37380b980e2db2e0dfdb920140c75f3cf2e98a27 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 27 Aug 2014 10:52:54 -0300 Subject: dma: mv_xor: Remove dead code The driver currently defines the USE_TIMER macro, but the timer-feature is never used in the code. The XOR and CRC32 results are never used. The 'unmap_xxx' fields are no longer needed, they were made obsolete in commit: 54f8d501e842 dmaengine: remove DMA unmap from drivers. Let's remove all this dead code. Signed-off-by: Ezequiel Garcia Signed-off-by: Vinod Koul diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index cbc90e5..744a007 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -517,8 +517,6 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, sw_desc->type = DMA_XOR; sw_desc->async_tx.flags = flags; mv_desc_init(sw_desc, dest, len, flags); - sw_desc->unmap_src_cnt = src_cnt; - sw_desc->unmap_len = len; while (src_cnt--) mv_desc_set_src_addr(sw_desc, src_cnt, src[src_cnt]); } diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h index 21b0828..de40036 100644 --- a/drivers/dma/mv_xor.h +++ b/drivers/dma/mv_xor.h @@ -23,7 +23,6 @@ #include #include -#define USE_TIMER #define MV_XOR_POOL_SIZE PAGE_SIZE #define MV_XOR_SLOT_SIZE 64 #define MV_XOR_THRESHOLD 1 @@ -117,10 +116,6 @@ struct mv_xor_chan { struct list_head all_slots; int slots_allocated; struct tasklet_struct irq_tasklet; -#ifdef USE_TIMER - unsigned long cleanup_time; - u32 current_on_last_cleanup; -#endif }; /** @@ -132,12 +127,8 @@ struct mv_xor_chan { * @phys: hardware address of the hardware descriptor chain * @slot_used: slot in use or not * @idx: pool index - * @unmap_src_cnt: number of xor sources - * @unmap_len: transaction bytecount * @tx_list: list of slots that make up a multi-descriptor transaction * @async_tx: support for the async_tx api - * @xor_check_result: result of zero sum - * @crc32_result: result crc calculation */ struct mv_xor_desc_slot { struct list_head slot_node; @@ -147,18 +138,7 @@ struct mv_xor_desc_slot { void *hw_desc; u16 slot_used; u16 idx; - u16 unmap_src_cnt; - u32 value; - size_t unmap_len; struct dma_async_tx_descriptor async_tx; - union { - u32 *xor_check_result; - u32 *crc32_result; - }; -#ifdef USE_TIMER - unsigned long arrival_time; - struct timer_list timeout; -#endif }; /* -- cgit v0.10.2 From 22843545b20007ae33bc3774043303e0b44e3d65 Mon Sep 17 00:00:00 2001 From: Lior Amsalem Date: Wed, 27 Aug 2014 10:52:55 -0300 Subject: dma: mv_xor: Add support for DMA_INTERRUPT The driver is capable of supporting DMA_INTERRUPT by issuing a dummy 128-byte transfer. This helps removing a poll in the async_tx stack, replacing it with a completion interrupt. Signed-off-by: Lior Amsalem Signed-off-by: Ezequiel Garcia Signed-off-by: Vinod Koul diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 744a007..769d35c 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -538,6 +538,24 @@ mv_xor_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, return mv_xor_prep_dma_xor(chan, dest, &src, 1, len, flags); } +static struct dma_async_tx_descriptor * +mv_xor_prep_dma_interrupt(struct dma_chan *chan, unsigned long flags) +{ + struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); + dma_addr_t src, dest; + size_t len; + + src = mv_chan->dummy_src_addr; + dest = mv_chan->dummy_dst_addr; + len = MV_XOR_MIN_BYTE_COUNT; + + /* + * We implement the DMA_INTERRUPT operation as a minimum sized + * XOR operation with a single dummy source address. + */ + return mv_xor_prep_dma_xor(chan, dest, &src, 1, len, flags); +} + static void mv_xor_free_chan_resources(struct dma_chan *chan) { struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); @@ -881,6 +899,10 @@ static int mv_xor_channel_remove(struct mv_xor_chan *mv_chan) dma_free_coherent(dev, MV_XOR_POOL_SIZE, mv_chan->dma_desc_pool_virt, mv_chan->dma_desc_pool); + dma_unmap_single(dev, mv_chan->dummy_src_addr, + MV_XOR_MIN_BYTE_COUNT, DMA_FROM_DEVICE); + dma_unmap_single(dev, mv_chan->dummy_dst_addr, + MV_XOR_MIN_BYTE_COUNT, DMA_TO_DEVICE); list_for_each_entry_safe(chan, _chan, &mv_chan->dmadev.channels, device_node) { @@ -910,6 +932,16 @@ mv_xor_channel_add(struct mv_xor_device *xordev, dma_dev = &mv_chan->dmadev; + /* + * These source and destination dummy buffers are used to implement + * a DMA_INTERRUPT operation as a minimum-sized XOR operation. + * Hence, we only need to map the buffers at initialization-time. + */ + mv_chan->dummy_src_addr = dma_map_single(dma_dev->dev, + mv_chan->dummy_src, MV_XOR_MIN_BYTE_COUNT, DMA_FROM_DEVICE); + mv_chan->dummy_dst_addr = dma_map_single(dma_dev->dev, + mv_chan->dummy_dst, MV_XOR_MIN_BYTE_COUNT, DMA_TO_DEVICE); + /* allocate coherent memory for hardware descriptors * note: writecombine gives slightly better performance, but * requires that we explicitly flush the writes @@ -934,6 +966,8 @@ mv_xor_channel_add(struct mv_xor_device *xordev, dma_dev->dev = &pdev->dev; /* set prep routines based on capability */ + if (dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask)) + dma_dev->device_prep_dma_interrupt = mv_xor_prep_dma_interrupt; if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) dma_dev->device_prep_dma_memcpy = mv_xor_prep_dma_memcpy; if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) { diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h index de40036..78edc7e 100644 --- a/drivers/dma/mv_xor.h +++ b/drivers/dma/mv_xor.h @@ -28,6 +28,9 @@ #define MV_XOR_THRESHOLD 1 #define MV_XOR_MAX_CHANNELS 2 +#define MV_XOR_MIN_BYTE_COUNT SZ_128 +#define MV_XOR_MAX_BYTE_COUNT (SZ_16M - 1) + /* Values for the XOR_CONFIG register */ #define XOR_OPERATION_MODE_XOR 0 #define XOR_OPERATION_MODE_MEMCPY 2 @@ -116,6 +119,9 @@ struct mv_xor_chan { struct list_head all_slots; int slots_allocated; struct tasklet_struct irq_tasklet; + char dummy_src[MV_XOR_MIN_BYTE_COUNT]; + char dummy_dst[MV_XOR_MIN_BYTE_COUNT]; + dma_addr_t dummy_src_addr, dummy_dst_addr; }; /** @@ -184,9 +190,4 @@ struct mv_xor_desc { #define mv_hw_desc_slot_idx(hw_desc, idx) \ ((void *)(((unsigned long)hw_desc) + ((idx) << 5))) -#define MV_XOR_MIN_BYTE_COUNT (128) -#define XOR_MAX_BYTE_COUNT ((16 * 1024 * 1024) - 1) -#define MV_XOR_MAX_BYTE_COUNT XOR_MAX_BYTE_COUNT - - #endif -- cgit v0.10.2 From d9ff958bb34aabdce08d11b0db24123c093d87cd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 20 Aug 2014 19:20:53 +0200 Subject: dmaengine: Mark the struct dma_slave_config direction field deprecated The direction passed to the device_prep_slave_sg, device_prep_dma_cyclic or device_prep_interleaved_dma (through struct dma_interleaved_template) should be used instead. Signed-off-by: Laurent Pinchart Signed-off-by: Vinod Koul diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 1f9e642..3d291f5 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -307,7 +307,9 @@ enum dma_slave_buswidth { * struct dma_slave_config - dma slave channel runtime config * @direction: whether the data shall go in or out on this slave * channel, right now. DMA_MEM_TO_DEV and DMA_DEV_TO_MEM are - * legal values. + * legal values. DEPRECATED, drivers should use the direction argument + * to the device_prep_slave_sg and device_prep_dma_cyclic functions or + * the dir field in the dma_interleaved_template structure. * @src_addr: this is the physical address where DMA slave data * should be read (RX), if the source is memory this argument is * ignored. -- cgit v0.10.2 From c2e6f424a4abc9bb561133b00b2134ce11be34e9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Aug 2014 15:19:44 +0300 Subject: dmatest: prevent memory leakage on error path in thread When we fail to allocate memory for thread->srcs or thread->dsts and src_cnt or dst_cnt great than 1 we leak memory on error path. This patch fixes the issue. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index e27cec2..a8d7809 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -688,14 +688,14 @@ static int dmatest_func(void *data) runtime = ktime_us_delta(ktime_get(), ktime); ret = 0; +err_dstbuf: for (i = 0; thread->dsts[i]; i++) kfree(thread->dsts[i]); -err_dstbuf: kfree(thread->dsts); err_dsts: +err_srcbuf: for (i = 0; thread->srcs[i]; i++) kfree(thread->srcs[i]); -err_srcbuf: kfree(thread->srcs); err_srcs: kfree(pq_coefs); -- cgit v0.10.2 From 50cf5534df852d30f1fd07030c2084b708a88308 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 28 Aug 2014 13:50:19 -0300 Subject: dma: Kconfig: Include mx6 in the IMX_SDMA help section MX6 processors also use the IMX_SDMA driver, so include it in the help text. Signed-off-by: Fabio Estevam Signed-off-by: Vinod Koul diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 9b1ea0e..9621671 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -270,7 +270,7 @@ config IMX_SDMA select DMA_ENGINE help Support the i.MX SDMA engine. This engine is integrated into - Freescale i.MX25/31/35/51/53 chips. + Freescale i.MX25/31/35/51/53/6 chips. config IMX_DMA tristate "i.MX DMA support" -- cgit v0.10.2 From 14e0e2833d44f61cb8168d04e979a2bfbc0f4bfb Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sat, 6 Sep 2014 18:47:28 +0800 Subject: dmaengine: sun6i: Remove obsolete clk muxing code The sun6i DMA controller requires the AHB1 bus clock to be clocked from PLL6. This was originally done by the dmaengine driver during probe time. The AHB1 clock driver has since been unified, so the original code does not work. Remove the clk muxing code, and replace it with DT clk default properties. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Vinod Koul diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c index 1f92a56..3aa10b3 100644 --- a/drivers/dma/sun6i-dma.c +++ b/drivers/dma/sun6i-dma.c @@ -862,7 +862,6 @@ static int sun6i_dma_probe(struct platform_device *pdev) { struct sun6i_dma_dev *sdc; struct resource *res; - struct clk *mux, *pll6; int ret, i; sdc = devm_kzalloc(&pdev->dev, sizeof(*sdc), GFP_KERNEL); @@ -886,28 +885,6 @@ static int sun6i_dma_probe(struct platform_device *pdev) return PTR_ERR(sdc->clk); } - mux = clk_get(NULL, "ahb1_mux"); - if (IS_ERR(mux)) { - dev_err(&pdev->dev, "Couldn't get AHB1 Mux\n"); - return PTR_ERR(mux); - } - - pll6 = clk_get(NULL, "pll6"); - if (IS_ERR(pll6)) { - dev_err(&pdev->dev, "Couldn't get PLL6\n"); - clk_put(mux); - return PTR_ERR(pll6); - } - - ret = clk_set_parent(mux, pll6); - clk_put(pll6); - clk_put(mux); - - if (ret) { - dev_err(&pdev->dev, "Couldn't reparent AHB1 on PLL6\n"); - return ret; - } - sdc->rstc = devm_reset_control_get(&pdev->dev, NULL); if (IS_ERR(sdc->rstc)) { dev_err(&pdev->dev, "No reset controller specified\n"); -- cgit v0.10.2 From fe6cf28936cc948cd1045568975c5b0d196e76d4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 26 Sep 2014 23:24:00 +0200 Subject: dma: imx-sdma: fix another incorrect __init annotation In e34b731faa7d1 ("dma: imx-sdma: Remove spurious __init annotation on sdma_probe()"), Mark found an extraneous __init label and fixed it. However, he missed another one, because now we get this other warning: WARNING: drivers/dma/imx-sdma.o(.text+0x3bb4): Section mismatch in reference from the function sdma_probe() to the function .init.text:sdma_get_firmware() The function sdma_probe() references the function __init sdma_get_firmware(). Same reasoning as the last time, the function may get called at runtime, so it can't be __init. Signed-off-by: Arnd Bergmann Signed-off-by: Vinod Koul diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 52ce1d2..88afc48 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1334,7 +1334,7 @@ err_firmware: release_firmware(fw); } -static int __init sdma_get_firmware(struct sdma_engine *sdma, +static int sdma_get_firmware(struct sdma_engine *sdma, const char *fw_name) { int ret; -- cgit v0.10.2 From 937cb2f2498dcbd8bcf6d79dcc24e5c8a3627067 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 29 Sep 2014 14:42:18 +0200 Subject: dmaengine: pl330: Remove non-NULL check for pl330_submit_req parameters The pl330_submit_req() checked supplied 'struct pl330_thread thrd' and 'struct dma_pl330_desc desc' parameters for non-NULL. However these checks are useless because supplied arguments won't be NULL. The pl330_submit_req() is called in only one place and: 1. 'desc' is already dereferenced in fill_queue() before calling pl330_submit_req(). 2. 'thrd' is always dereferenced after calling fill_queue()->pl330_submit_req(). Removing the checks for non-NULL values fixes following warning: drivers/dma/pl330.c:1376 pl330_submit_req() warn: variable dereferenced before check 'thrd' (see line 1367) Signed-off-by: Krzysztof Kozlowski Signed-off-by: Vinod Koul diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index d5149aa..57049f8 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -1372,10 +1372,6 @@ static int pl330_submit_req(struct pl330_thread *thrd, u32 ccr; int ret = 0; - /* No Req or Unacquired Channel or DMAC */ - if (!desc || !thrd || thrd->free) - return -EINVAL; - regs = thrd->dmac->base; if (pl330->state == DYING -- cgit v0.10.2 From c3cb38f43cb9130a3727a24a6a6e74742bd3e910 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 29 Sep 2014 14:42:19 +0200 Subject: dmaengine: pl330: Remove unused 'regs' variable in pl330_submit_req() The 'void __iomem *regs' is not used in pl330_submit_req() function. Remove it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Vinod Koul diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 57049f8..28e3775 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -1367,13 +1367,10 @@ static int pl330_submit_req(struct pl330_thread *thrd, struct pl330_dmac *pl330 = thrd->dmac; struct _xfer_spec xs; unsigned long flags; - void __iomem *regs; unsigned idx; u32 ccr; int ret = 0; - regs = thrd->dmac->base; - if (pl330->state == DYING || pl330->dmac_tbd.reset_chan & (1 << thrd->id)) { dev_info(thrd->dmac->ddma.dev, "%s:%d\n", -- cgit v0.10.2 From 0f5ebabdd03b471da1906f7edddc61ceb35cee02 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 29 Sep 2014 14:42:20 +0200 Subject: dmaengine: pl330: Fix NULL pointer dereference on probe failure If dma_async_device_register() returns error and probe should clean up and return error, a NULL pointer exception happens because of dereference of not allocated channel thread: Dmesg log (from early printk): dma-pl330 12680000.pdma: unable to register DMAC DMA pl330_control: removing pch: eeac4000, chan: eeac4014, thread: (null) Unable to handle kernel NULL pointer dereference at virtual address 0000000c pgd = c0004000 [0000000c] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP ARM Modules linked in: CPU: 2 PID: 1 Comm: swapper/0 Not tainted 3.17.0-rc3-next-20140904-00005-g6cc4c1937d90-dirty #427 task: ee80a800 ti: ee888000 task.ti: ee888000 PC is at _stop+0x8/0x2c8 LR is at pl330_control+0x70/0x2e8 pc : [] lr : [] psr: 60000193 sp : ee889df8 ip : 00000002 fp : 00000000 r10: eeac4014 r9 : ee0e62bc r8 : 00000000 r7 : eeac405c r6 : 60000113 r5 : ee0e6210 r4 : eeac4000 r3 : 00000002 r2 : 00000002 r1 : 00010000 r0 : 00000000 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c5387d Table: 4000404a DAC: 00000015 Process swapper/0 (pid: 1, stack limit = 0xee888240) Stack: (0xee889df8 to 0xee88a000) 9de0: 00000002 eeac4000 9e00: ee0e6210 eeac4000 ee0e6210 60000113 eeac405c c020623c 00000000 c020725c 9e20: ee889e20 ee889e20 ee0e6210 eeac4080 00200200 00100100 eeac4014 00000020 9e40: ee0e6218 c0208374 00000000 ee9bb340 ee0e6210 00000000 00000000 c0605cd8 9e60: ee970000 c0605c84 ee9700f8 00000000 c05c4270 00000000 00000000 c0203b3c 9e80: ee970000 c06624a8 00000000 c0605c84 00000000 c023f890 ee970000 c0605c84 9ea0: ee970034 00000000 c05b23d0 c023fa3c 00000000 c0605c84 c023f9b0 c023e0d4 9ec0: ee947e78 ee9b9440 c0605c84 eea1e780 c0605acc c023f094 c0513b50 c0605c84 9ee0: c05ecbd8 c0605c84 c05ecbd8 ee11ba40 c0626500 c0240064 00000000 c05ecbd8 9f00: c05ecbd8 c0008964 c040f13c 0000009f c0626500 c057465c ee80a800 60000113 9f20: 00000000 c05efdb0 60000113 00000000 ef7fc89d c0421168 0000008f c003787c 9f40: c0573d6c 00000006 ef7fc8bb 00000006 c05efd50 ef7fc800 c05dfbc4 00000006 9f60: c05c4264 c0626500 0000008f c05c4270 c059b518 c059bcb4 00000006 00000006 9f80: c059b518 c003c08c 00000000 c040091c 00000000 00000000 00000000 00000000 9fa0: 00000000 c0400924 00000000 c000e7b8 00000000 00000000 00000000 00000000 9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 9fe0: 00000000 00000000 00000000 00000000 00000013 00000000 c0c0c0c0 c0c0c0c0 [] (_stop) from [] (pl330_control+0x70/0x2e8) [] (pl330_control) from [] (pl330_probe+0x594/0x75c) [] (pl330_probe) from [] (amba_probe+0xb8/0x120) [] (amba_probe) from [] (driver_probe_device+0x10c/0x22c) [] (driver_probe_device) from [] (__driver_attach+0x8c/0x90) [] (__driver_attach) from [] (bus_for_each_dev+0x54/0x88) [] (bus_for_each_dev) from [] (bus_add_driver+0xd4/0x1d0) [] (bus_add_driver) from [] (driver_register+0x78/0xf4) [] (driver_register) from [] (do_one_initcall+0x80/0x1d0) [] (do_one_initcall) from [] (kernel_init_freeable+0x108/0x1d4) [] (kernel_init_freeable) from [] (kernel_init+0x8/0xec) [] (kernel_init) from [] (ret_from_fork+0x14/0x3c) Code: e5813010 e12fff1e e92d40f0 e24dd00c (e590200c) ---[ end trace c94b2f4f38dff3bf ]--- This happens because the necessary resources were not yet allocated - no call to pl330_alloc_chan_resources(). Terminate the thread and free channel resource only if channel thread is not NULL. Signed-off-by: Krzysztof Kozlowski Cc: Fixes: 0b94c5771705 ("DMA: PL330: Add check if device tree compatible") Reviewed-by: Lars-Peter Clausen Signed-off-by: Vinod Koul diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 28e3775..4a2caaa 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2748,8 +2748,10 @@ probe_err3: list_del(&pch->chan.device_node); /* Flush the channel */ - pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0); - pl330_free_chan_resources(&pch->chan); + if (pch->thread) { + pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0); + pl330_free_chan_resources(&pch->chan); + } } probe_err2: pl330_del(pl330); -- cgit v0.10.2 From 6e4a2a83f95826201bbd89f55522537ea52d1d67 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 29 Sep 2014 14:42:21 +0200 Subject: dmaengine: pl330: Fix NULL pointer dereference on driver unbind Fix a NULL pointer dereference after unbinding the driver, if channel resources were not yet allocated (no call to pl330_alloc_chan_resources()): $ echo 12850000.mdma > /sys/bus/amba/drivers/dma-pl330/unbind [ 13.606533] DMA pl330_control: removing pch: eeab6800, chan: eeab6814, thread: (null) [ 13.614472] Unable to handle kernel NULL pointer dereference at virtual address 0000000c [ 13.622537] pgd = ee284000 [ 13.625228] [0000000c] *pgd=6e1e4831, *pte=00000000, *ppte=00000000 [ 13.631482] Internal error: Oops: 17 [#1] PREEMPT SMP ARM [ 13.636859] Modules linked in: [ 13.639903] CPU: 0 PID: 1 Comm: sh Not tainted 3.17.0-rc3-next-20140904-00004-g7020ffc33ca3-dirty #420 [ 13.649187] task: ee80a800 ti: ee888000 task.ti: ee888000 [ 13.654589] PC is at _stop+0x8/0x2c8 [ 13.658131] LR is at pl330_control+0x70/0x2e8 [ 13.662468] pc : [] lr : [] psr: 60000093 [ 13.662468] sp : ee889e58 ip : 00000001 fp : 000bab70 [ 13.673922] r10: eeab6814 r9 : ee16debc r8 : 00000000 [ 13.679131] r7 : eeab685c r6 : 60000013 r5 : ee16de10 r4 : eeab6800 [ 13.685641] r3 : 00000002 r2 : 00000000 r1 : 00010000 r0 : 00000000 [ 13.692153] Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user [ 13.699357] Control: 10c5387d Table: 6e28404a DAC: 00000015 [ 13.705085] Process sh (pid: 1, stack limit = 0xee888240) [ 13.710466] Stack: (0xee889e58 to 0xee88a000) [ 13.714808] 9e40: 00000002 eeab6800 [ 13.722969] 9e60: ee16de10 eeab6800 ee16de10 60000013 eeab685c c020649c 00000000 c040280c [ 13.731128] 9e80: ee889e80 ee889e80 ee16de18 ee16de10 eeab6880 eeab6814 00200200 eeab68a8 [ 13.739287] 9ea0: 00100100 c0208048 00000000 c0409fc4 eea80800 eea808f8 c0605c44 0000000e [ 13.747446] 9ec0: 0000000e eeb3960c eeb39600 c0203c48 eea80800 c0605c44 c0605a8c c023f694 [ 13.755605] 9ee0: ee80a800 eea80834 eea80800 c023f704 ee80a800 eea80800 c0605c44 c023e8ec [ 13.763764] 9f00: 0000000e ee149780 ee29e580 ee889f80 ee29e580 c023e19c 0000000e c01167e4 [ 13.771923] 9f20: c01167a0 00000000 00000000 c0115e88 00000000 00000000 ee0b1a00 0000000e [ 13.780082] 9f40: b6f48000 ee889f80 0000000e ee888000 b6f48000 c00bfadc 00000000 00000003 [ 13.788241] 9f60: 00000000 00000000 00000000 ee0b1a00 ee0b1a00 0000000e b6f48000 c00bfdf4 [ 13.796401] 9f80: 00000000 00000000 ffffffff 0000000e b6f48000 b6edc5d0 00000004 c000e7a4 [ 13.804560] 9fa0: 00000000 c000e620 0000000e b6f48000 00000001 b6f48000 0000000e 00000000 [ 13.812719] 9fc0: 0000000e b6f48000 b6edc5d0 00000004 0000000e b6f4c8c0 000c3470 000bab70 [ 13.820879] 9fe0: 00000000 bed2aa50 b6e18bdc b6e6b52c 60000010 00000001 c0c0c0c0 c0c0c0c0 [ 13.829058] [] (_stop) from [] (pl330_control+0x70/0x2e8) [ 13.836165] [] (pl330_control) from [] (pl330_remove+0xb0/0xdc) [ 13.843800] [] (pl330_remove) from [] (amba_remove+0x24/0xc0) [ 13.851272] [] (amba_remove) from [] (__device_release_driver+0x70/0xc4) [ 13.859685] [] (__device_release_driver) from [] (device_release_driver+0x1c/0x28) [ 13.868971] [] (device_release_driver) from [] (unbind_store+0x58/0x90) [ 13.877303] [] (unbind_store) from [] (drv_attr_store+0x20/0x2c) [ 13.885036] [] (drv_attr_store) from [] (sysfs_kf_write+0x44/0x48) [ 13.892928] [] (sysfs_kf_write) from [] (kernfs_fop_write+0xc0/0x17c) [ 13.901090] [] (kernfs_fop_write) from [] (vfs_write+0xa0/0x1a8) [ 13.908812] [] (vfs_write) from [] (SyS_write+0x40/0x8c) [ 13.915850] [] (SyS_write) from [] (ret_fast_syscall+0x0/0x30) [ 13.923392] Code: e5813010 e12fff1e e92d40f0 e24dd00c (e590200c) [ 13.929467] ---[ end trace 10064e15a5929cf8 ]--- Terminate the thread and free channel resource only if channel resources were allocated (thread is not NULL). Signed-off-by: Krzysztof Kozlowski Cc: Fixes: b3040e40675e ("DMA: PL330: Add dma api driver") Reviewed-by: Lars-Peter Clausen Signed-off-by: Vinod Koul diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 4a2caaa..4839bfa 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2777,8 +2777,10 @@ static int pl330_remove(struct amba_device *adev) list_del(&pch->chan.device_node); /* Flush the channel */ - pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0); - pl330_free_chan_resources(&pch->chan); + if (pch->thread) { + pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0); + pl330_free_chan_resources(&pch->chan); + } } pl330_del(pl330); -- cgit v0.10.2 From f0f3b5fa7537e13dfd20b4cd399f00545f9fc0e7 Mon Sep 17 00:00:00 2001 From: Kiran Padwal Date: Wed, 24 Sep 2014 15:53:46 +0530 Subject: dma: cppi41: Switch to using managed resource in probe This change uses managed resource APIs to allocate resources such as, mem, irq in order to simplify the driver unload or failure cases Signed-off-by: Kiran Padwal Signed-off-by: Vinod Koul diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c index 8f8b0b6..a58eec3 100644 --- a/drivers/dma/cppi41.c +++ b/drivers/dma/cppi41.c @@ -938,7 +938,7 @@ static int cppi41_dma_probe(struct platform_device *pdev) if (!glue_info) return -EINVAL; - cdd = kzalloc(sizeof(*cdd), GFP_KERNEL); + cdd = devm_kzalloc(&pdev->dev, sizeof(*cdd), GFP_KERNEL); if (!cdd) return -ENOMEM; @@ -959,10 +959,8 @@ static int cppi41_dma_probe(struct platform_device *pdev) cdd->qmgr_mem = of_iomap(dev->of_node, 3); if (!cdd->usbss_mem || !cdd->ctrl_mem || !cdd->sched_mem || - !cdd->qmgr_mem) { - ret = -ENXIO; - goto err_remap; - } + !cdd->qmgr_mem) + return -ENXIO; pm_runtime_enable(dev); ret = pm_runtime_get_sync(dev); @@ -989,7 +987,7 @@ static int cppi41_dma_probe(struct platform_device *pdev) cppi_writel(USBSS_IRQ_PD_COMP, cdd->usbss_mem + USBSS_IRQ_ENABLER); - ret = request_irq(irq, glue_info->isr, IRQF_SHARED, + ret = devm_request_irq(&pdev->dev, irq, glue_info->isr, IRQF_SHARED, dev_name(dev), cdd); if (ret) goto err_irq; @@ -1009,7 +1007,6 @@ static int cppi41_dma_probe(struct platform_device *pdev) err_of: dma_async_device_unregister(&cdd->ddev); err_dma_reg: - free_irq(irq, cdd); err_irq: cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR); cleanup_chans(cdd); @@ -1023,8 +1020,6 @@ err_get_sync: iounmap(cdd->ctrl_mem); iounmap(cdd->sched_mem); iounmap(cdd->qmgr_mem); -err_remap: - kfree(cdd); return ret; } @@ -1036,7 +1031,7 @@ static int cppi41_dma_remove(struct platform_device *pdev) dma_async_device_unregister(&cdd->ddev); cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR); - free_irq(cdd->irq, cdd); + devm_free_irq(&pdev->dev, cdd->irq, cdd); cleanup_chans(cdd); deinit_cppi41(&pdev->dev, cdd); iounmap(cdd->usbss_mem); @@ -1045,7 +1040,6 @@ static int cppi41_dma_remove(struct platform_device *pdev) iounmap(cdd->qmgr_mem); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - kfree(cdd); return 0; } -- cgit v0.10.2 From 46e8c83c83c06b90ebc000df481c2fdcee79a141 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Sep 2014 17:18:10 +0300 Subject: dmaengine: dw: move private definitions to regs.h Since we don't allow user to set registers directly through private slave configuration we may move definitions to the regs.h because they are not used anywhere except core.c part. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h index 00d27a9..e8f92b2 100644 --- a/drivers/dma/dw/regs.h +++ b/drivers/dma/dw/regs.h @@ -11,7 +11,6 @@ #include #include -#include #define DW_DMA_MAX_NR_CHANNELS 8 #define DW_DMA_MAX_NR_REQUESTS 16 @@ -132,6 +131,18 @@ struct dw_dma_regs { /* Bitfields in DWC_PARAMS */ #define DWC_PARAMS_MBLK_EN 11 /* multi block transfer */ +/* bursts size */ +enum dw_dma_msize { + DW_DMA_MSIZE_1, + DW_DMA_MSIZE_4, + DW_DMA_MSIZE_8, + DW_DMA_MSIZE_16, + DW_DMA_MSIZE_32, + DW_DMA_MSIZE_64, + DW_DMA_MSIZE_128, + DW_DMA_MSIZE_256, +}; + /* Bitfields in CTL_LO */ #define DWC_CTLL_INT_EN (1 << 0) /* irqs enabled? */ #define DWC_CTLL_DST_WIDTH(n) ((n)<<1) /* bytes per element */ @@ -161,20 +172,35 @@ struct dw_dma_regs { #define DWC_CTLH_DONE 0x00001000 #define DWC_CTLH_BLOCK_TS_MASK 0x00000fff -/* Bitfields in CFG_LO. Platform-configurable bits are in */ +/* Bitfields in CFG_LO */ #define DWC_CFGL_CH_PRIOR_MASK (0x7 << 5) /* priority mask */ #define DWC_CFGL_CH_PRIOR(x) ((x) << 5) /* priority */ #define DWC_CFGL_CH_SUSP (1 << 8) /* pause xfer */ #define DWC_CFGL_FIFO_EMPTY (1 << 9) /* pause xfer */ #define DWC_CFGL_HS_DST (1 << 10) /* handshake w/dst */ #define DWC_CFGL_HS_SRC (1 << 11) /* handshake w/src */ +#define DWC_CFGL_LOCK_CH_XFER (0 << 12) /* scope of LOCK_CH */ +#define DWC_CFGL_LOCK_CH_BLOCK (1 << 12) +#define DWC_CFGL_LOCK_CH_XACT (2 << 12) +#define DWC_CFGL_LOCK_BUS_XFER (0 << 14) /* scope of LOCK_BUS */ +#define DWC_CFGL_LOCK_BUS_BLOCK (1 << 14) +#define DWC_CFGL_LOCK_BUS_XACT (2 << 14) +#define DWC_CFGL_LOCK_CH (1 << 15) /* channel lockout */ +#define DWC_CFGL_LOCK_BUS (1 << 16) /* busmaster lockout */ +#define DWC_CFGL_HS_DST_POL (1 << 18) /* dst handshake active low */ +#define DWC_CFGL_HS_SRC_POL (1 << 19) /* src handshake active low */ #define DWC_CFGL_MAX_BURST(x) ((x) << 20) #define DWC_CFGL_RELOAD_SAR (1 << 30) #define DWC_CFGL_RELOAD_DAR (1 << 31) -/* Bitfields in CFG_HI. Platform-configurable bits are in */ +/* Bitfields in CFG_HI */ +#define DWC_CFGH_FCMODE (1 << 0) +#define DWC_CFGH_FIFO_MODE (1 << 1) +#define DWC_CFGH_PROTCTL(x) ((x) << 2) #define DWC_CFGH_DS_UPD_EN (1 << 5) #define DWC_CFGH_SS_UPD_EN (1 << 6) +#define DWC_CFGH_SRC_PER(x) ((x) << 7) +#define DWC_CFGH_DST_PER(x) ((x) << 11) /* Bitfields in SGR */ #define DWC_SGR_SGI(x) ((x) << 0) diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h index bc411a1..d0c97da 100644 --- a/include/linux/platform_data/dma-dw.h +++ b/include/linux/platform_data/dma-dw.h @@ -56,37 +56,6 @@ struct dw_dma_platform_data { unsigned char data_width[4]; }; -/* bursts size */ -enum dw_dma_msize { - DW_DMA_MSIZE_1, - DW_DMA_MSIZE_4, - DW_DMA_MSIZE_8, - DW_DMA_MSIZE_16, - DW_DMA_MSIZE_32, - DW_DMA_MSIZE_64, - DW_DMA_MSIZE_128, - DW_DMA_MSIZE_256, -}; - -/* Platform-configurable bits in CFG_HI */ -#define DWC_CFGH_FCMODE (1 << 0) -#define DWC_CFGH_FIFO_MODE (1 << 1) -#define DWC_CFGH_PROTCTL(x) ((x) << 2) -#define DWC_CFGH_SRC_PER(x) ((x) << 7) -#define DWC_CFGH_DST_PER(x) ((x) << 11) - -/* Platform-configurable bits in CFG_LO */ -#define DWC_CFGL_LOCK_CH_XFER (0 << 12) /* scope of LOCK_CH */ -#define DWC_CFGL_LOCK_CH_BLOCK (1 << 12) -#define DWC_CFGL_LOCK_CH_XACT (2 << 12) -#define DWC_CFGL_LOCK_BUS_XFER (0 << 14) /* scope of LOCK_BUS */ -#define DWC_CFGL_LOCK_BUS_BLOCK (1 << 14) -#define DWC_CFGL_LOCK_BUS_XACT (2 << 14) -#define DWC_CFGL_LOCK_CH (1 << 15) /* channel lockout */ -#define DWC_CFGL_LOCK_BUS (1 << 16) /* busmaster lockout */ -#define DWC_CFGL_HS_DST_POL (1 << 18) /* dst handshake active low */ -#define DWC_CFGL_HS_SRC_POL (1 << 19) /* src handshake active low */ - /* DMA API extensions */ struct dw_cyclic_desc { struct dw_desc **desc; -- cgit v0.10.2 From 3d588f83e4d6a5230d9094b97d38621cbaa9a972 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Sep 2014 17:18:11 +0300 Subject: dmaengine: dw: split dma-dw.h to platform and private parts The introduced include/linux/dma/dw.h is going to contain the private extensions and structures which are shared for dw_dmac users in the kernel. Meanwhile include/linux/platform_data/dma-dw.h keeps only platform related data types and definitions. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h index 82258a1..9a886e3 100644 --- a/drivers/dma/dw/internal.h +++ b/drivers/dma/dw/internal.h @@ -12,6 +12,8 @@ #define _DW_DMAC_INTERNAL_H #include + +#include #include #include "regs.h" diff --git a/include/linux/dma/dw.h b/include/linux/dma/dw.h new file mode 100644 index 0000000..2475613 --- /dev/null +++ b/include/linux/dma/dw.h @@ -0,0 +1,37 @@ +/* + * Driver for the Synopsys DesignWare DMA Controller + * + * Copyright (C) 2007 Atmel Corporation + * Copyright (C) 2010-2011 ST Microelectronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _DMA_DW_H +#define _DMA_DW_H + +#include + +/* DMA API extensions */ +struct dw_desc; + +struct dw_cyclic_desc { + struct dw_desc **desc; + unsigned long periods; + void (*period_callback)(void *param); + void *period_callback_param; +}; + +struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, + dma_addr_t buf_addr, size_t buf_len, size_t period_len, + enum dma_transfer_direction direction); +void dw_dma_cyclic_free(struct dma_chan *chan); +int dw_dma_cyclic_start(struct dma_chan *chan); +void dw_dma_cyclic_stop(struct dma_chan *chan); + +dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan); + +dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan); + +#endif /* _DMA_DW_H */ diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h index d0c97da..d8155c0 100644 --- a/include/linux/platform_data/dma-dw.h +++ b/include/linux/platform_data/dma-dw.h @@ -8,10 +8,10 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef DW_DMAC_H -#define DW_DMAC_H +#ifndef _PLATFORM_DATA_DMA_DW_H +#define _PLATFORM_DATA_DMA_DW_H -#include +#include /** * struct dw_dma_slave - Controller-specific information about a slave @@ -56,23 +56,4 @@ struct dw_dma_platform_data { unsigned char data_width[4]; }; -/* DMA API extensions */ -struct dw_cyclic_desc { - struct dw_desc **desc; - unsigned long periods; - void (*period_callback)(void *param); - void *period_callback_param; -}; - -struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, - dma_addr_t buf_addr, size_t buf_len, size_t period_len, - enum dma_transfer_direction direction); -void dw_dma_cyclic_free(struct dma_chan *chan); -int dw_dma_cyclic_start(struct dma_chan *chan); -void dw_dma_cyclic_stop(struct dma_chan *chan); - -dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan); - -dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan); - -#endif /* DW_DMAC_H */ +#endif /* _PLATFORM_DATA_DMA_DW_H */ diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c index 154a7c4..31061e3 100644 --- a/sound/atmel/abdac.c +++ b/sound/atmel/abdac.c @@ -9,7 +9,6 @@ */ #include #include -#include #include #include #include @@ -25,6 +24,9 @@ #include #include +#include +#include + /* DAC register offsets */ #define DAC_DATA 0x0000 #define DAC_CTRL 0x0008 diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 1dfb35a..b59427d 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -32,6 +32,7 @@ #include #include +#include #include -- cgit v0.10.2 From 7a83c045435e896db6c689145d752d28b8b99b7b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Sep 2014 17:18:12 +0300 Subject: dmaengine: dw: introduce dw_dma_on() helper As an opposite to dw_dma_off() let's introduce dw_dma_on() helper. It will be useful later as well. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 9546b1f..e94de00 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -1470,6 +1470,11 @@ static void dw_dma_off(struct dw_dma *dw) dw->chan[i].initialized = false; } +static void dw_dma_on(struct dw_dma *dw) +{ + dma_writel(dw, CFG, DW_CFG_DMA_EN); +} + int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata) { struct dw_dma *dw; @@ -1643,7 +1648,7 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata) dw->dma.device_tx_status = dwc_tx_status; dw->dma.device_issue_pending = dwc_issue_pending; - dma_writel(dw, CFG, DW_CFG_DMA_EN); + dw_dma_on(dw); err = dma_async_device_register(&dw->dma); if (err) @@ -1705,7 +1710,7 @@ int dw_dma_resume(struct dw_dma_chip *chip) { struct dw_dma *dw = chip->dw; - dma_writel(dw, CFG, DW_CFG_DMA_EN); + dw_dma_on(dw); return 0; } EXPORT_SYMBOL_GPL(dw_dma_resume); -- cgit v0.10.2 From 2540f74b187e3ec0fe106b7427c4a84c955dc140 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Sep 2014 17:18:13 +0300 Subject: dmaengine: dw: always export dw_dma_{en,dis}able Instead of conditional exporing of dw_dma_suspend() / dw_dma_resume() let's export dw_dma_disable() / dw_dma_enable(). Since dw_dma_shutdown() repeats dw_dma_disable() we may safely remove it at all. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index e94de00..4812638 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -1687,35 +1687,23 @@ int dw_dma_remove(struct dw_dma_chip *chip) } EXPORT_SYMBOL_GPL(dw_dma_remove); -void dw_dma_shutdown(struct dw_dma_chip *chip) -{ - struct dw_dma *dw = chip->dw; - - dw_dma_off(dw); -} -EXPORT_SYMBOL_GPL(dw_dma_shutdown); - -#ifdef CONFIG_PM_SLEEP - -int dw_dma_suspend(struct dw_dma_chip *chip) +int dw_dma_disable(struct dw_dma_chip *chip) { struct dw_dma *dw = chip->dw; dw_dma_off(dw); return 0; } -EXPORT_SYMBOL_GPL(dw_dma_suspend); +EXPORT_SYMBOL_GPL(dw_dma_disable); -int dw_dma_resume(struct dw_dma_chip *chip) +int dw_dma_enable(struct dw_dma_chip *chip) { struct dw_dma *dw = chip->dw; dw_dma_on(dw); return 0; } -EXPORT_SYMBOL_GPL(dw_dma_resume); - -#endif /* CONFIG_PM_SLEEP */ +EXPORT_SYMBOL_GPL(dw_dma_enable); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller core driver"); diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h index 9a886e3..c55c3e0 100644 --- a/drivers/dma/dw/internal.h +++ b/drivers/dma/dw/internal.h @@ -38,14 +38,8 @@ struct dw_dma_chip { int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata); int dw_dma_remove(struct dw_dma_chip *chip); -void dw_dma_shutdown(struct dw_dma_chip *chip); - -#ifdef CONFIG_PM_SLEEP - -int dw_dma_suspend(struct dw_dma_chip *chip); -int dw_dma_resume(struct dw_dma_chip *chip); - -#endif /* CONFIG_PM_SLEEP */ +int dw_dma_disable(struct dw_dma_chip *chip); +int dw_dma_enable(struct dw_dma_chip *chip); extern bool dw_dma_filter(struct dma_chan *chan, void *param); diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c index 9c88828..b144706 100644 --- a/drivers/dma/dw/pci.c +++ b/drivers/dma/dw/pci.c @@ -82,7 +82,7 @@ static int dw_pci_suspend_late(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct dw_dma_chip *chip = pci_get_drvdata(pci); - return dw_dma_suspend(chip); + return dw_dma_disable(chip); }; static int dw_pci_resume_early(struct device *dev) @@ -90,7 +90,7 @@ static int dw_pci_resume_early(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct dw_dma_chip *chip = pci_get_drvdata(pci); - return dw_dma_resume(chip); + return dw_dma_enable(chip); }; #endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index d50077e..a630161 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -226,7 +226,7 @@ static void dw_shutdown(struct platform_device *pdev) { struct dw_dma_chip *chip = platform_get_drvdata(pdev); - dw_dma_shutdown(chip); + dw_dma_disable(chip); clk_disable_unprepare(chip->clk); } @@ -253,7 +253,7 @@ static int dw_suspend_late(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct dw_dma_chip *chip = platform_get_drvdata(pdev); - dw_dma_suspend(chip); + dw_dma_disable(chip); clk_disable_unprepare(chip->clk); return 0; @@ -265,7 +265,7 @@ static int dw_resume_early(struct device *dev) struct dw_dma_chip *chip = platform_get_drvdata(pdev); clk_prepare_enable(chip->clk); - return dw_dma_resume(chip); + return dw_dma_enable(chip); } #endif /* CONFIG_PM_SLEEP */ @@ -277,7 +277,7 @@ static const struct dev_pm_ops dw_dev_pm_ops = { static struct platform_driver dw_driver = { .probe = dw_probe, .remove = dw_remove, - .shutdown = dw_shutdown, + .shutdown = dw_shutdown, .driver = { .name = "dw_dmac", .pm = &dw_dev_pm_ops, -- cgit v0.10.2 From 99d9bf4ed27c63d5559e31d112f71af655c7182b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Sep 2014 17:18:14 +0300 Subject: dmaengine: dw: enable and disable controller when needed Enable controller automatically whenever first user requires for a channel and disable it when the last user gone. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 4812638..2447221 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -1094,6 +1094,31 @@ static void dwc_issue_pending(struct dma_chan *chan) spin_unlock_irqrestore(&dwc->lock, flags); } +/*----------------------------------------------------------------------*/ + +static void dw_dma_off(struct dw_dma *dw) +{ + int i; + + dma_writel(dw, CFG, 0); + + channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask); + channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask); + channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask); + channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask); + + while (dma_readl(dw, CFG) & DW_CFG_DMA_EN) + cpu_relax(); + + for (i = 0; i < dw->dma.chancnt; i++) + dw->chan[i].initialized = false; +} + +static void dw_dma_on(struct dw_dma *dw) +{ + dma_writel(dw, CFG, DW_CFG_DMA_EN); +} + static int dwc_alloc_chan_resources(struct dma_chan *chan) { struct dw_dma_chan *dwc = to_dw_dma_chan(chan); @@ -1118,6 +1143,11 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan) * doesn't mean what you think it means), and status writeback. */ + /* Enable controller here if needed */ + if (!dw->in_use) + dw_dma_on(dw); + dw->in_use |= dwc->mask; + spin_lock_irqsave(&dwc->lock, flags); i = dwc->descs_allocated; while (dwc->descs_allocated < NR_DESCS_PER_CHANNEL) { @@ -1182,6 +1212,11 @@ static void dwc_free_chan_resources(struct dma_chan *chan) spin_unlock_irqrestore(&dwc->lock, flags); + /* Disable controller in case it was a last user */ + dw->in_use &= ~dwc->mask; + if (!dw->in_use) + dw_dma_off(dw); + list_for_each_entry_safe(desc, _desc, &list, desc_node) { dev_vdbg(chan2dev(chan), " freeing descriptor %p\n", desc); dma_pool_free(dw->desc_pool, desc, desc->txd.phys); @@ -1452,29 +1487,6 @@ EXPORT_SYMBOL(dw_dma_cyclic_free); /*----------------------------------------------------------------------*/ -static void dw_dma_off(struct dw_dma *dw) -{ - int i; - - dma_writel(dw, CFG, 0); - - channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask); - channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask); - channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask); - channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask); - - while (dma_readl(dw, CFG) & DW_CFG_DMA_EN) - cpu_relax(); - - for (i = 0; i < dw->dma.chancnt; i++) - dw->chan[i].initialized = false; -} - -static void dw_dma_on(struct dw_dma *dw) -{ - dma_writel(dw, CFG, DW_CFG_DMA_EN); -} - int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata) { struct dw_dma *dw; @@ -1648,8 +1660,6 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata) dw->dma.device_tx_status = dwc_tx_status; dw->dma.device_issue_pending = dwc_issue_pending; - dw_dma_on(dw); - err = dma_async_device_register(&dw->dma); if (err) goto err_dma_register; diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h index e8f92b2..848e232 100644 --- a/drivers/dma/dw/regs.h +++ b/drivers/dma/dw/regs.h @@ -281,6 +281,7 @@ struct dw_dma { /* channels */ struct dw_dma_chan *chan; u8 all_chan_mask; + u8 in_use; /* hardware configuration */ unsigned char nr_masters; -- cgit v0.10.2 From 2a52f6e49e5e400ed98a79503193d81207009647 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Sep 2014 17:18:15 +0300 Subject: dmaengine: dw: export probe()/remove() and Co to users The driver library functions can be used directly by the compound devices such as ADSP or serial driver where DesignWare DMA IP is privately attached to the main hardware. Instead of creating a new platform device leaf they may call dw_dma_probe() with given struct dw_dma_chip directly and make sure that the main device is DMA capable. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h index c55c3e0..4143973 100644 --- a/drivers/dma/dw/internal.h +++ b/drivers/dma/dw/internal.h @@ -8,39 +8,16 @@ * published by the Free Software Foundation. */ -#ifndef _DW_DMAC_INTERNAL_H -#define _DW_DMAC_INTERNAL_H - -#include +#ifndef _DMA_DW_INTERNAL_H +#define _DMA_DW_INTERNAL_H #include -#include #include "regs.h" -/** - * struct dw_dma_chip - representation of DesignWare DMA controller hardware - * @dev: struct device of the DMA controller - * @irq: irq line - * @regs: memory mapped I/O space - * @clk: hclk clock - * @dw: struct dw_dma that is filed by dw_dma_probe() - */ -struct dw_dma_chip { - struct device *dev; - int irq; - void __iomem *regs; - struct clk *clk; - struct dw_dma *dw; -}; - -/* Export to the platform drivers */ -int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata); -int dw_dma_remove(struct dw_dma_chip *chip); - int dw_dma_disable(struct dw_dma_chip *chip); int dw_dma_enable(struct dw_dma_chip *chip); extern bool dw_dma_filter(struct dma_chan *chan, void *param); -#endif /* _DW_DMAC_INTERNAL_H */ +#endif /* _DMA_DW_INTERNAL_H */ diff --git a/include/linux/dma/dw.h b/include/linux/dma/dw.h index 2475613..7145644 100644 --- a/include/linux/dma/dw.h +++ b/include/linux/dma/dw.h @@ -3,6 +3,7 @@ * * Copyright (C) 2007 Atmel Corporation * Copyright (C) 2010-2011 ST Microelectronics + * Copyright (C) 2014 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -11,8 +12,34 @@ #ifndef _DMA_DW_H #define _DMA_DW_H +#include +#include #include +#include + +struct dw_dma; + +/** + * struct dw_dma_chip - representation of DesignWare DMA controller hardware + * @dev: struct device of the DMA controller + * @irq: irq line + * @regs: memory mapped I/O space + * @clk: hclk clock + * @dw: struct dw_dma that is filed by dw_dma_probe() + */ +struct dw_dma_chip { + struct device *dev; + int irq; + void __iomem *regs; + struct clk *clk; + struct dw_dma *dw; +}; + +/* Export to the platform drivers */ +int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata); +int dw_dma_remove(struct dw_dma_chip *chip); + /* DMA API extensions */ struct dw_desc; -- cgit v0.10.2 From 639559ada6194b722304fe267455b5bdf75c2f90 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 29 Sep 2014 20:06:45 +0200 Subject: dmaengine: edma: check for echan->edesc => NULL in edma_dma_pause() I added book keeping of whether or not the 8250-dma driver has an RX transfer pending or not so we don't BUG here if it calls dmaengine_pause() on a channel which has not a pending transfer. Guess what, this is not enough. The following can be triggered with a busy RX channel and hackbench in background: - DMA transfer completes. The callback is delayed via vchan_cookie_complete() into a tasklet so it das not happen asap. - hackbench keeps the system busy so the tasklet does not run "soon". - the UART collected enough data and generates an "timeout"-interrupt. Since 8250-dma *thinks* the DMA-transfer is still pending it tries to cancel it via invoking dmaengine_pause() first. This causes the segfault because echan->edesc is NULL now that the transfer completed (however the callback did not run yet). With this patch we don't BUG in the scenario described. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Peter Ujfalusi Signed-off-by: Vinod Koul diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 7b65633..123f578 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -288,7 +288,7 @@ static int edma_slave_config(struct edma_chan *echan, static int edma_dma_pause(struct edma_chan *echan) { /* Pause/Resume only allowed with cyclic mode */ - if (!echan->edesc->cyclic) + if (!echan->edesc || !echan->edesc->cyclic) return -EINVAL; edma_pause(echan->ch_num); -- cgit v0.10.2 From 72b2caff4aac45157f79502aae5019e96059b301 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:10:29 +0530 Subject: pata_arasan_cf: use dmaengine_terminate_all() API The drivers should use dmaengine_terminate_all() API instead of accessing the device_control which will be deprecated soon Acked-by: Viresh Kumar Signed-off-by: Vinod Koul diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index 4edb1a8..38216b9 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -420,7 +420,7 @@ dma_xfer(struct arasan_cf_dev *acdev, dma_addr_t src, dma_addr_t dest, u32 len) /* Wait for DMA to complete */ if (!wait_for_completion_timeout(&acdev->dma_completion, TIMEOUT)) { - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(chan); dev_err(acdev->host->dev, "wait_for_completion_timeout\n"); return -ETIMEDOUT; } @@ -928,8 +928,7 @@ static int arasan_cf_suspend(struct device *dev) struct arasan_cf_dev *acdev = host->ports[0]->private_data; if (acdev->dma_chan) - acdev->dma_chan->device->device_control(acdev->dma_chan, - DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(acdev->dma_chan); cf_exit(acdev); return ata_host_suspend(host, PMSG_SUSPEND); -- cgit v0.10.2 From 7e606d3bfe308115b7a0b516bcb8934d97b4275a Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:10:30 +0530 Subject: dmaengine: coh901318: use dmaengine_terminate_all() API The drivers should use dmaengine_terminate_all() API instead of accessing the device_control which will be deprecated soon Signed-off-by: Vinod Koul diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index 3c6716e..e88588d 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c @@ -2156,7 +2156,7 @@ coh901318_free_chan_resources(struct dma_chan *chan) spin_unlock_irqrestore(&cohc->lock, flags); - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(chan); } -- cgit v0.10.2 From 0aae803a08ae1c788b47f01eddd8787a8457a930 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:10:31 +0530 Subject: V4L2: mx3_camer: use dmaengine_pause() API The drivers should use dmaengine_pause() API instead of accessing the device_control which will be deprecated soon Signed-off-by: Vinod Koul diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index 83315df..7696a87 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -415,10 +415,8 @@ static void mx3_stop_streaming(struct vb2_queue *q) struct mx3_camera_buffer *buf, *tmp; unsigned long flags; - if (ichan) { - struct dma_chan *chan = &ichan->dma_chan; - chan->device->device_control(chan, DMA_PAUSE, 0); - } + if (ichan) + dmaengine_pause(&ichan->dma_chan); spin_lock_irqsave(&mx3_cam->lock, flags); -- cgit v0.10.2 From b177ea341a588ab270c31496f34c503c31589649 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:10:32 +0530 Subject: mtd: fsmc_nand: use dmaengine_terminate_all() API The drivers should use dmaengine_terminate_all() API instead of accessing the device_control which will be deprecated soon Signed-off-by: Vinod Koul diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 1550692..7a91587 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -605,7 +605,7 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len, wait_for_completion_timeout(&host->dma_access_complete, msecs_to_jiffies(3000)); if (ret <= 0) { - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(chan); dev_err(host->dev, "wait_for_completion_timeout\n"); if (!ret) ret = -ETIMEDOUT; -- cgit v0.10.2 From 0e497c36deef92ec7a54c6af6f4e87d5b4f39dda Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:10:33 +0530 Subject: mtd: sh_flctl: use dmaengine_terminate_all() API The drivers should use dmaengine_terminate_all() API instead of accessing the device_control which will be deprecated soon Acked-by: Laurent Pinchart Signed-off-by: Vinod Koul diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index c067023..0ed7c60 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -395,7 +395,7 @@ static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf, msecs_to_jiffies(3000)); if (ret <= 0) { - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(chan); dev_err(&flctl->pdev->dev, "wait_for_completion_timeout\n"); } -- cgit v0.10.2 From 843d349c20bc3562ae7b59de4067e304e89843c7 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:10:34 +0530 Subject: net: ks8842: use dmaengine_terminate_all() API The drivers should use dmaengine_terminate_all() API instead of accessing the device_control which will be deprecated soon Signed-off-by: Vinod Koul diff --git a/drivers/net/ethernet/micrel/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c index 822616e..0c33b92 100644 --- a/drivers/net/ethernet/micrel/ks8842.c +++ b/drivers/net/ethernet/micrel/ks8842.c @@ -875,13 +875,11 @@ static void ks8842_stop_dma(struct ks8842_adapter *adapter) tx_ctl->adesc = NULL; if (tx_ctl->chan) - tx_ctl->chan->device->device_control(tx_ctl->chan, - DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(tx_ctl->chan); rx_ctl->adesc = NULL; if (rx_ctl->chan) - rx_ctl->chan->device->device_control(rx_ctl->chan, - DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(rx_ctl->chan); if (sg_dma_address(&rx_ctl->sg)) dma_unmap_single(adapter->dev, sg_dma_address(&rx_ctl->sg), -- cgit v0.10.2 From 2bcd90d56c6025189be98bed47c80c5261855a7e Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:10:37 +0530 Subject: serial: sh-sci: use dmaengine_terminate_all() API The drivers should use dmaengine_terminate_all() API instead of accessing the device_control which will be deprecated soon Acked-by: Greg Kroah-Hartman Signed-off-by: Vinod Koul diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 3081e46..eb17c71 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1403,7 +1403,7 @@ static void work_fn_rx(struct work_struct *work) unsigned long flags; int count; - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(chan); dev_dbg(port->dev, "Read %zu bytes with cookie %d\n", sh_desc->partial, sh_desc->cookie); -- cgit v0.10.2 From a500789d42f478bc5511e1ddafadc323a6036d11 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:10:40 +0530 Subject: video: mx3fb: use dmaengine_terminate_all() API The drivers should use dmaengine_terminate_all() API instead of accessing the device_control which will be deprecated soon Signed-off-by: Vinod Koul diff --git a/drivers/video/fbdev/mx3fb.c b/drivers/video/fbdev/mx3fb.c index c645a0a..cdbc93a 100644 --- a/drivers/video/fbdev/mx3fb.c +++ b/drivers/video/fbdev/mx3fb.c @@ -461,8 +461,7 @@ static void sdc_disable_channel(struct mx3fb_info *mx3_fbi) spin_unlock_irqrestore(&mx3fb->lock, flags); - mx3_fbi->txd->chan->device->device_control(mx3_fbi->txd->chan, - DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(mx3_fbi->txd->chan); mx3_fbi->txd = NULL; mx3_fbi->cookie = -EINVAL; } -- cgit v0.10.2 From b65612a868768cd0431084ccf376d0946c12132d Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:16:43 +0530 Subject: dmaengine: add dmaengine_prep_dma_sg() helper This was only prep API which didnt have an helper Signed-off-by: Vinod Koul diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 1f9e642..7e6b3a2 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -755,6 +755,16 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_interleaved_dma( return chan->device->device_prep_interleaved_dma(chan, xt, flags); } +static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_sg( + struct dma_chan *chan, + struct scatterlist *dst_sg, unsigned int dst_nents, + struct scatterlist *src_sg, unsigned int src_nents, + unsigned long flags) +{ + return chan->device->device_prep_dma_sg(chan, dst_sg, dst_nents, + src_sg, src_nents, flags); +} + static inline int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps) { if (!chan || !caps) -- cgit v0.10.2 From 0a5642be03293f73706961a7649ac1d12bd0be59 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:16:44 +0530 Subject: dmaengine: freescale: add and export fsl_dma_external_start() The freescale driver uses custom device control FSLDMA_EXTERNAL_START to put the controller in external start mode. Since we are planning to deprecate the device control, move this to exported API. Subsequent patches will remove the FSLDMA_EXTERNAL_START Signed-off-by: Vinod Koul diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index d5d6885..0cded86 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -36,7 +36,7 @@ #include #include #include - +#include #include "dmaengine.h" #include "fsldma.h" @@ -367,6 +367,20 @@ static void fsl_chan_toggle_ext_start(struct fsldma_chan *chan, int enable) chan->feature &= ~FSL_DMA_CHAN_START_EXT; } +int fsl_dma_external_start(struct dma_chan *dchan, int enable) +{ + struct fsldma_chan *chan; + + if (!dchan) + return -EINVAL; + + chan = to_fsl_chan(dchan); + + fsl_chan_toggle_ext_start(chan, enable); + return 0; +} +EXPORT_SYMBOL_GPL(fsl_dma_external_start); + static void append_ld_queue(struct fsldma_chan *chan, struct fsl_desc_sw *desc) { struct fsl_desc_sw *tail = to_fsl_desc(chan->ld_pending.prev); diff --git a/include/linux/fsldma.h b/include/linux/fsldma.h new file mode 100644 index 0000000..b213c02 --- /dev/null +++ b/include/linux/fsldma.h @@ -0,0 +1,13 @@ +/* + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef FSL_DMA_H +#define FSL_DMA_H +/* fsl dma API for enxternal start */ +int fsl_dma_external_start(struct dma_chan *dchan, int enable); + +#endif -- cgit v0.10.2 From 4fdcf68487e520844e077f75943b1e04cc05943b Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:16:45 +0530 Subject: carma-fpga: use dmaengine_xxx() API The drivers should use dmaengine_slave_config() and dmaengine_prep_dma_sg() API instead of accessing the device_control which will be deprecated soon Signed-off-by: Vinod Koul diff --git a/drivers/misc/carma/carma-fpga-program.c b/drivers/misc/carma/carma-fpga-program.c index 7be8983..fd0cb8b 100644 --- a/drivers/misc/carma/carma-fpga-program.c +++ b/drivers/misc/carma/carma-fpga-program.c @@ -518,8 +518,7 @@ static noinline int fpga_program_dma(struct fpga_dev *priv) config.direction = DMA_MEM_TO_DEV; config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; config.dst_maxburst = fpga_fifo_size(priv->regs) / 2 / 4; - ret = chan->device->device_control(chan, DMA_SLAVE_CONFIG, - (unsigned long)&config); + ret = dmaengine_slave_config(chan, &config); if (ret) { dev_err(priv->dev, "DMA slave configuration failed\n"); goto out_dma_unmap; @@ -532,9 +531,9 @@ static noinline int fpga_program_dma(struct fpga_dev *priv) } /* setup and submit the DMA transaction */ - tx = chan->device->device_prep_dma_sg(chan, - table.sgl, num_pages, - vb->sglist, vb->sglen, 0); + + tx = dmaengine_prep_dma_sg(chan, table.sgl, num_pages, + vb->sglist, vb->sglen, 0); if (!tx) { dev_err(priv->dev, "Unable to prep DMA transaction\n"); ret = -ENOMEM; -- cgit v0.10.2 From 7abfe6eca8f978f090b3c203cfb53d37a66ea9f2 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:16:46 +0530 Subject: carma-fpga: move to fsl_dma_external_start() carma-fpga driver uses device control with custom FSLDMA_EXTERNAL_START command. Since we wnat to deprecate the device control, move this driver to use new fsl_dma_external_start() API Signed-off-by: Vinod Koul diff --git a/drivers/misc/carma/carma-fpga-program.c b/drivers/misc/carma/carma-fpga-program.c index fd0cb8b..298f912 100644 --- a/drivers/misc/carma/carma-fpga-program.c +++ b/drivers/misc/carma/carma-fpga-program.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -524,7 +525,7 @@ static noinline int fpga_program_dma(struct fpga_dev *priv) goto out_dma_unmap; } - ret = chan->device->device_control(chan, FSLDMA_EXTERNAL_START, 1); + ret = fsl_dma_external_start(chan, 1) if (ret) { dev_err(priv->dev, "DMA external control setup failed\n"); goto out_dma_unmap; -- cgit v0.10.2 From 01c6ad660cb4a388d15d0e7ba9744c5ffc583a61 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:16:47 +0530 Subject: dmaengine: freescale: remove FSLDMA_EXTERNAL_START control method since users have been move to fsl_dma_external_start() API, so remove this now Signed-off-by: Vinod Koul diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 0cded86..994bcb2 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -1012,15 +1012,6 @@ static int fsl_dma_device_control(struct dma_chan *dchan, chan->set_request_count(chan, size); return 0; - case FSLDMA_EXTERNAL_START: - - /* make sure the channel supports external start */ - if (!chan->toggle_ext_start) - return -ENXIO; - - chan->toggle_ext_start(chan, arg); - return 0; - default: return -ENXIO; } -- cgit v0.10.2 From b80719b6bd083130c112cb4d3e5329a164eef4c3 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 11 Oct 2014 21:16:48 +0530 Subject: dmaengine: remove FSLDMA_EXTERNAL_START as users have been converted, so no need of this custom method Signed-off-by: Vinod Koul diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 7e6b3a2..f8e5a9e 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -199,15 +199,12 @@ enum dma_ctrl_flags { * configuration data in statically from the platform). An additional * argument of struct dma_slave_config must be passed in with this * command. - * @FSLDMA_EXTERNAL_START: this command will put the Freescale DMA controller - * into external start mode. */ enum dma_ctrl_cmd { DMA_TERMINATE_ALL, DMA_PAUSE, DMA_RESUME, DMA_SLAVE_CONFIG, - FSLDMA_EXTERNAL_START, }; /** -- cgit v0.10.2 From 6b997bab20448cfe85456e4789d5d9222ab6b830 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 16 Oct 2014 12:59:06 +0530 Subject: serial: atmel: add missing dmaengine header The atmel serial driver uses dmaengine APIs but never included the dmaengine header as it was getting inculded thru one of driver headers. commit 3d588f83e4d6a5230d9094b97d38621cbaa9a972 - "dmaengine: dw: split dma-dw.h to platform and private parts" broke this as it moved headers around. Fix this by doing the right thing to include the dmaengine header Reported-by: kbuild test robot Fixes: 08f738be88bb (serial: at91: add tx dma support) Acked-by: Greg Kroah-Hartman Signed-off-by: Vinod Koul diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 7b63677..d8185c7 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2