ALSA: firewire-lib: change waking up timing to process packets
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Thu, 20 May 2021 04:01:54 +0000 (13:01 +0900)
committerTakashi Iwai <tiwai@suse.de>
Thu, 20 May 2021 12:01:17 +0000 (14:01 +0200)
When starting AMDTP domain, tasks in process context yields running CPU
till all of isochronous context get callback, with an assumption that
it's OK to process content of packet.

However several isochronous cycles are skipped to transfer rx packets, or
the content of rx packets are dropped, to manage the timing to start
processing the packets.

This commit changes the timing for tasks in process context to wake up
when processing content of packet is actually ready.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20210520040154.80450-9-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/firewire/amdtp-stream.c
sound/firewire/amdtp-stream.h
sound/firewire/bebob/bebob_stream.c
sound/firewire/dice/dice-stream.c
sound/firewire/digi00x/digi00x-stream.c
sound/firewire/fireface/ff-stream.c
sound/firewire/fireworks/fireworks_stream.c
sound/firewire/motu/motu-stream.c
sound/firewire/oxfw/oxfw-stream.c
sound/firewire/tascam/tascam-stream.c

index e9bdb60..a6a7a72 100644 (file)
@@ -107,7 +107,7 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
        INIT_WORK(&s->period_work, pcm_period_work);
        s->packet_index = 0;
 
-       init_waitqueue_head(&s->callback_wait);
+       init_waitqueue_head(&s->ready_wait);
        s->callbacked = false;
 
        s->fmt = fmt;
@@ -1029,6 +1029,9 @@ static void process_rx_packets_intermediately(struct fw_iso_context *context, u3
        }
 
        if (offset < packets) {
+               s->ready_processing = true;
+               wake_up(&s->ready_wait);
+
                process_rx_packets(context, tstamp, header_length, ctx_header, private_data);
                if (amdtp_streaming_error(s))
                        return;
@@ -1145,6 +1148,9 @@ static void process_tx_packets_intermediately(struct fw_iso_context *context, u3
        }
 
        if (offset < packets) {
+               s->ready_processing = true;
+               wake_up(&s->ready_wait);
+
                process_tx_packets(context, tstamp, header_length, ctx_header, s);
                if (amdtp_streaming_error(s))
                        return;
@@ -1286,12 +1292,9 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
        const __be32 *ctx_header = header;
        u32 cycle;
 
-       /*
-        * For in-stream, first packet has come.
-        * For out-stream, prepared to transmit first packet
-        */
+       // For in-stream, first packet has come.
+       // For out-stream, prepared to transmit first packet
        s->callbacked = true;
-       wake_up(&s->callback_wait);
 
        if (s->direction == AMDTP_IN_STREAM) {
                cycle = compute_ohci_cycle_count(ctx_header[1]);
@@ -1464,6 +1467,7 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
                tag |= FW_ISO_CONTEXT_MATCH_TAG0;
 
        s->callbacked = false;
+       s->ready_processing = false;
        err = fw_iso_context_start(s->context, -1, 0, tag);
        if (err < 0)
                goto err_pkt_descs;
index 7725d97..b362a64 100644 (file)
@@ -167,9 +167,11 @@ struct amdtp_stream {
        snd_pcm_uframes_t pcm_buffer_pointer;
        unsigned int pcm_period_pointer;
 
-       /* To wait for first packet. */
-       bool callbacked;
-       wait_queue_head_t callback_wait;
+       // To start processing content of packets at the same cycle in several contexts for
+       // each direction.
+       bool callbacked:1;
+       bool ready_processing:1;
+       wait_queue_head_t ready_wait;
        unsigned int next_cycle;
 
        /* For backends to process data blocks. */
@@ -259,21 +261,6 @@ static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc)
        return sfc & 1;
 }
 
-/**
- * amdtp_stream_wait_callback - sleep till callbacked or timeout
- * @s: the AMDTP stream
- * @timeout: msec till timeout
- *
- * If this function return false, the AMDTP stream should be stopped.
- */
-static inline bool amdtp_stream_wait_callback(struct amdtp_stream *s,
-                                             unsigned int timeout)
-{
-       return wait_event_timeout(s->callback_wait,
-                                 s->callbacked,
-                                 msecs_to_jiffies(timeout)) > 0;
-}
-
 struct seq_desc {
        unsigned int syt_offset;
        unsigned int data_blocks;
@@ -327,4 +314,25 @@ 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);
 
+/**
+ * amdtp_domain_wait_ready - sleep till being ready to process packets or timeout
+ * @d: the AMDTP domain
+ * @timeout_ms: msec till timeout
+ *
+ * If this function return false, the AMDTP domain should be stopped.
+ */
+static inline bool amdtp_domain_wait_ready(struct amdtp_domain *d, unsigned int timeout_ms)
+{
+       struct amdtp_stream *s;
+
+       list_for_each_entry(s, &d->streams, list) {
+               unsigned int j = msecs_to_jiffies(timeout_ms);
+
+               if (wait_event_interruptible_timeout(s->ready_wait, s->ready_processing, j) <= 0)
+                       return false;
+       }
+
+       return true;
+}
+
 #endif
index 8053d02..df76417 100644 (file)
@@ -7,8 +7,7 @@
 
 #include "./bebob.h"
 
-#define CALLBACK_TIMEOUT       2500
-#define FW_ISO_RESOURCE_DELAY  1000
+#define READY_TIMEOUT_MS       2500
 
 /*
  * NOTE;
@@ -679,10 +678,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
 
                // Some devices postpone start of transmission mostly for 1 sec after receives
                // packets firstly.
-               if (!amdtp_stream_wait_callback(&bebob->rx_stream,
-                                               CALLBACK_TIMEOUT) ||
-                   !amdtp_stream_wait_callback(&bebob->tx_stream,
-                                               CALLBACK_TIMEOUT)) {
+               if (!amdtp_domain_wait_ready(&bebob->domain, READY_TIMEOUT_MS)) {
                        err = -ETIMEDOUT;
                        goto error;
                }
index c4dfe76..a9a0fe9 100644 (file)
@@ -8,7 +8,7 @@
 
 #include "dice.h"
 
-#define        CALLBACK_TIMEOUT        200
+#define        READY_TIMEOUT_MS        200
 #define NOTIFICATION_TIMEOUT_MS        (2 * MSEC_PER_SEC)
 
 struct reg_params {
@@ -463,16 +463,9 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice)
                if (err < 0)
                        goto error;
 
-               for (i = 0; i < MAX_STREAMS; i++) {
-                       if ((i < tx_params.count &&
-                           !amdtp_stream_wait_callback(&dice->tx_stream[i],
-                                                       CALLBACK_TIMEOUT)) ||
-                           (i < rx_params.count &&
-                            !amdtp_stream_wait_callback(&dice->rx_stream[i],
-                                                        CALLBACK_TIMEOUT))) {
-                               err = -ETIMEDOUT;
-                               goto error;
-                       }
+               if (!amdtp_domain_wait_ready(&dice->domain, READY_TIMEOUT_MS)) {
+                       err = -ETIMEDOUT;
+                       goto error;
                }
        }
 
index 405d690..f11aaff 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "digi00x.h"
 
-#define CALLBACK_TIMEOUT 500
+#define READY_TIMEOUT_MS       500
 
 const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT] = {
        [SND_DG00X_RATE_44100] = 44100,
@@ -379,10 +379,7 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
                if (err < 0)
                        goto error;
 
-               if (!amdtp_stream_wait_callback(&dg00x->rx_stream,
-                                               CALLBACK_TIMEOUT) ||
-                   !amdtp_stream_wait_callback(&dg00x->tx_stream,
-                                               CALLBACK_TIMEOUT)) {
+               if (!amdtp_domain_wait_ready(&dg00x->domain, READY_TIMEOUT_MS)) {
                        err = -ETIMEDOUT;
                        goto error;
                }
index 5452115..53a21fb 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "ff.h"
 
-#define CALLBACK_TIMEOUT_MS    200
+#define READY_TIMEOUT_MS       200
 
 int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
                                      enum snd_ff_stream_mode *mode)
@@ -203,10 +203,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
                if (err < 0)
                        goto error;
 
-               if (!amdtp_stream_wait_callback(&ff->rx_stream,
-                                               CALLBACK_TIMEOUT_MS) ||
-                   !amdtp_stream_wait_callback(&ff->tx_stream,
-                                               CALLBACK_TIMEOUT_MS)) {
+               if (!amdtp_domain_wait_ready(&ff->domain, READY_TIMEOUT_MS)) {
                        err = -ETIMEDOUT;
                        goto error;
                }
index 2206af0..858cd60 100644 (file)
@@ -6,7 +6,7 @@
  */
 #include "./fireworks.h"
 
-#define CALLBACK_TIMEOUT       100
+#define READY_TIMEOUT_MS       100
 
 static int init_stream(struct snd_efw *efw, struct amdtp_stream *stream)
 {
@@ -276,11 +276,7 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw)
                if (err < 0)
                        goto error;
 
-               // Wait first callback.
-               if (!amdtp_stream_wait_callback(&efw->rx_stream,
-                                               CALLBACK_TIMEOUT) ||
-                   !amdtp_stream_wait_callback(&efw->tx_stream,
-                                               CALLBACK_TIMEOUT)) {
+               if (!amdtp_domain_wait_ready(&efw->domain, READY_TIMEOUT_MS)) {
                        err = -ETIMEDOUT;
                        goto error;
                }
index 2028c54..925241a 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "motu.h"
 
-#define        CALLBACK_TIMEOUT        200
+#define        READY_TIMEOUT_MS        200
 
 #define ISOC_COMM_CONTROL_OFFSET               0x0b00
 #define  ISOC_COMM_CONTROL_MASK                        0xffff0000
@@ -264,10 +264,7 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu)
                if (err < 0)
                        goto stop_streams;
 
-               if (!amdtp_stream_wait_callback(&motu->tx_stream,
-                                               CALLBACK_TIMEOUT) ||
-                   !amdtp_stream_wait_callback(&motu->rx_stream,
-                                               CALLBACK_TIMEOUT)) {
+               if (!amdtp_domain_wait_ready(&motu->domain, READY_TIMEOUT_MS)) {
                        err = -ETIMEDOUT;
                        goto stop_streams;
                }
index e9b6a9f..4121d95 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/delay.h>
 
 #define AVC_GENERIC_FRAME_MAXIMUM_BYTES        512
-#define CALLBACK_TIMEOUT       200
+#define READY_TIMEOUT_MS       200
 
 /*
  * According to datasheet of Oxford Semiconductor:
@@ -358,20 +358,10 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
                if (err < 0)
                        goto error;
 
-               // Wait first packet.
-               if (!amdtp_stream_wait_callback(&oxfw->rx_stream,
-                                               CALLBACK_TIMEOUT)) {
+               if (!amdtp_domain_wait_ready(&oxfw->domain, READY_TIMEOUT_MS)) {
                        err = -ETIMEDOUT;
                        goto error;
                }
-
-               if (oxfw->has_output) {
-                       if (!amdtp_stream_wait_callback(&oxfw->tx_stream,
-                                                       CALLBACK_TIMEOUT)) {
-                               err = -ETIMEDOUT;
-                               goto error;
-                       }
-               }
        }
 
        return 0;
index eb07e1d..296ecf5 100644 (file)
@@ -11,7 +11,7 @@
 #define CLOCK_STATUS_MASK      0xffff0000
 #define CLOCK_CONFIG_MASK      0x0000ffff
 
-#define CALLBACK_TIMEOUT 500
+#define READY_TIMEOUT_MS       500
 
 static int get_clock(struct snd_tscm *tscm, u32 *data)
 {
@@ -477,10 +477,7 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
                if (err < 0)
                        return err;
 
-               if (!amdtp_stream_wait_callback(&tscm->rx_stream,
-                                               CALLBACK_TIMEOUT) ||
-                   !amdtp_stream_wait_callback(&tscm->tx_stream,
-                                               CALLBACK_TIMEOUT)) {
+               if (!amdtp_domain_wait_ready(&tscm->domain, READY_TIMEOUT_MS)) {
                        err = -ETIMEDOUT;
                        goto error;
                }