diff options
| -rw-r--r-- | drivers/dma/pl330.c | 74 |
1 files changed, 72 insertions, 2 deletions
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 2dbc93011c0e..944b67622916 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c | |||
| @@ -504,6 +504,9 @@ struct dma_pl330_desc { | |||
| 504 | 504 | ||
| 505 | enum desc_status status; | 505 | enum desc_status status; |
| 506 | 506 | ||
| 507 | int bytes_requested; | ||
| 508 | bool last; | ||
| 509 | |||
| 507 | /* The channel which currently holds this desc */ | 510 | /* The channel which currently holds this desc */ |
| 508 | struct dma_pl330_chan *pchan; | 511 | struct dma_pl330_chan *pchan; |
| 509 | 512 | ||
| @@ -2173,11 +2176,74 @@ static void pl330_free_chan_resources(struct dma_chan *chan) | |||
| 2173 | pm_runtime_put_autosuspend(pch->dmac->ddma.dev); | 2176 | pm_runtime_put_autosuspend(pch->dmac->ddma.dev); |
| 2174 | } | 2177 | } |
| 2175 | 2178 | ||
| 2179 | int pl330_get_current_xferred_count(struct dma_pl330_chan *pch, | ||
| 2180 | struct dma_pl330_desc *desc) | ||
| 2181 | { | ||
| 2182 | struct pl330_thread *thrd = pch->thread; | ||
| 2183 | struct pl330_dmac *pl330 = pch->dmac; | ||
| 2184 | void __iomem *regs = thrd->dmac->base; | ||
| 2185 | u32 val, addr; | ||
| 2186 | |||
| 2187 | pm_runtime_get_sync(pl330->ddma.dev); | ||
| 2188 | val = addr = 0; | ||
| 2189 | if (desc->rqcfg.src_inc) { | ||
| 2190 | val = readl(regs + SA(thrd->id)); | ||
| 2191 | addr = desc->px.src_addr; | ||
| 2192 | } else { | ||
| 2193 | val = readl(regs + DA(thrd->id)); | ||
| 2194 | addr = desc->px.dst_addr; | ||
| 2195 | } | ||
| 2196 | pm_runtime_mark_last_busy(pch->dmac->ddma.dev); | ||
| 2197 | pm_runtime_put_autosuspend(pl330->ddma.dev); | ||
| 2198 | return val - addr; | ||
| 2199 | } | ||
| 2200 | |||
| 2176 | static enum dma_status | 2201 | static enum dma_status |
| 2177 | pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie, | 2202 | pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie, |
| 2178 | struct dma_tx_state *txstate) | 2203 | struct dma_tx_state *txstate) |
| 2179 | { | 2204 | { |
| 2180 | return dma_cookie_status(chan, cookie, txstate); | 2205 | enum dma_status ret; |
| 2206 | unsigned long flags; | ||
| 2207 | struct dma_pl330_desc *desc, *running = NULL; | ||
| 2208 | struct dma_pl330_chan *pch = to_pchan(chan); | ||
| 2209 | unsigned int transferred, residual = 0; | ||
| 2210 | |||
| 2211 | ret = dma_cookie_status(chan, cookie, txstate); | ||
| 2212 | |||
| 2213 | if (!txstate) | ||
| 2214 | return ret; | ||
| 2215 | |||
| 2216 | if (ret == DMA_COMPLETE) | ||
| 2217 | goto out; | ||
| 2218 | |||
| 2219 | spin_lock_irqsave(&pch->lock, flags); | ||
| 2220 | |||
| 2221 | if (pch->thread->req_running != -1) | ||
| 2222 | running = pch->thread->req[pch->thread->req_running].desc; | ||
| 2223 | |||
| 2224 | /* Check in pending list */ | ||
| 2225 | list_for_each_entry(desc, &pch->work_list, node) { | ||
| 2226 | if (desc->status == DONE) | ||
| 2227 | transferred = desc->bytes_requested; | ||
| 2228 | else if (running && desc == running) | ||
| 2229 | transferred = | ||
| 2230 | pl330_get_current_xferred_count(pch, desc); | ||
| 2231 | else | ||
| 2232 | transferred = 0; | ||
| 2233 | residual += desc->bytes_requested - transferred; | ||
| 2234 | if (desc->txd.cookie == cookie) { | ||
| 2235 | ret = desc->status; | ||
| 2236 | break; | ||
| 2237 | } | ||
| 2238 | if (desc->last) | ||
| 2239 | residual = 0; | ||
| 2240 | } | ||
| 2241 | spin_unlock_irqrestore(&pch->lock, flags); | ||
| 2242 | |||
| 2243 | out: | ||
| 2244 | dma_set_residue(txstate, residual); | ||
| 2245 | |||
| 2246 | return ret; | ||
| 2181 | } | 2247 | } |
| 2182 | 2248 | ||
| 2183 | static void pl330_issue_pending(struct dma_chan *chan) | 2249 | static void pl330_issue_pending(struct dma_chan *chan) |
| @@ -2222,12 +2288,14 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx) | |||
| 2222 | desc->txd.callback = last->txd.callback; | 2288 | desc->txd.callback = last->txd.callback; |
| 2223 | desc->txd.callback_param = last->txd.callback_param; | 2289 | desc->txd.callback_param = last->txd.callback_param; |
| 2224 | } | 2290 | } |
| 2291 | last->last = false; | ||
| 2225 | 2292 | ||
| 2226 | dma_cookie_assign(&desc->txd); | 2293 | dma_cookie_assign(&desc->txd); |
| 2227 | 2294 | ||
| 2228 | list_move_tail(&desc->node, &pch->submitted_list); | 2295 | list_move_tail(&desc->node, &pch->submitted_list); |
| 2229 | } | 2296 | } |
| 2230 | 2297 | ||
| 2298 | last->last = true; | ||
| 2231 | cookie = dma_cookie_assign(&last->txd); | 2299 | cookie = dma_cookie_assign(&last->txd); |
| 2232 | list_add_tail(&last->node, &pch->submitted_list); | 2300 | list_add_tail(&last->node, &pch->submitted_list); |
| 2233 | spin_unlock_irqrestore(&pch->lock, flags); | 2301 | spin_unlock_irqrestore(&pch->lock, flags); |
| @@ -2450,6 +2518,7 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( | |||
| 2450 | desc->rqtype = direction; | 2518 | desc->rqtype = direction; |
| 2451 | desc->rqcfg.brst_size = pch->burst_sz; | 2519 | desc->rqcfg.brst_size = pch->burst_sz; |
| 2452 | desc->rqcfg.brst_len = 1; | 2520 | desc->rqcfg.brst_len = 1; |
| 2521 | desc->bytes_requested = period_len; | ||
| 2453 | fill_px(&desc->px, dst, src, period_len); | 2522 | fill_px(&desc->px, dst, src, period_len); |
| 2454 | 2523 | ||
| 2455 | if (!first) | 2524 | if (!first) |
| @@ -2592,6 +2661,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
| 2592 | desc->rqcfg.brst_size = pch->burst_sz; | 2661 | desc->rqcfg.brst_size = pch->burst_sz; |
| 2593 | desc->rqcfg.brst_len = 1; | 2662 | desc->rqcfg.brst_len = 1; |
| 2594 | desc->rqtype = direction; | 2663 | desc->rqtype = direction; |
| 2664 | desc->bytes_requested = sg_dma_len(sg); | ||
| 2595 | } | 2665 | } |
| 2596 | 2666 | ||
| 2597 | /* Return the last desc in the chain */ | 2667 | /* Return the last desc in the chain */ |
| @@ -2777,7 +2847,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) | |||
| 2777 | pd->src_addr_widths = PL330_DMA_BUSWIDTHS; | 2847 | pd->src_addr_widths = PL330_DMA_BUSWIDTHS; |
| 2778 | pd->dst_addr_widths = PL330_DMA_BUSWIDTHS; | 2848 | pd->dst_addr_widths = PL330_DMA_BUSWIDTHS; |
| 2779 | pd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); | 2849 | pd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); |
| 2780 | pd->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; | 2850 | pd->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; |
| 2781 | 2851 | ||
| 2782 | ret = dma_async_device_register(pd); | 2852 | ret = dma_async_device_register(pd); |
| 2783 | if (ret) { | 2853 | if (ret) { |
