All of lore.kernel.org
 help / color / mirror / Atom feed
* [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context
@ 2019-10-18  6:19 Takashi Sakamoto
  2019-10-18  6:19 ` [alsa-devel] [PATCH 1/6] ALSA: firewire-lib: add irq_target member into amdtp_domain struct Takashi Sakamoto
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Takashi Sakamoto @ 2019-10-18  6:19 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel

Hi,

This patchset is a part of my continuous work to improve ALSA IEC
61883-1/6 packet streaming engine for clock-recovery, addressed in
my previous message:
https://mailman.alsa-project.org/pipermail/alsa-devel/2019-August/153388.html

For the clock-recovery, information in the sequence of tx packet from
device should be used to generate the sequence of rx packet to the
device. In current implementation of the engine, the packets are
processed in different tasklet contexts for each IR/IT context.
This is inconvenient to bypass information between these IR/IT contexts.

In this patchset, the engine is improved to process all of IR/IT
contexts in the same domain by a tasklet context for one of IT context.
For convenience, the IT context is called as 'IRQ target'. As a result,
1394 OHCI controller is managed to generate hardware IRQ just for the
IRQ target. All of rx/tx packets are processed in tasklet for the
hardware IRQ.

Takashi Sakamoto (6):
  ALSA: firewire-lib: add irq_target member into amdtp_domain struct
  ALSA: firewire-lib: replace pointer callback to flush isoc contexts in
    AMDTP domain
  ALSA: firewire-lib: replace ack callback to flush isoc contexts in
    AMDTP domain
  ALSA: firewire-lib: cancel flushing isoc context in the laste step to
    process context callback
  ALSA: firewire-lib: handle several AMDTP streams in callback handler
    of IRQ target
  ALSA: firewire-lib: postpone to start IR context

 sound/firewire/amdtp-stream.c               | 329 +++++++++++++++-----
 sound/firewire/amdtp-stream.h               |  17 +-
 sound/firewire/bebob/bebob_pcm.c            |  18 +-
 sound/firewire/bebob/bebob_stream.c         |  10 +-
 sound/firewire/dice/dice-pcm.c              |   8 +-
 sound/firewire/dice/dice-stream.c           |   2 +-
 sound/firewire/digi00x/digi00x-pcm.c        |   8 +-
 sound/firewire/digi00x/digi00x-stream.c     |   2 +-
 sound/firewire/fireface/ff-pcm.c            |   8 +-
 sound/firewire/fireface/ff-stream.c         |  10 +-
 sound/firewire/fireworks/fireworks_pcm.c    |  10 +-
 sound/firewire/fireworks/fireworks_stream.c |   2 +-
 sound/firewire/motu/motu-pcm.c              |   8 +-
 sound/firewire/motu/motu-stream.c           |   2 +-
 sound/firewire/oxfw/oxfw-pcm.c              |   8 +-
 sound/firewire/oxfw/oxfw-stream.c           |   2 +-
 sound/firewire/tascam/tascam-pcm.c          |   8 +-
 sound/firewire/tascam/tascam-stream.c       |   2 +-
 18 files changed, 325 insertions(+), 129 deletions(-)

-- 
2.20.1

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [alsa-devel] [PATCH 1/6] ALSA: firewire-lib: add irq_target member into amdtp_domain struct
  2019-10-18  6:19 [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context Takashi Sakamoto
@ 2019-10-18  6:19 ` Takashi Sakamoto
  2019-10-18  6:19 ` [alsa-devel] [PATCH 2/6] ALSA: firewire-lib: replace pointer callback to flush isoc contexts in AMDTP domain Takashi Sakamoto
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Takashi Sakamoto @ 2019-10-18  6:19 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel

This commit is a preparation to handle several IR/IT contexts in the same
domain by tasklet context for one of the IT context. Such IT context is
stored to AMDTP domain structure as 'irq_target'.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/amdtp-stream.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h
index 344818e936df..f92397a2f35f 100644
--- a/sound/firewire/amdtp-stream.h
+++ b/sound/firewire/amdtp-stream.h
@@ -279,6 +279,8 @@ struct amdtp_domain {
 
 	unsigned int events_per_period;
 	unsigned int events_per_buffer;
+
+	struct amdtp_stream *irq_target;
 };
 
 int amdtp_domain_init(struct amdtp_domain *d);
-- 
2.20.1

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [alsa-devel] [PATCH 2/6] ALSA: firewire-lib: replace pointer callback to flush isoc contexts in AMDTP domain
  2019-10-18  6:19 [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context Takashi Sakamoto
  2019-10-18  6:19 ` [alsa-devel] [PATCH 1/6] ALSA: firewire-lib: add irq_target member into amdtp_domain struct Takashi Sakamoto
@ 2019-10-18  6:19 ` Takashi Sakamoto
  2019-10-18  6:19 ` [alsa-devel] [PATCH 3/6] ALSA: firewire-lib: replace ack " Takashi Sakamoto
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Takashi Sakamoto @ 2019-10-18  6:19 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel

An isoc context for AMDTP stream is flushed to queue packet
by a call of pcm.pointer. This commit extends this for AMDTP
domain.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/amdtp-stream.c            | 51 ++++++++++++++----------
 sound/firewire/amdtp-stream.h            |  3 +-
 sound/firewire/bebob/bebob_pcm.c         | 14 ++++---
 sound/firewire/dice/dice-pcm.c           |  4 +-
 sound/firewire/digi00x/digi00x-pcm.c     |  4 +-
 sound/firewire/fireface/ff-pcm.c         |  4 +-
 sound/firewire/fireworks/fireworks_pcm.c |  6 ++-
 sound/firewire/motu/motu-pcm.c           |  4 +-
 sound/firewire/oxfw/oxfw-pcm.c           |  4 +-
 sound/firewire/tascam/tascam-pcm.c       |  4 +-
 10 files changed, 56 insertions(+), 42 deletions(-)

diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index 7486eec4d958..23677b805b05 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -1099,35 +1099,44 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
 }
 
 /**
- * amdtp_stream_pcm_pointer - get the PCM buffer position
+ * amdtp_domain_stream_pcm_pointer - get the PCM buffer position
+ * @d: the AMDTP domain.
  * @s: the AMDTP stream that transports the PCM data
  *
  * Returns the current buffer position, in frames.
  */
-unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s)
+unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d,
+					      struct amdtp_stream *s)
 {
-	/*
-	 * This function is called in software IRQ context of period_tasklet or
-	 * process context.
-	 *
-	 * When the software IRQ context was scheduled by software IRQ context
-	 * of IR/IT contexts, queued packets were already handled. Therefore,
-	 * no need to flush the queue in buffer anymore.
-	 *
-	 * When the process context reach here, some packets will be already
-	 * queued in the buffer. These packets should be handled immediately
-	 * to keep better granularity of PCM pointer.
-	 *
-	 * Later, the process context will sometimes schedules software IRQ
-	 * context of the period_tasklet. Then, no need to flush the queue by
-	 * the same reason as described for IR/IT contexts.
-	 */
-	if (!in_interrupt() && amdtp_stream_running(s))
-		fw_iso_context_flush_completions(s->context);
+	struct amdtp_stream *irq_target = d->irq_target;
+
+	if (irq_target && amdtp_stream_running(irq_target)) {
+		// This function is called in software IRQ context of
+		// period_tasklet or process context.
+		//
+		// When the software IRQ context was scheduled by software IRQ
+		// context of IT contexts, queued packets were already handled.
+		// Therefore, no need to flush the queue in buffer furthermore.
+		//
+		// When the process context reach here, some packets will be
+		// already queued in the buffer. These packets should be handled
+		// immediately to keep better granularity of PCM pointer.
+		//
+		// Later, the process context will sometimes schedules software
+		// IRQ context of the period_tasklet. Then, no need to flush the
+		// queue by the same reason as described in the above
+		if (!in_interrupt()) {
+			// Queued packet should be processed without any kernel
+			// preemption to keep latency against bus cycle.
+			preempt_disable();
+			fw_iso_context_flush_completions(irq_target->context);
+			preempt_enable();
+		}
+	}
 
 	return READ_ONCE(s->pcm_buffer_pointer);
 }
-EXPORT_SYMBOL(amdtp_stream_pcm_pointer);
+EXPORT_SYMBOL_GPL(amdtp_domain_stream_pcm_pointer);
 
 /**
  * amdtp_stream_pcm_ack - acknowledge queued PCM frames
diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h
index f92397a2f35f..ba0bbeddfdcb 100644
--- a/sound/firewire/amdtp-stream.h
+++ b/sound/firewire/amdtp-stream.h
@@ -198,7 +198,6 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
 					struct snd_pcm_runtime *runtime);
 
 void amdtp_stream_pcm_prepare(struct amdtp_stream *s);
-unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s);
 int amdtp_stream_pcm_ack(struct amdtp_stream *s);
 void amdtp_stream_pcm_abort(struct amdtp_stream *s);
 
@@ -302,4 +301,6 @@ static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d,
 	return 0;
 }
 
+unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d,
+					      struct amdtp_stream *s);
 #endif
diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c
index 8b2e0ceffe82..dc15ea8d0dc5 100644
--- a/sound/firewire/bebob/bebob_pcm.c
+++ b/sound/firewire/bebob/bebob_pcm.c
@@ -313,17 +313,19 @@ pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 	return 0;
 }
 
-static snd_pcm_uframes_t
-pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
+static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
 {
 	struct snd_bebob *bebob = sbstrm->private_data;
-	return amdtp_stream_pcm_pointer(&bebob->tx_stream);
+
+	return amdtp_domain_stream_pcm_pointer(&bebob->domain,
+					       &bebob->tx_stream);
 }
-static snd_pcm_uframes_t
-pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
+static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
 {
 	struct snd_bebob *bebob = sbstrm->private_data;
-	return amdtp_stream_pcm_pointer(&bebob->rx_stream);
+
+	return amdtp_domain_stream_pcm_pointer(&bebob->domain,
+					       &bebob->rx_stream);
 }
 
 static int pcm_capture_ack(struct snd_pcm_substream *substream)
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c
index 7c0c34c5bd47..81b78e7d181d 100644
--- a/sound/firewire/dice/dice-pcm.c
+++ b/sound/firewire/dice/dice-pcm.c
@@ -379,14 +379,14 @@ static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
 	struct snd_dice *dice = substream->private_data;
 	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 
-	return amdtp_stream_pcm_pointer(stream);
+	return amdtp_domain_stream_pcm_pointer(&dice->domain, stream);
 }
 static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_dice *dice = substream->private_data;
 	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 
-	return amdtp_stream_pcm_pointer(stream);
+	return amdtp_domain_stream_pcm_pointer(&dice->domain, stream);
 }
 
 static int capture_ack(struct snd_pcm_substream *substream)
diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c
index c9a833dff20d..f6a2053d5f10 100644
--- a/sound/firewire/digi00x/digi00x-pcm.c
+++ b/sound/firewire/digi00x/digi00x-pcm.c
@@ -301,14 +301,14 @@ static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
 {
 	struct snd_dg00x *dg00x = sbstrm->private_data;
 
-	return amdtp_stream_pcm_pointer(&dg00x->tx_stream);
+	return amdtp_domain_stream_pcm_pointer(&dg00x->domain, &dg00x->tx_stream);
 }
 
 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
 {
 	struct snd_dg00x *dg00x = sbstrm->private_data;
 
-	return amdtp_stream_pcm_pointer(&dg00x->rx_stream);
+	return amdtp_domain_stream_pcm_pointer(&dg00x->domain, &dg00x->rx_stream);
 }
 
 static int pcm_capture_ack(struct snd_pcm_substream *substream)
diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c
index 005d959f8651..5af1dce90921 100644
--- a/sound/firewire/fireface/ff-pcm.c
+++ b/sound/firewire/fireface/ff-pcm.c
@@ -341,14 +341,14 @@ static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
 {
 	struct snd_ff *ff = sbstrm->private_data;
 
-	return amdtp_stream_pcm_pointer(&ff->tx_stream);
+	return amdtp_domain_stream_pcm_pointer(&ff->domain, &ff->tx_stream);
 }
 
 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
 {
 	struct snd_ff *ff = sbstrm->private_data;
 
-	return amdtp_stream_pcm_pointer(&ff->rx_stream);
+	return amdtp_domain_stream_pcm_pointer(&ff->domain, &ff->rx_stream);
 }
 
 static int pcm_capture_ack(struct snd_pcm_substream *substream)
diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c
index abcc53dac8a5..71f5057caa0d 100644
--- a/sound/firewire/fireworks/fireworks_pcm.c
+++ b/sound/firewire/fireworks/fireworks_pcm.c
@@ -348,12 +348,14 @@ static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
 {
 	struct snd_efw *efw = sbstrm->private_data;
-	return amdtp_stream_pcm_pointer(&efw->tx_stream);
+
+	return amdtp_domain_stream_pcm_pointer(&efw->domain, &efw->tx_stream);
 }
 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
 {
 	struct snd_efw *efw = sbstrm->private_data;
-	return amdtp_stream_pcm_pointer(&efw->rx_stream);
+
+	return amdtp_domain_stream_pcm_pointer(&efw->domain, &efw->rx_stream);
 }
 
 static int pcm_capture_ack(struct snd_pcm_substream *substream)
diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c
index 00e693da0cad..13e2577c2a07 100644
--- a/sound/firewire/motu/motu-pcm.c
+++ b/sound/firewire/motu/motu-pcm.c
@@ -320,13 +320,13 @@ static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_motu *motu = substream->private_data;
 
-	return amdtp_stream_pcm_pointer(&motu->tx_stream);
+	return amdtp_domain_stream_pcm_pointer(&motu->domain, &motu->tx_stream);
 }
 static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_motu *motu = substream->private_data;
 
-	return amdtp_stream_pcm_pointer(&motu->rx_stream);
+	return amdtp_domain_stream_pcm_pointer(&motu->domain, &motu->rx_stream);
 }
 
 static int capture_ack(struct snd_pcm_substream *substream)
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c
index ba586d1ac91d..3be35dfcf270 100644
--- a/sound/firewire/oxfw/oxfw-pcm.c
+++ b/sound/firewire/oxfw/oxfw-pcm.c
@@ -393,13 +393,13 @@ static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstm)
 {
 	struct snd_oxfw *oxfw = sbstm->private_data;
 
-	return amdtp_stream_pcm_pointer(&oxfw->tx_stream);
+	return amdtp_domain_stream_pcm_pointer(&oxfw->domain, &oxfw->tx_stream);
 }
 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstm)
 {
 	struct snd_oxfw *oxfw = sbstm->private_data;
 
-	return amdtp_stream_pcm_pointer(&oxfw->rx_stream);
+	return amdtp_domain_stream_pcm_pointer(&oxfw->domain, &oxfw->rx_stream);
 }
 
 static int pcm_capture_ack(struct snd_pcm_substream *substream)
diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c
index b18664fdf955..1f66c8be7528 100644
--- a/sound/firewire/tascam/tascam-pcm.c
+++ b/sound/firewire/tascam/tascam-pcm.c
@@ -230,14 +230,14 @@ static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
 {
 	struct snd_tscm *tscm = sbstrm->private_data;
 
-	return amdtp_stream_pcm_pointer(&tscm->tx_stream);
+	return amdtp_domain_stream_pcm_pointer(&tscm->domain, &tscm->tx_stream);
 }
 
 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
 {
 	struct snd_tscm *tscm = sbstrm->private_data;
 
-	return amdtp_stream_pcm_pointer(&tscm->rx_stream);
+	return amdtp_domain_stream_pcm_pointer(&tscm->domain, &tscm->rx_stream);
 }
 
 static int pcm_capture_ack(struct snd_pcm_substream *substream)
-- 
2.20.1

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [alsa-devel] [PATCH 3/6] ALSA: firewire-lib: replace ack callback to flush isoc contexts in AMDTP domain
  2019-10-18  6:19 [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context Takashi Sakamoto
  2019-10-18  6:19 ` [alsa-devel] [PATCH 1/6] ALSA: firewire-lib: add irq_target member into amdtp_domain struct Takashi Sakamoto
  2019-10-18  6:19 ` [alsa-devel] [PATCH 2/6] ALSA: firewire-lib: replace pointer callback to flush isoc contexts in AMDTP domain Takashi Sakamoto
@ 2019-10-18  6:19 ` Takashi Sakamoto
  2019-10-18  6:19 ` [alsa-devel] [PATCH 4/6] ALSA: firewire-lib: cancel flushing isoc context in the laste step to process context callback Takashi Sakamoto
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Takashi Sakamoto @ 2019-10-18  6:19 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel

An isoc context for AMDTP stream is flushed to queue packet
by a call of pcm.ack. This commit extends this for AMDTP
domain.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/amdtp-stream.c            | 24 +++++++++++++++---------
 sound/firewire/amdtp-stream.h            |  3 ++-
 sound/firewire/bebob/bebob_pcm.c         |  4 ++--
 sound/firewire/dice/dice-pcm.c           |  4 ++--
 sound/firewire/digi00x/digi00x-pcm.c     |  4 ++--
 sound/firewire/fireface/ff-pcm.c         |  4 ++--
 sound/firewire/fireworks/fireworks_pcm.c |  4 ++--
 sound/firewire/motu/motu-pcm.c           |  4 ++--
 sound/firewire/oxfw/oxfw-pcm.c           |  4 ++--
 sound/firewire/tascam/tascam-pcm.c       |  4 ++--
 10 files changed, 33 insertions(+), 26 deletions(-)

diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index 23677b805b05..3d27d4ce2b45 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -1139,23 +1139,29 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d,
 EXPORT_SYMBOL_GPL(amdtp_domain_stream_pcm_pointer);
 
 /**
- * amdtp_stream_pcm_ack - acknowledge queued PCM frames
+ * amdtp_domain_stream_pcm_ack - acknowledge queued PCM frames
+ * @d: the AMDTP domain.
  * @s: the AMDTP stream that transfers the PCM frames
  *
  * Returns zero always.
  */
-int amdtp_stream_pcm_ack(struct amdtp_stream *s)
+int amdtp_domain_stream_pcm_ack(struct amdtp_domain *d, struct amdtp_stream *s)
 {
-	/*
-	 * Process isochronous packets for recent isochronous cycle to handle
-	 * queued PCM frames.
-	 */
-	if (amdtp_stream_running(s))
-		fw_iso_context_flush_completions(s->context);
+	struct amdtp_stream *irq_target = d->irq_target;
+
+	// Process isochronous packets for recent isochronous cycle to handle
+	// queued PCM frames.
+	if (irq_target && amdtp_stream_running(irq_target)) {
+		// Queued packet should be processed without any kernel
+		// preemption to keep latency against bus cycle.
+		preempt_disable();
+		fw_iso_context_flush_completions(irq_target->context);
+		preempt_enable();
+	}
 
 	return 0;
 }
-EXPORT_SYMBOL(amdtp_stream_pcm_ack);
+EXPORT_SYMBOL_GPL(amdtp_domain_stream_pcm_ack);
 
 /**
  * amdtp_stream_update - update the stream after a bus reset
diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h
index ba0bbeddfdcb..470e77ca0061 100644
--- a/sound/firewire/amdtp-stream.h
+++ b/sound/firewire/amdtp-stream.h
@@ -198,7 +198,6 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
 					struct snd_pcm_runtime *runtime);
 
 void amdtp_stream_pcm_prepare(struct amdtp_stream *s);
-int amdtp_stream_pcm_ack(struct amdtp_stream *s);
 void amdtp_stream_pcm_abort(struct amdtp_stream *s);
 
 extern const unsigned int amdtp_syt_intervals[CIP_SFC_COUNT];
@@ -303,4 +302,6 @@ static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d,
 
 unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d,
 					      struct amdtp_stream *s);
+int amdtp_domain_stream_pcm_ack(struct amdtp_domain *d, struct amdtp_stream *s);
+
 #endif
diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c
index dc15ea8d0dc5..1b100159f4c5 100644
--- a/sound/firewire/bebob/bebob_pcm.c
+++ b/sound/firewire/bebob/bebob_pcm.c
@@ -332,14 +332,14 @@ static int pcm_capture_ack(struct snd_pcm_substream *substream)
 {
 	struct snd_bebob *bebob = substream->private_data;
 
-	return amdtp_stream_pcm_ack(&bebob->tx_stream);
+	return amdtp_domain_stream_pcm_ack(&bebob->domain, &bebob->tx_stream);
 }
 
 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 {
 	struct snd_bebob *bebob = substream->private_data;
 
-	return amdtp_stream_pcm_ack(&bebob->rx_stream);
+	return amdtp_domain_stream_pcm_ack(&bebob->domain, &bebob->rx_stream);
 }
 
 int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c
index 81b78e7d181d..f1848fb39bd0 100644
--- a/sound/firewire/dice/dice-pcm.c
+++ b/sound/firewire/dice/dice-pcm.c
@@ -394,7 +394,7 @@ static int capture_ack(struct snd_pcm_substream *substream)
 	struct snd_dice *dice = substream->private_data;
 	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 
-	return amdtp_stream_pcm_ack(stream);
+	return amdtp_domain_stream_pcm_ack(&dice->domain, stream);
 }
 
 static int playback_ack(struct snd_pcm_substream *substream)
@@ -402,7 +402,7 @@ static int playback_ack(struct snd_pcm_substream *substream)
 	struct snd_dice *dice = substream->private_data;
 	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 
-	return amdtp_stream_pcm_ack(stream);
+	return amdtp_domain_stream_pcm_ack(&dice->domain, stream);
 }
 
 int snd_dice_create_pcm(struct snd_dice *dice)
diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c
index f6a2053d5f10..8befc5d2ef22 100644
--- a/sound/firewire/digi00x/digi00x-pcm.c
+++ b/sound/firewire/digi00x/digi00x-pcm.c
@@ -315,14 +315,14 @@ static int pcm_capture_ack(struct snd_pcm_substream *substream)
 {
 	struct snd_dg00x *dg00x = substream->private_data;
 
-	return amdtp_stream_pcm_ack(&dg00x->tx_stream);
+	return amdtp_domain_stream_pcm_ack(&dg00x->domain, &dg00x->tx_stream);
 }
 
 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 {
 	struct snd_dg00x *dg00x = substream->private_data;
 
-	return amdtp_stream_pcm_ack(&dg00x->rx_stream);
+	return amdtp_domain_stream_pcm_ack(&dg00x->domain, &dg00x->rx_stream);
 }
 
 int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c
index 5af1dce90921..c29f87a65c0f 100644
--- a/sound/firewire/fireface/ff-pcm.c
+++ b/sound/firewire/fireface/ff-pcm.c
@@ -355,14 +355,14 @@ static int pcm_capture_ack(struct snd_pcm_substream *substream)
 {
 	struct snd_ff *ff = substream->private_data;
 
-	return amdtp_stream_pcm_ack(&ff->tx_stream);
+	return amdtp_domain_stream_pcm_ack(&ff->domain, &ff->tx_stream);
 }
 
 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 {
 	struct snd_ff *ff = substream->private_data;
 
-	return amdtp_stream_pcm_ack(&ff->rx_stream);
+	return amdtp_domain_stream_pcm_ack(&ff->domain, &ff->rx_stream);
 }
 
 int snd_ff_create_pcm_devices(struct snd_ff *ff)
diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c
index 71f5057caa0d..64c1bcf28dfa 100644
--- a/sound/firewire/fireworks/fireworks_pcm.c
+++ b/sound/firewire/fireworks/fireworks_pcm.c
@@ -362,14 +362,14 @@ static int pcm_capture_ack(struct snd_pcm_substream *substream)
 {
 	struct snd_efw *efw = substream->private_data;
 
-	return amdtp_stream_pcm_ack(&efw->tx_stream);
+	return amdtp_domain_stream_pcm_ack(&efw->domain, &efw->tx_stream);
 }
 
 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 {
 	struct snd_efw *efw = substream->private_data;
 
-	return amdtp_stream_pcm_ack(&efw->rx_stream);
+	return amdtp_domain_stream_pcm_ack(&efw->domain, &efw->rx_stream);
 }
 
 int snd_efw_create_pcm_devices(struct snd_efw *efw)
diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c
index 13e2577c2a07..55d3d6661731 100644
--- a/sound/firewire/motu/motu-pcm.c
+++ b/sound/firewire/motu/motu-pcm.c
@@ -333,14 +333,14 @@ static int capture_ack(struct snd_pcm_substream *substream)
 {
 	struct snd_motu *motu = substream->private_data;
 
-	return amdtp_stream_pcm_ack(&motu->tx_stream);
+	return amdtp_domain_stream_pcm_ack(&motu->domain, &motu->tx_stream);
 }
 
 static int playback_ack(struct snd_pcm_substream *substream)
 {
 	struct snd_motu *motu = substream->private_data;
 
-	return amdtp_stream_pcm_ack(&motu->rx_stream);
+	return amdtp_domain_stream_pcm_ack(&motu->domain, &motu->rx_stream);
 }
 
 int snd_motu_create_pcm_devices(struct snd_motu *motu)
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c
index 3be35dfcf270..74bd1811cec2 100644
--- a/sound/firewire/oxfw/oxfw-pcm.c
+++ b/sound/firewire/oxfw/oxfw-pcm.c
@@ -406,14 +406,14 @@ static int pcm_capture_ack(struct snd_pcm_substream *substream)
 {
 	struct snd_oxfw *oxfw = substream->private_data;
 
-	return amdtp_stream_pcm_ack(&oxfw->tx_stream);
+	return amdtp_domain_stream_pcm_ack(&oxfw->domain, &oxfw->tx_stream);
 }
 
 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 {
 	struct snd_oxfw *oxfw = substream->private_data;
 
-	return amdtp_stream_pcm_ack(&oxfw->rx_stream);
+	return amdtp_domain_stream_pcm_ack(&oxfw->domain, &oxfw->rx_stream);
 }
 
 int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c
index 1f66c8be7528..cd45f20ba515 100644
--- a/sound/firewire/tascam/tascam-pcm.c
+++ b/sound/firewire/tascam/tascam-pcm.c
@@ -244,14 +244,14 @@ static int pcm_capture_ack(struct snd_pcm_substream *substream)
 {
 	struct snd_tscm *tscm = substream->private_data;
 
-	return amdtp_stream_pcm_ack(&tscm->tx_stream);
+	return amdtp_domain_stream_pcm_ack(&tscm->domain, &tscm->tx_stream);
 }
 
 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 {
 	struct snd_tscm *tscm = substream->private_data;
 
-	return amdtp_stream_pcm_ack(&tscm->rx_stream);
+	return amdtp_domain_stream_pcm_ack(&tscm->domain, &tscm->rx_stream);
 }
 
 int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
-- 
2.20.1

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [alsa-devel] [PATCH 4/6] ALSA: firewire-lib: cancel flushing isoc context in the laste step to process context callback
  2019-10-18  6:19 [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context Takashi Sakamoto
                   ` (2 preceding siblings ...)
  2019-10-18  6:19 ` [alsa-devel] [PATCH 3/6] ALSA: firewire-lib: replace ack " Takashi Sakamoto
@ 2019-10-18  6:19 ` Takashi Sakamoto
  2019-10-18  6:19 ` [alsa-devel] [PATCH 5/6] ALSA: firewire-lib: handle several AMDTP streams in callback handler of IRQ target Takashi Sakamoto
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Takashi Sakamoto @ 2019-10-18  6:19 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel

The aim of AMDTP domain is to process several isoc context in the same
time. However, current implementation is against this idea because it
flushes each isoc context in the end of processing context callback.

This commit cancels it.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/amdtp-stream.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index 3d27d4ce2b45..36c3f1f9dbff 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -842,8 +842,6 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
 	}
 
 	s->event_count = event_count;
-
-	fw_iso_context_queue_flush(s->context);
 }
 
 static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
@@ -897,8 +895,6 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
 	}
 
 	s->event_count = event_count;
-
-	fw_iso_context_queue_flush(s->context);
 }
 
 /* this is executed one time */
