Skip to content

Commit c4b603c

Browse files
cristiccbroonie
authored andcommitted
ASoC: SOF: amd: Fix locking in ACP IRQ handler
A recent change in acp_irq_thread() was meant to address a potential race condition while trying to acquire the hardware semaphore responsible for the synchronization between firmware and host IPC interrupts. This resulted in an improper use of the IPC spinlock, causing normal kernel memory allocations (which may sleep) inside atomic contexts: 1707255557.133976 kernel: BUG: sleeping function called from invalid context at include/linux/sched/mm.h:315 ... 1707255557.134757 kernel: sof_ipc3_rx_msg+0x70/0x130 [snd_sof] 1707255557.134793 kernel: acp_sof_ipc_irq_thread+0x1e0/0x550 [snd_sof_amd_acp] 1707255557.134855 kernel: acp_irq_thread+0xa3/0x130 [snd_sof_amd_acp] 1707255557.134904 kernel: ? irq_thread+0xb5/0x1e0 1707255557.134947 kernel: ? __pfx_irq_thread_fn+0x10/0x10 1707255557.134985 kernel: irq_thread_fn+0x23/0x60 Moreover, there are attempts to lock a mutex from the same atomic context: 1707255557.136357 kernel: ============================= 1707255557.136393 kernel: [ BUG: Invalid wait context ] 1707255557.136413 kernel: 6.8.0-rc3-next-20240206-audio-next #9 Tainted: G W 1707255557.136432 kernel: ----------------------------- 1707255557.136451 kernel: irq/66-AudioDSP/502 is trying to lock: 1707255557.136470 kernel: ffff965152f26af8 (&sb->s_type->i_mutex_key#2){+.+.}-{3:3}, at: start_creating.part.0+0x5f/0x180 ... 1707255557.137429 kernel: start_creating.part.0+0x5f/0x180 1707255557.137457 kernel: __debugfs_create_file+0x61/0x210 1707255557.137475 kernel: snd_sof_debugfs_io_item+0x75/0xc0 [snd_sof] 1707255557.137494 kernel: sof_ipc3_do_rx_work+0x7cf/0x9f0 [snd_sof] 1707255557.137513 kernel: sof_ipc3_rx_msg+0xb3/0x130 [snd_sof] 1707255557.137532 kernel: acp_sof_ipc_irq_thread+0x1e0/0x550 [snd_sof_amd_acp] 1707255557.137551 kernel: acp_irq_thread+0xa3/0x130 [snd_sof_amd_acp] Fix the issues by reducing the lock scope in acp_irq_thread(), so that it guards only the hardware semaphore acquiring attempt. Additionally, restore the initial locking in acp_sof_ipc_irq_thread() to synchronize the handling of immediate replies from DSP core. Fixes: 802134c ("ASoC: SOF: amd: Refactor spinlock_irq(&sdev->ipc_lock) sequence in irq_handler") Signed-off-by: Cristian Ciocaltea <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 6ef5d5b commit c4b603c

File tree

2 files changed

+10
-9
lines changed

2 files changed

+10
-9
lines changed

sound/soc/sof/amd/acp-ipc.c

+2
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,13 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
188188

189189
dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write);
190190
if (dsp_ack) {
191+
spin_lock_irq(&sdev->ipc_lock);
191192
/* handle immediate reply from DSP core */
192193
acp_dsp_ipc_get_reply(sdev);
193194
snd_sof_ipc_reply(sdev, 0);
194195
/* set the done bit */
195196
acp_dsp_ipc_dsp_done(sdev);
197+
spin_unlock_irq(&sdev->ipc_lock);
196198
ipc_irq = true;
197199
}
198200

sound/soc/sof/amd/acp.c

+8-9
Original file line numberDiff line numberDiff line change
@@ -355,21 +355,20 @@ static irqreturn_t acp_irq_thread(int irq, void *context)
355355
unsigned int count = ACP_HW_SEM_RETRY_COUNT;
356356

357357
spin_lock_irq(&sdev->ipc_lock);
358-
while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) {
359-
/* Wait until acquired HW Semaphore lock or timeout */
360-
count--;
361-
if (!count) {
362-
dev_err(sdev->dev, "%s: Failed to acquire HW lock\n", __func__);
363-
spin_unlock_irq(&sdev->ipc_lock);
364-
return IRQ_NONE;
365-
}
358+
/* Wait until acquired HW Semaphore lock or timeout */
359+
while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset) && --count)
360+
;
361+
spin_unlock_irq(&sdev->ipc_lock);
362+
363+
if (!count) {
364+
dev_err(sdev->dev, "%s: Failed to acquire HW lock\n", __func__);
365+
return IRQ_NONE;
366366
}
367367

368368
sof_ops(sdev)->irq_thread(irq, sdev);
369369
/* Unlock or Release HW Semaphore */
370370
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset, 0x0);
371371

372-
spin_unlock_irq(&sdev->ipc_lock);
373372
return IRQ_HANDLED;
374373
};
375374

0 commit comments

Comments
 (0)