diff options
-rw-r--r-- | drivers/dma/coh901318.c | 103 |
1 files changed, 65 insertions, 38 deletions
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index 1656fdcdb6c2..20889c98e9b0 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; |
@@ -565,29 +565,30 @@ static int coh901318_config(struct coh901318_chan *cohc, | |||
565 | */ | 565 | */ |
566 | static struct coh901318_desc *coh901318_queue_start(struct coh901318_chan *cohc) | 566 | static struct coh901318_desc *coh901318_queue_start(struct coh901318_chan *cohc) |
567 | { | 567 | { |
568 | struct coh901318_desc *cohd_que; | 568 | struct coh901318_desc *cohd; |
569 | 569 | ||
570 | /* start queued jobs, if any | 570 | /* |
571 | * start queued jobs, if any | ||
571 | * TODO: transmit all queued jobs in one go | 572 | * TODO: transmit all queued jobs in one go |
572 | */ | 573 | */ |
573 | cohd_que = coh901318_first_queued(cohc); | 574 | cohd = coh901318_first_queued(cohc); |
574 | 575 | ||
575 | if (cohd_que != NULL) { | 576 | if (cohd != NULL) { |
576 | /* Remove from queue */ | 577 | /* Remove from queue */ |
577 | coh901318_desc_remove(cohd_que); | 578 | coh901318_desc_remove(cohd); |
578 | /* initiate DMA job */ | 579 | /* initiate DMA job */ |
579 | cohc->busy = 1; | 580 | cohc->busy = 1; |
580 | 581 | ||
581 | coh901318_desc_submit(cohc, cohd_que); | 582 | coh901318_desc_submit(cohc, cohd); |
582 | 583 | ||
583 | coh901318_prep_linked_list(cohc, cohd_que->data); | 584 | coh901318_prep_linked_list(cohc, cohd->lli); |
584 | 585 | ||
585 | /* start dma job */ | 586 | /* start dma job on this channel */ |
586 | coh901318_start(cohc); | 587 | coh901318_start(cohc); |
587 | 588 | ||
588 | } | 589 | } |
589 | 590 | ||
590 | return cohd_que; | 591 | return cohd; |
591 | } | 592 | } |
592 | 593 | ||
593 | /* | 594 | /* |
@@ -622,7 +623,7 @@ static void dma_tasklet(unsigned long data) | |||
622 | cohc->completed = cohd_fin->desc.cookie; | 623 | cohc->completed = cohd_fin->desc.cookie; |
623 | 624 | ||
624 | /* release the lli allocation and remove the descriptor */ | 625 | /* release the lli allocation and remove the descriptor */ |
625 | coh901318_lli_free(&cohc->base->pool, &cohd_fin->data); | 626 | coh901318_lli_free(&cohc->base->pool, &cohd_fin->lli); |
626 | 627 | ||
627 | /* return desc to free-list */ | 628 | /* return desc to free-list */ |
628 | coh901318_desc_remove(cohd_fin); | 629 | coh901318_desc_remove(cohd_fin); |
@@ -666,23 +667,44 @@ static void dma_tasklet(unsigned long data) | |||
666 | /* called from interrupt context */ | 667 | /* called from interrupt context */ |
667 | static void dma_tc_handle(struct coh901318_chan *cohc) | 668 | static void dma_tc_handle(struct coh901318_chan *cohc) |
668 | { | 669 | { |
669 | BUG_ON(!cohc->allocated && (list_empty(&cohc->active) || | 670 | /* |
670 | list_empty(&cohc->queue))); | 671 | * If the channel is not allocated, then we shouldn't have |
671 | 672 | * any TC interrupts on it. | |
672 | if (!cohc->allocated) | 673 | */ |
674 | if (!cohc->allocated) { | ||
675 | dev_err(COHC_2_DEV(cohc), "spurious interrupt from " | ||
676 | "unallocated channel\n"); | ||
673 | return; | 677 | return; |
678 | } | ||
674 | 679 | ||
675 | spin_lock(&cohc->lock); | 680 | spin_lock(&cohc->lock); |
676 | 681 | ||
682 | /* | ||
683 | * When we reach this point, at least one queue item | ||
684 | * should have been moved over from cohc->queue to | ||
685 | * cohc->active and run to completion, that is why we're | ||
686 | * getting a terminal count interrupt is it not? | ||
687 | * If you get this BUG() the most probable cause is that | ||
688 | * the individual nodes in the lli chain have IRQ enabled, | ||
689 | * so check your platform config for lli chain ctrl. | ||
690 | */ | ||
691 | BUG_ON(list_empty(&cohc->active)); | ||
692 | |||
677 | cohc->nbr_active_done++; | 693 | cohc->nbr_active_done++; |
678 | 694 | ||
695 | /* | ||
696 | * This attempt to take a job from cohc->queue, put it | ||
697 | * into cohc->active and start it. | ||
698 | */ | ||
679 | if (coh901318_queue_start(cohc) == NULL) | 699 | if (coh901318_queue_start(cohc) == NULL) |
680 | cohc->busy = 0; | 700 | cohc->busy = 0; |
681 | 701 | ||
682 | BUG_ON(list_empty(&cohc->active)); | ||
683 | |||
684 | spin_unlock(&cohc->lock); | 702 | spin_unlock(&cohc->lock); |
685 | 703 | ||
704 | /* | ||
705 | * This tasklet will remove items from cohc->active | ||
706 | * and thus terminates them. | ||
707 | */ | ||
686 | if (cohc_chan_conf(cohc)->priority_high) | 708 | if (cohc_chan_conf(cohc)->priority_high) |
687 | tasklet_hi_schedule(&cohc->tasklet); | 709 | tasklet_hi_schedule(&cohc->tasklet); |
688 | else | 710 | else |
@@ -870,7 +892,7 @@ static struct dma_async_tx_descriptor * | |||
870 | coh901318_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, | 892 | coh901318_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, |
871 | size_t size, unsigned long flags) | 893 | size_t size, unsigned long flags) |
872 | { | 894 | { |
873 | struct coh901318_lli *data; | 895 | struct coh901318_lli *lli; |
874 | struct coh901318_desc *cohd; | 896 | struct coh901318_desc *cohd; |
875 | unsigned long flg; | 897 | unsigned long flg; |
876 | struct coh901318_chan *cohc = to_coh901318_chan(chan); | 898 | struct coh901318_chan *cohc = to_coh901318_chan(chan); |
@@ -892,23 +914,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) | 914 | if ((lli_len << MAX_DMA_PACKET_SIZE_SHIFT) < size) |
893 | lli_len++; | 915 | lli_len++; |
894 | 916 | ||
895 | data = coh901318_lli_alloc(&cohc->base->pool, lli_len); | 917 | lli = coh901318_lli_alloc(&cohc->base->pool, lli_len); |
896 | 918 | ||
897 | if (data == NULL) | 919 | if (lli == NULL) |
898 | goto err; | 920 | goto err; |
899 | 921 | ||
900 | ret = coh901318_lli_fill_memcpy( | 922 | ret = coh901318_lli_fill_memcpy( |
901 | &cohc->base->pool, data, src, size, dest, | 923 | &cohc->base->pool, lli, src, size, dest, |
902 | cohc_chan_param(cohc)->ctrl_lli_chained, | 924 | cohc_chan_param(cohc)->ctrl_lli_chained, |
903 | ctrl_last); | 925 | ctrl_last); |
904 | if (ret) | 926 | if (ret) |
905 | goto err; | 927 | goto err; |
906 | 928 | ||
907 | COH_DBG(coh901318_list_print(cohc, data)); | 929 | COH_DBG(coh901318_list_print(cohc, lli)); |
908 | 930 | ||
909 | /* Pick a descriptor to handle this transfer */ | 931 | /* Pick a descriptor to handle this transfer */ |
910 | cohd = coh901318_desc_get(cohc); | 932 | cohd = coh901318_desc_get(cohc); |
911 | cohd->data = data; | 933 | cohd->lli = lli; |
912 | cohd->flags = flags; | 934 | cohd->flags = flags; |
913 | cohd->desc.tx_submit = coh901318_tx_submit; | 935 | cohd->desc.tx_submit = coh901318_tx_submit; |
914 | 936 | ||
@@ -926,7 +948,7 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
926 | unsigned long flags) | 948 | unsigned long flags) |
927 | { | 949 | { |
928 | struct coh901318_chan *cohc = to_coh901318_chan(chan); | 950 | struct coh901318_chan *cohc = to_coh901318_chan(chan); |
929 | struct coh901318_lli *data; | 951 | struct coh901318_lli *lli; |
930 | struct coh901318_desc *cohd; | 952 | struct coh901318_desc *cohd; |
931 | const struct coh901318_params *params; | 953 | const struct coh901318_params *params; |
932 | struct scatterlist *sg; | 954 | struct scatterlist *sg; |
@@ -999,13 +1021,13 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
999 | } | 1021 | } |
1000 | 1022 | ||
1001 | pr_debug("Allocate %d lli:s for this transfer\n", len); | 1023 | pr_debug("Allocate %d lli:s for this transfer\n", len); |
1002 | data = coh901318_lli_alloc(&cohc->base->pool, len); | 1024 | lli = coh901318_lli_alloc(&cohc->base->pool, len); |
1003 | 1025 | ||
1004 | if (data == NULL) | 1026 | if (lli == NULL) |
1005 | goto err_dma_alloc; | 1027 | goto err_dma_alloc; |
1006 | 1028 | ||
1007 | /* initiate allocated data list */ | 1029 | /* initiate allocated lli list */ |
1008 | ret = coh901318_lli_fill_sg(&cohc->base->pool, data, sgl, sg_len, | 1030 | ret = coh901318_lli_fill_sg(&cohc->base->pool, lli, sgl, sg_len, |
1009 | cohc_dev_addr(cohc), | 1031 | cohc_dev_addr(cohc), |
1010 | ctrl_chained, | 1032 | ctrl_chained, |
1011 | ctrl, | 1033 | ctrl, |
@@ -1014,14 +1036,14 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
1014 | if (ret) | 1036 | if (ret) |
1015 | goto err_lli_fill; | 1037 | goto err_lli_fill; |
1016 | 1038 | ||
1017 | COH_DBG(coh901318_list_print(cohc, data)); | 1039 | COH_DBG(coh901318_list_print(cohc, lli)); |
1018 | 1040 | ||
1019 | /* Pick a descriptor to handle this transfer */ | 1041 | /* Pick a descriptor to handle this transfer */ |
1020 | cohd = coh901318_desc_get(cohc); | 1042 | cohd = coh901318_desc_get(cohc); |
1021 | cohd->dir = direction; | 1043 | cohd->dir = direction; |
1022 | cohd->flags = flags; | 1044 | cohd->flags = flags; |
1023 | cohd->desc.tx_submit = coh901318_tx_submit; | 1045 | cohd->desc.tx_submit = coh901318_tx_submit; |
1024 | cohd->data = data; | 1046 | cohd->lli = lli; |
1025 | 1047 | ||
1026 | spin_unlock_irqrestore(&cohc->lock, flg); | 1048 | spin_unlock_irqrestore(&cohc->lock, flg); |
1027 | 1049 | ||
@@ -1065,7 +1087,12 @@ coh901318_issue_pending(struct dma_chan *chan) | |||
1065 | 1087 | ||
1066 | spin_lock_irqsave(&cohc->lock, flags); | 1088 | spin_lock_irqsave(&cohc->lock, flags); |
1067 | 1089 | ||
1068 | /* Busy means that pending jobs are already being processed */ | 1090 | /* |
1091 | * Busy means that pending jobs are already being processed, | ||
1092 | * and then there is no point in starting the queue: the | ||
1093 | * terminal count interrupt on the channel will take the next | ||
1094 | * job on the queue and execute it anyway. | ||
1095 | */ | ||
1069 | if (!cohc->busy) | 1096 | if (!cohc->busy) |
1070 | coh901318_queue_start(cohc); | 1097 | coh901318_queue_start(cohc); |
1071 | 1098 | ||
@@ -1099,7 +1126,7 @@ coh901318_terminate_all(struct dma_chan *chan) | |||
1099 | 1126 | ||
1100 | while ((cohd = coh901318_first_active_get(cohc))) { | 1127 | while ((cohd = coh901318_first_active_get(cohc))) { |
1101 | /* release the lli allocation*/ | 1128 | /* release the lli allocation*/ |
1102 | coh901318_lli_free(&cohc->base->pool, &cohd->data); | 1129 | coh901318_lli_free(&cohc->base->pool, &cohd->lli); |
1103 | 1130 | ||
1104 | /* return desc to free-list */ | 1131 | /* return desc to free-list */ |
1105 | coh901318_desc_remove(cohd); | 1132 | coh901318_desc_remove(cohd); |
@@ -1108,7 +1135,7 @@ coh901318_terminate_all(struct dma_chan *chan) | |||
1108 | 1135 | ||
1109 | while ((cohd = coh901318_first_queued(cohc))) { | 1136 | while ((cohd = coh901318_first_queued(cohc))) { |
1110 | /* release the lli allocation*/ | 1137 | /* release the lli allocation*/ |
1111 | coh901318_lli_free(&cohc->base->pool, &cohd->data); | 1138 | coh901318_lli_free(&cohc->base->pool, &cohd->lli); |
1112 | 1139 | ||
1113 | /* return desc to free-list */ | 1140 | /* return desc to free-list */ |
1114 | coh901318_desc_remove(cohd); | 1141 | coh901318_desc_remove(cohd); |