Skip to content

Commit 7ba5ca3

Browse files
takaswietiwai
authored andcommitted
ALSA: firewire-lib: operate for period elapse event in process context
All of drivers in ALSA firewire stack processes two chances to process isochronous packets in any isochronous context; in software IRQ context for 1394 OHCI, and in process context of ALSA PCM application. In the process context, callbacks of .pointer and .ack are utilized. The callbacks are done by ALSA PCM core under acquiring lock of PCM substream, In design of ALSA PCM core, call of snd_pcm_period_elapsed() is used for drivers to awaken user processes from waiting for available frames. The function voluntarily acquires lock of PCM substream, therefore it is not called in the process context since it causes dead lock. As a workaround to avoid the dead lock, all of drivers in ALSA firewire stack uses workqueue to delegate the call. A variant of snd_pcm_period_elapsed() without lock acquisition can obsolete the workqueue. An extra care is needed for the callback of .pointer since it's called from snd_pcm_period_elapsed(). The isochronous context in Linux FireWire subsystem is safe mostly for nested call except in software IRQ context. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Link: https://lore.kernel.org/r/20210610031733.56297-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent 47271b1 commit 7ba5ca3

File tree

1 file changed

+14
-17
lines changed

1 file changed

+14
-17
lines changed

sound/firewire/amdtp-stream.c

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -613,8 +613,16 @@ static void update_pcm_pointers(struct amdtp_stream *s,
613613
// The program in user process should periodically check the status of intermediate
614614
// buffer associated to PCM substream to process PCM frames in the buffer, instead
615615
// of receiving notification of period elapsed by poll wait.
616-
if (!pcm->runtime->no_period_wakeup)
617-
queue_work(system_highpri_wq, &s->period_work);
616+
if (!pcm->runtime->no_period_wakeup) {
617+
if (in_interrupt()) {
618+
// In software IRQ context for 1394 OHCI.
619+
snd_pcm_period_elapsed(pcm);
620+
} else {
621+
// In process context of ALSA PCM application under acquired lock of
622+
// PCM substream.
623+
snd_pcm_period_elapsed_under_stream_lock(pcm);
624+
}
625+
}
618626
}
619627
}
620628

@@ -1740,22 +1748,11 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d,
17401748
{
17411749
struct amdtp_stream *irq_target = d->irq_target;
17421750

1751+
// Process isochronous packets queued till recent isochronous cycle to handle PCM frames.
17431752
if (irq_target && amdtp_stream_running(irq_target)) {
1744-
// This function is called in software IRQ context of
1745-
// period_work or process context.
1746-
//
1747-
// When the software IRQ context was scheduled by software IRQ
1748-
// context of IT contexts, queued packets were already handled.
1749-
// Therefore, no need to flush the queue in buffer furthermore.
1750-
//
1751-
// When the process context reach here, some packets will be
1752-
// already queued in the buffer. These packets should be handled
1753-
// immediately to keep better granularity of PCM pointer.
1754-
//
1755-
// Later, the process context will sometimes schedules software
1756-
// IRQ context of the period_work. Then, no need to flush the
1757-
// queue by the same reason as described in the above
1758-
if (current_work() != &s->period_work)
1753+
// In software IRQ context, the call causes dead-lock to disable the tasklet
1754+
// synchronously.
1755+
if (!in_interrupt())
17591756
fw_iso_context_flush_completions(irq_target->context);
17601757
}
17611758

0 commit comments

Comments
 (0)