Skip to content

Commit 4e2b10b

Browse files
Robin GongShawn Guo
authored andcommitted
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 Signed-off-by: Robin Gong <yibin.gong@nxp.com> Reported-by: Richard Leitner <richard.leitner@skidata.com> Reviewed-by: Lucas Stach <l.stach@pengutronix.de> Signed-off-by: Shawn Guo <shawnguo@kernel.org>
1 parent b98ce2f commit 4e2b10b

1 file changed

Lines changed: 10 additions & 7 deletions

File tree

drivers/dma/imx-sdma.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ struct sdma_channel {
439439
enum dma_status status;
440440
struct imx_dma_data data;
441441
struct work_struct terminate_worker;
442+
struct list_head terminated;
442443
bool is_ram_script;
443444
};
444445

@@ -1107,9 +1108,6 @@ static void sdma_channel_terminate_work(struct work_struct *work)
11071108
{
11081109
struct sdma_channel *sdmac = container_of(work, struct sdma_channel,
11091110
terminate_worker);
1110-
unsigned long flags;
1111-
LIST_HEAD(head);
1112-
11131111
/*
11141112
* According to NXP R&D team a delay of one BD SDMA cost time
11151113
* (maximum is 1ms) should be added after disable of the channel
@@ -1118,10 +1116,7 @@ static void sdma_channel_terminate_work(struct work_struct *work)
11181116
*/
11191117
usleep_range(1000, 2000);
11201118

1121-
spin_lock_irqsave(&sdmac->vc.lock, flags);
1122-
vchan_get_all_descriptors(&sdmac->vc, &head);
1123-
spin_unlock_irqrestore(&sdmac->vc.lock, flags);
1124-
vchan_dma_desc_free_list(&sdmac->vc, &head);
1119+
vchan_dma_desc_free_list(&sdmac->vc, &sdmac->terminated);
11251120
}
11261121

11271122
static int sdma_terminate_all(struct dma_chan *chan)
@@ -1135,6 +1130,13 @@ static int sdma_terminate_all(struct dma_chan *chan)
11351130

11361131
if (sdmac->desc) {
11371132
vchan_terminate_vdesc(&sdmac->desc->vd);
1133+
/*
1134+
* move out current descriptor into terminated list so that
1135+
* it could be free in sdma_channel_terminate_work alone
1136+
* later without potential involving next descriptor raised
1137+
* up before the last descriptor terminated.
1138+
*/
1139+
vchan_get_all_descriptors(&sdmac->vc, &sdmac->terminated);
11381140
sdmac->desc = NULL;
11391141
schedule_work(&sdmac->terminate_worker);
11401142
}
@@ -2130,6 +2132,7 @@ static int sdma_probe(struct platform_device *pdev)
21302132

21312133
sdmac->channel = i;
21322134
sdmac->vc.desc_free = sdma_desc_free;
2135+
INIT_LIST_HEAD(&sdmac->terminated);
21332136
INIT_WORK(&sdmac->terminate_worker,
21342137
sdma_channel_terminate_work);
21352138
/*

0 commit comments

Comments
 (0)