| From foo@baz Fri Sep 21 09:36:02 CEST 2018 |
| From: John Keeping <john@metanate.com> |
| Date: Tue, 17 Jul 2018 11:48:16 +0100 |
| Subject: dmaengine: pl330: fix irq race with terminate_all |
| |
| From: John Keeping <john@metanate.com> |
| |
| [ Upstream commit e49756544a21f5625b379b3871d27d8500764670 ] |
| |
| In pl330_update() when checking if a channel has been aborted, the |
| channel's lock is not taken, only the overall pl330_dmac lock. But in |
| pl330_terminate_all() the aborted flag (req_running==-1) is set under |
| the channel lock and not the pl330_dmac lock. |
| |
| With threaded interrupts, this leads to a potential race: |
| |
| pl330_terminate_all pl330_update |
| ------------------- ------------ |
| lock channel |
| entry |
| lock pl330 |
| _stop channel |
| unlock pl330 |
| lock pl330 |
| check req_running != -1 |
| req_running = -1 |
| _start channel |
| |
| Signed-off-by: John Keeping <john@metanate.com> |
| Signed-off-by: Vinod Koul <vkoul@kernel.org> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/dma/pl330.c | 5 +++-- |
| 1 file changed, 3 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/dma/pl330.c |
| +++ b/drivers/dma/pl330.c |
| @@ -2167,13 +2167,14 @@ static int pl330_terminate_all(struct dm |
| |
| pm_runtime_get_sync(pl330->ddma.dev); |
| spin_lock_irqsave(&pch->lock, flags); |
| + |
| spin_lock(&pl330->lock); |
| _stop(pch->thread); |
| - spin_unlock(&pl330->lock); |
| - |
| pch->thread->req[0].desc = NULL; |
| pch->thread->req[1].desc = NULL; |
| pch->thread->req_running = -1; |
| + spin_unlock(&pl330->lock); |
| + |
| power_down = pch->active; |
| pch->active = false; |
| |