audio/pcm: skip period_elapsed for streams that are not started#31
Open
Vakarux12 wants to merge 2 commits into
Open
audio/pcm: skip period_elapsed for streams that are not started#31Vakarux12 wants to merge 2 commits into
Vakarux12 wants to merge 2 commits into
Conversation
The T2 chip continuously sends timestamp events for all registered audio
devices regardless of whether an ALSA stream is open. Previously,
aaudio_handle_stream_timestamp() would call snd_pcm_period_elapsed() for
every substream that had a PCM, even when no audio was playing.
On PREEMPT(full) kernels this is fatal: the BCE DMA IRQ handler runs with
bottom halves disabled, so any call chain that reaches schedule() triggers
BUG: scheduling while atomic. The specific path is:
bce_handle_dma_irq
aaudio_handle_cmd_timestamp
aaudio_handle_stream_timestamp
snd_pcm_period_elapsed <- called on stopped stream
snd_pcm_update_state <- ALSA detects XRUN, tries to stop
snd_pcm_do_stop
aaudio_pcm_trigger(STOP)
aaudio_cmd_stop_io
__aaudio_send_cmd_sync
wait_for_completion_timeout <- sleeps, crash
Fix this by returning early when stream->started is 0. This matches the
existing guard in aaudio_pcm_pointer() which already handles the same
condition.
aaudio_cmd_stop_io blocks waiting for a T2 firmware reply. When called from PCM trigger(STOP), it can block PipeWire's main thread while the RT data thread holds a lock the main thread needs, causing a deadlock. It can also be called from atomic context (BCE DMA BH handler via snd_pcm_period_elapsed -> snd_pcm_do_stop) causing scheduling-while-atomic. Always defer the stop via schedule_work so trigger(STOP) returns immediately. In trigger(START), use cancel_work_sync to cancel any pending (not yet running) stop before starting, avoiding a start/stop race without blocking callers unnecessarily.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On PREEMPT(full) kernels, connecting speakers or headphones to the 3.5mm jack causes a kernel crash:
The T2 chip sends continuous timestamp events for all registered audio devices, even when no ALSA stream is open. When a jack is connected, ALSA calls `snd_pcm_period_elapsed`, which can trigger `snd_pcm_do_stop` → `aaudio_pcm_trigger(STOP)` → `aaudio_cmd_stop_io` → `wait_for_completion_timeout` inside the BCE DMA BH handler (atomic context). This also causes a deadlock when called from PipeWire's main thread: the RT data thread holds a lock the main thread needs, while the main thread blocks waiting for T2 to respond.
Fix
Three commits:
Skip
period_elapsedfor stopped streams — guardaaudio_handle_stream_timestampwith!stream->startedto avoid callingsnd_pcm_period_elapsedon streams that are not running.Use
os_timestampfor playback — fixes a reload crash when the timestamp function receives an incompatible device timestamp for playback streams.Defer
stop_ioto a workqueue —aaudio_cmd_stop_ioblocks waiting for a T2 reply, which is unsafe in both atomic context and from PipeWire's main thread. Always defer it viaschedule_work. InTRIGGER_START, usecancel_work_syncto cancel any pending (not yet running) stop before starting, avoiding a start/stop race without blocking callers unnecessarily.Testing
Tested on MacBook Pro 16,1 (T2) running Arch Linux with kernel 7.0.12 (PREEMPT full). Previously crashed immediately on speaker/headphone connection. Now: