Skip to content

Commit 5c49cc0

Browse files
committed
ALSA: firewire: use nonatomic PCM operation
In the former commits, the callback of isochronous context runs on usual work process. In the case, ALSA PCM device has a flag, nonatomic, to acquire mutex lock instead of spin lock for PCM substream group. This commit uses the flag. It has an advantage in the case that ALSA PCM application uses the large size of intermediate buffer, since it takes too long time even in tasklet softIRQ to process many of isochronous packets, then result in the delay of system event due to disabled IRQ so long. It is avertible to switch to nonatomic operation. Reviewed-by: Takashi Iwai <[email protected]> Tested-by: Edmund Raile <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Sakamoto <[email protected]>
1 parent f62ec13 commit 5c49cc0

File tree

10 files changed

+36
-7
lines changed

10 files changed

+36
-7
lines changed

sound/firewire/amdtp-stream.c

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,22 @@ static void update_pcm_pointers(struct amdtp_stream *s,
615615
// The program in user process should periodically check the status of intermediate
616616
// buffer associated to PCM substream to process PCM frames in the buffer, instead
617617
// of receiving notification of period elapsed by poll wait.
618+
//
619+
// Use another work item for period elapsed event to prevent the following AB/BA
620+
// deadlock:
621+
//
622+
// thread 1 thread 2
623+
// ================================= =================================
624+
// A.work item (process) pcm ioctl (process)
625+
// v v
626+
// process_rx_packets() B.PCM stream lock
627+
// process_tx_packets() v
628+
// v callbacks in snd_pcm_ops
629+
// update_pcm_pointers() v
630+
// snd_pcm_elapsed() fw_iso_context_flush_completions()
631+
// snd_pcm_stream_lock_irqsave() disable_work_sync()
632+
// v v
633+
// wait until release of B wait until A exits
618634
if (!pcm->runtime->no_period_wakeup)
619635
queue_work(system_highpri_wq, &s->period_work);
620636
}
@@ -1055,8 +1071,15 @@ static void generate_rx_packet_descs(struct amdtp_stream *s, struct pkt_desc *de
10551071

10561072
static inline void cancel_stream(struct amdtp_stream *s)
10571073
{
1074+
struct work_struct *work = current_work();
1075+
10581076
s->packet_index = -1;
1059-
if (in_softirq())
1077+
1078+
// Detect work items for any isochronous context. The work item for pcm_period_work()
1079+
// should be avoided since the call of snd_pcm_period_elapsed() can reach via
1080+
// snd_pcm_ops.pointer() under acquiring PCM stream(group) lock and causes dead lock at
1081+
// snd_pcm_stop_xrun().
1082+
if (work && work != &s->period_work)
10601083
amdtp_stream_pcm_abort(s);
10611084
WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN);
10621085
}
@@ -1856,12 +1879,9 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d,
18561879
struct amdtp_stream *irq_target = d->irq_target;
18571880

18581881
if (irq_target && amdtp_stream_running(irq_target)) {
1859-
// use wq to prevent AB/BA deadlock competition for
1860-
// substream lock:
1861-
// fw_iso_context_flush_completions() acquires
1862-
// lock by ohci_flush_iso_completions(),
1863-
// amdtp-stream process_rx_packets() attempts to
1864-
// acquire same lock by snd_pcm_elapsed()
1882+
// The work item to call snd_pcm_period_elapsed() can reach here by the call of
1883+
// snd_pcm_ops.pointer(), however less packets would be available then. Therefore
1884+
// the following call is just for user process contexts.
18651885
if (current_work() != &s->period_work)
18661886
fw_iso_context_flush_completions(irq_target->context);
18671887
}

sound/firewire/bebob/bebob_pcm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
367367
goto end;
368368

369369
pcm->private_data = bebob;
370+
pcm->nonatomic = true;
370371
snprintf(pcm->name, sizeof(pcm->name),
371372
"%s PCM", bebob->card->shortname);
372373
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);

sound/firewire/dice/dice-pcm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ int snd_dice_create_pcm(struct snd_dice *dice)
441441
if (err < 0)
442442
return err;
443443
pcm->private_data = dice;
444+
pcm->nonatomic = true;
444445
strcpy(pcm->name, dice->card->shortname);
445446

446447
if (capture > 0)

sound/firewire/digi00x/digi00x-pcm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
350350
return err;
351351

352352
pcm->private_data = dg00x;
353+
pcm->nonatomic = true;
353354
snprintf(pcm->name, sizeof(pcm->name),
354355
"%s PCM", dg00x->card->shortname);
355356
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);

sound/firewire/fireface/ff-pcm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff)
390390
return err;
391391

392392
pcm->private_data = ff;
393+
pcm->nonatomic = true;
393394
snprintf(pcm->name, sizeof(pcm->name),
394395
"%s PCM", ff->card->shortname);
395396
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);

sound/firewire/fireworks/fireworks_pcm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw)
397397
goto end;
398398

399399
pcm->private_data = efw;
400+
pcm->nonatomic = true;
400401
snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname);
401402
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
402403
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);

sound/firewire/isight.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ static int isight_create_pcm(struct isight *isight)
454454
if (err < 0)
455455
return err;
456456
pcm->private_data = isight;
457+
pcm->nonatomic = true;
457458
strcpy(pcm->name, "iSight");
458459
isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
459460
isight->pcm->ops = &ops;

sound/firewire/motu/motu-pcm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu)
360360
if (err < 0)
361361
return err;
362362
pcm->private_data = motu;
363+
pcm->nonatomic = true;
363364
strcpy(pcm->name, motu->card->shortname);
364365

365366
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);

sound/firewire/oxfw/oxfw-pcm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
440440
return err;
441441

442442
pcm->private_data = oxfw;
443+
pcm->nonatomic = true;
443444
strcpy(pcm->name, oxfw->card->shortname);
444445
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
445446
if (cap > 0)

sound/firewire/tascam/tascam-pcm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
279279
return err;
280280

281281
pcm->private_data = tscm;
282+
pcm->nonatomic = true;
282283
snprintf(pcm->name, sizeof(pcm->name),
283284
"%s PCM", tscm->card->shortname);
284285
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);

0 commit comments

Comments
 (0)