diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-12 18:26:48 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-12 18:26:48 -0500 |
commit | 26ceb127f7bcf473db926c6a026b18ddd6f274e8 (patch) | |
tree | a8944a9c0730c409b0cfb17c541085face068556 /drivers/dma | |
parent | 8d14066755592a2906b4f2378aeb5471b602d3cb (diff) | |
parent | e9f2d6d66037cdf97487491e04053f411abc5d16 (diff) |
Merge branch 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm
Pull ARM updates from Russell King:
"The major updates included in this update are:
- Clang compatible stack pointer accesses by Behan Webster.
- SA11x0 updates from Dmitry Eremin-Solenikov.
- kgdb handling of breakpoints with read-only text/modules
- Support for Privileged-no-execute feature on ARMv7 to prevent
userspace code execution by the kernel.
- AMBA primecell bus handling of irq-safe runtime PM
- Unwinding support for memset/memzero/memmove/memcpy functions
- VFP fixes for Krait CPUs and improvements in detecting the VFP
architecture
- A number of code cleanups (using pr_*, removing or reducing the
severity of a couple of kernel messages, splitting ftrace asm code
out to a separate file, etc.)
- Add machine name to stack dump output"
* 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm: (62 commits)
ARM: 8247/2: pcmcia: sa1100: make use of device clock
ARM: 8246/2: pcmcia: sa1111: provide device clock
ARM: 8245/1: pcmcia: soc-common: enable/disable socket clocks
ARM: 8244/1: fbdev: sa1100fb: make use of device clock
ARM: 8243/1: sa1100: add a clock alias for sa1111 pcmcia device
ARM: 8242/1: sa1100: add cpu clock
ARM: 8221/1: PJ4: allow building in Thumb-2 mode
ARM: 8234/1: sa1100: reorder IRQ handling code
ARM: 8233/1: sa1100: switch to hwirq usage
ARM: 8232/1: sa1100: merge GPIO multiplexer IRQ to "normal" irq domain
ARM: 8231/1: sa1100: introduce irqdomains support
ARM: 8230/1: sa1100: shift IRQs by one
ARM: 8229/1: sa1100: replace irq numbers with names in irq driver
ARM: 8228/1: sa1100: drop entry-macro.S
ARM: 8227/1: sa1100: switch to MULTI_IRQ_HANDLER
ARM: 8241/1: Update processor_modes for hyp and monitor mode
ARM: 8240/1: MCPM: document mcpm_sync_init()
ARM: 8239/1: Introduce {set,clear}_pte_bit
ARM: 8238/1: mm: Refine set_memory_* functions
ARM: 8237/1: fix flush_pfn_alias
...
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/pl330.c | 99 |
1 files changed, 95 insertions, 4 deletions
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 025b905f6db2..bdf40b530032 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/of.h> | 27 | #include <linux/of.h> |
28 | #include <linux/of_dma.h> | 28 | #include <linux/of_dma.h> |
29 | #include <linux/err.h> | 29 | #include <linux/err.h> |
30 | #include <linux/pm_runtime.h> | ||
30 | 31 | ||
31 | #include "dmaengine.h" | 32 | #include "dmaengine.h" |
32 | #define PL330_MAX_CHAN 8 | 33 | #define PL330_MAX_CHAN 8 |
@@ -265,6 +266,9 @@ static unsigned cmd_line; | |||
265 | 266 | ||
266 | #define NR_DEFAULT_DESC 16 | 267 | #define NR_DEFAULT_DESC 16 |
267 | 268 | ||
269 | /* Delay for runtime PM autosuspend, ms */ | ||
270 | #define PL330_AUTOSUSPEND_DELAY 20 | ||
271 | |||
268 | /* Populated by the PL330 core driver for DMA API driver's info */ | 272 | /* Populated by the PL330 core driver for DMA API driver's info */ |
269 | struct pl330_config { | 273 | struct pl330_config { |
270 | u32 periph_id; | 274 | u32 periph_id; |
@@ -1958,6 +1962,7 @@ static void pl330_tasklet(unsigned long data) | |||
1958 | struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data; | 1962 | struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data; |
1959 | struct dma_pl330_desc *desc, *_dt; | 1963 | struct dma_pl330_desc *desc, *_dt; |
1960 | unsigned long flags; | 1964 | unsigned long flags; |
1965 | bool power_down = false; | ||
1961 | 1966 | ||
1962 | spin_lock_irqsave(&pch->lock, flags); | 1967 | spin_lock_irqsave(&pch->lock, flags); |
1963 | 1968 | ||
@@ -1972,10 +1977,17 @@ static void pl330_tasklet(unsigned long data) | |||
1972 | /* Try to submit a req imm. next to the last completed cookie */ | 1977 | /* Try to submit a req imm. next to the last completed cookie */ |
1973 | fill_queue(pch); | 1978 | fill_queue(pch); |
1974 | 1979 | ||
1975 | /* Make sure the PL330 Channel thread is active */ | 1980 | if (list_empty(&pch->work_list)) { |
1976 | spin_lock(&pch->thread->dmac->lock); | 1981 | spin_lock(&pch->thread->dmac->lock); |
1977 | _start(pch->thread); | 1982 | _stop(pch->thread); |
1978 | spin_unlock(&pch->thread->dmac->lock); | 1983 | spin_unlock(&pch->thread->dmac->lock); |
1984 | power_down = true; | ||
1985 | } else { | ||
1986 | /* Make sure the PL330 Channel thread is active */ | ||
1987 | spin_lock(&pch->thread->dmac->lock); | ||
1988 | _start(pch->thread); | ||
1989 | spin_unlock(&pch->thread->dmac->lock); | ||
1990 | } | ||
1979 | 1991 | ||
1980 | while (!list_empty(&pch->completed_list)) { | 1992 | while (!list_empty(&pch->completed_list)) { |
1981 | dma_async_tx_callback callback; | 1993 | dma_async_tx_callback callback; |
@@ -1990,6 +2002,12 @@ static void pl330_tasklet(unsigned long data) | |||
1990 | if (pch->cyclic) { | 2002 | if (pch->cyclic) { |
1991 | desc->status = PREP; | 2003 | desc->status = PREP; |
1992 | list_move_tail(&desc->node, &pch->work_list); | 2004 | list_move_tail(&desc->node, &pch->work_list); |
2005 | if (power_down) { | ||
2006 | spin_lock(&pch->thread->dmac->lock); | ||
2007 | _start(pch->thread); | ||
2008 | spin_unlock(&pch->thread->dmac->lock); | ||
2009 | power_down = false; | ||
2010 | } | ||
1993 | } else { | 2011 | } else { |
1994 | desc->status = FREE; | 2012 | desc->status = FREE; |
1995 | list_move_tail(&desc->node, &pch->dmac->desc_pool); | 2013 | list_move_tail(&desc->node, &pch->dmac->desc_pool); |
@@ -2004,6 +2022,12 @@ static void pl330_tasklet(unsigned long data) | |||
2004 | } | 2022 | } |
2005 | } | 2023 | } |
2006 | spin_unlock_irqrestore(&pch->lock, flags); | 2024 | spin_unlock_irqrestore(&pch->lock, flags); |
2025 | |||
2026 | /* If work list empty, power down */ | ||
2027 | if (power_down) { | ||
2028 | pm_runtime_mark_last_busy(pch->dmac->ddma.dev); | ||
2029 | pm_runtime_put_autosuspend(pch->dmac->ddma.dev); | ||
2030 | } | ||
2007 | } | 2031 | } |
2008 | 2032 | ||
2009 | bool pl330_filter(struct dma_chan *chan, void *param) | 2033 | bool pl330_filter(struct dma_chan *chan, void *param) |
@@ -2073,6 +2097,7 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned | |||
2073 | 2097 | ||
2074 | switch (cmd) { | 2098 | switch (cmd) { |
2075 | case DMA_TERMINATE_ALL: | 2099 | case DMA_TERMINATE_ALL: |
2100 | pm_runtime_get_sync(pl330->ddma.dev); | ||
2076 | spin_lock_irqsave(&pch->lock, flags); | 2101 | spin_lock_irqsave(&pch->lock, flags); |
2077 | 2102 | ||
2078 | spin_lock(&pl330->lock); | 2103 | spin_lock(&pl330->lock); |
@@ -2099,10 +2124,15 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned | |||
2099 | dma_cookie_complete(&desc->txd); | 2124 | dma_cookie_complete(&desc->txd); |
2100 | } | 2125 | } |
2101 | 2126 | ||
2127 | if (!list_empty(&pch->work_list)) | ||
2128 | pm_runtime_put(pl330->ddma.dev); | ||
2129 | |||
2102 | list_splice_tail_init(&pch->submitted_list, &pl330->desc_pool); | 2130 | list_splice_tail_init(&pch->submitted_list, &pl330->desc_pool); |
2103 | list_splice_tail_init(&pch->work_list, &pl330->desc_pool); | 2131 | list_splice_tail_init(&pch->work_list, &pl330->desc_pool); |
2104 | list_splice_tail_init(&pch->completed_list, &pl330->desc_pool); | 2132 | list_splice_tail_init(&pch->completed_list, &pl330->desc_pool); |
2105 | spin_unlock_irqrestore(&pch->lock, flags); | 2133 | spin_unlock_irqrestore(&pch->lock, flags); |
2134 | pm_runtime_mark_last_busy(pl330->ddma.dev); | ||
2135 | pm_runtime_put_autosuspend(pl330->ddma.dev); | ||
2106 | break; | 2136 | break; |
2107 | case DMA_SLAVE_CONFIG: | 2137 | case DMA_SLAVE_CONFIG: |
2108 | slave_config = (struct dma_slave_config *)arg; | 2138 | slave_config = (struct dma_slave_config *)arg; |
@@ -2138,6 +2168,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan) | |||
2138 | 2168 | ||
2139 | tasklet_kill(&pch->task); | 2169 | tasklet_kill(&pch->task); |
2140 | 2170 | ||
2171 | pm_runtime_get_sync(pch->dmac->ddma.dev); | ||
2141 | spin_lock_irqsave(&pch->lock, flags); | 2172 | spin_lock_irqsave(&pch->lock, flags); |
2142 | 2173 | ||
2143 | pl330_release_channel(pch->thread); | 2174 | pl330_release_channel(pch->thread); |
@@ -2147,6 +2178,8 @@ static void pl330_free_chan_resources(struct dma_chan *chan) | |||
2147 | list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool); | 2178 | list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool); |
2148 | 2179 | ||
2149 | spin_unlock_irqrestore(&pch->lock, flags); | 2180 | spin_unlock_irqrestore(&pch->lock, flags); |
2181 | pm_runtime_mark_last_busy(pch->dmac->ddma.dev); | ||
2182 | pm_runtime_put_autosuspend(pch->dmac->ddma.dev); | ||
2150 | } | 2183 | } |
2151 | 2184 | ||
2152 | static enum dma_status | 2185 | static enum dma_status |
@@ -2162,6 +2195,15 @@ static void pl330_issue_pending(struct dma_chan *chan) | |||
2162 | unsigned long flags; | 2195 | unsigned long flags; |
2163 | 2196 | ||
2164 | spin_lock_irqsave(&pch->lock, flags); | 2197 | spin_lock_irqsave(&pch->lock, flags); |
2198 | if (list_empty(&pch->work_list)) { | ||
2199 | /* | ||
2200 | * Warn on nothing pending. Empty submitted_list may | ||
2201 | * break our pm_runtime usage counter as it is | ||
2202 | * updated on work_list emptiness status. | ||
2203 | */ | ||
2204 | WARN_ON(list_empty(&pch->submitted_list)); | ||
2205 | pm_runtime_get_sync(pch->dmac->ddma.dev); | ||
2206 | } | ||
2165 | list_splice_tail_init(&pch->submitted_list, &pch->work_list); | 2207 | list_splice_tail_init(&pch->submitted_list, &pch->work_list); |
2166 | spin_unlock_irqrestore(&pch->lock, flags); | 2208 | spin_unlock_irqrestore(&pch->lock, flags); |
2167 | 2209 | ||
@@ -2594,6 +2636,46 @@ static int pl330_dma_device_slave_caps(struct dma_chan *dchan, | |||
2594 | return 0; | 2636 | return 0; |
2595 | } | 2637 | } |
2596 | 2638 | ||
2639 | /* | ||
2640 | * Runtime PM callbacks are provided by amba/bus.c driver. | ||
2641 | * | ||
2642 | * It is assumed here that IRQ safe runtime PM is chosen in probe and amba | ||
2643 | * bus driver will only disable/enable the clock in runtime PM callbacks. | ||
2644 | */ | ||
2645 | static int __maybe_unused pl330_suspend(struct device *dev) | ||
2646 | { | ||
2647 | struct amba_device *pcdev = to_amba_device(dev); | ||
2648 | |||
2649 | pm_runtime_disable(dev); | ||
2650 | |||
2651 | if (!pm_runtime_status_suspended(dev)) { | ||
2652 | /* amba did not disable the clock */ | ||
2653 | amba_pclk_disable(pcdev); | ||
2654 | } | ||
2655 | amba_pclk_unprepare(pcdev); | ||
2656 | |||
2657 | return 0; | ||
2658 | } | ||
2659 | |||
2660 | static int __maybe_unused pl330_resume(struct device *dev) | ||
2661 | { | ||
2662 | struct amba_device *pcdev = to_amba_device(dev); | ||
2663 | int ret; | ||
2664 | |||
2665 | ret = amba_pclk_prepare(pcdev); | ||
2666 | if (ret) | ||
2667 | return ret; | ||
2668 | |||
2669 | if (!pm_runtime_status_suspended(dev)) | ||
2670 | ret = amba_pclk_enable(pcdev); | ||
2671 | |||
2672 | pm_runtime_enable(dev); | ||
2673 | |||
2674 | return ret; | ||
2675 | } | ||
2676 | |||
2677 | static SIMPLE_DEV_PM_OPS(pl330_pm, pl330_suspend, pl330_resume); | ||
2678 | |||
2597 | static int | 2679 | static int |
2598 | pl330_probe(struct amba_device *adev, const struct amba_id *id) | 2680 | pl330_probe(struct amba_device *adev, const struct amba_id *id) |
2599 | { | 2681 | { |
@@ -2748,6 +2830,12 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) | |||
2748 | pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan, | 2830 | pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan, |
2749 | pcfg->num_peri, pcfg->num_events); | 2831 | pcfg->num_peri, pcfg->num_events); |
2750 | 2832 | ||
2833 | pm_runtime_irq_safe(&adev->dev); | ||
2834 | pm_runtime_use_autosuspend(&adev->dev); | ||
2835 | pm_runtime_set_autosuspend_delay(&adev->dev, PL330_AUTOSUSPEND_DELAY); | ||
2836 | pm_runtime_mark_last_busy(&adev->dev); | ||
2837 | pm_runtime_put_autosuspend(&adev->dev); | ||
2838 | |||
2751 | return 0; | 2839 | return 0; |
2752 | probe_err3: | 2840 | probe_err3: |
2753 | /* Idle the DMAC */ | 2841 | /* Idle the DMAC */ |
@@ -2774,6 +2862,8 @@ static int pl330_remove(struct amba_device *adev) | |||
2774 | struct pl330_dmac *pl330 = amba_get_drvdata(adev); | 2862 | struct pl330_dmac *pl330 = amba_get_drvdata(adev); |
2775 | struct dma_pl330_chan *pch, *_p; | 2863 | struct dma_pl330_chan *pch, *_p; |
2776 | 2864 | ||
2865 | pm_runtime_get_noresume(pl330->ddma.dev); | ||
2866 | |||
2777 | if (adev->dev.of_node) | 2867 | if (adev->dev.of_node) |
2778 | of_dma_controller_free(adev->dev.of_node); | 2868 | of_dma_controller_free(adev->dev.of_node); |
2779 | 2869 | ||
@@ -2812,6 +2902,7 @@ static struct amba_driver pl330_driver = { | |||
2812 | .drv = { | 2902 | .drv = { |
2813 | .owner = THIS_MODULE, | 2903 | .owner = THIS_MODULE, |
2814 | .name = "dma-pl330", | 2904 | .name = "dma-pl330", |
2905 | .pm = &pl330_pm, | ||
2815 | }, | 2906 | }, |
2816 | .id_table = pl330_ids, | 2907 | .id_table = pl330_ids, |
2817 | .probe = pl330_probe, | 2908 | .probe = pl330_probe, |