Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dmaengine: stm32-dma: fix residue calculation in stm32-dma

In double buffer mode, during residue calculation, the DMA can
automatically switch to the next transfer. Indeed the CT bit that
gives position in the double buffer can has been updated by the
hardware, during calculation.
In this case the SxNDTR register value can not be trusted.
If a transition is detected we consider that the DMA has switched to
the beginning of next sg.

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
Signed-off-by: Pierre-Yves MORDRET <pierre-yves.mordret@st.com>
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Arnaud Pouliquen and committed by
Vinod Koul
2a4885ab 66c30aa6

+77 -13
+77 -13
drivers/dma/stm32-dma.c
··· 1042 1042 return ndtr << width; 1043 1043 } 1044 1044 1045 + /** 1046 + * stm32_dma_is_current_sg - check that expected sg_req is currently transferred 1047 + * @chan: dma channel 1048 + * 1049 + * This function called when IRQ are disable, checks that the hardware has not 1050 + * switched on the next transfer in double buffer mode. The test is done by 1051 + * comparing the next_sg memory address with the hardware related register 1052 + * (based on CT bit value). 1053 + * 1054 + * Returns true if expected current transfer is still running or double 1055 + * buffer mode is not activated. 1056 + */ 1057 + static bool stm32_dma_is_current_sg(struct stm32_dma_chan *chan) 1058 + { 1059 + struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 1060 + struct stm32_dma_sg_req *sg_req; 1061 + u32 dma_scr, dma_smar, id; 1062 + 1063 + id = chan->id; 1064 + dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); 1065 + 1066 + if (!(dma_scr & STM32_DMA_SCR_DBM)) 1067 + return true; 1068 + 1069 + sg_req = &chan->desc->sg_req[chan->next_sg]; 1070 + 1071 + if (dma_scr & STM32_DMA_SCR_CT) { 1072 + dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM0AR(id)); 1073 + return (dma_smar == sg_req->chan_reg.dma_sm0ar); 1074 + } 1075 + 1076 + dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM1AR(id)); 1077 + 1078 + return (dma_smar == sg_req->chan_reg.dma_sm1ar); 1079 + } 1080 + 1045 1081 static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, 1046 1082 struct stm32_dma_desc *desc, 1047 1083 u32 next_sg) 1048 1084 { 1049 1085 u32 modulo, burst_size; 1050 - u32 residue = 0; 1086 + u32 residue; 1087 + u32 n_sg = next_sg; 1088 + struct stm32_dma_sg_req *sg_req = &chan->desc->sg_req[chan->next_sg]; 1051 1089 int i; 1052 1090 1053 1091 /* 1054 - * In cyclic mode, for the last period, residue = remaining bytes from 1055 - * NDTR 1092 + * Calculate the residue means compute the descriptors 1093 + * information: 1094 + * - the sg_req currently transferred 1095 + * - the Hardware remaining position in this sg (NDTR bits field). 1096 + * 1097 + * A race condition may occur if DMA is running in cyclic or double 1098 + * buffer mode, since the DMA register are automatically reloaded at end 1099 + * of period transfer. The hardware may have switched to the next 1100 + * transfer (CT bit updated) just before the position (SxNDTR reg) is 1101 + * read. 1102 + * In this case the SxNDTR reg could (or not) correspond to the new 1103 + * transfer position, and not the expected one. 1104 + * The strategy implemented in the stm32 driver is to: 1105 + * - read the SxNDTR register 1106 + * - crosscheck that hardware is still in current transfer. 1107 + * In case of switch, we can assume that the DMA is at the beginning of 1108 + * the next transfer. So we approximate the residue in consequence, by 1109 + * pointing on the beginning of next transfer. 1110 + * 1111 + * This race condition doesn't apply for none cyclic mode, as double 1112 + * buffer is not used. In such situation registers are updated by the 1113 + * software. 1056 1114 */ 1057 - if (chan->desc->cyclic && next_sg == 0) { 1058 - residue = stm32_dma_get_remaining_bytes(chan); 1059 - goto end; 1115 + 1116 + residue = stm32_dma_get_remaining_bytes(chan); 1117 + 1118 + if (!stm32_dma_is_current_sg(chan)) { 1119 + n_sg++; 1120 + if (n_sg == chan->desc->num_sgs) 1121 + n_sg = 0; 1122 + residue = sg_req->len; 1060 1123 } 1061 1124 1062 1125 /* 1063 - * For all other periods in cyclic mode, and in sg mode, 1064 - * residue = remaining bytes from NDTR + remaining periods/sg to be 1065 - * transferred 1126 + * In cyclic mode, for the last period, residue = remaining bytes 1127 + * from NDTR, 1128 + * else for all other periods in cyclic mode, and in sg mode, 1129 + * residue = remaining bytes from NDTR + remaining 1130 + * periods/sg to be transferred 1066 1131 */ 1067 - for (i = next_sg; i < desc->num_sgs; i++) 1068 - residue += desc->sg_req[i].len; 1069 - residue += stm32_dma_get_remaining_bytes(chan); 1132 + if (!chan->desc->cyclic || n_sg != 0) 1133 + for (i = n_sg; i < desc->num_sgs; i++) 1134 + residue += desc->sg_req[i].len; 1070 1135 1071 - end: 1072 1136 if (!chan->mem_burst) 1073 1137 return residue; 1074 1138