summaryrefslogtreecommitdiffstats
path: root/drivers/dma/dw
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2016-03-18 10:24:53 -0400
committerVinod Koul <vinod.koul@intel.com>2016-04-13 12:06:16 -0400
commitb68fd0976286e0cc4e163a83b8b68d6efca814dd (patch)
tree10737c6c433fe56d420952f63183657c002a01b9 /drivers/dma/dw
parent423f9cbf2da8110e01eee56b8f755332432e82c7 (diff)
dmaengine: dw: move residue to a descriptor
Residue is a property of any active descriptor. So, any descriptor may be in different state but residue is a feature of active descriptor. Check if the asked descriptor is active and return proper residue value for it. Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma/dw')
-rw-r--r--drivers/dma/dw/core.c60
-rw-r--r--drivers/dma/dw/regs.h2
2 files changed, 41 insertions, 21 deletions
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index 848d33507df9..a6d96f32f4f9 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -242,7 +242,7 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
242 242
243 dwc_initialize(dwc); 243 dwc_initialize(dwc);
244 244
245 dwc->residue = first->total_len; 245 first->residue = first->total_len;
246 dwc->tx_node_active = &first->tx_list; 246 dwc->tx_node_active = &first->tx_list;
247 247
248 /* Submit first block */ 248 /* Submit first block */
@@ -372,11 +372,11 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
372 372
373 head = &desc->tx_list; 373 head = &desc->tx_list;
374 if (active != head) { 374 if (active != head) {
375 /* Update desc to reflect last sent one */ 375 /* Update residue to reflect last sent descriptor */
376 if (active != head->next) 376 if (active == head->next)
377 desc = to_dw_desc(active->prev); 377 desc->residue -= desc->len;
378 378 else
379 dwc->residue -= desc->len; 379 desc->residue -= to_dw_desc(active->prev)->len;
380 380
381 child = to_dw_desc(active); 381 child = to_dw_desc(active);
382 382
@@ -391,8 +391,6 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
391 clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags); 391 clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
392 } 392 }
393 393
394 dwc->residue = 0;
395
396 spin_unlock_irqrestore(&dwc->lock, flags); 394 spin_unlock_irqrestore(&dwc->lock, flags);
397 395
398 dwc_complete_all(dw, dwc); 396 dwc_complete_all(dw, dwc);
@@ -400,7 +398,6 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
400 } 398 }
401 399
402 if (list_empty(&dwc->active_list)) { 400 if (list_empty(&dwc->active_list)) {
403 dwc->residue = 0;
404 spin_unlock_irqrestore(&dwc->lock, flags); 401 spin_unlock_irqrestore(&dwc->lock, flags);
405 return; 402 return;
406 } 403 }
@@ -415,7 +412,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
415 412
416 list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) { 413 list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
417 /* Initial residue value */ 414 /* Initial residue value */
418 dwc->residue = desc->total_len; 415 desc->residue = desc->total_len;
419 416
420 /* Check first descriptors addr */ 417 /* Check first descriptors addr */
421 if (desc->txd.phys == DWC_LLP_LOC(llp)) { 418 if (desc->txd.phys == DWC_LLP_LOC(llp)) {
@@ -426,20 +423,20 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
426 /* Check first descriptors llp */ 423 /* Check first descriptors llp */
427 if (lli_read(desc, llp) == llp) { 424 if (lli_read(desc, llp) == llp) {
428 /* This one is currently in progress */ 425 /* This one is currently in progress */
429 dwc->residue -= dwc_get_sent(dwc); 426 desc->residue -= dwc_get_sent(dwc);
430 spin_unlock_irqrestore(&dwc->lock, flags); 427 spin_unlock_irqrestore(&dwc->lock, flags);
431 return; 428 return;
432 } 429 }
433 430
434 dwc->residue -= desc->len; 431 desc->residue -= desc->len;
435 list_for_each_entry(child, &desc->tx_list, desc_node) { 432 list_for_each_entry(child, &desc->tx_list, desc_node) {
436 if (lli_read(child, llp) == llp) { 433 if (lli_read(child, llp) == llp) {
437 /* Currently in progress */ 434 /* Currently in progress */
438 dwc->residue -= dwc_get_sent(dwc); 435 desc->residue -= dwc_get_sent(dwc);
439 spin_unlock_irqrestore(&dwc->lock, flags); 436 spin_unlock_irqrestore(&dwc->lock, flags);
440 return; 437 return;
441 } 438 }
442 dwc->residue -= child->len; 439 desc->residue -= child->len;
443 } 440 }
444 441
445 /* 442 /*
@@ -1059,16 +1056,37 @@ static int dwc_terminate_all(struct dma_chan *chan)
1059 return 0; 1056 return 0;
1060} 1057}
1061 1058
1062static inline u32 dwc_get_residue(struct dw_dma_chan *dwc) 1059static struct dw_desc *dwc_find_desc(struct dw_dma_chan *dwc, dma_cookie_t c)
1060{
1061 struct dw_desc *desc;
1062
1063 list_for_each_entry(desc, &dwc->active_list, desc_node)
1064 if (desc->txd.cookie == c)
1065 return desc;
1066
1067 return NULL;
1068}
1069
1070static u32 dwc_get_residue(struct dw_dma_chan *dwc, dma_cookie_t cookie)
1063{ 1071{
1072 struct dw_desc *desc;
1064 unsigned long flags; 1073 unsigned long flags;
1065 u32 residue; 1074 u32 residue;
1066 1075
1067 spin_lock_irqsave(&dwc->lock, flags); 1076 spin_lock_irqsave(&dwc->lock, flags);
1068 1077
1069 residue = dwc->residue; 1078 desc = dwc_find_desc(dwc, cookie);
1070 if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags) && residue) 1079 if (desc) {
1071 residue -= dwc_get_sent(dwc); 1080 if (desc == dwc_first_active(dwc)) {
1081 residue = desc->residue;
1082 if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags) && residue)
1083 residue -= dwc_get_sent(dwc);
1084 } else {
1085 residue = desc->total_len;
1086 }
1087 } else {
1088 residue = 0;
1089 }
1072 1090
1073 spin_unlock_irqrestore(&dwc->lock, flags); 1091 spin_unlock_irqrestore(&dwc->lock, flags);
1074 return residue; 1092 return residue;
@@ -1089,8 +1107,10 @@ dwc_tx_status(struct dma_chan *chan,
1089 dwc_scan_descriptors(to_dw_dma(chan->device), dwc); 1107 dwc_scan_descriptors(to_dw_dma(chan->device), dwc);
1090 1108
1091 ret = dma_cookie_status(chan, cookie, txstate); 1109 ret = dma_cookie_status(chan, cookie, txstate);
1092 if (ret != DMA_COMPLETE) 1110 if (ret == DMA_COMPLETE)
1093 dma_set_residue(txstate, dwc_get_residue(dwc)); 1111 return ret;
1112
1113 dma_set_residue(txstate, dwc_get_residue(dwc, cookie));
1094 1114
1095 if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags) && ret == DMA_IN_PROGRESS) 1115 if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags) && ret == DMA_IN_PROGRESS)
1096 return DMA_PAUSED; 1116 return DMA_PAUSED;
diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h
index 89178641e80b..96f498188257 100644
--- a/drivers/dma/dw/regs.h
+++ b/drivers/dma/dw/regs.h
@@ -237,7 +237,6 @@ struct dw_dma_chan {
237 struct list_head active_list; 237 struct list_head active_list;
238 struct list_head queue; 238 struct list_head queue;
239 struct list_head free_list; 239 struct list_head free_list;
240 u32 residue;
241 struct dw_cyclic_desc *cdesc; 240 struct dw_cyclic_desc *cdesc;
242 241
243 unsigned int descs_allocated; 242 unsigned int descs_allocated;
@@ -352,6 +351,7 @@ struct dw_desc {
352 struct dma_async_tx_descriptor txd; 351 struct dma_async_tx_descriptor txd;
353 size_t len; 352 size_t len;
354 size_t total_len; 353 size_t total_len;
354 u32 residue;
355}; 355};
356 356
357#define to_dw_desc(h) list_entry(h, struct dw_desc, desc_node) 357#define to_dw_desc(h) list_entry(h, struct dw_desc, desc_node)