|
@@ -693,9 +693,15 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|
|
reg = dws->tx_reg;
|
|
|
for_each_sg(sgl, sg, sg_len, i) {
|
|
|
struct dw_desc *desc;
|
|
|
- u32 len;
|
|
|
- u32 mem;
|
|
|
+ u32 len, dlen, mem;
|
|
|
|
|
|
+ mem = sg_phys(sg);
|
|
|
+ len = sg_dma_len(sg);
|
|
|
+ mem_width = 2;
|
|
|
+ if (unlikely(mem & 3 || len & 3))
|
|
|
+ mem_width = 0;
|
|
|
+
|
|
|
+slave_sg_todev_fill_desc:
|
|
|
desc = dwc_desc_get(dwc);
|
|
|
if (!desc) {
|
|
|
dev_err(chan2dev(chan),
|
|
@@ -703,16 +709,19 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|
|
goto err_desc_get;
|
|
|
}
|
|
|
|
|
|
- mem = sg_phys(sg);
|
|
|
- len = sg_dma_len(sg);
|
|
|
- mem_width = 2;
|
|
|
- if (unlikely(mem & 3 || len & 3))
|
|
|
- mem_width = 0;
|
|
|
-
|
|
|
desc->lli.sar = mem;
|
|
|
desc->lli.dar = reg;
|
|
|
desc->lli.ctllo = ctllo | DWC_CTLL_SRC_WIDTH(mem_width);
|
|
|
- desc->lli.ctlhi = len >> mem_width;
|
|
|
+ if ((len >> mem_width) > DWC_MAX_COUNT) {
|
|
|
+ dlen = DWC_MAX_COUNT << mem_width;
|
|
|
+ mem += dlen;
|
|
|
+ len -= dlen;
|
|
|
+ } else {
|
|
|
+ dlen = len;
|
|
|
+ len = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ desc->lli.ctlhi = dlen >> mem_width;
|
|
|
|
|
|
if (!first) {
|
|
|
first = desc;
|
|
@@ -726,7 +735,10 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|
|
&first->tx_list);
|
|
|
}
|
|
|
prev = desc;
|
|
|
- total_len += len;
|
|
|
+ total_len += dlen;
|
|
|
+
|
|
|
+ if (len)
|
|
|
+ goto slave_sg_todev_fill_desc;
|
|
|
}
|
|
|
break;
|
|
|
case DMA_FROM_DEVICE:
|
|
@@ -739,15 +751,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|
|
reg = dws->rx_reg;
|
|
|
for_each_sg(sgl, sg, sg_len, i) {
|
|
|
struct dw_desc *desc;
|
|
|
- u32 len;
|
|
|
- u32 mem;
|
|
|
-
|
|
|
- desc = dwc_desc_get(dwc);
|
|
|
- if (!desc) {
|
|
|
- dev_err(chan2dev(chan),
|
|
|
- "not enough descriptors available\n");
|
|
|
- goto err_desc_get;
|
|
|
- }
|
|
|
+ u32 len, dlen, mem;
|
|
|
|
|
|
mem = sg_phys(sg);
|
|
|
len = sg_dma_len(sg);
|
|
@@ -755,10 +759,26 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|
|
if (unlikely(mem & 3 || len & 3))
|
|
|
mem_width = 0;
|
|
|
|
|
|
+slave_sg_fromdev_fill_desc:
|
|
|
+ desc = dwc_desc_get(dwc);
|
|
|
+ if (!desc) {
|
|
|
+ dev_err(chan2dev(chan),
|
|
|
+ "not enough descriptors available\n");
|
|
|
+ goto err_desc_get;
|
|
|
+ }
|
|
|
+
|
|
|
desc->lli.sar = reg;
|
|
|
desc->lli.dar = mem;
|
|
|
desc->lli.ctllo = ctllo | DWC_CTLL_DST_WIDTH(mem_width);
|
|
|
- desc->lli.ctlhi = len >> reg_width;
|
|
|
+ if ((len >> reg_width) > DWC_MAX_COUNT) {
|
|
|
+ dlen = DWC_MAX_COUNT << reg_width;
|
|
|
+ mem += dlen;
|
|
|
+ len -= dlen;
|
|
|
+ } else {
|
|
|
+ dlen = len;
|
|
|
+ len = 0;
|
|
|
+ }
|
|
|
+ desc->lli.ctlhi = dlen >> reg_width;
|
|
|
|
|
|
if (!first) {
|
|
|
first = desc;
|
|
@@ -772,7 +792,10 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|
|
&first->tx_list);
|
|
|
}
|
|
|
prev = desc;
|
|
|
- total_len += len;
|
|
|
+ total_len += dlen;
|
|
|
+
|
|
|
+ if (len)
|
|
|
+ goto slave_sg_fromdev_fill_desc;
|
|
|
}
|
|
|
break;
|
|
|
default:
|