diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-14 16:49:31 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-14 16:49:31 -0800 |
| commit | 23c258763ba992f6a95a4b8980ffa7c1890bc8d8 (patch) | |
| tree | 7f089cb2c2a3f01ff071bca2dc9cc4e2b939a8c4 /drivers/dma | |
| parent | e0ca3826b147a7ada526856af25a87c8ffad489f (diff) | |
| parent | cecd5fc5512349662b9e7a9e06231055d803e3f6 (diff) | |
| download | linux-23c258763ba992f6a95a4b8980ffa7c1890bc8d8.tar.gz linux-23c258763ba992f6a95a4b8980ffa7c1890bc8d8.tar.bz2 linux-23c258763ba992f6a95a4b8980ffa7c1890bc8d8.zip | |
Merge tag 'dmaengine-4.15-rc1' of git://git.infradead.org/users/vkoul/slave-dma
Pull dmaengine updates from Vinod Koul:
"Updates for this cycle include:
- new driver for Spreadtrum dma controller, ST MDMA and DMAMUX
controllers
- PM support for IMG MDC drivers
- updates to bcm-sba-raid driver and improvements to sun6i driver
- subsystem conversion for:
- timers to use timer_setup()
- remove usage of PCI pool API
- usage of %p format specifier
- minor updates to bunch of drivers"
* tag 'dmaengine-4.15-rc1' of git://git.infradead.org/users/vkoul/slave-dma: (49 commits)
dmaengine: ti-dma-crossbar: Correct am335x/am43xx mux value type
dmaengine: dmatest: warn user when dma test times out
dmaengine: Revert "rcar-dmac: use TCRB instead of TCR for residue"
dmaengine: stm32_mdma: activate pack/unpack feature
dmaengine: at_hdmac: Remove unnecessary 0x prefixes before %pad
dmaengine: coh901318: Remove unnecessary 0x prefixes before %pad
MAINTAINERS: Step down from a co-maintaner of DW DMAC driver
dmaengine: pch_dma: Replace PCI pool old API
dmaengine: Convert timers to use timer_setup()
dmaengine: sprd: Add Spreadtrum DMA driver
dt-bindings: dmaengine: Add Spreadtrum SC9860 DMA controller
dmaengine: sun6i: Retrieve channel count/max request from devicetree
dmaengine: Build bcm-sba-raid driver as loadable module for iProc SoCs
dmaengine: bcm-sba-raid: Use common GPL comment header
dmaengine: bcm-sba-raid: Use only single mailbox channel
dmaengine: bcm-sba-raid: serialize dma_cookie_complete() using reqs_lock
dmaengine: pl330: fix descriptor allocation fail
dmaengine: rcar-dmac: use TCRB instead of TCR for residue
dmaengine: sun6i: Add support for Allwinner A64 and compatibles
arm64: allwinner: a64: Add devicetree binding for DMA controller
...
Diffstat (limited to 'drivers/dma')
| -rw-r--r-- | drivers/dma/Kconfig | 31 | ||||
| -rw-r--r-- | drivers/dma/Makefile | 3 | ||||
| -rw-r--r-- | drivers/dma/at_hdmac_regs.h | 2 | ||||
| -rw-r--r-- | drivers/dma/bcm-sba-raid.c | 117 | ||||
| -rw-r--r-- | drivers/dma/coh901318.c | 6 | ||||
| -rw-r--r-- | drivers/dma/dma-axi-dmac.c | 75 | ||||
| -rw-r--r-- | drivers/dma/dmatest.c | 1 | ||||
| -rw-r--r-- | drivers/dma/edma.c | 5 | ||||
| -rw-r--r-- | drivers/dma/img-mdc-dma.c | 98 | ||||
| -rw-r--r-- | drivers/dma/imx-dma.c | 8 | ||||
| -rw-r--r-- | drivers/dma/imx-sdma.c | 14 | ||||
| -rw-r--r-- | drivers/dma/ioat/dma.c | 6 | ||||
| -rw-r--r-- | drivers/dma/ioat/dma.h | 3 | ||||
| -rw-r--r-- | drivers/dma/ioat/init.c | 2 | ||||
| -rw-r--r-- | drivers/dma/nbpfaxi.c | 5 | ||||
| -rw-r--r-- | drivers/dma/omap-dma.c | 5 | ||||
| -rw-r--r-- | drivers/dma/pch_dma.c | 12 | ||||
| -rw-r--r-- | drivers/dma/pl330.c | 39 | ||||
| -rw-r--r-- | drivers/dma/qcom/bam_dma.c | 169 | ||||
| -rw-r--r-- | drivers/dma/sa11x0-dma.c | 11 | ||||
| -rw-r--r-- | drivers/dma/sprd-dma.c | 988 | ||||
| -rw-r--r-- | drivers/dma/stm32-dmamux.c | 327 | ||||
| -rw-r--r-- | drivers/dma/stm32-mdma.c | 1682 | ||||
| -rw-r--r-- | drivers/dma/sun6i-dma.c | 257 | ||||
| -rw-r--r-- | drivers/dma/ti-dma-crossbar.c | 8 | ||||
| -rw-r--r-- | drivers/dma/xilinx/xilinx_dma.c | 14 |
26 files changed, 3597 insertions, 291 deletions
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index fadc4d8783bd..27df3e2837fd 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -115,7 +115,7 @@ config BCM_SBA_RAID select DMA_ENGINE_RAID select ASYNC_TX_DISABLE_XOR_VAL_DMA select ASYNC_TX_DISABLE_PQ_VAL_DMA - default ARCH_BCM_IPROC + default m if ARCH_BCM_IPROC help Enable support for Broadcom SBA RAID Engine. The SBA RAID engine is available on most of the Broadcom iProc SoCs. It @@ -483,6 +483,35 @@ config STM32_DMA If you have a board based on such a MCU and wish to use DMA say Y here. +config STM32_DMAMUX + bool "STMicroelectronics STM32 dma multiplexer support" + depends on STM32_DMA || COMPILE_TEST + help + Enable support for the on-chip DMA multiplexer on STMicroelectronics + STM32 MCUs. + If you have a board based on such a MCU and wish to use DMAMUX say Y + here. + +config STM32_MDMA + bool "STMicroelectronics STM32 master dma support" + depends on ARCH_STM32 || COMPILE_TEST + depends on OF + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Enable support for the on-chip MDMA controller on STMicroelectronics + STM32 platforms. + If you have a board based on STM32 SoC and wish to use the master DMA + say Y here. + +config SPRD_DMA + tristate "Spreadtrum DMA support" + depends on ARCH_SPRD || COMPILE_TEST + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Enable support for the on-chip DMA controller on Spreadtrum platform. + config S3C24XX_DMAC bool "Samsung S3C24XX DMA support" depends on ARCH_S3C24XX || COMPILE_TEST diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 9d0156b50294..b9dca8a0e142 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -60,6 +60,9 @@ obj-$(CONFIG_RENESAS_DMA) += sh/ obj-$(CONFIG_SIRF_DMA) += sirf-dma.o obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o obj-$(CONFIG_STM32_DMA) += stm32-dma.o +obj-$(CONFIG_STM32_DMAMUX) += stm32-dmamux.o +obj-$(CONFIG_STM32_MDMA) += stm32-mdma.o +obj-$(CONFIG_SPRD_DMA) += sprd-dma.o obj-$(CONFIG_S3C24XX_DMAC) += s3c24xx-dma.o obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index 7f58f06157f6..ef3f227ce3e6 100644 --- a/drivers/dma/at_hdmac_regs.h +++ b/drivers/dma/at_hdmac_regs.h @@ -385,7 +385,7 @@ static void vdbg_dump_regs(struct at_dma_chan *atchan) {} static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli) { dev_crit(chan2dev(&atchan->chan_common), - " desc: s%pad d%pad ctrl0x%x:0x%x l0x%pad\n", + "desc: s%pad d%pad ctrl0x%x:0x%x l%pad\n", &lli->saddr, &lli->daddr, lli->ctrla, lli->ctrlb, &lli->dscr); } diff --git a/drivers/dma/bcm-sba-raid.c b/drivers/dma/bcm-sba-raid.c index 6c2c44724637..3956a018bf5a 100644 --- a/drivers/dma/bcm-sba-raid.c +++ b/drivers/dma/bcm-sba-raid.c @@ -1,9 +1,14 @@ /* * Copyright (C) 2017 Broadcom * - * 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. + * This program 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ /* @@ -25,11 +30,8 @@ * * The Broadcom SBA RAID driver does not require any register programming * except submitting request to SBA hardware device via mailbox channels. - * This driver implements a DMA device with one DMA channel using a set - * of mailbox channels provided by Broadcom SoC specific ring manager - * driver. To exploit parallelism (as described above), all DMA request - * coming to SBA RAID DMA channel are broken down to smaller requests - * and submitted to multiple mailbox channels in round-robin fashion. + * This driver implements a DMA device with one DMA channel using a single + * mailbox channel provided by Broadcom SoC specific ring manager driver. * For having more SBA DMA channels, we can create more SBA device nodes * in Broadcom SoC specific DTS based on number of hardware rings supported * by Broadcom SoC ring manager. @@ -85,6 +87,7 @@ #define SBA_CMD_GALOIS 0xe #define SBA_MAX_REQ_PER_MBOX_CHANNEL 8192 +#define SBA_MAX_MSG_SEND_PER_MBOX_CHANNEL 8 /* Driver helper macros */ #define to_sba_request(tx) \ @@ -142,9 +145,7 @@ struct sba_device { u32 max_cmds_pool_size; /* Maibox client and Mailbox channels */ struct mbox_client client; - int mchans_count; - atomic_t mchans_current; - struct mbox_chan **mchans; + struct mbox_chan *mchan; struct device *mbox_dev; /* DMA device and DMA channel */ struct dma_device dma_dev; @@ -200,14 +201,6 @@ static inline u32 __pure sba_cmd_pq_c_mdata(u32 d, u32 b1, u32 b0) /* ====== General helper routines ===== */ -static void sba_peek_mchans(struct sba_device *sba) -{ - int mchan_idx; - - for (mchan_idx = 0; mchan_idx < sba->mchans_count; mchan_idx++) - mbox_client_peek_data(sba->mchans[mchan_idx]); -} - static struct sba_request *sba_alloc_request(struct sba_device *sba) { bool found = false; @@ -231,7 +224,7 @@ static struct sba_request *sba_alloc_request(struct sba_device *sba) * would have completed which will create more * room for new requests. */ - sba_peek_mchans(sba); + mbox_client_peek_data(sba->mchan); return NULL; } @@ -369,15 +362,11 @@ static void sba_cleanup_pending_requests(struct sba_device *sba) static int sba_send_mbox_request(struct sba_device *sba, struct sba_request *req) { - int mchans_idx, ret = 0; - - /* Select mailbox channel in round-robin fashion */ - mchans_idx = atomic_inc_return(&sba->mchans_current); - mchans_idx = mchans_idx % sba->mchans_count; + int ret = 0; /* Send message for the request */ req->msg.error = 0; - ret = mbox_send_message(sba->mchans[mchans_idx], &req->msg); + ret = mbox_send_message(sba->mchan, &req->msg); if (ret < 0) { dev_err(sba->dev, "send message failed with error %d", ret); return ret; @@ -390,7 +379,7 @@ static int sba_send_mbox_request(struct sba_device *sba, } /* Signal txdone for mailbox channel */ - mbox_client_txdone(sba->mchans[mchans_idx], ret); + mbox_client_txdone(sba->mchan, ret); return ret; } @@ -402,13 +391,8 @@ static void _sba_process_pending_requests(struct sba_device *sba) u32 count; struct sba_request *req; - /* - * Process few pending requests - * - * For now, we process (<number_of_mailbox_channels> * 8) - * number of requests at a time. - */ - count = sba->mchans_count * 8; + /* Process few pending requests */ + count = SBA_MAX_MSG_SEND_PER_MBOX_CHANNEL; while (!list_empty(&sba->reqs_pending_list) && count) { /* Get the first pending request */ req = list_first_entry(&sba->reqs_pending_list, @@ -442,7 +426,9 @@ static void sba_process_received_request(struct sba_device *sba, WARN_ON(tx->cookie < 0); if (tx->cookie > 0) { + spin_lock_irqsave(&sba->reqs_lock, flags); dma_cookie_complete(tx); + spin_unlock_irqrestore(&sba->reqs_lock, flags); dmaengine_desc_get_callback_invoke(tx, NULL); dma_descriptor_unmap(tx); tx->callback = NULL; @@ -570,7 +556,7 @@ static enum dma_status sba_tx_status(struct dma_chan *dchan, if (ret == DMA_COMPLETE) return ret; - sba_peek_mchans(sba); + mbox_client_peek_data(sba->mchan); return dma_cookie_status(dchan, cookie, txstate); } @@ -1637,7 +1623,7 @@ static int sba_async_register(struct sba_device *sba) static int sba_probe(struct platform_device *pdev) { - int i, ret = 0, mchans_count; + int ret = 0; struct sba_device *sba; struct platform_device *mbox_pdev; struct of_phandle_args args; @@ -1650,12 +1636,11 @@ static int sba_probe(struct platform_device *pdev) sba->dev = &pdev->dev; platform_set_drvdata(pdev, sba); - /* Number of channels equals number of mailbox channels */ + /* Number of mailbox channels should be atleast 1 */ ret = of_count_phandle_with_args(pdev->dev.of_node, "mboxes", "#mbox-cells"); if (ret <= 0) return -ENODEV; - mchans_count = ret; /* Determine SBA version from DT compatible string */ if (of_device_is_compatible(sba->dev->of_node, "brcm,iproc-sba")) @@ -1688,7 +1673,7 @@ static int sba_probe(struct platform_device *pdev) default: return -EINVAL; } - sba->max_req = SBA_MAX_REQ_PER_MBOX_CHANNEL * mchans_count; + sba->max_req = SBA_MAX_REQ_PER_MBOX_CHANNEL; sba->max_cmd_per_req = sba->max_pq_srcs + 3; sba->max_xor_srcs = sba->max_cmd_per_req - 1; sba->max_resp_pool_size = sba->max_req * sba->hw_resp_size; @@ -1702,55 +1687,30 @@ static int sba_probe(struct platform_device *pdev) sba->client.knows_txdone = true; sba->client.tx_tout = 0; - /* Allocate mailbox channel array */ - sba->mchans = devm_kcalloc(&pdev->dev, mchans_count, - sizeof(*sba->mchans), GFP_KERNEL); - if (!sba->mchans) - return -ENOMEM; - - /* Request mailbox channels */ - sba->mchans_count = 0; - for (i = 0; i < mchans_count; i++) { - sba->mchans[i] = mbox_request_channel(&sba->client, i); - if (IS_ERR(sba->mchans[i])) { - ret = PTR_ERR(sba->mchans[i]); - goto fail_free_mchans; - } - sba->mchans_count++; + /* Request mailbox channel */ + sba->mchan = mbox_request_channel(&sba->client, 0); + if (IS_ERR(sba->mchan)) { + ret = PTR_ERR(sba->mchan); + goto fail_free_mchan; } - atomic_set(&sba->mchans_current, 0); /* Find-out underlying mailbox device */ ret = of_parse_phandle_with_args(pdev->dev.of_node, "mboxes", "#mbox-cells", 0, &args); if (ret) - goto fail_free_mchans; + goto fail_free_mchan; mbox_pdev = of_find_device_by_node(args.np); of_node_put(args.np); if (!mbox_pdev) { ret = -ENODEV; - goto fail_free_mchans; + goto fail_free_mchan; } sba->mbox_dev = &mbox_pdev->dev; - /* All mailbox channels should be of same ring manager device */ - for (i = 1; i < mchans_count; i++) { - ret = of_parse_phandle_with_args(pdev->dev.of_node, - "mboxes", "#mbox-cells", i, &args); - if (ret) - goto fail_free_mchans; - mbox_pdev = of_find_device_by_node(args.np); - of_node_put(args.np); - if (sba->mbox_dev != &mbox_pdev->dev) { - ret = -EINVAL; - goto fail_free_mchans; - } - } - /* Prealloc channel resource */ ret = sba_prealloc_channel_resources(sba); if (ret) - goto fail_free_mchans; + goto fail_free_mchan; /* Check availability of debugfs */ if (!debugfs_initialized()) @@ -1777,24 +1737,22 @@ skip_debugfs: goto fail_free_resources; /* Print device info */ - dev_info(sba->dev, "%s using SBAv%d and %d mailbox channels", + dev_info(sba->dev, "%s using SBAv%d mailbox channel from %s", dma_chan_name(&sba->dma_chan), sba->ver+1, - sba->mchans_count); + dev_name(sba->mbox_dev)); return 0; fail_free_resources: debugfs_remove_recursive(sba->root); sba_freeup_channel_resources(sba); -fail_free_mchans: - for (i = 0; i < sba->mchans_count; i++) - mbox_free_channel(sba->mchans[i]); +fail_free_mchan: + mbox_free_channel(sba->mchan); return ret; } static int sba_remove(struct platform_device *pdev) { - int i; struct sba_device *sba = platform_get_drvdata(pdev); dma_async_device_unregister(&sba->dma_dev); @@ -1803,8 +1761,7 @@ static int sba_remove(struct platform_device *pdev) sba_freeup_channel_resources(sba); - for (i = 0; i < sba->mchans_count; i++) - mbox_free_channel(sba->mchans[i]); + mbox_free_channel(sba->mchan); return 0; } diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index 74794c9859f6..da74fd74636b 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c @@ -1319,8 +1319,8 @@ static void coh901318_list_print(struct coh901318_chan *cohc, int i = 0; while (l) { - dev_vdbg(COHC_2_DEV(cohc), "i %d, lli %p, ctrl 0x%x, src 0x%pad" - ", dst 0x%pad, link 0x%pad virt_link_addr 0x%p\n", + dev_vdbg(COHC_2_DEV(cohc), "i %d, lli %p, ctrl 0x%x, src %pad" + ", dst %pad, link %pad virt_link_addr 0x%p\n", i, l, l->control, &l->src_addr, &l->dst_addr, &l->link_addr, l->virt_link_addr); i++; @@ -2231,7 +2231,7 @@ coh901318_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, spin_lock_irqsave(&cohc->lock, flg); dev_vdbg(COHC_2_DEV(cohc), - "[%s] channel %d src 0x%pad dest 0x%pad size %zu\n", + "[%s] channel %d src %pad dest %pad size %zu\n", __func__, cohc->id, &src, &dest, size); if (flags & DMA_PREP_INTERRUPT) diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index 7f0b9aa15867..2419fe524daa 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -72,6 +72,9 @@ #define AXI_DMAC_FLAG_CYCLIC BIT(0) +/* The maximum ID allocated by the hardware is 31 */ +#define AXI_DMAC_SG_UNUSED 32U + struct axi_dmac_sg { dma_addr_t src_addr; dma_addr_t dest_addr; @@ -80,6 +83,7 @@ struct axi_dmac_sg { unsigned int dest_stride; unsigned int src_stride; unsigned int id; + bool schedule_when_free; }; struct axi_dmac_desc { @@ -200,11 +204,21 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) } sg = &desc->sg[desc->num_submitted]; + /* Already queued in cyclic mode. Wait for it to finish */ + if (sg->id != AXI_DMAC_SG_UNUSED) { + sg->schedule_when_free = true; + return; + } + desc->num_submitted++; - if (desc->num_submitted == desc->num_sgs) - chan->next_desc = NULL; - else + if (desc->num_submitted == desc->num_sgs) { + if (desc->cyclic) + desc->num_submitted = 0; /* Start again */ + else + chan->next_desc = NULL; + } else { chan->next_desc = desc; + } sg->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID); @@ -220,9 +234,11 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) /* * If the hardware supports cyclic transfers and there is no callback to - * call, enable hw cyclic mode to avoid unnecessary interrupts. + * call and only a single segment, enable hw cyclic mode to avoid + * unnecessary interrupts. */ - if (chan->hw_cyclic && desc->cyclic && !desc->vdesc.tx.callback) + if (chan->hw_cyclic && desc->cyclic && !desc->vdesc.tx.callback && + desc->num_sgs == 1) flags |= AXI_DMAC_FLAG_CYCLIC; axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, sg->x_len - 1); @@ -237,37 +253,52 @@ static struct axi_dmac_desc *axi_dmac_active_desc(struct axi_dmac_chan *chan) struct axi_dmac_desc, vdesc.node); } -static void axi_dmac_transfer_done(struct axi_dmac_chan *chan, +static bool axi_dmac_transfer_done(struct axi_dmac_chan *chan, unsigned int completed_transfers) { struct axi_dmac_desc *active; struct axi_dmac_sg *sg; + bool start_next = false; active = axi_dmac_active_desc(chan); if (!active) - return; + return false; - if (active->cyclic) { - vchan_cyclic_callback(&active->vdesc); - } else { - do { - sg = &active->sg[active->num_completed]; - if (!(BIT(sg->id) & completed_transfers)) - break; - active->num_completed++; - if (active->num_completed == active->num_sgs) { + do { + sg = &active->sg[active->num_completed]; + if (sg->id == AXI_DMAC_SG_UNUSED) /* Not yet submitted */ + break; + if (!(BIT(sg->id) & completed_transfers)) + break; + active->num_completed++; + sg->id = AXI_DMAC_SG_UNUSED; + if (sg->schedule_when_free) { + sg->schedule_when_free = false; + start_next = true; + } + + if (active->cyclic) + vchan_cyclic_callback(&active->vdesc); + + if (active->num_completed == active->num_sgs) { + if (active->cyclic) { + active->num_completed = 0; /* wrap around */ + } else { list_del(&active->vdesc.node); vchan_cookie_complete(&active->vdesc); active = axi_dmac_active_desc(chan); } - } while (active); - } + } + } while (active); + + return start_next; } static irqreturn_t axi_dmac_interrupt_handler(int irq, void *devid) { struct axi_dmac *dmac = devid; unsigned int pending; + bool start_next = false; pending = axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING); if (!pending) @@ -281,10 +312,10 @@ static irqreturn_t axi_dmac_interrupt_handler(int irq, void *devid) unsigned int completed; completed = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_DONE); - axi_dmac_transfer_done(&dmac->chan, completed); + start_next = axi_dmac_transfer_done(&dmac->chan, completed); } /* Space has become available in the descriptor queue */ - if (pending & AXI_DMAC_IRQ_SOT) + if ((pending & AXI_DMAC_IRQ_SOT) || start_next) axi_dmac_start_transfer(&dmac->chan); spin_unlock(&dmac->chan.vchan.lock); @@ -334,12 +365,16 @@ static void axi_dmac_issue_pending(struct dma_chan *c) static struct axi_dmac_desc *axi_dmac_alloc_desc(unsigned int num_sgs) { struct axi_dmac_desc *desc; + unsigned int i; desc = kzalloc(sizeof(struct axi_dmac_desc) + sizeof(struct axi_dmac_sg) * num_sgs, GFP_NOWAIT); if (!desc) return NULL; + for (i = 0; i < num_sgs; i++) + desc->sg[i].id = AXI_DMAC_SG_UNUSED; + desc->num_sgs = num_sgs; return desc; diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 34ff53290b03..47edc7fbf91f 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -702,6 +702,7 @@ static int dmatest_func(void *data) * free it this time?" dancing. For now, just * leave it dangling. */ + WARN(1, "dmatest: Kernel stack may be corrupted!!\n"); dmaengine_unmap_put(um); result("test timed out", total_tests, src_off, dst_off, len, 0); diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index a7ea20e7b8e9..9364a3ed345a 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -891,6 +891,10 @@ static int edma_slave_config(struct dma_chan *chan, cfg->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) return -EINVAL; + if (cfg->src_maxburst > chan->device->max_burst || + cfg->dst_maxburst > chan->device->max_burst) + return -EINVAL; + memcpy(&echan->cfg, cfg, sizeof(echan->cfg)); return 0; @@ -1868,6 +1872,7 @@ static void edma_dma_init(struct edma_cc *ecc, bool legacy_mode) s_ddev->dst_addr_widths = EDMA_DMA_BUSWIDTHS; s_ddev->directions |= (BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV)); s_ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + s_ddev->max_burst = SZ_32K - 1; /* CIDX: 16bit signed */ s_ddev->dev = ecc->dev; INIT_LIST_HEAD(&s_ddev->channels); diff --git a/drivers/dma/img-mdc-dma.c b/drivers/dma/img-mdc-dma.c index 54db1411ce73..0391f930aecc 100644 --- a/drivers/dma/img-mdc-dma.c +++ b/drivers/dma/img-mdc-dma.c @@ -23,6 +23,7 @@ #include <linux/of_device.h> #include <linux/of_dma.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/spinlock.h> @@ -730,14 +731,23 @@ static int mdc_slave_config(struct dma_chan *chan, return 0; } +static int mdc_alloc_chan_resources(struct dma_chan *chan) +{ + struct mdc_chan *mchan = to_mdc_chan(chan); + struct device *dev = mdma2dev(mchan->mdma); + + return pm_runtime_get_sync(dev); +} + static void mdc_free_chan_resources(struct dma_chan *chan) { struct mdc_chan *mchan = to_mdc_chan(chan); struct mdc_dma *mdma = mchan->mdma; + struct device *dev = mdma2dev(mdma); mdc_terminate_all(chan); - mdma->soc->disable_chan(mchan); + pm_runtime_put(dev); } static irqreturn_t mdc_chan_irq(int irq, void *dev_id) @@ -854,6 +864,22 @@ static const struct of_device_id mdc_dma_of_match[] = { }; MODULE_DEVICE_TABLE(of, mdc_dma_of_match); +static int img_mdc_runtime_suspend(struct device *dev) +{ + struct mdc_dma *mdma = dev_get_drvdata(dev); + + clk_disable_unprepare(mdma->clk); + + return 0; +} + +static int img_mdc_runtime_resume(struct device *dev) +{ + struct mdc_dma *mdma = dev_get_drvdata(dev); + + return clk_prepare_enable(mdma->clk); +} + static int mdc_dma_probe(struct platform_device *pdev) { struct mdc_dma *mdma; @@ -883,10 +909,6 @@ static int mdc_dma_probe(struct platform_device *pdev) if (IS_ERR(mdma->clk)) return PTR_ERR(mdma->clk); - ret = clk_prepare_enable(mdma->clk); - if (ret) - return ret; - dma_cap_zero(mdma->dma_dev.cap_mask); dma_cap_set(DMA_SLAVE, mdma->dma_dev.cap_mask); dma_cap_set(DMA_PRIVATE, mdma->dma_dev.cap_mask); @@ -919,12 +941,13 @@ static int mdc_dma_probe(struct platform_device *pdev) "img,max-burst-multiplier", &mdma->max_burst_mult); if (ret) - goto disable_clk; + return ret; mdma->dma_dev.dev = &pdev->dev; mdma->dma_dev.device_prep_slave_sg = mdc_prep_slave_sg; mdma->dma_dev.device_prep_dma_cyclic = mdc_prep_dma_cyclic; mdma->dma_dev.device_prep_dma_memcpy = mdc_prep_dma_memcpy; + mdma->dma_dev.device_alloc_chan_resources = mdc_alloc_chan_resources; mdma->dma_dev.device_free_chan_resources = mdc_free_chan_resources; mdma->dma_dev.device_tx_status = mdc_tx_status; mdma->dma_dev.device_issue_pending = mdc_issue_pending; @@ -945,15 +968,14 @@ static int mdc_dma_probe(struct platform_device *pdev) mchan->mdma = mdma; mchan->chan_nr = i; mchan->irq = platform_get_irq(pdev, i); - if (mchan->irq < 0) { - ret = mchan->irq; - goto disable_clk; - } + if (mchan->irq < 0) + return mchan->irq; + ret = devm_request_irq(&pdev->dev, mchan->irq, mdc_chan_irq, IRQ_TYPE_LEVEL_HIGH, dev_name(&pdev->dev), mchan); if (ret < 0) - goto disable_clk; + return ret; mchan->vc.desc_free = mdc_desc_free; vchan_init(&mchan->vc, &mdma->dma_dev); @@ -962,14 +984,19 @@ static int mdc_dma_probe(struct platform_device *pdev) mdma->desc_pool = dmam_pool_create(dev_name(&pdev->dev), &pdev->dev, sizeof(struct mdc_hw_list_desc), 4, 0); - if (!mdma->desc_pool) { - ret = -ENOMEM; - goto disable_clk; + if (!mdma->desc_pool) + return -ENOMEM; + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = img_mdc_runtime_resume(&pdev->dev); + if (ret) + return ret; } ret = dma_async_device_register(&mdma->dma_dev); if (ret) - goto disable_clk; + goto suspend; ret = of_dma_controller_register(pdev->dev.of_node, mdc_of_xlate, mdma); if (ret) @@ -982,8 +1009,10 @@ static int mdc_dma_probe(struct platform_device *pdev) unregister: dma_async_device_unregister(&mdma->dma_dev); -disable_clk: - clk_disable_unprepare(mdma->clk); +suspend: + if (!pm_runtime_enabled(&pdev->dev)) + img_mdc_runtime_suspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); return ret; } @@ -1004,14 +1033,47 @@ static int mdc_dma_remove(struct platform_device *pdev) tasklet_kill(&mchan->vc.task); } - clk_disable_unprepare(mdma->clk); + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + img_mdc_runtime_suspend(&pdev->dev); return 0; } +#ifdef CONFIG_PM_SLEEP +static int img_mdc_suspend_late(struct device *dev) +{ + struct mdc_dma *mdma = dev_get_drvdata(dev); + int i; + + /* Check that all channels are idle */ + for (i = 0; i < mdma->nr_channels; i++) { + struct mdc_chan *mchan = &mdma->channels[i]; + + if (unlikely(mchan->desc)) + return -EBUSY; + } + + return pm_runtime_force_suspend(dev); +} + +static int img_mdc_resume_early(struct device *dev) +{ + return pm_runtime_force_resume(dev); +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops img_mdc_pm_ops = { + SET_RUNTIME_PM_OPS(img_mdc_runtime_suspend, + img_mdc_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(img_mdc_suspend_late, + img_mdc_resume_early) +}; + static struct platform_driver mdc_dma_driver = { .driver = { .name = "img-mdc-dma", + .pm = &img_mdc_pm_ops, .of_match_table = of_match_ptr(mdc_dma_of_match), }, .probe = mdc_dma_probe, diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index f681df8f0ed3..331f863c605e 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -364,9 +364,9 @@ static void imxdma_disable_hw(struct imxdma_channel *imxdmac) local_irq_restore(flags); } -static void imxdma_watchdog(unsigned long data) +static void imxdma_watchdog(struct timer_list *t) { - struct imxdma_channel *imxdmac = (struct imxdma_channel *)data; + struct imxdma_channel *imxdmac = from_timer(imxdmac, t, watchdog); struct imxdma_engine *imxdma = imxdmac->imxdma; int channel = imxdmac->channel; @@ -1153,9 +1153,7 @@ static int __init imxdma_probe(struct platform_device *pdev) } imxdmac->irq = irq + i; - init_timer(&imxdmac->watchdog); - imxdmac->watchdog.function = &imxdma_watchdog; - imxdmac->watchdog.data = (unsigned long)imxdmac; + timer_setup(&imxdmac->watchdog, imxdma_watchdog, 0); } imxdmac->imxdma = imxdma; |
