Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 76fb8789 authored by Clemens Ladisch's avatar Clemens Ladisch Committed by Takashi Iwai
Browse files

ALSA: firewire-lib: taskletize the snd_pcm_period_elapsed() call



The following patch might introduce this call chain:
  PCM .pointer callback
  + fw_iso_context_flush_completions
    + packet callback
      + snd_pcm_period_elapsed
        + PCM .pointer callback
Recursive calls to the pointer callback are not possible due to the PCM
group locking, so avoid this by moving the period notification into
a separate tasklet.

Signed-off-by: default avatarClemens Ladisch <clemens@ladisch.de>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 7df4a691
Loading
Loading
Loading
Loading
+28 −1
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@
#define INTERRUPT_INTERVAL	16
#define QUEUE_LENGTH		48

static void pcm_period_tasklet(unsigned long data);

/**
 * amdtp_out_stream_init - initialize an AMDTP output stream structure
 * @s: the AMDTP output stream to initialize
@@ -47,6 +49,7 @@ int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit,
	s->flags = flags;
	s->context = ERR_PTR(-1);
	mutex_init(&s->mutex);
	tasklet_init(&s->period_tasklet, pcm_period_tasklet, (unsigned long)s);
	s->packet_index = 0;

	return 0;
@@ -164,6 +167,20 @@ void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s,
}
EXPORT_SYMBOL(amdtp_out_stream_set_pcm_format);

/**
 * amdtp_out_stream_pcm_prepare - prepare PCM device for running
 * @s: the AMDTP output stream
 *
 * This function should be called from the PCM device's .prepare callback.
 */
void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s)
{
	tasklet_kill(&s->period_tasklet);
	s->pcm_buffer_pointer = 0;
	s->pcm_period_pointer = 0;
}
EXPORT_SYMBOL(amdtp_out_stream_pcm_prepare);

static unsigned int calculate_data_blocks(struct amdtp_out_stream *s)
{
	unsigned int phase, data_blocks;
@@ -376,9 +393,18 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle)
		s->pcm_period_pointer += data_blocks;
		if (s->pcm_period_pointer >= pcm->runtime->period_size) {
			s->pcm_period_pointer -= pcm->runtime->period_size;
			snd_pcm_period_elapsed(pcm);
			tasklet_hi_schedule(&s->period_tasklet);
		}
	}
}

static void pcm_period_tasklet(unsigned long data)
{
	struct amdtp_out_stream *s = (void *)data;
	struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);

	if (pcm)
		snd_pcm_period_elapsed(pcm);
}

static void out_packet_callback(struct fw_iso_context *context, u32 cycle,
@@ -532,6 +558,7 @@ void amdtp_out_stream_stop(struct amdtp_out_stream *s)
		return;
	}

	tasklet_kill(&s->period_tasklet);
	fw_iso_context_stop(s->context);
	fw_iso_context_destroy(s->context);
	s->context = ERR_PTR(-1);
+3 −12
Original line number Diff line number Diff line
#ifndef SOUND_FIREWIRE_AMDTP_H_INCLUDED
#define SOUND_FIREWIRE_AMDTP_H_INCLUDED

#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include "packets-buffer.h"
@@ -55,6 +56,7 @@ struct amdtp_out_stream {
	struct iso_packets_buffer buffer;

	struct snd_pcm_substream *pcm;
	struct tasklet_struct period_tasklet;

	int packet_index;
	unsigned int data_block_counter;
@@ -81,6 +83,7 @@ void amdtp_out_stream_stop(struct amdtp_out_stream *s);

void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s,
				     snd_pcm_format_t format);
void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s);
void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s);

/**
@@ -122,18 +125,6 @@ static inline bool amdtp_out_streaming_error(struct amdtp_out_stream *s)
	return s->packet_index < 0;
}

/**
 * amdtp_out_stream_pcm_prepare - prepare PCM device for running
 * @s: the AMDTP output stream
 *
 * This function should be called from the PCM device's .prepare callback.
 */
static inline void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s)
{
	s->pcm_buffer_pointer = 0;
	s->pcm_period_pointer = 0;
}

/**
 * amdtp_out_stream_pcm_trigger - start/stop playback from a PCM device
 * @s: the AMDTP output stream