aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/dw_dmac.c
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@st.com>2011-04-18 05:24:56 -0400
committerVinod Koul <vinod.koul@intel.com>2011-05-13 10:10:00 -0400
commit69dc14b51c1aad9d82afd8f96bf4e4835089bffc (patch)
tree494e852ee6531c5e91720246baf53623e45e4112 /drivers/dma/dw_dmac.c
parentabf53902dcc6d44d2e06b09817fa67857aa686fe (diff)
dmaengine/dw_dmac: Divide one sg to many desc, if sg len is greater than DWC_MAX_COUNT
If len passed in sg for slave_sg transfers is greater than DWC_MAX_COUNT, then driver programmes controller incorrectly. This patch adds code to handle this situation by allocation more than one desc for same sg. Signed-off-by: Viresh Kumar <viresh.kumar@st.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma/dw_dmac.c')
-rw-r--r--drivers/dma/dw_dmac.c65
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
704slave_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
762slave_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: