[PATCH] ALSA: firewire-lib: support NO_PERIOD_WAKEUP in ALSA PCM runtime

Takashi Sakamoto o-takashi at sakamocchi.jp
Thu May 27 14:32:53 CEST 2021


Drivers of ALSA firewire stack can process packets for IT/IR context in
process context when the process operates ALSA PCM character device by
calling ioctl(2) with some requests. The ioctl requests are:

 * SNDRV_PCM_IOCTL_HWSYNC
 * SNDRV_PCM_IOCTL_SYNC_PTR
 * SNDRV_PCM_IOCTL_REWIND
 * SNDRV_PCM_IOCTL_FORWARD
 * SNDRV_PCM_IOCTL_WRITEI_FRAMES
 * SNDRV_PCM_IOCTL_READI_FRAMES
 * SNDRV_PCM_IOCTL_WRITEN_FRAMES
 * SNDRV_PCM_IOCTL_READN_FRAMES

This means that general application can process PCM frames apart from
hardware IRQ invocation, even if they are programmed by either IRQ-based
scheduling model or Timer-based scheduling model.

This commit add support for Timer-based scheduling model by allowing
PCM runtime to suppress both process wakeup per period and scheduling
hardware IRQ.

SNDRV_PCM_INFO_BATCH is obsoleted since ALSA IEC 61883-1/6 packet streaming
engine can report the number of transferred PCM frames within PCM period
boundary. The granularity equals to SYT_INTERVAL in blocking transmission.
In non-blocking transmission, it doesn't equal to SYT_INTERVAL but doesn't
exceed.

This patch is tested with PulseAudio, and --sched-model option of axfer
with fix against the issue reported at:

 * https://lore.kernel.org/alsa-devel/687f9871-7484-1370-04d1-9c968e86f72b@linux.intel.com/#r

Signed-off-by: Takashi Sakamoto <o-takashi at sakamocchi.jp>
---
 sound/firewire/amdtp-stream.c | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index 68ffbc33f692..8e72e7f4c082 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -191,14 +191,13 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
 	unsigned int maximum_usec_per_period;
 	int err;
 
-	hw->info = SNDRV_PCM_INFO_BATCH |
-		   SNDRV_PCM_INFO_BLOCK_TRANSFER |
+	hw->info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
 		   SNDRV_PCM_INFO_INTERLEAVED |
 		   SNDRV_PCM_INFO_JOINT_DUPLEX |
 		   SNDRV_PCM_INFO_MMAP |
-		   SNDRV_PCM_INFO_MMAP_VALID;
+		   SNDRV_PCM_INFO_MMAP_VALID |
+		   SNDRV_PCM_INFO_NO_PERIOD_WAKEUP;
 
-	/* SNDRV_PCM_INFO_BATCH */
 	hw->periods_min = 2;
 	hw->periods_max = UINT_MAX;
 
@@ -503,7 +502,12 @@ static void update_pcm_pointers(struct amdtp_stream *s,
 	s->pcm_period_pointer += frames;
 	if (s->pcm_period_pointer >= pcm->runtime->period_size) {
 		s->pcm_period_pointer -= pcm->runtime->period_size;
-		queue_work(system_highpri_wq, &s->period_work);
+
+		// The program in user process should periodically check the status of intermediate
+		// buffer associated to PCM substream to process PCM frames in the buffer, instead
+		// of receiving notification of period elapsed by poll wait.
+		if (!pcm->runtime->no_period_wakeup)
+			queue_work(system_highpri_wq, &s->period_work);
 	}
 }
 
@@ -949,6 +953,7 @@ static void process_rx_packets(struct fw_iso_context *context, u32 tstamp, size_
 	unsigned int event_count = s->ctx_data.rx.event_count;
 	unsigned int pkt_header_length;
 	unsigned int packets;
+	bool need_hw_irq;
 	int i;
 
 	if (s->packet_index < 0)
@@ -968,6 +973,16 @@ static void process_rx_packets(struct fw_iso_context *context, u32 tstamp, size_
 	else
 		pkt_header_length = 0;
 
+	if (s == d->irq_target) {
+		// At NO_PERIOD_WAKEUP mode, the packets for all IT/IR contexts are processed by
+		// the tasks of user process operating ALSA PCM character device by calling ioctl(2)
+		// with some requests, instead of scheduled hardware IRQ of an IT context.
+		struct snd_pcm_substream *pcm = READ_ONCE(s->pcm);
+		need_hw_irq = !pcm || !pcm->runtime->no_period_wakeup;
+	} else {
+		need_hw_irq = false;
+	}
+
 	for (i = 0; i < packets; ++i) {
 		const struct pkt_desc *desc = s->pkt_descs + i;
 		struct {
@@ -984,7 +999,7 @@ static void process_rx_packets(struct fw_iso_context *context, u32 tstamp, size_
 			event_count += desc->data_blocks;
 			if (event_count >= events_per_period) {
 				event_count -= events_per_period;
-				sched_irq = true;
+				sched_irq = need_hw_irq;
 			}
 		}
 
-- 
2.27.0



More information about the Alsa-devel mailing list