diff options
| author | Ira Snyder <iws@ovro.caltech.edu> | 2010-01-06 08:34:06 -0500 |
|---|---|---|
| committer | Dan Williams <dan.j.williams@intel.com> | 2010-02-02 16:51:42 -0500 |
| commit | 9c3a50b7d7ec45da34e73cac66cde12dd6092dd8 (patch) | |
| tree | a16b2dd972ba8ebdd9e6796ad8f0027513316f49 | |
| parent | a1c03319018061304be28d131073ac13a5cb86fb (diff) | |
fsldma: major cleanups and fixes
Fix locking. Use two queues in the driver, one for pending transacions, and
one for transactions which are actually running on the hardware. Call
dma_run_dependencies() on descriptor cleanup so that the async_tx API works
correctly.
There are a number of places throughout the code where lists of descriptors
are freed in a loop. Create functions to handle this, and use them instead
of open-coding the loop each time.
Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
| -rw-r--r-- | drivers/dma/fsldma.c | 386 | ||||
| -rw-r--r-- | drivers/dma/fsldma.h | 3 |
2 files changed, 207 insertions, 182 deletions
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 7b5f88cb495b..19011c20390b 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c | |||
| @@ -61,7 +61,6 @@ static void dma_init(struct fsldma_chan *chan) | |||
| 61 | | FSL_DMA_MR_PRC_RM, 32); | 61 | | FSL_DMA_MR_PRC_RM, 32); |
| 62 | break; | 62 | break; |
| 63 | } | 63 | } |
| 64 | |||
| 65 | } | 64 | } |
| 66 | 65 | ||
| 67 | static void set_sr(struct fsldma_chan *chan, u32 val) | 66 | static void set_sr(struct fsldma_chan *chan, u32 val) |
| @@ -120,11 +119,6 @@ static dma_addr_t get_cdar(struct fsldma_chan *chan) | |||
| 120 | return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN; | 119 | return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN; |
| 121 | } | 120 | } |
| 122 | 121 | ||
| 123 | static void set_ndar(struct fsldma_chan *chan, dma_addr_t addr) | ||
| 124 | { | ||
| 125 | DMA_OUT(chan, &chan->regs->ndar, addr, 64); | ||
| 126 | } | ||
| 127 | |||
| 128 | static dma_addr_t get_ndar(struct fsldma_chan *chan) | 122 | static dma_addr_t get_ndar(struct fsldma_chan *chan) |
| 129 | { | 123 | { |
| 130 | return DMA_IN(chan, &chan->regs->ndar, 64); | 124 | return DMA_IN(chan, &chan->regs->ndar, 64); |
| @@ -178,11 +172,12 @@ static void dma_halt(struct fsldma_chan *chan) | |||
| 178 | 172 | ||
| 179 | for (i = 0; i < 100; i++) { | 173 | for (i = 0; i < 100; i++) { |
| 180 | if (dma_is_idle(chan)) | 174 | if (dma_is_idle(chan)) |
| 181 | break; | 175 | return; |
| 176 | |||
| 182 | udelay(10); | 177 | udelay(10); |
| 183 | } | 178 | } |
| 184 | 179 | ||
| 185 | if (i >= 100 && !dma_is_idle(chan)) | 180 | if (!dma_is_idle(chan)) |
| 186 | dev_err(chan->dev, "DMA halt timeout!\n"); | 181 | dev_err(chan->dev, "DMA halt timeout!\n"); |
| 187 | } | 182 | } |
| 188 | 183 | ||
| @@ -199,27 +194,6 @@ static void set_ld_eol(struct fsldma_chan *chan, | |||
| 199 | | snoop_bits, 64); | 194 | | snoop_bits, 64); |
| 200 | } | 195 | } |
| 201 | 196 | ||
| 202 | static void append_ld_queue(struct fsldma_chan *chan, | ||
| 203 | struct fsl_desc_sw *new_desc) | ||
| 204 | { | ||
| 205 | struct fsl_desc_sw *queue_tail = to_fsl_desc(chan->ld_queue.prev); | ||
| 206 | |||
| 207 | if (list_empty(&chan->ld_queue)) | ||
| 208 | return; | ||
| 209 | |||
| 210 | /* Link to the new descriptor physical address and | ||
| 211 | * Enable End-of-segment interrupt for | ||
| 212 | * the last link descriptor. | ||
| 213 | * (the previous node's next link descriptor) | ||
| 214 | * | ||
| 215 | * For FSL_DMA_IP_83xx, the snoop enable bit need be set. | ||
| 216 | */ | ||
| 217 | queue_tail->hw.next_ln_addr = CPU_TO_DMA(chan, | ||
| 218 | new_desc->async_tx.phys | FSL_DMA_EOSIE | | ||
| 219 | (((chan->feature & FSL_DMA_IP_MASK) | ||
| 220 | == FSL_DMA_IP_83XX) ? FSL_DMA_SNEN : 0), 64); | ||
| 221 | } | ||
| 222 | |||
| 223 | /** | 197 | /** |
| 224 | * fsl_chan_set_src_loop_size - Set source address hold transfer size | 198 | * fsl_chan_set_src_loop_size - Set source address hold transfer size |
| 225 | * @chan : Freescale DMA channel | 199 | * @chan : Freescale DMA channel |
| @@ -343,6 +317,31 @@ static void fsl_chan_toggle_ext_start(struct fsldma_chan *chan, int enable) | |||
| 343 | chan->feature &= ~FSL_DMA_CHAN_START_EXT; | 317 | chan->feature &= ~FSL_DMA_CHAN_START_EXT; |
| 344 | } | 318 | } |
| 345 | 319 | ||
| 320 | static void append_ld_queue(struct fsldma_chan *chan, | ||
| 321 | struct fsl_desc_sw *desc) | ||
| 322 | { | ||
| 323 | struct fsl_desc_sw *tail = to_fsl_desc(chan->ld_pending.prev); | ||
| 324 | |||
| 325 | if (list_empty(&chan->ld_pending)) | ||
| 326 | goto out_splice; | ||
| 327 | |||
| 328 | /* | ||
| 329 | * Add the hardware descriptor to the chain of hardware descriptors | ||
| 330 | * that already exists in memory. | ||
| 331 | * | ||
| 332 | * This will un-set the EOL bit of the existing transaction, and the | ||
| 333 | * last link in this transaction will become the EOL descriptor. | ||
| 334 | */ | ||
| 335 | set_desc_next(chan, &tail->hw, desc->async_tx.phys); | ||
| 336 | |||
| 337 | /* | ||
| 338 | * Add the software descriptor and all children to the list | ||
| 339 | * of pending transactions | ||
| 340 | */ | ||
| 341 | out_splice: | ||
| 342 | list_splice_tail_init(&desc->tx_list, &chan->ld_pending); | ||
| 343 | } | ||
| 344 | |||
| 346 | static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx) | 345 | static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx) |
| 347 | { | 346 | { |
| 348 | struct fsldma_chan *chan = to_fsl_chan(tx->chan); | 347 | struct fsldma_chan *chan = to_fsl_chan(tx->chan); |
| @@ -351,9 +350,12 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx) | |||
| 351 | unsigned long flags; | 350 | unsigned long flags; |
| 352 | dma_cookie_t cookie; | 351 | dma_cookie_t cookie; |
| 353 | 352 | ||
| 354 | /* cookie increment and adding to ld_queue must be atomic */ | ||
| 355 | spin_lock_irqsave(&chan->desc_lock, flags); | 353 | spin_lock_irqsave(&chan->desc_lock, flags); |
| 356 | 354 | ||
| 355 | /* | ||
| 356 | * assign cookies to all of the software descriptors | ||
| 357 | * that make up this transaction | ||
| 358 | */ | ||
| 357 | cookie = chan->common.cookie; | 359 | cookie = chan->common.cookie; |
| 358 | list_for_each_entry(child, &desc->tx_list, node) { | 360 | list_for_each_entry(child, &desc->tx_list, node) { |
| 359 | cookie++; | 361 | cookie++; |
| @@ -364,8 +366,9 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx) | |||
| 364 | } | 366 | } |
| 365 | 367 | ||
| 366 | chan->common.cookie = cookie; | 368 | chan->common.cookie = cookie; |
| 369 | |||
| 370 | /* put this transaction onto the tail of the pending queue */ | ||
| 367 | append_ld_queue(chan, desc); | 371 | append_ld_queue(chan, desc); |
| 368 | list_splice_init(&desc->tx_list, chan->ld_queue.prev); | ||
| 369 | 372 | ||
| 370 | spin_unlock_irqrestore(&chan->desc_lock, flags); | 373 | spin_unlock_irqrestore(&chan->desc_lock, flags); |
| 371 | 374 | ||
| @@ -381,20 +384,22 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx) | |||
| 381 | static struct fsl_desc_sw *fsl_dma_alloc_descriptor( | 384 | static struct fsl_desc_sw *fsl_dma_alloc_descriptor( |
| 382 | struct fsldma_chan *chan) | 385 | struct fsldma_chan *chan) |
| 383 | { | 386 | { |
| 387 | struct fsl_desc_sw *desc; | ||
| 384 | dma_addr_t pdesc; | 388 | dma_addr_t pdesc; |
| 385 | struct fsl_desc_sw *desc_sw; | 389 | |
| 386 | 390 | desc = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &pdesc); | |
| 387 | desc_sw = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &pdesc); | 391 | if (!desc) { |
| 388 | if (desc_sw) { | 392 | dev_dbg(chan->dev, "out of memory for link desc\n"); |
| 389 | memset(desc_sw, 0, sizeof(struct fsl_desc_sw)); | 393 | return NULL; |
| 390 | INIT_LIST_HEAD(&desc_sw->tx_list); | ||
| 391 | dma_async_tx_descriptor_init(&desc_sw->async_tx, | ||
| 392 | &chan->common); | ||
| 393 | desc_sw->async_tx.tx_submit = fsl_dma_tx_submit; | ||
| 394 | desc_sw->async_tx.phys = pdesc; | ||
| 395 | } | 394 | } |
| 396 | 395 | ||
| 397 | return desc_sw; | 396 | memset(desc, 0, sizeof(*desc)); |
| 397 | INIT_LIST_HEAD(&desc->tx_list); | ||
| 398 | dma_async_tx_descriptor_init(&desc->async_tx, &chan->common); | ||
| 399 | desc->async_tx.tx_submit = fsl_dma_tx_submit; | ||
| 400 | desc->async_tx.phys = pdesc; | ||
| 401 | |||
| 402 | return desc; | ||
| 398 | } | 403 | } |
| 399 | 404 | ||
| 400 | 405 | ||
| @@ -414,45 +419,69 @@ static int fsl_dma_alloc_chan_resources(struct dma_chan *dchan) | |||
| 414 | if (chan->desc_pool) | 419 | if (chan->desc_pool) |
| 415 | return 1; | 420 | return 1; |
| 416 | 421 | ||
| 417 | /* We need the descriptor to be aligned to 32bytes | 422 | /* |
| 423 | * We need the descriptor to be aligned to 32bytes | ||
| 418 | * for meeting FSL DMA specification requirement. | 424 | * for meeting FSL DMA specification requirement. |
| 419 | */ | 425 | */ |
| 420 | chan->desc_pool = dma_pool_create("fsl_dma_engine_desc_pool", | 426 | chan->desc_pool = dma_pool_create("fsl_dma_engine_desc_pool", |
| 421 | chan->dev, sizeof(struct fsl_desc_sw), | 427 | chan->dev, |
| 422 | 32, 0); | 428 | sizeof(struct fsl_desc_sw), |
| 429 | __alignof__(struct fsl_desc_sw), 0); | ||
| 423 | if (!chan->desc_pool) { | 430 | if (!chan->desc_pool) { |
| 424 | dev_err(chan->dev, "No memory for channel %d " | 431 | dev_err(chan->dev, "unable to allocate channel %d " |
| 425 | "descriptor dma pool.\n", chan->id); | 432 | "descriptor pool\n", chan->id); |
| 426 | return 0; | 433 | return -ENOMEM; |
| 427 | } | 434 | } |
| 428 | 435 | ||
| 436 | /* there is at least one descriptor free to be allocated */ | ||
| 429 | return 1; | 437 | return 1; |
| 430 | } | 438 | } |
| 431 | 439 | ||
| 432 | /** | 440 | /** |
| 441 | * fsldma_free_desc_list - Free all descriptors in a queue | ||
| 442 | * @chan: Freescae DMA channel | ||
| 443 | * @list: the list to free | ||
| 444 | * | ||
| 445 | * LOCKING: must hold chan->desc_lock | ||
| 446 | */ | ||
| 447 | static void fsldma_free_desc_list(struct fsldma_chan *chan, | ||
| 448 | struct list_head *list) | ||
| 449 | { | ||
| 450 | struct fsl_desc_sw *desc, *_desc; | ||
| 451 | |||
| 452 | list_for_each_entry_safe(desc, _desc, list, node) { | ||
| 453 | list_del(&desc->node); | ||
| 454 | dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); | ||
| 455 | } | ||
| 456 | } | ||
| 457 | |||
| 458 | static void fsldma_free_desc_list_reverse(struct fsldma_chan *chan, | ||
| 459 | struct list_head *list) | ||
| 460 | { | ||
| 461 | struct fsl_desc_sw *desc, *_desc; | ||
| 462 | |||
| 463 | list_for_each_entry_safe_reverse(desc, _desc, list, node) { | ||
| 464 | list_del(&desc->node); | ||
| 465 | dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); | ||
| 466 | } | ||
| 467 | } | ||
| 468 | |||
| 469 | /** | ||
| 433 | * fsl_dma_free_chan_resources - Free all resources of the channel. | 470 | * fsl_dma_free_chan_resources - Free all resources of the channel. |
| 434 | * @chan : Freescale DMA channel | 471 | * @chan : Freescale DMA channel |
| 435 | */ | 472 | */ |
| 436 | static void fsl_dma_free_chan_resources(struct dma_chan *dchan) | 473 | static void fsl_dma_free_chan_resources(struct dma_chan *dchan) |
| 437 | { | 474 | { |
| 438 | struct fsldma_chan *chan = to_fsl_chan(dchan); | 475 | struct fsldma_chan *chan = to_fsl_chan(dchan); |
| 439 | struct fsl_desc_sw *desc, *_desc; | ||
| 440 | unsigned long flags; | 476 | unsigned long flags; |
| 441 | 477 | ||
| 442 | dev_dbg(chan->dev, "Free all channel resources.\n"); | 478 | dev_dbg(chan->dev, "Free all channel resources.\n"); |
| 443 | spin_lock_irqsave(&chan->desc_lock, flags); | 479 | spin_lock_irqsave(&chan->desc_lock, flags); |
| 444 | list_for_each_entry_safe(desc, _desc, &chan->ld_queue, node) { | 480 | fsldma_free_desc_list(chan, &chan->ld_pending); |
| 445 | #ifdef FSL_DMA_LD_DEBUG | 481 | fsldma_free_desc_list(chan, &chan->ld_running); |
| 446 | dev_dbg(chan->dev, | ||
| 447 | "LD %p will be released.\n", desc); | ||
| 448 | #endif | ||
| 449 | list_del(&desc->node); | ||
| 450 | /* free link descriptor */ | ||
| 451 | dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); | ||
| 452 | } | ||
| 453 | spin_unlock_irqrestore(&chan->desc_lock, flags); | 482 | spin_unlock_irqrestore(&chan->desc_lock, flags); |
| 454 | dma_pool_destroy(chan->desc_pool); | ||
| 455 | 483 | ||
| 484 | dma_pool_destroy(chan->desc_pool); | ||
| 456 | chan->desc_pool = NULL; | 485 | chan->desc_pool = NULL; |
| 457 | } | 486 | } |
| 458 | 487 | ||
| @@ -491,7 +520,6 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( | |||
| 491 | { | 520 | { |
| 492 | struct fsldma_chan *chan; | 521 | struct fsldma_chan *chan; |
| 493 | struct fsl_desc_sw *first = NULL, *prev = NULL, *new; | 522 | struct fsl_desc_sw *first = NULL, *prev = NULL, *new; |
| 494 | struct list_head *list; | ||
| 495 | size_t copy; | 523 | size_t copy; |
| 496 | 524 | ||
| 497 | if (!dchan) | 525 | if (!dchan) |
| @@ -550,12 +578,7 @@ fail: | |||
| 550 | if (!first) | 578 | if (!first) |
| 551 | return NULL; | 579 | return NULL; |
| 552 | 580 | ||
| 553 | list = &first->tx_list; | 581 | fsldma_free_desc_list_reverse(chan, &first->tx_list); |
| 554 | list_for_each_entry_safe_reverse(new, prev, list, node) { | ||
| 555 | list_del(&new->node); | ||
| 556 | dma_pool_free(chan->desc_pool, new, new->async_tx.phys); | ||
| 557 | } | ||
| 558 | |||
| 559 | return NULL; | 582 | return NULL; |
| 560 | } | 583 | } |
| 561 | 584 | ||
| @@ -578,7 +601,6 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg( | |||
| 578 | struct fsldma_chan *chan; | 601 | struct fsldma_chan *chan; |
| 579 | struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL; | 602 | struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL; |
| 580 | struct fsl_dma_slave *slave; | 603 | struct fsl_dma_slave *slave; |
| 581 | struct list_head *tx_list; | ||
| 582 | size_t copy; | 604 | size_t copy; |
| 583 | 605 | ||
| 584 | int i; | 606 | int i; |
| @@ -748,19 +770,13 @@ fail: | |||
| 748 | * | 770 | * |
| 749 | * We're re-using variables for the loop, oh well | 771 | * We're re-using variables for the loop, oh well |
| 750 | */ | 772 | */ |
| 751 | tx_list = &first->tx_list; | 773 | fsldma_free_desc_list_reverse(chan, &first->tx_list); |
| 752 | list_for_each_entry_safe_reverse(new, prev, tx_list, node) { | ||
| 753 | list_del_init(&new->node); | ||
| 754 | dma_pool_free(chan->desc_pool, new, new->async_tx.phys); | ||
| 755 | } | ||
| 756 | |||
| 757 | return NULL; | 774 | return NULL; |
| 758 | } | 775 | } |
| 759 | 776 | ||
| 760 | static void fsl_dma_device_terminate_all(struct dma_chan *dchan) | 777 | static void fsl_dma_device_terminate_all(struct dma_chan *dchan) |
| 761 | { | 778 | { |
| 762 | struct fsldma_chan *chan; | 779 | struct fsldma_chan *chan; |
| 763 | struct fsl_desc_sw *desc, *tmp; | ||
| 764 | unsigned long flags; | 780 | unsigned long flags; |
| 765 | 781 | ||
| 766 | if (!dchan) | 782 | if (!dchan) |
| @@ -774,10 +790,8 @@ static void fsl_dma_device_terminate_all(struct dma_chan *dchan) | |||
| 774 | spin_lock_irqsave(&chan->desc_lock, flags); | 790 | spin_lock_irqsave(&chan->desc_lock, flags); |
| 775 | 791 | ||
| 776 | /* Remove and free all of the descriptors in the LD queue */ | 792 | /* Remove and free all of the descriptors in the LD queue */ |
| 777 | list_for_each_entry_safe(desc, tmp, &chan->ld_queue, node) { | 793 | fsldma_free_desc_list(chan, &chan->ld_pending); |
| 778 | list_del(&desc->node); | 794 | fsldma_free_desc_list(chan, &chan->ld_running); |
| 779 | dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); | ||
| 780 | } | ||
| 781 | 795 | ||
| 782 | spin_unlock_irqrestore(&chan->desc_lock, flags); | 796 | spin_unlock_irqrestore(&chan->desc_lock, flags); |
| 783 | } | 797 | } |
| @@ -785,31 +799,48 @@ static void fsl_dma_device_terminate_all(struct dma_chan *dchan) | |||
| 785 | /** | 799 | /** |
| 786 | * fsl_dma_update_completed_cookie - Update the completed cookie. | 800 | * fsl_dma_update_completed_cookie - Update the completed cookie. |
| 787 | * @chan : Freescale DMA channel | 801 | * @chan : Freescale DMA channel |
| 802 | * | ||
| 803 | * CONTEXT: hardirq | ||
| 788 | */ | 804 | */ |
| 789 | static void fsl_dma_update_completed_cookie(struct fsldma_chan *chan) | 805 | static void fsl_dma_update_completed_cookie(struct fsldma_chan *chan) |
| 790 | { | 806 | { |
| 791 | struct fsl_desc_sw *cur_desc, *desc; | 807 | struct fsl_desc_sw *desc; |
| 792 | dma_addr_t ld_phy; | 808 | unsigned long flags; |
| 793 | 809 | dma_cookie_t cookie; | |
| 794 | ld_phy = get_cdar(chan) & FSL_DMA_NLDA_MASK; | ||
| 795 | 810 | ||
| 796 | if (ld_phy) { | 811 | spin_lock_irqsave(&chan->desc_lock, flags); |
| 797 | cur_desc = NULL; | ||
| 798 | list_for_each_entry(desc, &chan->ld_queue, node) | ||
| 799 | if (desc->async_tx.phys == ld_phy) { | ||
| 800 | cur_desc = desc; | ||
| 801 | break; | ||
| 802 | } | ||
| 803 | 812 | ||
| 804 | if (cur_desc && cur_desc->async_tx.cookie) { | 813 | if (list_empty(&chan->ld_running)) { |
| 805 | if (dma_is_idle(chan)) | 814 | dev_dbg(chan->dev, "no running descriptors\n"); |
| 806 | chan->completed_cookie = | 815 | goto out_unlock; |
| 807 | cur_desc->async_tx.cookie; | ||
| 808 | else | ||
| 809 | chan->completed_cookie = | ||
| 810 | cur_desc->async_tx.cookie - 1; | ||
| 811 | } | ||
| 812 | } | 816 | } |
| 817 | |||
| 818 | /* Get the last descriptor, update the cookie to that */ | ||
| 819 | desc = to_fsl_desc(chan->ld_running.prev); | ||
| 820 | if (dma_is_idle(chan)) | ||
| 821 | cookie = desc->async_tx.cookie; | ||
| 822 | else | ||
| 823 | cookie = desc->async_tx.cookie - 1; | ||
| 824 | |||
| 825 | chan->completed_cookie = cookie; | ||
| 826 | |||
| 827 | out_unlock: | ||
| 828 | spin_unlock_irqrestore(&chan->desc_lock, flags); | ||
| 829 | } | ||
| 830 | |||
| 831 | /** | ||
| 832 | * fsldma_desc_status - Check the status of a descriptor | ||
| 833 | * @chan: Freescale DMA channel | ||
| 834 | * @desc: DMA SW descriptor | ||
| 835 | * | ||
| 836 | * This function will return the status of the given descriptor | ||
| 837 | */ | ||
| 838 | static enum dma_status fsldma_desc_status(struct fsldma_chan *chan, | ||
| 839 | struct fsl_desc_sw *desc) | ||
| 840 | { | ||
| 841 | return dma_async_is_complete(desc->async_tx.cookie, | ||
| 842 | chan->completed_cookie, | ||
| 843 | chan->common.cookie); | ||
| 813 | } | 844 | } |
| 814 | 845 | ||
| 815 | /** | 846 | /** |
| @@ -817,8 +848,6 @@ static void fsl_dma_update_completed_cookie(struct fsldma_chan *chan) | |||
| 817 | * @chan : Freescale DMA channel | 848 | * @chan : Freescale DMA channel |
| 818 | * | 849 | * |
| 819 | * This function clean up the ld_queue of DMA channel. | 850 | * This function clean up the ld_queue of DMA channel. |
| 820 | * If 'in_intr' is set, the function will move the link descriptor to | ||
| 821 | * the recycle list. Otherwise, free it directly. | ||
| 822 | */ | 851 | */ |
| 823 | static void fsl_chan_ld_cleanup(struct fsldma_chan *chan) | 852 | static void fsl_chan_ld_cleanup(struct fsldma_chan *chan) |
| 824 | { | 853 | { |
| @@ -827,80 +856,95 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan) | |||
| 827 | 856 | ||
| 828 | spin_lock_irqsave(&chan->desc_lock, flags); | 857 | spin_lock_irqsave(&chan->desc_lock, flags); |
| 829 | 858 | ||
| 830 | dev_dbg(chan->dev, "chan completed_cookie = %d\n", | 859 | dev_dbg(chan->dev, "chan completed_cookie = %d\n", chan->completed_cookie); |
| 831 | chan->completed_cookie); | 860 | list_for_each_entry_safe(desc, _desc, &chan->ld_running, node) { |
| 832 | list_for_each_entry_safe(desc, _desc, &chan->ld_queue, node) { | ||
| 833 | dma_async_tx_callback callback; | 861 | dma_async_tx_callback callback; |
| 834 | void *callback_param; | 862 | void *callback_param; |
| 835 | 863 | ||
| 836 | if (dma_async_is_complete(desc->async_tx.cookie, | 864 | if (fsldma_desc_status(chan, desc) == DMA_IN_PROGRESS) |
| 837 | chan->completed_cookie, chan->common.cookie) | ||
| 838 | == DMA_IN_PROGRESS) | ||
| 839 | break; | 865 | break; |
| 840 | 866 | ||
| 841 | callback = desc->async_tx.callback; | 867 | /* Remove from the list of running transactions */ |
| 842 | callback_param = desc->async_tx.callback_param; | ||
| 843 | |||
| 844 | /* Remove from ld_queue list */ | ||
| 845 | list_del(&desc->node); | 868 | list_del(&desc->node); |
| 846 | 869 | ||
| 847 | dev_dbg(chan->dev, "link descriptor %p will be recycle.\n", | ||
| 848 | desc); | ||
| 849 | dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); | ||
| 850 | |||
| 851 | /* Run the link descriptor callback function */ | 870 | /* Run the link descriptor callback function */ |
| 871 | callback = desc->async_tx.callback; | ||
| 872 | callback_param = desc->async_tx.callback_param; | ||
| 852 | if (callback) { | 873 | if (callback) { |
| 853 | spin_unlock_irqrestore(&chan->desc_lock, flags); | 874 | spin_unlock_irqrestore(&chan->desc_lock, flags); |
| 854 | dev_dbg(chan->dev, "link descriptor %p callback\n", | 875 | dev_dbg(chan->dev, "LD %p callback\n", desc); |
| 855 | desc); | ||
| 856 | callback(callback_param); | 876 | callback(callback_param); |
| 857 | spin_lock_irqsave(&chan->desc_lock, flags); | 877 | spin_lock_irqsave(&chan->desc_lock, flags); |
| 858 | } | 878 | } |
| 879 | |||
| 880 | /* Run any dependencies, then free the descriptor */ | ||
| 881 | dma_run_dependencies(&desc->async_tx); | ||
| 882 | dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); | ||
| 859 | } | 883 | } |
| 884 | |||
| 860 | spin_unlock_irqrestore(&chan->desc_lock, flags); | 885 | spin_unlock_irqrestore(&chan->desc_lock, flags); |
| 861 | } | 886 | } |
| 862 | 887 | ||
| 863 | /** | 888 | /** |
| 864 | * fsl_chan_xfer_ld_queue - Transfer link descriptors in channel ld_queue. | 889 | * fsl_chan_xfer_ld_queue - transfer any pending transactions |
| 865 | * @chan : Freescale DMA channel | 890 | * @chan : Freescale DMA channel |
| 891 | * | ||
| 892 | * This will make sure that any pending transactions will be run. | ||
| 893 | * If the DMA controller is idle, it will be started. Otherwise, | ||
| 894 | * the DMA controller's interrupt handler will start any pending | ||
| 895 | * transactions when it becomes idle. | ||
| 866 | */ | 896 | */ |
| 867 | static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) | 897 | static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) |
| 868 | { | 898 | { |
| 869 | struct list_head *ld_node; | 899 | struct fsl_desc_sw *desc; |
| 870 | dma_addr_t next_dst_addr; | ||
| 871 | unsigned long flags; | 900 | unsigned long flags; |
| 872 | 901 | ||
| 873 | spin_lock_irqsave(&chan->desc_lock, flags); | 902 | spin_lock_irqsave(&chan->desc_lock, flags); |
| 874 | 903 | ||
| 875 | if (!dma_is_idle(chan)) | 904 | /* |
| 905 | * If the list of pending descriptors is empty, then we | ||
| 906 | * don't need to do any work at all | ||
| 907 | */ | ||
| 908 | if (list_empty(&chan->ld_pending)) { | ||
| 909 | dev_dbg(chan->dev, "no pending LDs\n"); | ||
| 876 | goto out_unlock; | 910 | goto out_unlock; |
| 911 | } | ||
| 877 | 912 | ||
| 913 | /* | ||
| 914 | * The DMA controller is not idle, which means the interrupt | ||
| 915 | * handler will start any queued transactions when it runs | ||
| 916 | * at the end of the current transaction | ||
| 917 | */ | ||
| 918 | if (!dma_is_idle(chan)) { | ||
| 919 | dev_dbg(chan->dev, "DMA controller still busy\n"); | ||
| 920 | goto out_unlock; | ||
| 921 | } | ||
| 922 | |||
| 923 | /* | ||
| 924 | * TODO: | ||
| 925 | * make sure the dma_halt() function really un-wedges the | ||
| 926 | * controller as much as possible | ||
| 927 | */ | ||
| 878 | dma_halt(chan); | 928 | dma_halt(chan); |
| 879 | 929 | ||
| 880 | /* If there are some link descriptors | 930 | /* |
| 881 | * not transfered in queue. We need to start it. | 931 | * If there are some link descriptors which have not been |
| 932 | * transferred, we need to start the controller | ||
| 882 | */ | 933 | */ |
| 883 | 934 | ||
| 884 | /* Find the first un-transfer desciptor */ | 935 | /* |
| 885 | for (ld_node = chan->ld_queue.next; | 936 | * Move all elements from the queue of pending transactions |
| 886 | (ld_node != &chan->ld_queue) | 937 | * onto the list of running transactions |
| 887 | && (dma_async_is_complete( | 938 | */ |
| 888 | to_fsl_desc(ld_node)->async_tx.cookie, | 939 | desc = list_first_entry(&chan->ld_pending, struct fsl_desc_sw, node); |
| 889 | chan->completed_cookie, | 940 | list_splice_tail_init(&chan->ld_pending, &chan->ld_running); |
| 890 | chan->common.cookie) == DMA_SUCCESS); | 941 | |
| 891 | ld_node = ld_node->next); | 942 | /* |
| 892 | 943 | * Program the descriptor's address into the DMA controller, | |
| 893 | if (ld_node != &chan->ld_queue) { | 944 | * then start the DMA transaction |
| 894 | /* Get the ld start address from ld_queue */ | 945 | */ |
| 895 | next_dst_addr = to_fsl_desc(ld_node)->async_tx.phys; | 946 | set_cdar(chan, desc->async_tx.phys); |
| 896 | dev_dbg(chan->dev, "xfer LDs staring from 0x%llx\n", | 947 | dma_start(chan); |
| 897 | (unsigned long long)next_dst_addr); | ||
| 898 | set_cdar(chan, next_dst_addr); | ||
| 899 | dma_start(chan); | ||
| 900 | } else { | ||
| 901 | set_cdar(chan, 0); | ||
| 902 | set_ndar(chan, 0); | ||
| 903 | } | ||
| 904 | 948 | ||
| 905 | out_unlock: | 949 | out_unlock: |
| 906 | spin_unlock_irqrestore(&chan->desc_lock, flags); | 950 | spin_unlock_irqrestore(&chan->desc_lock, flags); |
| @@ -913,30 +957,6 @@ out_unlock: | |||
| 913 | static void fsl_dma_memcpy_issue_pending(struct dma_chan *dchan) | 957 | static void fsl_dma_memcpy_issue_pending(struct dma_chan *dchan) |
| 914 | { | 958 | { |
| 915 | struct fsldma_chan *chan = to_fsl_chan(dchan); | 959 | struct fsldma_chan *chan = to_fsl_chan(dchan); |
| 916 | |||
| 917 | #ifdef FSL_DMA_LD_DEBUG | ||
| 918 | struct fsl_desc_sw *ld; | ||
| 919 | unsigned long flags; | ||
| 920 | |||
| 921 | spin_lock_irqsave(&chan->desc_lock, flags); | ||
| 922 | if (list_empty(&chan->ld_queue)) { | ||
| 923 | spin_unlock_irqrestore(&chan->desc_lock, flags); | ||
| 924 | return; | ||
| 925 | } | ||
| 926 | |||
| 927 | dev_dbg(chan->dev, "--memcpy issue--\n"); | ||
| 928 | list_for_each_entry(ld, &chan->ld_queue, node) { | ||
| 929 | int i; | ||
| 930 | dev_dbg(chan->dev, "Ch %d, LD %08x\n", | ||
| 931 | chan->id, ld->async_tx.phys); | ||
| 932 | for (i = 0; i < 8; i++) | ||
| 933 | dev_dbg(chan->dev, "LD offset %d: %08x\n", | ||
| 934 | i, *(((u32 *)&ld->hw) + i)); | ||
| 935 | } | ||
| 936 | dev_dbg(chan->dev, "----------------\n"); | ||
| 937 | spin_unlock_irqrestore(&chan->desc_lock, flags); | ||
| 938 | #endif | ||
| 939 | |||
| 940 | fsl_chan_xfer_ld_queue(chan); | 960 | fsl_chan_xfer_ld_queue(chan); |
| 941 | } | 961 | } |
| 942 | 962 | ||
| @@ -978,10 +998,10 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) | |||
| 978 | int xfer_ld_q = 0; | 998 | int xfer_ld_q = 0; |
| 979 | u32 stat; | 999 | u32 stat; |
| 980 | 1000 | ||
| 1001 | /* save and clear the status register */ | ||
| 981 | stat = get_sr(chan); | 1002 | stat = get_sr(chan); |
| 982 | dev_dbg(chan->dev, "event: channel %d, stat = 0x%x\n", | 1003 | set_sr(chan, stat); |
| 983 | chan->id, stat); | 1004 | dev_dbg(chan->dev, "irq: channel %d, stat = 0x%x\n", chan->id, stat); |
| 984 | set_sr(chan, stat); /* Clear the event register */ | ||
| 985 | 1005 | ||
| 986 | stat &= ~(FSL_DMA_SR_CB | FSL_DMA_SR_CH); | 1006 | stat &= ~(FSL_DMA_SR_CB | FSL_DMA_SR_CH); |
| 987 | if (!stat) | 1007 | if (!stat) |
| @@ -990,12 +1010,13 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) | |||
| 990 | if (stat & FSL_DMA_SR_TE) | 1010 | if (stat & FSL_DMA_SR_TE) |
| 991 | dev_err(chan->dev, "Transfer Error!\n"); | 1011 | dev_err(chan->dev, "Transfer Error!\n"); |
| 992 | 1012 | ||
| 993 | /* Programming Error | 1013 | /* |
| 1014 | * Programming Error | ||
| 994 | * The DMA_INTERRUPT async_tx is a NULL transfer, which will | 1015 | * The DMA_INTERRUPT async_tx is a NULL transfer, which will |
| 995 | * triger a PE interrupt. | 1016 | * triger a PE interrupt. |
| 996 | */ | 1017 | */ |
| 997 | if (stat & FSL_DMA_SR_PE) { | 1018 | if (stat & FSL_DMA_SR_PE) { |
| 998 | dev_dbg(chan->dev, "event: Programming Error INT\n"); | 1019 | dev_dbg(chan->dev, "irq: Programming Error INT\n"); |
| 999 | if (get_bcr(chan) == 0) { | 1020 | if (get_bcr(chan) == 0) { |
| 1000 | /* BCR register is 0, this is a DMA_INTERRUPT async_tx. | 1021 | /* BCR register is 0, this is a DMA_INTERRUPT async_tx. |
| 1001 | * Now, update the completed cookie, and continue the | 1022 | * Now, update the completed cookie, and continue the |
| @@ -1007,34 +1028,37 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) | |||
| 1007 | stat &= ~FSL_DMA_SR_PE; | 1028 | stat &= ~FSL_DMA_SR_PE; |
| 1008 | } | 1029 | } |
| 1009 | 1030 | ||
| 1010 | /* If the link descriptor segment transfer finishes, | 1031 | /* |
| 1032 | * If the link descriptor segment transfer finishes, | ||
| 1011 | * we will recycle the used descriptor. | 1033 | * we will recycle the used descriptor. |
| 1012 | */ | 1034 | */ |
| 1013 | if (stat & FSL_DMA_SR_EOSI) { | 1035 | if (stat & FSL_DMA_SR_EOSI) { |
| 1014 | dev_dbg(chan->dev, "event: End-of-segments INT\n"); | 1036 | dev_dbg(chan->dev, "irq: End-of-segments INT\n"); |
| 1015 | dev_dbg(chan->dev, "event: clndar 0x%llx, nlndar 0x%llx\n", | 1037 | dev_dbg(chan->dev, "irq: clndar 0x%llx, nlndar 0x%llx\n", |
| 1016 | (unsigned long long)get_cdar(chan), | 1038 | (unsigned long long)get_cdar(chan), |
| 1017 | (unsigned long long)get_ndar(chan)); | 1039 | (unsigned long long)get_ndar(chan)); |
| 1018 | stat &= ~FSL_DMA_SR_EOSI; | 1040 | stat &= ~FSL_DMA_SR_EOSI; |
| 1019 | update_cookie = 1; | 1041 | update_cookie = 1; |
| 1020 | } | 1042 | } |
| 1021 | 1043 | ||
| 1022 | /* For MPC8349, EOCDI event need to update cookie | 1044 | /* |
| 1045 | * For MPC8349, EOCDI event need to update cookie | ||
| 1023 | * and start the next transfer if it exist. | 1046 | * and start the next transfer if it exist. |
| 1024 | */ | 1047 | */ |
| 1025 | if (stat & FSL_DMA_SR_EOCDI) { | 1048 | if (stat & FSL_DMA_SR_EOCDI) { |
| 1026 | dev_dbg(chan->dev, "event: End-of-Chain link INT\n"); | 1049 | dev_dbg(chan->dev, "irq: End-of-Chain link INT\n"); |
| 1027 | stat &= ~FSL_DMA_SR_EOCDI; | 1050 | stat &= ~FSL_DMA_SR_EOCDI; |
| 1028 | update_cookie = 1; | 1051 | update_cookie = 1; |
| 1029 | xfer_ld_q = 1; | 1052 | xfer_ld_q = 1; |
| 1030 | } | 1053 | } |
| 1031 | 1054 | ||
| 1032 | /* If it current transfer is the end-of-transfer, | 1055 | /* |
| 1056 | * If it current transfer is the end-of-transfer, | ||
| 1033 | * we should clear the Channel Start bit for | 1057 | * we should clear the Channel Start bit for |
| 1034 | * prepare next transfer. | 1058 | * prepare next transfer. |
| 1035 | */ | 1059 | */ |
| 1036 | if (stat & FSL_DMA_SR_EOLNI) { | 1060 | if (stat & FSL_DMA_SR_EOLNI) { |
| 1037 | dev_dbg(chan->dev, "event: End-of-link INT\n"); | 1061 | dev_dbg(chan->dev, "irq: End-of-link INT\n"); |
| 1038 | stat &= ~FSL_DMA_SR_EOLNI; | 1062 | stat &= ~FSL_DMA_SR_EOLNI; |
| 1039 | xfer_ld_q = 1; | 1063 | xfer_ld_q = 1; |
| 1040 | } | 1064 | } |
| @@ -1044,10 +1068,9 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) | |||
| 1044 | if (xfer_ld_q) | 1068 | if (xfer_ld_q) |
| 1045 | fsl_chan_xfer_ld_queue(chan); | 1069 | fsl_chan_xfer_ld_queue(chan); |
| 1046 | if (stat) | 1070 | if (stat) |
| 1047 | dev_dbg(chan->dev, "event: unhandled sr 0x%02x\n", | 1071 | dev_dbg(chan->dev, "irq: unhandled sr 0x%02x\n", stat); |
| 1048 | stat); | ||
| 1049 | 1072 | ||
| 1050 | dev_dbg(chan->dev, "event: Exit\n"); | 1073 | dev_dbg(chan->dev, "irq: Exit\n"); |
| 1051 | tasklet_schedule(&chan->tasklet); | 1074 | tasklet_schedule(&chan->tasklet); |
| 1052 | return IRQ_HANDLED; | 1075 | return IRQ_HANDLED; |
| 1053 | } | 1076 | } |
| @@ -1235,7 +1258,8 @@ static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev, | |||
| 1235 | } | 1258 | } |
| 1236 | 1259 | ||
| 1237 | spin_lock_init(&chan->desc_lock); | 1260 | spin_lock_init(&chan->desc_lock); |
| 1238 | INIT_LIST_HEAD(&chan->ld_queue); | 1261 | INIT_LIST_HEAD(&chan->ld_pending); |
| 1262 | INIT_LIST_HEAD(&chan->ld_running); | ||
| 1239 | 1263 | ||
| 1240 | chan->common.device = &fdev->common; | 1264 | chan->common.device = &fdev->common; |
| 1241 | 1265 | ||
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h index ea3b19c8708c..cb4d6ff51597 100644 --- a/drivers/dma/fsldma.h +++ b/drivers/dma/fsldma.h | |||
| @@ -131,7 +131,8 @@ struct fsldma_chan { | |||
| 131 | struct fsldma_chan_regs __iomem *regs; | 131 | struct fsldma_chan_regs __iomem *regs; |
| 132 | dma_cookie_t completed_cookie; /* The maximum cookie completed */ | 132 | dma_cookie_t completed_cookie; /* The maximum cookie completed */ |
| 133 | spinlock_t desc_lock; /* Descriptor operation lock */ | 133 | spinlock_t desc_lock; /* Descriptor operation lock */ |
| 134 | struct list_head ld_queue; /* Link descriptors queue */ | 134 | struct list_head ld_pending; /* Link descriptors queue */ |
| 135 | struct list_head ld_running; /* Link descriptors queue */ | ||
| 135 | struct dma_chan common; /* DMA common channel */ | 136 | struct dma_chan common; /* DMA common channel */ |
| 136 | struct dma_pool *desc_pool; /* Descriptors pool */ | 137 | struct dma_pool *desc_pool; /* Descriptors pool */ |
| 137 | struct device *dev; /* Channel device */ | 138 | struct device *dev; /* Channel device */ |
