diff options
Diffstat (limited to 'drivers/dma/coh901318.c')
-rw-r--r-- | drivers/dma/coh901318.c | 263 |
1 files changed, 191 insertions, 72 deletions
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index 1656fdcdb6c2..a724e6be1b4d 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c | |||
@@ -37,7 +37,7 @@ struct coh901318_desc { | |||
37 | struct list_head node; | 37 | struct list_head node; |
38 | struct scatterlist *sg; | 38 | struct scatterlist *sg; |
39 | unsigned int sg_len; | 39 | unsigned int sg_len; |
40 | struct coh901318_lli *data; | 40 | struct coh901318_lli *lli; |
41 | enum dma_data_direction dir; | 41 | enum dma_data_direction dir; |
42 | unsigned long flags; | 42 | unsigned long flags; |
43 | }; | 43 | }; |
@@ -283,7 +283,7 @@ static int coh901318_start(struct coh901318_chan *cohc) | |||
283 | } | 283 | } |
284 | 284 | ||
285 | static int coh901318_prep_linked_list(struct coh901318_chan *cohc, | 285 | static int coh901318_prep_linked_list(struct coh901318_chan *cohc, |
286 | struct coh901318_lli *data) | 286 | struct coh901318_lli *lli) |
287 | { | 287 | { |
288 | int channel = cohc->id; | 288 | int channel = cohc->id; |
289 | void __iomem *virtbase = cohc->base->virtbase; | 289 | void __iomem *virtbase = cohc->base->virtbase; |
@@ -292,18 +292,18 @@ static int coh901318_prep_linked_list(struct coh901318_chan *cohc, | |||
292 | COH901318_CX_STAT_SPACING*channel) & | 292 | COH901318_CX_STAT_SPACING*channel) & |
293 | COH901318_CX_STAT_ACTIVE); | 293 | COH901318_CX_STAT_ACTIVE); |
294 | 294 | ||
295 | writel(data->src_addr, | 295 | writel(lli->src_addr, |
296 | virtbase + COH901318_CX_SRC_ADDR + | 296 | virtbase + COH901318_CX_SRC_ADDR + |
297 | COH901318_CX_SRC_ADDR_SPACING * channel); | 297 | COH901318_CX_SRC_ADDR_SPACING * channel); |
298 | 298 | ||
299 | writel(data->dst_addr, virtbase + | 299 | writel(lli->dst_addr, virtbase + |
300 | COH901318_CX_DST_ADDR + | 300 | COH901318_CX_DST_ADDR + |
301 | COH901318_CX_DST_ADDR_SPACING * channel); | 301 | COH901318_CX_DST_ADDR_SPACING * channel); |
302 | 302 | ||
303 | writel(data->link_addr, virtbase + COH901318_CX_LNK_ADDR + | 303 | writel(lli->link_addr, virtbase + COH901318_CX_LNK_ADDR + |
304 | COH901318_CX_LNK_ADDR_SPACING * channel); | 304 | COH901318_CX_LNK_ADDR_SPACING * channel); |
305 | 305 | ||
306 | writel(data->control, virtbase + COH901318_CX_CTRL + | 306 | writel(lli->control, virtbase + COH901318_CX_CTRL + |
307 | COH901318_CX_CTRL_SPACING * channel); | 307 | COH901318_CX_CTRL_SPACING * channel); |
308 | 308 | ||
309 | return 0; | 309 | return 0; |
@@ -408,33 +408,107 @@ coh901318_first_queued(struct coh901318_chan *cohc) | |||
408 | return d; | 408 | return d; |
409 | } | 409 | } |
410 | 410 | ||
411 | static inline u32 coh901318_get_bytes_in_lli(struct coh901318_lli *in_lli) | ||
412 | { | ||
413 | struct coh901318_lli *lli = in_lli; | ||
414 | u32 bytes = 0; | ||
415 | |||
416 | while (lli) { | ||
417 | bytes += lli->control & COH901318_CX_CTRL_TC_VALUE_MASK; | ||
418 | lli = lli->virt_link_addr; | ||
419 | } | ||
420 | return bytes; | ||
421 | } | ||
422 | |||
411 | /* | 423 | /* |
412 | * DMA start/stop controls | 424 | * Get the number of bytes left to transfer on this channel, |
425 | * it is unwise to call this before stopping the channel for | ||
426 | * absolute measures, but for a rough guess you can still call | ||
427 | * it. | ||
413 | */ | 428 | */ |
414 | u32 coh901318_get_bytes_left(struct dma_chan *chan) | 429 | static u32 coh901318_get_bytes_left(struct dma_chan *chan) |
415 | { | 430 | { |
416 | unsigned long flags; | ||
417 | u32 ret; | ||
418 | struct coh901318_chan *cohc = to_coh901318_chan(chan); | 431 | struct coh901318_chan *cohc = to_coh901318_chan(chan); |
432 | struct coh901318_desc *cohd; | ||
433 | struct list_head *pos; | ||
434 | unsigned long flags; | ||
435 | u32 left = 0; | ||
436 | int i = 0; | ||
419 | 437 | ||
420 | spin_lock_irqsave(&cohc->lock, flags); | 438 | spin_lock_irqsave(&cohc->lock, flags); |
421 | 439 | ||
422 | /* Read transfer count value */ | 440 | /* |
423 | ret = readl(cohc->base->virtbase + | 441 | * If there are many queued jobs, we iterate and add the |
424 | COH901318_CX_CTRL+COH901318_CX_CTRL_SPACING * | 442 | * size of them all. We take a special look on the first |
425 | cohc->id) & COH901318_CX_CTRL_TC_VALUE_MASK; | 443 | * job though, since it is probably active. |
444 | */ | ||
445 | list_for_each(pos, &cohc->active) { | ||
446 | /* | ||
447 | * The first job in the list will be working on the | ||
448 | * hardware. The job can be stopped but still active, | ||
449 | * so that the transfer counter is somewhere inside | ||
450 | * the buffer. | ||
451 | */ | ||
452 | cohd = list_entry(pos, struct coh901318_desc, node); | ||
453 | |||
454 | if (i == 0) { | ||
455 | struct coh901318_lli *lli; | ||
456 | dma_addr_t ladd; | ||
457 | |||
458 | /* Read current transfer count value */ | ||
459 | left = readl(cohc->base->virtbase + | ||
460 | COH901318_CX_CTRL + | ||
461 | COH901318_CX_CTRL_SPACING * cohc->id) & | ||
462 | COH901318_CX_CTRL_TC_VALUE_MASK; | ||
463 | |||
464 | /* See if the transfer is linked... */ | ||
465 | ladd = readl(cohc->base->virtbase + | ||
466 | COH901318_CX_LNK_ADDR + | ||
467 | COH901318_CX_LNK_ADDR_SPACING * | ||
468 | cohc->id) & | ||
469 | ~COH901318_CX_LNK_LINK_IMMEDIATE; | ||
470 | /* Single transaction */ | ||
471 | if (!ladd) | ||
472 | continue; | ||
473 | |||
474 | /* | ||
475 | * Linked transaction, follow the lli, find the | ||
476 | * currently processing lli, and proceed to the next | ||
477 | */ | ||
478 | lli = cohd->lli; | ||
479 | while (lli && lli->link_addr != ladd) | ||
480 | lli = lli->virt_link_addr; | ||
481 | |||
482 | if (lli) | ||
483 | lli = lli->virt_link_addr; | ||
484 | |||
485 | /* | ||
486 | * Follow remaining lli links around to count the total | ||
487 | * number of bytes left | ||
488 | */ | ||
489 | left += coh901318_get_bytes_in_lli(lli); | ||
490 | } else { | ||
491 | left += coh901318_get_bytes_in_lli(cohd->lli); | ||
492 | } | ||
493 | i++; | ||
494 | } | ||
495 | |||
496 | /* Also count bytes in the queued jobs */ | ||
497 | list_for_each(pos, &cohc->queue) { | ||
498 | cohd = list_entry(pos, struct coh901318_desc, node); | ||
499 | left += coh901318_get_bytes_in_lli(cohd->lli); | ||
500 | } | ||
426 | 501 | ||
427 | spin_unlock_irqrestore(&cohc->lock, flags); | 502 | spin_unlock_irqrestore(&cohc->lock, flags); |
428 | 503 | ||
429 | return ret; | 504 | return left; |
430 | } | 505 | } |
431 | EXPORT_SYMBOL(coh901318_get_bytes_left); | ||
432 | |||
433 | 506 | ||
434 | /* Stops a transfer without losing data. Enables power save. | 507 | /* |
435 | Use this function in conjunction with coh901318_continue(..) | 508 | * Pauses a transfer without losing data. Enables power save. |
436 | */ | 509 | * Use this function in conjunction with coh901318_resume. |
437 | void coh901318_stop(struct dma_chan *chan) | 510 | */ |
511 | static void coh901318_pause(struct dma_chan *chan) | ||
438 | { | 512 | { |
439 | u32 val; | 513 | u32 val; |
440 | unsigned long flags; | 514 | unsigned long flags; |
@@ -475,12 +549,11 @@ void coh901318_stop(struct dma_chan *chan) | |||
475 | 549 | ||
476 | spin_unlock_irqrestore(&cohc->lock, flags); | 550 | spin_unlock_irqrestore(&cohc->lock, flags); |
477 | } | 551 | } |
478 | EXPORT_SYMBOL(coh901318_stop); | ||
479 | 552 | ||
480 | /* Continues a transfer that has been stopped via 300_dma_stop(..). | 553 | /* Resumes a transfer that has been stopped via 300_dma_stop(..). |
481 | Power save is handled. | 554 | Power save is handled. |
482 | */ | 555 | */ |
483 | void coh901318_continue(struct dma_chan *chan) | 556 | static void coh901318_resume(struct dma_chan *chan) |
484 | { | 557 | { |
485 | u32 val; | 558 | u32 val; |
486 | unsigned long flags; | 559 | unsigned long flags; |
@@ -506,7 +579,6 @@ void coh901318_continue(struct dma_chan *chan) | |||
506 | 579 | ||
507 | spin_unlock_irqrestore(&cohc->lock, flags); | 580 | spin_unlock_irqrestore(&cohc->lock, flags); |
508 | } | 581 | } |
509 | EXPORT_SYMBOL(coh901318_continue); | ||
510 | 582 | ||
511 | bool coh901318_filter_id(struct dma_chan *chan, void *chan_id) | 583 | bool coh901318_filter_id(struct dma_chan *chan, void *chan_id) |
512 | { | 584 | { |
@@ -565,29 +637,30 @@ static int coh901318_config(struct coh901318_chan *cohc, | |||
565 | */ | 637 | */ |
566 | static struct coh901318_desc *coh901318_queue_start(struct coh901318_chan *cohc) | 638 | static struct coh901318_desc *coh901318_queue_start(struct coh901318_chan *cohc) |
567 | { | 639 | { |
568 | struct coh901318_desc *cohd_que; | 640 | struct coh901318_desc *cohd; |
569 | 641 | ||
570 | /* start queued jobs, if any | 642 | /* |
643 | * start queued jobs, if any | ||
571 | * TODO: transmit all queued jobs in one go | 644 | * TODO: transmit all queued jobs in one go |
572 | */ | 645 | */ |
573 | cohd_que = coh901318_first_queued(cohc); | 646 | cohd = coh901318_first_queued(cohc); |
574 | 647 | ||
575 | if (cohd_que != NULL) { | 648 | if (cohd != NULL) { |
576 | /* Remove from queue */ | 649 | /* Remove from queue */ |
577 | coh901318_desc_remove(cohd_que); | 650 | coh901318_desc_remove(cohd); |
578 | /* initiate DMA job */ | 651 | /* initiate DMA job */ |
579 | cohc->busy = 1; | 652 | cohc->busy = 1; |
580 | 653 | ||
581 | coh901318_desc_submit(cohc, cohd_que); | 654 | coh901318_desc_submit(cohc, cohd); |
582 | 655 | ||
583 | coh901318_prep_linked_list(cohc, cohd_que->data); | 656 | coh901318_prep_linked_list(cohc, cohd->lli); |
584 | 657 | ||
585 | /* start dma job */ | 658 | /* start dma job on this channel */ |
586 | coh901318_start(cohc); | 659 | coh901318_start(cohc); |
587 | 660 | ||
588 | } | 661 | } |
589 | 662 | ||
590 | return cohd_que; | 663 | return cohd; |
591 | } | 664 | } |
592 | 665 | ||
593 | /* | 666 | /* |
@@ -622,7 +695,7 @@ static void dma_tasklet(unsigned long data) | |||
622 | cohc->completed = cohd_fin->desc.cookie; | 695 | cohc->completed = cohd_fin->desc.cookie; |
623 | 696 | ||
624 | /* release the lli allocation and remove the descriptor */ | 697 | /* release the lli allocation and remove the descriptor */ |
625 | coh901318_lli_free(&cohc->base->pool, &cohd_fin->data); | 698 | coh901318_lli_free(&cohc->base->pool, &cohd_fin->lli); |
626 | 699 | ||
627 | /* return desc to free-list */ | 700 | /* return desc to free-list */ |
628 | coh901318_desc_remove(cohd_fin); | 701 | coh901318_desc_remove(cohd_fin); |
@@ -666,23 +739,44 @@ static void dma_tasklet(unsigned long data) | |||
666 | /* called from interrupt context */ | 739 | /* called from interrupt context */ |
667 | static void dma_tc_handle(struct coh901318_chan *cohc) | 740 | static void dma_tc_handle(struct coh901318_chan *cohc) |
668 | { | 741 | { |
669 | BUG_ON(!cohc->allocated && (list_empty(&cohc->active) || | 742 | /* |
670 | list_empty(&cohc->queue))); | 743 | * If the channel is not allocated, then we shouldn't have |
671 | 744 | * any TC interrupts on it. | |
672 | if (!cohc->allocated) | 745 | */ |
746 | if (!cohc->allocated) { | ||
747 | dev_err(COHC_2_DEV(cohc), "spurious interrupt from " | ||
748 | "unallocated channel\n"); | ||
673 | return; | 749 | return; |
750 | } | ||
674 | 751 | ||
675 | spin_lock(&cohc->lock); | 752 | spin_lock(&cohc->lock); |
676 | 753 | ||
754 | /* | ||
755 | * When we reach this point, at least one queue item | ||
756 | * should have been moved over from cohc->queue to | ||
757 | * cohc->active and run to completion, that is why we're | ||
758 | * getting a terminal count interrupt is it not? | ||
759 | * If you get this BUG() the most probable cause is that | ||
760 | * the individual nodes in the lli chain have IRQ enabled, | ||
761 | * so check your platform config for lli chain ctrl. | ||
762 | */ | ||
763 | BUG_ON(list_empty(&cohc->active)); | ||
764 | |||
677 | cohc->nbr_active_done++; | 765 | cohc->nbr_active_done++; |
678 | 766 | ||
767 | /* | ||
768 | * This attempt to take a job from cohc->queue, put it | ||
769 | * into cohc->active and start it. | ||
770 | */ | ||
679 | if (coh901318_queue_start(cohc) == NULL) | 771 | if (coh901318_queue_start(cohc) == NULL) |
680 | cohc->busy = 0; | 772 | cohc->busy = 0; |
681 | 773 | ||
682 | BUG_ON(list_empty(&cohc->active)); | ||
683 | |||
684 | spin_unlock(&cohc->lock); | 774 | spin_unlock(&cohc->lock); |
685 | 775 | ||
776 | /* | ||
777 | * This tasklet will remove items from cohc->active | ||
778 | * and thus terminates them. | ||
779 | */ | ||
686 | if (cohc_chan_conf(cohc)->priority_high) | 780 | if (cohc_chan_conf(cohc)->priority_high) |
687 | tasklet_hi_schedule(&cohc->tasklet); | 781 | tasklet_hi_schedule(&cohc->tasklet); |
688 | else | 782 | else |
@@ -809,6 +903,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) | |||
809 | static int coh901318_alloc_chan_resources(struct dma_chan *chan) | 903 | static int coh901318_alloc_chan_resources(struct dma_chan *chan) |
810 | { | 904 | { |
811 | struct coh901318_chan *cohc = to_coh901318_chan(chan); | 905 | struct coh901318_chan *cohc = to_coh901318_chan(chan); |
906 | unsigned long flags; | ||
812 | 907 | ||
813 | dev_vdbg(COHC_2_DEV(cohc), "[%s] DMA channel %d\n", | 908 | dev_vdbg(COHC_2_DEV(cohc), "[%s] DMA channel %d\n", |
814 | __func__, cohc->id); | 909 | __func__, cohc->id); |
@@ -816,11 +911,15 @@ static int coh901318_alloc_chan_resources(struct dma_chan *chan) | |||
816 | if (chan->client_count > 1) | 911 | if (chan->client_count > 1) |
817 | return -EBUSY; | 912 | return -EBUSY; |
818 | 913 | ||
914 | spin_lock_irqsave(&cohc->lock, flags); | ||
915 | |||
819 | coh901318_config(cohc, NULL); | 916 | coh901318_config(cohc, NULL); |
820 | 917 | ||
821 | cohc->allocated = 1; | 918 | cohc->allocated = 1; |
822 | cohc->completed = chan->cookie = 1; | 919 | cohc->completed = chan->cookie = 1; |
823 | 920 | ||
921 | spin_unlock_irqrestore(&cohc->lock, flags); | ||
922 | |||
824 | return 1; | 923 | return 1; |
825 | } | 924 | } |
826 | 925 | ||
@@ -843,7 +942,7 @@ coh901318_free_chan_resources(struct dma_chan *chan) | |||
843 | 942 | ||
844 | spin_unlock_irqrestore(&cohc->lock, flags); | 943 | spin_unlock_irqrestore(&cohc->lock, flags); |
845 | 944 | ||
846 | chan->device->device_terminate_all(chan); | 945 | chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); |
847 | } | 946 | } |
848 | 947 | ||
849 | 948 | ||
@@ -870,7 +969,7 @@ static struct dma_async_tx_descriptor * | |||
870 | coh901318_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, | 969 | coh901318_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, |
871 | size_t size, unsigned long flags) | 970 | size_t size, unsigned long flags) |
872 | { | 971 | { |
873 | struct coh901318_lli *data; | 972 | struct coh901318_lli *lli; |
874 | struct coh901318_desc *cohd; | 973 | struct coh901318_desc *cohd; |
875 | unsigned long flg; | 974 | unsigned long flg; |
876 | struct coh901318_chan *cohc = to_coh901318_chan(chan); | 975 | struct coh901318_chan *cohc = to_coh901318_chan(chan); |
@@ -892,23 +991,23 @@ coh901318_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, | |||
892 | if ((lli_len << MAX_DMA_PACKET_SIZE_SHIFT) < size) | 991 | if ((lli_len << MAX_DMA_PACKET_SIZE_SHIFT) < size) |
893 | lli_len++; | 992 | lli_len++; |
894 | 993 | ||
895 | data = coh901318_lli_alloc(&cohc->base->pool, lli_len); | 994 | lli = coh901318_lli_alloc(&cohc->base->pool, lli_len); |
896 | 995 | ||
897 | if (data == NULL) | 996 | if (lli == NULL) |
898 | goto err; | 997 | goto err; |
899 | 998 | ||
900 | ret = coh901318_lli_fill_memcpy( | 999 | ret = coh901318_lli_fill_memcpy( |
901 | &cohc->base->pool, data, src, size, dest, | 1000 | &cohc->base->pool, lli, src, size, dest, |
902 | cohc_chan_param(cohc)->ctrl_lli_chained, | 1001 | cohc_chan_param(cohc)->ctrl_lli_chained, |
903 | ctrl_last); | 1002 | ctrl_last); |
904 | if (ret) | 1003 | if (ret) |
905 | goto err; | 1004 | goto err; |
906 | 1005 | ||
907 | COH_DBG(coh901318_list_print(cohc, data)); | 1006 | COH_DBG(coh901318_list_print(cohc, lli)); |
908 | 1007 | ||
909 | /* Pick a descriptor to handle this transfer */ | 1008 | /* Pick a descriptor to handle this transfer */ |
910 | cohd = coh901318_desc_get(cohc); | 1009 | cohd = coh901318_desc_get(cohc); |
911 | cohd->data = data; | 1010 | cohd->lli = lli; |
912 | cohd->flags = flags; | 1011 | cohd->flags = flags; |
913 | cohd->desc.tx_submit = coh901318_tx_submit; | 1012 | cohd->desc.tx_submit = coh901318_tx_submit; |
914 | 1013 | ||
@@ -926,7 +1025,7 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
926 | unsigned long flags) | 1025 | unsigned long flags) |
927 | { | 1026 | { |
928 | struct coh901318_chan *cohc = to_coh901318_chan(chan); | 1027 | struct coh901318_chan *cohc = to_coh901318_chan(chan); |
929 | struct coh901318_lli *data; | 1028 | struct coh901318_lli *lli; |
930 | struct coh901318_desc *cohd; | 1029 | struct coh901318_desc *cohd; |
931 | const struct coh901318_params *params; | 1030 | const struct coh901318_params *params; |
932 | struct scatterlist *sg; | 1031 | struct scatterlist *sg; |
@@ -999,13 +1098,13 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
999 | } | 1098 | } |
1000 | 1099 | ||
1001 | pr_debug("Allocate %d lli:s for this transfer\n", len); | 1100 | pr_debug("Allocate %d lli:s for this transfer\n", len); |
1002 | data = coh901318_lli_alloc(&cohc->base->pool, len); | 1101 | lli = coh901318_lli_alloc(&cohc->base->pool, len); |
1003 | 1102 | ||
1004 | if (data == NULL) | 1103 | if (lli == NULL) |
1005 | goto err_dma_alloc; | 1104 | goto err_dma_alloc; |
1006 | 1105 | ||
1007 | /* initiate allocated data list */ | 1106 | /* initiate allocated lli list */ |
1008 | ret = coh901318_lli_fill_sg(&cohc->base->pool, data, sgl, sg_len, | 1107 | ret = coh901318_lli_fill_sg(&cohc->base->pool, lli, sgl, sg_len, |
1009 | cohc_dev_addr(cohc), | 1108 | cohc_dev_addr(cohc), |
1010 | ctrl_chained, | 1109 | ctrl_chained, |
1011 | ctrl, | 1110 | ctrl, |
@@ -1014,14 +1113,14 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
1014 | if (ret) | 1113 | if (ret) |
1015 | goto err_lli_fill; | 1114 | goto err_lli_fill; |
1016 | 1115 | ||
1017 | COH_DBG(coh901318_list_print(cohc, data)); | 1116 | COH_DBG(coh901318_list_print(cohc, lli)); |
1018 | 1117 | ||
1019 | /* Pick a descriptor to handle this transfer */ | 1118 | /* Pick a descriptor to handle this transfer */ |
1020 | cohd = coh901318_desc_get(cohc); | 1119 | cohd = coh901318_desc_get(cohc); |
1021 | cohd->dir = direction; | 1120 | cohd->dir = direction; |
1022 | cohd->flags = flags; | 1121 | cohd->flags = flags; |
1023 | cohd->desc.tx_submit = coh901318_tx_submit; | 1122 | cohd->desc.tx_submit = coh901318_tx_submit; |
1024 | cohd->data = data; | 1123 | cohd->lli = lli; |
1025 | 1124 | ||
1026 | spin_unlock_irqrestore(&cohc->lock, flg); | 1125 | spin_unlock_irqrestore(&cohc->lock, flg); |
1027 | 1126 | ||
@@ -1035,9 +1134,8 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
1035 | } | 1134 | } |
1036 | 1135 | ||
1037 | static enum dma_status | 1136 | static enum dma_status |
1038 | coh901318_is_tx_complete(struct dma_chan *chan, | 1137 | coh901318_tx_status(struct dma_chan *chan, dma_cookie_t cookie, |
1039 | dma_cookie_t cookie, dma_cookie_t *done, | 1138 | struct dma_tx_state *txstate) |
1040 | dma_cookie_t *used) | ||
1041 | { | 1139 | { |
1042 | struct coh901318_chan *cohc = to_coh901318_chan(chan); | 1140 | struct coh901318_chan *cohc = to_coh901318_chan(chan); |
1043 | dma_cookie_t last_used; | 1141 | dma_cookie_t last_used; |
@@ -1049,10 +1147,10 @@ coh901318_is_tx_complete(struct dma_chan *chan, | |||
1049 | 1147 | ||
1050 | ret = dma_async_is_complete(cookie, last_complete, last_used); | 1148 | ret = dma_async_is_complete(cookie, last_complete, last_used); |
1051 | 1149 | ||
1052 | if (done) | 1150 | dma_set_tx_state(txstate, last_complete, last_used, |
1053 | *done = last_complete; | 1151 | coh901318_get_bytes_left(chan)); |
1054 | if (used) | 1152 | if (ret == DMA_IN_PROGRESS && cohc->stopped) |
1055 | *used = last_used; | 1153 | ret = DMA_PAUSED; |
1056 | 1154 | ||
1057 | return ret; | 1155 | return ret; |
1058 | } | 1156 | } |
@@ -1065,23 +1163,42 @@ coh901318_issue_pending(struct dma_chan *chan) | |||
1065 | 1163 | ||
1066 | spin_lock_irqsave(&cohc->lock, flags); | 1164 | spin_lock_irqsave(&cohc->lock, flags); |
1067 | 1165 | ||
1068 | /* Busy means that pending jobs are already being processed */ | 1166 | /* |
1167 | * Busy means that pending jobs are already being processed, | ||
1168 | * and then there is no point in starting the queue: the | ||
1169 | * terminal count interrupt on the channel will take the next | ||
1170 | * job on the queue and execute it anyway. | ||
1171 | */ | ||
1069 | if (!cohc->busy) | 1172 | if (!cohc->busy) |
1070 | coh901318_queue_start(cohc); | 1173 | coh901318_queue_start(cohc); |
1071 | 1174 | ||
1072 | spin_unlock_irqrestore(&cohc->lock, flags); | 1175 | spin_unlock_irqrestore(&cohc->lock, flags); |
1073 | } | 1176 | } |
1074 | 1177 | ||
1075 | static void | 1178 | static int |
1076 | coh901318_terminate_all(struct dma_chan *chan) | 1179 | coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, |
1180 | unsigned long arg) | ||
1077 | { | 1181 | { |
1078 | unsigned long flags; | 1182 | unsigned long flags; |
1079 | struct coh901318_chan *cohc = to_coh901318_chan(chan); | 1183 | struct coh901318_chan *cohc = to_coh901318_chan(chan); |
1080 | struct coh901318_desc *cohd; | 1184 | struct coh901318_desc *cohd; |
1081 | void __iomem *virtbase = cohc->base->virtbase; | 1185 | void __iomem *virtbase = cohc->base->virtbase; |
1082 | 1186 | ||
1083 | coh901318_stop(chan); | 1187 | if (cmd == DMA_PAUSE) { |
1188 | coh901318_pause(chan); | ||
1189 | return 0; | ||
1190 | } | ||
1191 | |||
1192 | if (cmd == DMA_RESUME) { | ||
1193 | coh901318_resume(chan); | ||
1194 | return 0; | ||
1195 | } | ||
1084 | 1196 | ||
1197 | if (cmd != DMA_TERMINATE_ALL) | ||
1198 | return -ENXIO; | ||
1199 | |||
1200 | /* The remainder of this function terminates the transfer */ | ||
1201 | coh901318_pause(chan); | ||
1085 | spin_lock_irqsave(&cohc->lock, flags); | 1202 | spin_lock_irqsave(&cohc->lock, flags); |
1086 | 1203 | ||
1087 | /* Clear any pending BE or TC interrupt */ | 1204 | /* Clear any pending BE or TC interrupt */ |
@@ -1099,7 +1216,7 @@ coh901318_terminate_all(struct dma_chan *chan) | |||
1099 | 1216 | ||
1100 | while ((cohd = coh901318_first_active_get(cohc))) { | 1217 | while ((cohd = coh901318_first_active_get(cohc))) { |
1101 | /* release the lli allocation*/ | 1218 | /* release the lli allocation*/ |
1102 | coh901318_lli_free(&cohc->base->pool, &cohd->data); | 1219 | coh901318_lli_free(&cohc->base->pool, &cohd->lli); |
1103 | 1220 | ||
1104 | /* return desc to free-list */ | 1221 | /* return desc to free-list */ |
1105 | coh901318_desc_remove(cohd); | 1222 | coh901318_desc_remove(cohd); |
@@ -1108,7 +1225,7 @@ coh901318_terminate_all(struct dma_chan *chan) | |||
1108 | 1225 | ||
1109 | while ((cohd = coh901318_first_queued(cohc))) { | 1226 | while ((cohd = coh901318_first_queued(cohc))) { |
1110 | /* release the lli allocation*/ | 1227 | /* release the lli allocation*/ |
1111 | coh901318_lli_free(&cohc->base->pool, &cohd->data); | 1228 | coh901318_lli_free(&cohc->base->pool, &cohd->lli); |
1112 | 1229 | ||
1113 | /* return desc to free-list */ | 1230 | /* return desc to free-list */ |
1114 | coh901318_desc_remove(cohd); | 1231 | coh901318_desc_remove(cohd); |
@@ -1120,6 +1237,8 @@ coh901318_terminate_all(struct dma_chan *chan) | |||
1120 | cohc->busy = 0; | 1237 | cohc->busy = 0; |
1121 | 1238 | ||
1122 | spin_unlock_irqrestore(&cohc->lock, flags); | 1239 | spin_unlock_irqrestore(&cohc->lock, flags); |
1240 | |||
1241 | return 0; | ||
1123 | } | 1242 | } |
1124 | void coh901318_base_init(struct dma_device *dma, const int *pick_chans, | 1243 | void coh901318_base_init(struct dma_device *dma, const int *pick_chans, |
1125 | struct coh901318_base *base) | 1244 | struct coh901318_base *base) |
@@ -1235,9 +1354,9 @@ static int __init coh901318_probe(struct platform_device *pdev) | |||
1235 | base->dma_slave.device_alloc_chan_resources = coh901318_alloc_chan_resources; | 1354 | base->dma_slave.device_alloc_chan_resources = coh901318_alloc_chan_resources; |
1236 | base->dma_slave.device_free_chan_resources = coh901318_free_chan_resources; | 1355 | base->dma_slave.device_free_chan_resources = coh901318_free_chan_resources; |
1237 | base->dma_slave.device_prep_slave_sg = coh901318_prep_slave_sg; | 1356 | base->dma_slave.device_prep_slave_sg = coh901318_prep_slave_sg; |
1238 | base->dma_slave.device_is_tx_complete = coh901318_is_tx_complete; | 1357 | base->dma_slave.device_tx_status = coh901318_tx_status; |
1239 | base->dma_slave.device_issue_pending = coh901318_issue_pending; | 1358 | base->dma_slave.device_issue_pending = coh901318_issue_pending; |
1240 | base->dma_slave.device_terminate_all = coh901318_terminate_all; | 1359 | base->dma_slave.device_control = coh901318_control; |
1241 | base->dma_slave.dev = &pdev->dev; | 1360 | base->dma_slave.dev = &pdev->dev; |
1242 | 1361 | ||
1243 | err = dma_async_device_register(&base->dma_slave); | 1362 | err = dma_async_device_register(&base->dma_slave); |
@@ -1255,9 +1374,9 @@ static int __init coh901318_probe(struct platform_device *pdev) | |||
1255 | base->dma_memcpy.device_alloc_chan_resources = coh901318_alloc_chan_resources; | 1374 | base->dma_memcpy.device_alloc_chan_resources = coh901318_alloc_chan_resources; |
1256 | base->dma_memcpy.device_free_chan_resources = coh901318_free_chan_resources; | 1375 | base->dma_memcpy.device_free_chan_resources = coh901318_free_chan_resources; |
1257 | base->dma_memcpy.device_prep_dma_memcpy = coh901318_prep_memcpy; | 1376 | base->dma_memcpy.device_prep_dma_memcpy = coh901318_prep_memcpy; |
1258 | base->dma_memcpy.device_is_tx_complete = coh901318_is_tx_complete; | 1377 | base->dma_memcpy.device_tx_status = coh901318_tx_status; |
1259 | base->dma_memcpy.device_issue_pending = coh901318_issue_pending; | 1378 | base->dma_memcpy.device_issue_pending = coh901318_issue_pending; |
1260 | base->dma_memcpy.device_terminate_all = coh901318_terminate_all; | 1379 | base->dma_memcpy.device_control = coh901318_control; |
1261 | base->dma_memcpy.dev = &pdev->dev; | 1380 | base->dma_memcpy.dev = &pdev->dev; |
1262 | /* | 1381 | /* |
1263 | * This controller can only access address at even 32bit boundaries, | 1382 | * This controller can only access address at even 32bit boundaries, |