diff options
author | Andy Shevchenko <andriy.shevchenko@linux.intel.com> | 2016-03-18 10:24:53 -0400 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2016-04-13 12:06:16 -0400 |
commit | b68fd0976286e0cc4e163a83b8b68d6efca814dd (patch) | |
tree | 10737c6c433fe56d420952f63183657c002a01b9 /drivers/dma/dw | |
parent | 423f9cbf2da8110e01eee56b8f755332432e82c7 (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.c | 60 | ||||
-rw-r--r-- | drivers/dma/dw/regs.h | 2 |
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 | ||
1062 | static inline u32 dwc_get_residue(struct dw_dma_chan *dwc) | 1059 | static 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 | |||
1070 | static 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) |