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

ptdma: pt_core_execute_cmd() should use spinlock

The interrupt handler (pt_core_irq_handler()) of the ptdma
driver can be called from interrupt context. The code flow
in this function can lead down to pt_core_execute_cmd() which
will attempt to grab a mutex, which is not appropriate in
interrupt context and ultimately leads to a kernel panic.
The fix here changes this mutex to a spinlock, which has
been verified to resolve the issue.

Fixes: fa5d823b16a9 ("dmaengine: ptdma: Initial driver for the AMD PTDMA")
Signed-off-by: Eric Pilmore <epilmore@gigaio.com>
Link: https://lore.kernel.org/r/20230119033907.35071-1-epilmore@gigaio.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Eric Pilmore and committed by
Vinod Koul
95e5fda3 a7a7ee6f

+5 -4
+4 -3
drivers/dma/ptdma/ptdma-dev.c
··· 71 71 bool soc = FIELD_GET(DWORD0_SOC, desc->dw0); 72 72 u8 *q_desc = (u8 *)&cmd_q->qbase[cmd_q->qidx]; 73 73 u32 tail; 74 + unsigned long flags; 74 75 75 76 if (soc) { 76 77 desc->dw0 |= FIELD_PREP(DWORD0_IOC, desc->dw0); 77 78 desc->dw0 &= ~DWORD0_SOC; 78 79 } 79 - mutex_lock(&cmd_q->q_mutex); 80 + spin_lock_irqsave(&cmd_q->q_lock, flags); 80 81 81 82 /* Copy 32-byte command descriptor to hw queue. */ 82 83 memcpy(q_desc, desc, 32); ··· 92 91 93 92 /* Turn the queue back on using our cached control register */ 94 93 pt_start_queue(cmd_q); 95 - mutex_unlock(&cmd_q->q_mutex); 94 + spin_unlock_irqrestore(&cmd_q->q_lock, flags); 96 95 97 96 return 0; 98 97 } ··· 200 199 201 200 cmd_q->pt = pt; 202 201 cmd_q->dma_pool = dma_pool; 203 - mutex_init(&cmd_q->q_mutex); 202 + spin_lock_init(&cmd_q->q_lock); 204 203 205 204 /* Page alignment satisfies our needs for N <= 128 */ 206 205 cmd_q->qsize = Q_SIZE(Q_DESC_SIZE);
+1 -1
drivers/dma/ptdma/ptdma.h
··· 196 196 struct ptdma_desc *qbase; 197 197 198 198 /* Aligned queue start address (per requirement) */ 199 - struct mutex q_mutex ____cacheline_aligned; 199 + spinlock_t q_lock ____cacheline_aligned; 200 200 unsigned int qidx; 201 201 202 202 unsigned int qsize;