diff options
| -rw-r--r-- | drivers/dma/dw_dmac.c | 65 |
1 files changed, 44 insertions, 21 deletions
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index f209ff8835e8..a9755e3dd603 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c | |||
| @@ -693,9 +693,15 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
| 693 | reg = dws->tx_reg; | 693 | reg = dws->tx_reg; |
| 694 | for_each_sg(sgl, sg, sg_len, i) { | 694 | for_each_sg(sgl, sg, sg_len, i) { |
| 695 | struct dw_desc *desc; | 695 | struct dw_desc *desc; |
| 696 | u32 len; | 696 | u32 len, dlen, mem; |
| 697 | u32 mem; | ||
| 698 | 697 | ||
| 698 | mem = sg_phys(sg); | ||
| 699 | len = sg_dma_len(sg); | ||
| 700 | mem_width = 2; | ||
| 701 | if (unlikely(mem & 3 || len & 3)) | ||
| 702 | mem_width = 0; | ||
| 703 | |||
| 704 | slave_sg_todev_fill_desc: | ||
| 699 | desc = dwc_desc_get(dwc); | 705 | desc = dwc_desc_get(dwc); |
| 700 | if (!desc) { | 706 | if (!desc) { |
| 701 | dev_err(chan2dev(chan), | 707 | dev_err(chan2dev(chan), |
| @@ -703,16 +709,19 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
| 703 | goto err_desc_get; | 709 | goto err_desc_get; |
| 704 | } | 710 | } |
| 705 | 711 | ||
| 706 | mem = sg_phys(sg); | ||
| 707 | len = sg_dma_len(sg); | ||
| 708 | mem_width = 2; | ||
| 709 | if (unlikely(mem & 3 || len & 3)) | ||
| 710 | mem_width = 0; | ||
| 711 | |||
| 712 | desc->lli.sar = mem; | 712 | desc->lli.sar = mem; |
| 713 | desc->lli.dar = reg; | 713 | desc->lli.dar = reg; |
| 714 | desc->lli.ctllo = ctllo | DWC_CTLL_SRC_WIDTH(mem_width); | 714 | desc->lli.ctllo = ctllo | DWC_CTLL_SRC_WIDTH(mem_width); |
| 715 | desc->lli.ctlhi = len >> mem_width; | 715 | if ((len >> mem_width) > DWC_MAX_COUNT) { |
| 716 | dlen = DWC_MAX_COUNT << mem_width; | ||
| 717 | mem += dlen; | ||
| 718 | len -= dlen; | ||
| 719 | } else { | ||
| 720 | dlen = len; | ||
| 721 | len = 0; | ||
| 722 | } | ||
| 723 | |||
| 724 | desc->lli.ctlhi = dlen >> mem_width; | ||
| 716 | 725 | ||
| 717 | if (!first) { | 726 | if (!first) { |
| 718 | first = desc; | 727 | first = desc; |
| @@ -726,7 +735,10 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
| 726 | &first->tx_list); | 735 | &first->tx_list); |
| 727 | } | 736 | } |
| 728 | prev = desc; | 737 | prev = desc; |
| 729 | total_len += len; | 738 | total_len += dlen; |
| 739 | |||
| 740 | if (len) | ||
| 741 | goto slave_sg_todev_fill_desc; | ||
| 730 | } | 742 | } |
| 731 | break; | 743 | break; |
| 732 | case DMA_FROM_DEVICE: | 744 | case DMA_FROM_DEVICE: |
| @@ -739,15 +751,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
| 739 | reg = dws->rx_reg; | 751 | reg = dws->rx_reg; |
| 740 | for_each_sg(sgl, sg, sg_len, i) { | 752 | for_each_sg(sgl, sg, sg_len, i) { |
| 741 | struct dw_desc *desc; | 753 | struct dw_desc *desc; |
| 742 | u32 len; | 754 | u32 len, dlen, mem; |
| 743 | u32 mem; | ||
| 744 | |||
| 745 | desc = dwc_desc_get(dwc); | ||
| 746 | if (!desc) { | ||
| 747 | dev_err(chan2dev(chan), | ||
| 748 | "not enough descriptors available\n"); | ||
| 749 | goto err_desc_get; | ||
| 750 | } | ||
| 751 | 755 | ||
| 752 | mem = sg_phys(sg); | 756 | mem = sg_phys(sg); |
| 753 | len = sg_dma_len(sg); | 757 | len = sg_dma_len(sg); |
| @@ -755,10 +759,26 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
| 755 | if (unlikely(mem & 3 || len & 3)) | 759 | if (unlikely(mem & 3 || len & 3)) |
| 756 | mem_width = 0; | 760 | mem_width = 0; |
| 757 | 761 | ||
| 762 | slave_sg_fromdev_fill_desc: | ||
| 763 | desc = dwc_desc_get(dwc); | ||
| 764 | if (!desc) { | ||
| 765 | dev_err(chan2dev(chan), | ||
| 766 | "not enough descriptors available\n"); | ||
| 767 | goto err_desc_get; | ||
| 768 | } | ||
| 769 | |||
| 758 | desc->lli.sar = reg; | 770 | desc->lli.sar = reg; |
| 759 | desc->lli.dar = mem; | 771 | desc->lli.dar = mem; |
| 760 | desc->lli.ctllo = ctllo | DWC_CTLL_DST_WIDTH(mem_width); | 772 | desc->lli.ctllo = ctllo | DWC_CTLL_DST_WIDTH(mem_width); |
| 761 | desc->lli.ctlhi = len >> reg_width; | 773 | if ((len >> reg_width) > DWC_MAX_COUNT) { |
| 774 | dlen = DWC_MAX_COUNT << reg_width; | ||
| 775 | mem += dlen; | ||
| 776 | len -= dlen; | ||
| 777 | } else { | ||
| 778 | dlen = len; | ||
| 779 | len = 0; | ||
| 780 | } | ||
| 781 | desc->lli.ctlhi = dlen >> reg_width; | ||
| 762 | 782 | ||
| 763 | if (!first) { | 783 | if (!first) { |
| 764 | first = desc; | 784 | first = desc; |
| @@ -772,7 +792,10 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
| 772 | &first->tx_list); | 792 | &first->tx_list); |
| 773 | } | 793 | } |
| 774 | prev = desc; | 794 | prev = desc; |
| 775 | total_len += len; | 795 | total_len += dlen; |
| 796 | |||
| 797 | if (len) | ||
| 798 | goto slave_sg_fromdev_fill_desc; | ||
| 776 | } | 799 | } |
| 777 | break; | 800 | break; |
| 778 | default: | 801 | default: |
