diff options
-rw-r--r-- | drivers/dma/pl330.c | 58 |
1 files changed, 54 insertions, 4 deletions
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 4839bfa74a10..39ea8d436b81 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 | ||
@@ -2738,6 +2780,12 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) | |||
2738 | pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan, | 2780 | pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan, |
2739 | pcfg->num_peri, pcfg->num_events); | 2781 | pcfg->num_peri, pcfg->num_events); |
2740 | 2782 | ||
2783 | pm_runtime_irq_safe(&adev->dev); | ||
2784 | pm_runtime_use_autosuspend(&adev->dev); | ||
2785 | pm_runtime_set_autosuspend_delay(&adev->dev, PL330_AUTOSUSPEND_DELAY); | ||
2786 | pm_runtime_mark_last_busy(&adev->dev); | ||
2787 | pm_runtime_put_autosuspend(&adev->dev); | ||
2788 | |||
2741 | return 0; | 2789 | return 0; |
2742 | probe_err3: | 2790 | probe_err3: |
2743 | /* Idle the DMAC */ | 2791 | /* Idle the DMAC */ |
@@ -2764,6 +2812,8 @@ static int pl330_remove(struct amba_device *adev) | |||
2764 | struct pl330_dmac *pl330 = amba_get_drvdata(adev); | 2812 | struct pl330_dmac *pl330 = amba_get_drvdata(adev); |
2765 | struct dma_pl330_chan *pch, *_p; | 2813 | struct dma_pl330_chan *pch, *_p; |
2766 | 2814 | ||
2815 | pm_runtime_get_noresume(pl330->ddma.dev); | ||
2816 | |||
2767 | if (adev->dev.of_node) | 2817 | if (adev->dev.of_node) |
2768 | of_dma_controller_free(adev->dev.of_node); | 2818 | of_dma_controller_free(adev->dev.of_node); |
2769 | 2819 | ||