Commit 24e30e721438600a496bcf1ae44cb4d7c93eafd8
Committed by
fang hui
1 parent
b0bd033022
Exists in
smarc-8m-android-11.0.0_2.0.0
dmaengine: imx-sdma: add terminated list for freed descriptor in worker
Add terminated list for keeping descriptor so that it could be freed in worker without any potential involving next descriptor raised up before this descriptor freed, because vchan_get_all_descriptors get all descriptors including the last terminated descriptor and the next descriptor, hence, the next descriptor maybe freed unexpectly when it's done in worker without this patch. https://www.spinics.net/lists/dmaengine/msg23367.html Change-Id: Iece434f55f3c6b5cf861fc23e4076fd4aa670ac4 Signed-off-by: Robin Gong <yibin.gong@nxp.com> Reported-by: Richard Leitner <richard.leitner@skidata.com>
Showing 1 changed file with 10 additions and 7 deletions Side-by-side Diff
drivers/dma/imx-sdma.c
... | ... | @@ -394,6 +394,7 @@ |
394 | 394 | enum dma_status status; |
395 | 395 | struct imx_dma_data data; |
396 | 396 | struct work_struct terminate_worker; |
397 | + struct list_head terminated; | |
397 | 398 | bool is_ram_script; |
398 | 399 | bool src_dualfifo; |
399 | 400 | bool dst_dualfifo; |
... | ... | @@ -1216,9 +1217,6 @@ |
1216 | 1217 | { |
1217 | 1218 | struct sdma_channel *sdmac = container_of(work, struct sdma_channel, |
1218 | 1219 | terminate_worker); |
1219 | - unsigned long flags; | |
1220 | - LIST_HEAD(head); | |
1221 | - | |
1222 | 1220 | /* |
1223 | 1221 | * According to NXP R&D team a delay of one BD SDMA cost time |
1224 | 1222 | * (maximum is 1ms) should be added after disable of the channel |
... | ... | @@ -1227,10 +1225,7 @@ |
1227 | 1225 | */ |
1228 | 1226 | usleep_range(1000, 2000); |
1229 | 1227 | |
1230 | - spin_lock_irqsave(&sdmac->vc.lock, flags); | |
1231 | - vchan_get_all_descriptors(&sdmac->vc, &head); | |
1232 | - spin_unlock_irqrestore(&sdmac->vc.lock, flags); | |
1233 | - vchan_dma_desc_free_list(&sdmac->vc, &head); | |
1228 | + vchan_dma_desc_free_list(&sdmac->vc, &sdmac->terminated); | |
1234 | 1229 | } |
1235 | 1230 | |
1236 | 1231 | static int sdma_terminate_all(struct dma_chan *chan) |
... | ... | @@ -1244,6 +1239,13 @@ |
1244 | 1239 | |
1245 | 1240 | if (sdmac->desc) { |
1246 | 1241 | vchan_terminate_vdesc(&sdmac->desc->vd); |
1242 | + /* | |
1243 | + * move out current descriptor into terminated list so that | |
1244 | + * it could be free in sdma_channel_terminate_work alone | |
1245 | + * later without potential involving next descriptor raised | |
1246 | + * up before the last descriptor terminated. | |
1247 | + */ | |
1248 | + vchan_get_all_descriptors(&sdmac->vc, &sdmac->terminated); | |
1247 | 1249 | sdmac->desc = NULL; |
1248 | 1250 | schedule_work(&sdmac->terminate_worker); |
1249 | 1251 | } |
... | ... | @@ -2375,6 +2377,7 @@ |
2375 | 2377 | |
2376 | 2378 | sdmac->channel = i; |
2377 | 2379 | sdmac->vc.desc_free = sdma_desc_free; |
2380 | + INIT_LIST_HEAD(&sdmac->terminated); | |
2378 | 2381 | INIT_WORK(&sdmac->terminate_worker, |
2379 | 2382 | sdma_channel_terminate_work); |
2380 | 2383 | /* |