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

dmaengine: pl330: _stop: clear interrupt status

This patch kill instructs the DMAC to immediately terminate
execution of a thread. and then clear the interrupt status,
at last, stop generating interrupts for DMA_SEV. to guarantee
the next dma start is clean. otherwise, one interrupt maybe leave
to next start and make some mistake.

we can reporduce the problem as follows:

DMASEV: modify the event-interrupt resource, and if the INTEN sets
function as interrupt, the DMAC will set irq<event_num> HIGH to
generate interrupt. write INTCLR to clear interrupt.

DMA EXECUTING INSTRUCTS DMA TERMINATE
| |
| |
... _stop
| |
| spin_lock_irqsave
DMASEV |
| |
| mask INTEN
| |
| DMAKILL
| |
| spin_unlock_irqrestore

in above case, a interrupt was left, and if we unmask INTEN, the DMAC
will set irq<event_num> HIGH to generate interrupt.

to fix this, do as follows:

DMA EXECUTING INSTRUCTS DMA TERMINATE
| |
| |
... _stop
| |
| spin_lock_irqsave
DMASEV |
| |
| DMAKILL
| |
| clear INTCLR
| mask INTEN
| |
| spin_unlock_irqrestore

Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Sugar Zhang and committed by
Vinod Koul
2da254cc 9a05045d

+7 -3
+7 -3
drivers/dma/pl330.c
··· 967 967 { 968 968 void __iomem *regs = thrd->dmac->base; 969 969 u8 insn[6] = {0, 0, 0, 0, 0, 0}; 970 + u32 inten = readl(regs + INTEN); 970 971 971 972 if (_state(thrd) == PL330_STATE_FAULT_COMPLETING) 972 973 UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING); ··· 980 979 981 980 _emit_KILL(0, insn); 982 981 983 - /* Stop generating interrupts for SEV */ 984 - writel(readl(regs + INTEN) & ~(1 << thrd->ev), regs + INTEN); 985 - 986 982 _execute_DBGINSN(thrd, insn, is_manager(thrd)); 983 + 984 + /* clear the event */ 985 + if (inten & (1 << thrd->ev)) 986 + writel(1 << thrd->ev, regs + INTCLR); 987 + /* Stop generating interrupts for SEV */ 988 + writel(inten & ~(1 << thrd->ev), regs + INTEN); 987 989 } 988 990 989 991 /* Start doing req 'idx' of thread 'thrd' */