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>
This commit is contained in:
		
					parent
					
						
							
								abf53902dc
							
						
					
				
			
			
				commit
				
					
						69dc14b51c
					
				
			
		
					 1 changed files with 45 additions and 22 deletions
				
			
		|  | @ -693,15 +693,7 @@ 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; | ||||
| 
 | ||||
| 			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); | ||||
|  | @ -709,10 +701,27 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
| 			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), | ||||
| 					"not enough descriptors available\n"); | ||||
| 				goto err_desc_get; | ||||
| 			} | ||||
| 
 | ||||
| 			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: | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Viresh Kumar
				Viresh Kumar