-- 
2.20.1

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [alsa-devel] [PATCH 5/6] ALSA: firewire-lib: handle several AMDTP streams in callback handler of IRQ target
  2019-10-18  6:19 [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context Takashi Sakamoto
                   ` (3 preceding siblings ...)
  2019-10-18  6:19 ` [alsa-devel] [PATCH 4/6] ALSA: firewire-lib: cancel flushing isoc context in the laste step to process context callback Takashi Sakamoto
@ 2019-10-18  6:19 ` Takashi Sakamoto
  2019-10-18  6:19 ` [alsa-devel] [PATCH 6/6] ALSA: firewire-lib: postpone to start IR context Takashi Sakamoto
  2019-10-19  7:22 ` [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context Takashi Iwai
  6 siblings, 0 replies; 10+ messages in thread
From: Takashi Sakamoto @ 2019-10-18  6:19 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel

This commit changes AMDTP domain to run on an IT context of 1394 OHCI as
IRQ target. No hardware interrupt is scheduled for the other isoc
contexts. All of the isoc context are processed in a callback for an isoc
context of IRQ target.

The IRQ target is automatically selected from a list of AMDTP streams,
thus users of AMDTP domain should add an AMDTP stream for IT context
at least.

The reason to select IT context as IRQ target is that the IT context
runs on local 1394 OHCI controller and it can be used as reliable,
constant IRQ generator. On the other hand, IR context can include skip
cycle according to isoc packet transferred by device.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/amdtp-stream.c | 179 ++++++++++++++++++++++++++--------
 sound/firewire/amdtp-stream.h |   7 +-
 2 files changed, 140 insertions(+), 46 deletions(-)

diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index 36c3f1f9dbff..48be31eae9a5 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -482,13 +482,13 @@ static inline int queue_out_packet(struct amdtp_stream *s,
 }
 
 static inline int queue_in_packet(struct amdtp_stream *s,
-				  struct fw_iso_packet *params, bool sched_irq)
+				  struct fw_iso_packet *params)
 {
 	// Queue one packet for IR context.
 	params->header_length = s->ctx_data.tx.ctx_header_size;
 	params->payload_length = s->ctx_data.tx.max_ctx_payload_length;
 	params->skip = false;
-	return queue_packet(s, params, sched_irq);
+	return queue_packet(s, params, false);
 }
 
 static void generate_cip_header(struct amdtp_stream *s, __be32 cip_header[2],
@@ -790,15 +790,24 @@ static void process_ctx_payloads(struct amdtp_stream *s,
 		update_pcm_pointers(s, pcm, pcm_frames);
 }
 
+static void amdtp_stream_master_callback(struct fw_iso_context *context,
+					 u32 tstamp, size_t header_length,
+					 void *header, void *private_data);
+
+static void amdtp_stream_master_first_callback(struct fw_iso_context *context,
+					u32 tstamp, size_t header_length,
+					void *header, void *private_data);
+
 static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
 				size_t header_length, void *header,
 				void *private_data)
 {
 	struct amdtp_stream *s = private_data;
 	const __be32 *ctx_header = header;
-	unsigned int events_per_period = s->events_per_period;
-	unsigned int event_count = s->event_count;
+	unsigned int events_per_period = s->ctx_data.rx.events_per_period;
+	unsigned int event_count = s->ctx_data.rx.event_count;
 	unsigned int packets;
+	bool is_irq_target;
 	int i;
 
 	if (s->packet_index < 0)
@@ -811,6 +820,10 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
 
 	process_ctx_payloads(s, s->pkt_descs, packets);
 
+	is_irq_target =
+		!!(context->callback.sc == amdtp_stream_master_callback ||
+		   context->callback.sc == amdtp_stream_master_first_callback);
+
 	for (i = 0; i < packets; ++i) {
 		const struct pkt_desc *desc = s->pkt_descs + i;
 		unsigned int syt;
@@ -829,10 +842,12 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
 				    desc->data_blocks, desc->data_block_counter,
 				    syt, i);
 
-		event_count += desc->data_blocks;
-		if (event_count >= events_per_period) {
-			event_count -= events_per_period;
-			sched_irq = true;
+		if (is_irq_target) {
+			event_count += desc->data_blocks;
+			if (event_count >= events_per_period) {
+				event_count -= events_per_period;
+				sched_irq = true;
+			}
 		}
 
 		if (queue_out_packet(s, &template.params, sched_irq) < 0) {
@@ -841,7 +856,7 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
 		}
 	}
 
-	s->event_count = event_count;
+	s->ctx_data.rx.event_count = event_count;
 }
 
 static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
@@ -850,8 +865,6 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
 {
 	struct amdtp_stream *s = private_data;
 	__be32 *ctx_header = header;
-	unsigned int events_per_period = s->events_per_period;
-	unsigned int event_count = s->event_count;
 	unsigned int packets;
 	int i;
 	int err;
@@ -873,31 +886,47 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
 	}
 
 	for (i = 0; i < packets; ++i) {
-		const struct pkt_desc *desc = s->pkt_descs + i;
 		struct fw_iso_packet params = {0};
-		bool sched_irq = false;
-
-		if (err >= 0) {
-			event_count += desc->data_blocks;
-			if (event_count >= events_per_period) {
-				event_count -= events_per_period;
-				sched_irq = true;
-			}
-		} else {
-			sched_irq =
-				!((s->packet_index + 1) % s->idle_irq_interval);
-		}
 
-		if (queue_in_packet(s, &params, sched_irq) < 0) {
+		if (queue_in_packet(s, &params) < 0) {
 			cancel_stream(s);
 			return;
 		}
 	}
+}
+
+static void amdtp_stream_master_callback(struct fw_iso_context *context,
+					 u32 tstamp, size_t header_length,
+					 void *header, void *private_data)
+{
+	struct amdtp_domain *d = private_data;
+	struct amdtp_stream *irq_target = d->irq_target;
+	struct amdtp_stream *s;
+
+	out_stream_callback(context, tstamp, header_length, header, irq_target);
+	if (amdtp_streaming_error(irq_target))
+		goto error;
 
-	s->event_count = event_count;
+	list_for_each_entry(s, &d->streams, list) {
+		if (s != irq_target && amdtp_stream_running(s)) {
+			fw_iso_context_flush_completions(s->context);
+			if (amdtp_streaming_error(s))
+				goto error;
+		}
+	}
+
+	return;
+error:
+	if (amdtp_stream_running(irq_target))
+		cancel_stream(irq_target);
+
+	list_for_each_entry(s, &d->streams, list) {
+		if (amdtp_stream_running(s))
+			cancel_stream(s);
+	}
 }
 
-/* this is executed one time */
+// this is executed one time.
 static void amdtp_stream_first_callback(struct fw_iso_context *context,
 					u32 tstamp, size_t header_length,
 					void *header, void *private_data)
@@ -928,18 +957,39 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
 	context->callback.sc(context, tstamp, header_length, header, s);
 }
 
+static void amdtp_stream_master_first_callback(struct fw_iso_context *context,
+					       u32 tstamp, size_t header_length,
+					       void *header, void *private_data)
+{
+	struct amdtp_domain *d = private_data;
+	struct amdtp_stream *s = d->irq_target;
+	const __be32 *ctx_header = header;
+
+	s->callbacked = true;
+	wake_up(&s->callback_wait);
+
+	s->start_cycle = compute_it_cycle(*ctx_header, s->queue_size);
+
+	context->callback.sc = amdtp_stream_master_callback;
+
+	context->callback.sc(context, tstamp, header_length, header, d);
+}
+
 /**
  * amdtp_stream_start - start transferring packets
  * @s: the AMDTP stream to start
  * @channel: the isochronous channel on the bus
  * @speed: firewire speed code
+ * @d: the AMDTP domain to which the AMDTP stream belongs
+ * @is_irq_target: whether isoc context for the AMDTP stream is used to generate
+ *		   hardware IRQ.
  *
  * The stream cannot be started until it has been configured with
  * amdtp_stream_set_parameters() and it must be started before any PCM or MIDI
  * device can be started.
  */
 static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
-			      struct amdtp_domain *d)
+			      struct amdtp_domain *d, bool is_irq_target)
 {
 	static const struct {
 		unsigned int data_block;
@@ -955,10 +1005,13 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
 	};
 	unsigned int events_per_buffer = d->events_per_buffer;
 	unsigned int events_per_period = d->events_per_period;
+	unsigned int idle_irq_interval;
 	unsigned int ctx_header_size;
 	unsigned int max_ctx_payload_size;
 	enum dma_data_direction dir;
 	int type, tag, err;
+	fw_iso_callback_t ctx_cb;
+	void *ctx_data;
 
 	mutex_lock(&s->mutex);
 
@@ -969,6 +1022,12 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
 	}
 
 	if (s->direction == AMDTP_IN_STREAM) {
+		// NOTE: IT context should be used for constant IRQ.
+		if (is_irq_target) {
+			err = -EINVAL;
+			goto err_unlock;
+		}
+
 		s->data_block_counter = UINT_MAX;
 	} else {
 		entry = &initial_state[s->sfc];
@@ -1008,22 +1067,29 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
 	if (events_per_buffer == 0)
 		events_per_buffer = events_per_period * 3;
 
-	s->idle_irq_interval =
-			DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_period,
-				     amdtp_rate_table[s->sfc]);
+	idle_irq_interval = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_period,
+					 amdtp_rate_table[s->sfc]);
 	s->queue_size = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_buffer,
 				     amdtp_rate_table[s->sfc]);
-	s->events_per_period = events_per_period;
-	s->event_count = 0;
 
 	err = iso_packets_buffer_init(&s->buffer, s->unit, s->queue_size,
 				      max_ctx_payload_size, dir);
 	if (err < 0)
 		goto err_unlock;
 
+	if (is_irq_target) {
+		s->ctx_data.rx.events_per_period = events_per_period;
+		s->ctx_data.rx.event_count = 0;
+		ctx_cb = amdtp_stream_master_first_callback;
+		ctx_data = d;
+	} else {
+		ctx_cb = amdtp_stream_first_callback;
+		ctx_data = s;
+	}
+
 	s->context = fw_iso_context_create(fw_parent_device(s->unit)->card,
 					  type, channel, speed, ctx_header_size,
-					  amdtp_stream_first_callback, s);
+					  ctx_cb, ctx_data);
 	if (IS_ERR(s->context)) {
 		err = PTR_ERR(s->context);
 		if (err == -EBUSY)
@@ -1054,14 +1120,20 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
 	s->packet_index = 0;
 	do {
 		struct fw_iso_packet params;
-		bool sched_irq;
 
-		sched_irq = !((s->packet_index + 1) % s->idle_irq_interval);
 		if (s->direction == AMDTP_IN_STREAM) {
-			err = queue_in_packet(s, &params, sched_irq);
+			err = queue_in_packet(s, &params);
 		} else {
+			bool sched_irq = false;
+
 			params.header_length = 0;
 			params.payload_length = 0;
+
+			if (is_irq_target) {
+				sched_irq = !((s->packet_index + 1) %
+					      idle_irq_interval);
+			}
+
 			err = queue_out_packet(s, &params, sched_irq);
 		}
 		if (err < 0)
@@ -1276,17 +1348,33 @@ int amdtp_domain_start(struct amdtp_domain *d)
 	struct amdtp_stream *s;
 	int err = 0;
 
+	// Select an IT context as IRQ target.
 	list_for_each_entry(s, &d->streams, list) {
-		err = amdtp_stream_start(s, s->channel, s->speed, d);
-		if (err < 0)
+		if (s->direction == AMDTP_OUT_STREAM)
 			break;
 	}
+	if (!s)
+		return -ENXIO;
+	d->irq_target = s;
 
-	if (err < 0) {
-		list_for_each_entry(s, &d->streams, list)
-			amdtp_stream_stop(s);
+	list_for_each_entry(s, &d->streams, list) {
+		if (s != d->irq_target) {
+			err = amdtp_stream_start(s, s->channel, s->speed, d,
+						 false);
+			if (err < 0)
+				goto error;
+		}
 	}
 
+	s = d->irq_target;
+	err = amdtp_stream_start(s, s->channel, s->speed, d, true);
+	if (err < 0)
+		goto error;
+
+	return 0;
+error:
+	list_for_each_entry(s, &d->streams, list)
+		amdtp_stream_stop(s);
 	return err;
 }
 EXPORT_SYMBOL_GPL(amdtp_domain_start);
@@ -1299,12 +1387,17 @@ void amdtp_domain_stop(struct amdtp_domain *d)
 {
 	struct amdtp_stream *s, *next;
 
+	if (d->irq_target)
+		amdtp_stream_stop(d->irq_target);
+
 	list_for_each_entry_safe(s, next, &d->streams, list) {
 		list_del(&s->list);
 
-		amdtp_stream_stop(s);
+		if (s != d->irq_target)
+			amdtp_stream_stop(s);
 	}
 
 	d->events_per_period = 0;
+	d->irq_target = NULL;
 }
 EXPORT_SYMBOL_GPL(amdtp_domain_stop);
diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h
index 470e77ca0061..c4bde69c2d4f 100644
--- a/sound/firewire/amdtp-stream.h
+++ b/sound/firewire/amdtp-stream.h
@@ -143,11 +143,12 @@ struct amdtp_stream {
 			// To generate CIP header.
 			unsigned int fdf;
 			int syt_override;
+
+			// To generate constant hardware IRQ.
+			unsigned int event_count;
+			unsigned int events_per_period;
 		} rx;
 	} ctx_data;
-	unsigned int event_count;
-	unsigned int events_per_period;
-	unsigned int idle_irq_interval;
 
 	/* For CIP headers. */
 	unsigned int source_node_id_field;
-- 
2.20.1

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [alsa-devel] [PATCH 6/6] ALSA: firewire-lib: postpone to start IR context
  2019-10-18  6:19 [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context Takashi Sakamoto
                   ` (4 preceding siblings ...)
  2019-10-18  6:19 ` [alsa-devel] [PATCH 5/6] ALSA: firewire-lib: handle several AMDTP streams in callback handler of IRQ target Takashi Sakamoto
@ 2019-10-18  6:19 ` Takashi Sakamoto
  2019-10-19  7:22 ` [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context Takashi Iwai
  6 siblings, 0 replies; 10+ messages in thread
From: Takashi Sakamoto @ 2019-10-18  6:19 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel

Some devices have a quirk to postpone transmission of isoc packet for
several dozen or hundred isoc cycles since configured to transmit.
Furthermore, some devices have a quirk to transmit isoc packet with
discontinued data of its header.

In 1394 OHCI specification, software allows to start isoc context with
certain isoc cycle. Linux firewire subsystem has kernel API to use it
as well.

This commit uses the functionality of 1394 OHCI controller to handle
the quirks. At present, this feature is convenient to ALSA bebob and
fireface driver. As a result, some devices can be safely handled, as
long as I know:
 - MAudio FireWire solo
 - MAudio ProFire Lightbridge
 - MAudio FireWire 410
 - Roland FA-66

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/amdtp-stream.c               | 79 +++++++++++++++++++--
 sound/firewire/amdtp-stream.h               |  2 +-
 sound/firewire/bebob/bebob_stream.c         | 10 ++-
 sound/firewire/dice/dice-stream.c           |  2 +-
 sound/firewire/digi00x/digi00x-stream.c     |  2 +-
 sound/firewire/fireface/ff-stream.c         | 10 ++-
 sound/firewire/fireworks/fireworks_stream.c |  2 +-
 sound/firewire/motu/motu-stream.c           |  2 +-
 sound/firewire/oxfw/oxfw-stream.c           |  2 +-
 sound/firewire/tascam/tascam-stream.c       |  2 +-
 10 files changed, 98 insertions(+), 15 deletions(-)

diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index 48be31eae9a5..37d38efb4c87 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -9,6 +9,7 @@
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/firewire.h>
+#include <linux/firewire-constants.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <sound/pcm.h>
@@ -983,13 +984,16 @@ static void amdtp_stream_master_first_callback(struct fw_iso_context *context,
  * @d: the AMDTP domain to which the AMDTP stream belongs
  * @is_irq_target: whether isoc context for the AMDTP stream is used to generate
  *		   hardware IRQ.
+ * @start_cycle: the isochronous cycle to start the context. Start immediately
+ *		 if negative value is given.
  *
  * The stream cannot be started until it has been configured with
  * amdtp_stream_set_parameters() and it must be started before any PCM or MIDI
  * device can be started.
  */
 static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
-			      struct amdtp_domain *d, bool is_irq_target)
+			      struct amdtp_domain *d, bool is_irq_target,
+			      int start_cycle)
 {
 	static const struct {
 		unsigned int data_block;
@@ -1146,7 +1150,7 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
 		tag |= FW_ISO_CONTEXT_MATCH_TAG0;
 
 	s->callbacked = false;
-	err = fw_iso_context_start(s->context, -1, 0, tag);
+	err = fw_iso_context_start(s->context, start_cycle, 0, tag);
 	if (err < 0)
 		goto err_pkt_descs;
 
@@ -1339,14 +1343,40 @@ int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s,
 }
 EXPORT_SYMBOL_GPL(amdtp_domain_add_stream);
 
+static int get_current_cycle_time(struct fw_card *fw_card, int *cur_cycle)
+{
+	int generation;
+	int rcode;
+	__be32 reg;
+	u32 data;
+
+	// This is a request to local 1394 OHCI controller and expected to
+	// complete without any event waiting.
+	generation = fw_card->generation;
+	smp_rmb();	// node_id vs. generation.
+	rcode = fw_run_transaction(fw_card, TCODE_READ_QUADLET_REQUEST,
+				   fw_card->node_id, generation, SCODE_100,
+				   CSR_REGISTER_BASE + CSR_CYCLE_TIME,
+				   &reg, sizeof(reg));
+	if (rcode != RCODE_COMPLETE)
+		return -EIO;
+
+	data = be32_to_cpu(reg);
+	*cur_cycle = data >> 12;
+
+	return 0;
+}
+
 /**
  * amdtp_domain_start - start sending packets for isoc context in the domain.
  * @d: the AMDTP domain.
+ * @ir_delay_cycle: the cycle delay to start all IR contexts.
  */
-int amdtp_domain_start(struct amdtp_domain *d)
+int amdtp_domain_start(struct amdtp_domain *d, unsigned int ir_delay_cycle)
 {
 	struct amdtp_stream *s;
-	int err = 0;
+	int cycle;
+	int err;
 
 	// Select an IT context as IRQ target.
 	list_for_each_entry(s, &d->streams, list) {
@@ -1357,17 +1387,54 @@ int amdtp_domain_start(struct amdtp_domain *d)
 		return -ENXIO;
 	d->irq_target = s;
 
+	if (ir_delay_cycle > 0) {
+		struct fw_card *fw_card = fw_parent_device(s->unit)->card;
+
+		err = get_current_cycle_time(fw_card, &cycle);
+		if (err < 0)
+			return err;
+
+		// No need to care overflow in cycle field because of enough
+		// width.
+		cycle += ir_delay_cycle;
+
+		// Round up to sec field.
+		if ((cycle & 0x00001fff) >= CYCLES_PER_SECOND) {
+			unsigned int sec;
+
+			// The sec field can overflow.
+			sec = (cycle & 0xffffe000) >> 13;
+			cycle = (++sec << 13) |
+				((cycle & 0x00001fff) / CYCLES_PER_SECOND);
+		}
+
+		// In OHCI 1394 specification, lower 2 bits are available for
+		// sec field.
+		cycle &= 0x00007fff;
+	} else {
+		cycle = -1;
+	}
+
 	list_for_each_entry(s, &d->streams, list) {
+		int cycle_match;
+
+		if (s->direction == AMDTP_IN_STREAM) {
+			cycle_match = cycle;
+		} else {
+			// IT context starts immediately.
+			cycle_match = -1;
+		}
+
 		if (s != d->irq_target) {
 			err = amdtp_stream_start(s, s->channel, s->speed, d,
-						 false);
+						 false, cycle_match);
 			if (err < 0)
 				goto error;
 		}
 	}
 
 	s = d->irq_target;
-	err = amdtp_stream_start(s, s->channel, s->speed, d, true);
+	err = amdtp_stream_start(s, s->channel, s->speed, d, true, -1);
 	if (err < 0)
 		goto error;
 
diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h
index c4bde69c2d4f..f2d44e2dc3c8 100644
--- a/sound/firewire/amdtp-stream.h
+++ b/sound/firewire/amdtp-stream.h
@@ -288,7 +288,7 @@ void amdtp_domain_destroy(struct amdtp_domain *d);
 int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s,
 			    int channel, int speed);
 
-int amdtp_domain_start(struct amdtp_domain *d);
+int amdtp_domain_start(struct amdtp_domain *d, unsigned int ir_delay_cycle);
 void amdtp_domain_stop(struct amdtp_domain *d);
 
 static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d,
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c
index 5e4a61458be2..7ac0d9f495c4 100644
--- a/sound/firewire/bebob/bebob_stream.c
+++ b/sound/firewire/bebob/bebob_stream.c
@@ -658,7 +658,15 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
 		if (err < 0)
 			goto error;
 
-		err = amdtp_domain_start(&bebob->domain);
+		// The device postpones start of transmission mostly for 1 sec
+		// after receives packets firstly. For safe, IR context starts
+		// 1.5 sec (=12000 cycles) later. This is within 2.0 sec
+		// (=CALLBACK_TIMEOUT).
+		// Furthermore, some devices transfer isoc packets with
+		// discontinuous counter in the beginning of packet streaming.
+		// The delay has an effect to avoid detection of this
+		// discontinuity.
+		err = amdtp_domain_start(&bebob->domain, 12000);
 		if (err < 0)
 			goto error;
 
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c
index 0cff346e8052..6a3d60913e10 100644
--- a/sound/firewire/dice/dice-stream.c
+++ b/sound/firewire/dice/dice-stream.c
@@ -462,7 +462,7 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice)
 			goto error;
 		}
 
-		err = amdtp_domain_start(&dice->domain);
+		err = amdtp_domain_start(&dice->domain, 0);
 		if (err < 0)
 			goto error;
 
diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c
index 0c539188ba18..405d6903bfbc 100644
--- a/sound/firewire/digi00x/digi00x-stream.c
+++ b/sound/firewire/digi00x/digi00x-stream.c
@@ -375,7 +375,7 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
 		if (err < 0)
 			goto error;
 
-		err = amdtp_domain_start(&dg00x->domain);
+		err = amdtp_domain_start(&dg00x->domain, 0);
 		if (err < 0)
 			goto error;
 
diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c
index a13754f914e8..63b79c4a5405 100644
--- a/sound/firewire/fireface/ff-stream.c
+++ b/sound/firewire/fireface/ff-stream.c
@@ -184,6 +184,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
 	 */
 	if (!amdtp_stream_running(&ff->rx_stream)) {
 		int spd = fw_parent_device(ff->unit)->max_speed;
+		unsigned int ir_delay_cycle;
 
 		err = ff->spec->protocol->begin_session(ff, rate);
 		if (err < 0)
@@ -199,7 +200,14 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
 		if (err < 0)
 			goto error;
 
-		err = amdtp_domain_start(&ff->domain);
+		// The device postpones start of transmission mostly for several
+		// cycles after receiving packets firstly.
+		if (ff->spec->protocol == &snd_ff_protocol_ff800)
+			ir_delay_cycle = 800;	// = 100 msec
+		else
+			ir_delay_cycle = 16;	// = 2 msec
+
+		err = amdtp_domain_start(&ff->domain, ir_delay_cycle);
 		if (err < 0)
 			goto error;
 
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c
index f35a33d4d4e6..2206af0fef42 100644
--- a/sound/firewire/fireworks/fireworks_stream.c
+++ b/sound/firewire/fireworks/fireworks_stream.c
@@ -272,7 +272,7 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw)
 		if (err < 0)
 			goto error;
 
-		err = amdtp_domain_start(&efw->domain);
+		err = amdtp_domain_start(&efw->domain, 0);
 		if (err < 0)
 			goto error;
 
diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c
index 9975770c9b1f..a17ddceb1bec 100644
--- a/sound/firewire/motu/motu-stream.c
+++ b/sound/firewire/motu/motu-stream.c
@@ -260,7 +260,7 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu)
 		if (err < 0)
 			goto stop_streams;
 
-		err = amdtp_domain_start(&motu->domain);
+		err = amdtp_domain_start(&motu->domain, 0);
 		if (err < 0)
 			goto stop_streams;
 
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c
index 995e9c5bd84b..501a80094bf7 100644
--- a/sound/firewire/oxfw/oxfw-stream.c
+++ b/sound/firewire/oxfw/oxfw-stream.c
@@ -355,7 +355,7 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
 			}
 		}
 
-		err = amdtp_domain_start(&oxfw->domain);
+		err = amdtp_domain_start(&oxfw->domain, 0);
 		if (err < 0)
 			goto error;
 
diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c
index a9b3b7eb6d21..eb07e1decf9b 100644
--- a/sound/firewire/tascam/tascam-stream.c
+++ b/sound/firewire/tascam/tascam-stream.c
@@ -473,7 +473,7 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
 		if (err < 0)
 			goto error;
 
-		err = amdtp_domain_start(&tscm->domain);
+		err = amdtp_domain_start(&tscm->domain, 0);
 		if (err < 0)
 			return err;
 
-- 
2.20.1

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context
  2019-10-18  6:19 [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context Takashi Sakamoto
                   ` (5 preceding siblings ...)
  2019-10-18  6:19 ` [alsa-devel] [PATCH 6/6] ALSA: firewire-lib: postpone to start IR context Takashi Sakamoto
@ 2019-10-19  7:22 ` Takashi Iwai
  2019-10-20  8:37   ` Takashi Sakamoto
  6 siblings, 1 reply; 10+ messages in thread
From: Takashi Iwai @ 2019-10-19  7:22 UTC (permalink / raw)
  To: Takashi Sakamoto; +Cc: alsa-devel, clemens

On Fri, 18 Oct 2019 08:19:05 +0200,
Takashi Sakamoto wrote:
> 
> Hi,
> 
> This patchset is a part of my continuous work to improve ALSA IEC
> 61883-1/6 packet streaming engine for clock-recovery, addressed in
> my previous message:
> https://mailman.alsa-project.org/pipermail/alsa-devel/2019-August/153388.html
> 
> For the clock-recovery, information in the sequence of tx packet from
> device should be used to generate the sequence of rx packet to the
> device. In current implementation of the engine, the packets are
> processed in different tasklet contexts for each IR/IT context.
> This is inconvenient to bypass information between these IR/IT contexts.
> 
> In this patchset, the engine is improved to process all of IR/IT
> contexts in the same domain by a tasklet context for one of IT context.
> For convenience, the IT context is called as 'IRQ target'. As a result,
> 1394 OHCI controller is managed to generate hardware IRQ just for the
> IRQ target. All of rx/tx packets are processed in tasklet for the
> hardware IRQ.
> 
> Takashi Sakamoto (6):
>   ALSA: firewire-lib: add irq_target member into amdtp_domain struct
>   ALSA: firewire-lib: replace pointer callback to flush isoc contexts in
>     AMDTP domain
>   ALSA: firewire-lib: replace ack callback to flush isoc contexts in
>     AMDTP domain
>   ALSA: firewire-lib: cancel flushing isoc context in the laste step to
>     process context callback
>   ALSA: firewire-lib: handle several AMDTP streams in callback handler
>     of IRQ target
>   ALSA: firewire-lib: postpone to start IR context

Applied all patches now.

Although the preempt handling in AMDTP looks a bit suspicious, it
should be OK as long as the code has been tested, so I took as is.


thanks,

Takashi
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context
  2019-10-19  7:22 ` [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context Takashi Iwai
@ 2019-10-20  8:37   ` Takashi Sakamoto
  2019-10-21 14:40     ` Takashi Sakamoto
  0 siblings, 1 reply; 10+ messages in thread
From: Takashi Sakamoto @ 2019-10-20  8:37 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens

On Sat, Oct 19, 2019 at 09:22:16AM +0200, Takashi Iwai wrote:
> On Fri, 18 Oct 2019 08:19:05 +0200,
> Takashi Sakamoto wrote:
> > 
> > Hi,
> > 
> > This patchset is a part of my continuous work to improve ALSA IEC
> > 61883-1/6 packet streaming engine for clock-recovery, addressed in
> > my previous message:
> > https://mailman.alsa-project.org/pipermail/alsa-devel/2019-August/153388.html
> > 
> > For the clock-recovery, information in the sequence of tx packet from
> > device should be used to generate the sequence of rx packet to the
> > device. In current implementation of the engine, the packets are
> > processed in different tasklet contexts for each IR/IT context.
> > This is inconvenient to bypass information between these IR/IT contexts.
> > 
> > In this patchset, the engine is improved to process all of IR/IT
> > contexts in the same domain by a tasklet context for one of IT context.
> > For convenience, the IT context is called as 'IRQ target'. As a result,
> > 1394 OHCI controller is managed to generate hardware IRQ just for the
> > IRQ target. All of rx/tx packets are processed in tasklet for the
> > hardware IRQ.
> > 
> > Takashi Sakamoto (6):
> >   ALSA: firewire-lib: add irq_target member into amdtp_domain struct
> >   ALSA: firewire-lib: replace pointer callback to flush isoc contexts in
> >     AMDTP domain
> >   ALSA: firewire-lib: replace ack callback to flush isoc contexts in
> >     AMDTP domain
> >   ALSA: firewire-lib: cancel flushing isoc context in the laste step to
> >     process context callback
> >   ALSA: firewire-lib: handle several AMDTP streams in callback handler
> >     of IRQ target
> >   ALSA: firewire-lib: postpone to start IR context
> 
> Applied all patches now.
> 
> Although the preempt handling in AMDTP looks a bit suspicious, it
> should be OK as long as the code has been tested, so I took as is.

I can understand your concern but it works well as long as I tested.
In this time I use preemption-disable during processing queued packet in
process context but before I had used irq-disable instead.

I depict a call graph to process isoc packet in process context below:

On pcm.ack() or pcm.pointer() callbacks:
fw_iso_context_flush_completions()
->struct fw_card_driver.flush_iso_completions()
= ohci_flush_iso_completions()
  ->tasklet_disable()
  ->context_tasklet()
    (read registers on 1394 OHCI controller to get info for queued packet)
  ->flush_iso_completions()
    ->struct fw_iso_context.callback.sc()
    = amdtp_master_callback()
      ->out_stream_callback() (for irq-target)
      ->fw_iso_context_flush_completions()
        ->...
          ->out_stream_callback() or in_stream_callback() (for non irq-target)
  ->tasklet_enable()

The tasklet of IT context for irq-target AMDTP stream is temporarily
disabled when flushing isoc packets queued for the context. The tasklet
doesn't run even if it's queued in hw IRQ context. In a point to
processing queued packet for several isoc contexts in the same domain,
I have no concern without any irq-flag handling for local cpu.

1394 OHCI controller still continue isoc cycle during the above call
graph (= 125 usec interval according to 24.576 MHz clock). Actually the
number of queued packets for non-irq-target AMDTP stream can be slightly
different from the number for irq-target AMDTP stream by one or two
packets without any interruption. In a case that any interruption occurs
after processing queued packets for the irq-target stream, it's likely to
process largely different number of queued packets for the rest of AMDTP
streams in the same domain after resumed. It's desirable not to make such
count gap between streams in the same domain and I leave it for my future
work.

In this time the count gap is allowed. I use kernel preemption to avoid
the interruption but to catch hw IRQ from 1394 OHCI controller (and the
other hardware).


In another point, there's a race condition against flushing queued packet
in runtime between several PCM substreams for AMDTP streams in the same
domain. ALSA PCM core executes pcm.pointer and pcm.ack callback under spin
lock of runtime of PCM substream, thus the race is controlled for operations
to single PCM substream. However some PCM substreams are associated to the
same domain via AMDTP streams. At present I never add any solution for this
race.


Thanks

Takashi Sakamoto
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context
  2019-10-20  8:37   ` Takashi Sakamoto
@ 2019-10-21 14:40     ` Takashi Sakamoto
  0 siblings, 0 replies; 10+ messages in thread
From: Takashi Sakamoto @ 2019-10-21 14:40 UTC (permalink / raw)
  To: Takashi Iwai, clemens; +Cc: alsa-devel

Hi,

On Sun, Oct 20, 2019 at 05:37:19PM +0900, Takashi Sakamoto wrote:
> On Sat, Oct 19, 2019 at 09:22:16AM +0200, Takashi Iwai wrote:
> > Although the preempt handling in AMDTP looks a bit suspicious, it
> > should be OK as long as the code has been tested, so I took as is.
> 
> I can understand your concern but it works well as long as I tested.
> In this time I use preemption-disable during processing queued packet in
> process context but before I had used irq-disable instead.
> 
> I depict a call graph to process isoc packet in process context below:
> 
> On pcm.ack() or pcm.pointer() callbacks:
> fw_iso_context_flush_completions()
> ->struct fw_card_driver.flush_iso_completions()
> = ohci_flush_iso_completions()
>   ->tasklet_disable()
>   ->context_tasklet()
>     (read registers on 1394 OHCI controller to get info for queued packet)
>   ->flush_iso_completions()
>     ->struct fw_iso_context.callback.sc()
>     = amdtp_master_callback()
>       ->out_stream_callback() (for irq-target)
>       ->fw_iso_context_flush_completions()
>         ->...
>           ->out_stream_callback() or in_stream_callback() (for non irq-target)
>   ->tasklet_enable()
> 
> The tasklet of IT context for irq-target AMDTP stream is temporarily
> disabled when flushing isoc packets queued for the context. The tasklet
> doesn't run even if it's queued in hw IRQ context. In a point to
> processing queued packet for several isoc contexts in the same domain,
> I have no concern without any irq-flag handling for local cpu.
> 
> 1394 OHCI controller still continue isoc cycle during the above call
> graph (= 125 usec interval according to 24.576 MHz clock). Actually the
> number of queued packets for non-irq-target AMDTP stream can be slightly
> different from the number for irq-target AMDTP stream by one or two
> packets without any interruption. In a case that any interruption occurs
> after processing queued packets for the irq-target stream, it's likely to
> process largely different number of queued packets for the rest of AMDTP
> streams in the same domain after resumed. It's desirable not to make such
> count gap between streams in the same domain and I leave it for my future
> work.
> 
> In this time the count gap is allowed. I use kernel preemption to avoid
> the interruption but to catch hw IRQ from 1394 OHCI controller (and the
> other hardware).
> 
> 
> In another point, there's a race condition against flushing queued packet
> in runtime between several PCM substreams for AMDTP streams in the same
> domain. ALSA PCM core executes pcm.pointer and pcm.ack callback under spin
> lock of runtime of PCM substream, thus the race is controlled for operations
> to single PCM substream. However some PCM substreams are associated to the
> same domain via AMDTP streams. At present I never add any solution for this
> race.

I realize that this race is managed as well, by a call of
test_and_set_bit_lock(). When operations for several PCM substream call
pcm.pointer or pcm.ack simultaneously, one of them can flush queued
packets. I refine the above call graph:

On pcm.ack() or pcm.pointer() callbacks:
fw_iso_context_flush_completions()
->struct fw_card_driver.flush_iso_completions()
= ohci_flush_iso_completions()
  ->tasklet_disable()
  if (!test_and_set_bit_lock())
    ->context_tasklet()
      (read registers on 1394 OHCI controller to get info for queued packet)
    ->flush_iso_completions()
      ->struct fw_iso_context.callback.sc()
      = amdtp_master_callback()
        ->out_stream_callback() (for irq-target)
        ->fw_iso_context_flush_completions()
          ->...
            ->out_stream_callback() or in_stream_callback() (for non irq-target)
    ->clear_bit_unlock()
  ->tasklet_enable()


Regards

Takashi Sakamoto
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-10-21 14:41 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-18  6:19 [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context Takashi Sakamoto
2019-10-18  6:19 ` [alsa-devel] [PATCH 1/6] ALSA: firewire-lib: add irq_target member into amdtp_domain struct Takashi Sakamoto
2019-10-18  6:19 ` [alsa-devel] [PATCH 2/6] ALSA: firewire-lib: replace pointer callback to flush isoc contexts in AMDTP domain Takashi Sakamoto
2019-10-18  6:19 ` [alsa-devel] [PATCH 3/6] ALSA: firewire-lib: replace ack " Takashi Sakamoto
2019-10-18  6:19 ` [alsa-devel] [PATCH 4/6] ALSA: firewire-lib: cancel flushing isoc context in the laste step to process context callback Takashi Sakamoto
2019-10-18  6:19 ` [alsa-devel] [PATCH 5/6] ALSA: firewire-lib: handle several AMDTP streams in callback handler of IRQ target Takashi Sakamoto
2019-10-18  6:19 ` [alsa-devel] [PATCH 6/6] ALSA: firewire-lib: postpone to start IR context Takashi Sakamoto
2019-10-19  7:22 ` [alsa-devel] [PATCH 0/6] ALSA: firewire: handle several IR/IT context in callback of the IT context Takashi Iwai
2019-10-20  8:37   ` Takashi Sakamoto
2019-10-21 14:40     ` Takashi Sakamoto

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.