ALSA: firewire-lib: use variable size of queue for isoc packets instead of fixed...
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Thu, 17 Oct 2019 15:54:13 +0000 (00:54 +0900)
committerTakashi Iwai <tiwai@suse.de>
Fri, 18 Oct 2019 02:35:40 +0000 (04:35 +0200)
The number of packets in packet buffer has been fixed number (=48) since
first commit of ALSA IEC 61883-1/6 packet streaming engine.

This commit allows the engine to use variable number of packets in the
buffer. The size is calculated by a parameter in AMDTP domain structure
surely to store the number of events in the packets of buffer. Although
the value of parameter is expected to come from 'period size' parameter
of PCM substream, at present 48 is still used.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20191017155424.885-2-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 838f695b20de77d38b37c3bcb9a451a6c35e571a..1f38729c8e749026097d2570703bdc02bffb4fba 100644 (file)
@@ -54,7 +54,6 @@
 
 /* TODO: make these configurable */
 #define INTERRUPT_INTERVAL     16
-#define QUEUE_LENGTH           48
 
 // For iso header, tstamp and 2 CIP header.
 #define IR_CTX_HEADER_SIZE_CIP         16
@@ -451,7 +450,7 @@ static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params)
                goto end;
        }
 
-       if (++s->packet_index >= QUEUE_LENGTH)
+       if (++s->packet_index >= s->queue_size)
                s->packet_index = 0;
 end:
        return err;
@@ -669,13 +668,14 @@ static inline u32 increment_cycle_count(u32 cycle, unsigned int addend)
 }
 
 // Align to actual cycle count for the packet which is going to be scheduled.
-// This module queued the same number of isochronous cycle as QUEUE_LENGTH to
-// skip isochronous cycle, therefore it's OK to just increment the cycle by
-// QUEUE_LENGTH for scheduled cycle.
-static inline u32 compute_it_cycle(const __be32 ctx_header_tstamp)
+// This module queued the same number of isochronous cycle as the size of queue
+// to kip isochronous cycle, therefore it's OK to just increment the cycle by
+// the size of queue for scheduled cycle.
+static inline u32 compute_it_cycle(const __be32 ctx_header_tstamp,
+                                  unsigned int queue_size)
 {
        u32 cycle = compute_cycle_count(ctx_header_tstamp);
-       return increment_cycle_count(cycle, QUEUE_LENGTH);
+       return increment_cycle_count(cycle, queue_size);
 }
 
 static int generate_device_pkt_descs(struct amdtp_stream *s,
@@ -689,7 +689,7 @@ static int generate_device_pkt_descs(struct amdtp_stream *s,
 
        for (i = 0; i < packets; ++i) {
                struct pkt_desc *desc = descs + i;
-               unsigned int index = (s->packet_index + i) % QUEUE_LENGTH;
+               unsigned int index = (s->packet_index + i) % s->queue_size;
                unsigned int cycle;
                unsigned int payload_length;
                unsigned int data_blocks;
@@ -730,9 +730,9 @@ static void generate_ideal_pkt_descs(struct amdtp_stream *s,
 
        for (i = 0; i < packets; ++i) {
                struct pkt_desc *desc = descs + i;
-               unsigned int index = (s->packet_index + i) % QUEUE_LENGTH;
+               unsigned int index = (s->packet_index + i) % s->queue_size;
 
-               desc->cycle = compute_it_cycle(*ctx_header);
+               desc->cycle = compute_it_cycle(*ctx_header, s->queue_size);
                desc->syt = calculate_syt(s, desc->cycle);
                desc->data_blocks = calculate_data_blocks(s, desc->syt);
 
@@ -779,12 +779,15 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
 {
        struct amdtp_stream *s = private_data;
        const __be32 *ctx_header = header;
-       unsigned int packets = header_length / sizeof(*ctx_header);
+       unsigned int packets;
        int i;
 
        if (s->packet_index < 0)
                return;
 
+       // Calculate the number of packets in buffer and check XRUN.
+       packets = header_length / sizeof(*ctx_header);
+
        generate_ideal_pkt_descs(s, s->pkt_descs, ctx_header, packets);
 
        process_ctx_payloads(s, s->pkt_descs, packets);
@@ -828,7 +831,7 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
        if (s->packet_index < 0)
                return;
 
-       // The number of packets in buffer.
+       // Calculate the number of packets in buffer and check XRUN.
        packets = header_length / s->ctx_data.tx.ctx_header_size;
 
        err = generate_device_pkt_descs(s, s->pkt_descs, ctx_header, packets);
@@ -874,7 +877,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
 
                context->callback.sc = in_stream_callback;
        } else {
-               cycle = compute_it_cycle(*ctx_header);
+               cycle = compute_it_cycle(*ctx_header, s->queue_size);
 
                context->callback.sc = out_stream_callback;
        }
@@ -894,7 +897,8 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
  * 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)
+static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
+                             struct amdtp_domain *d)
 {
        static const struct {
                unsigned int data_block;
@@ -908,6 +912,7 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
                [CIP_SFC_88200]  = {  0,   67 },
                [CIP_SFC_176400] = {  0,   67 },
        };
+       unsigned int events_per_buffer = d->events_per_buffer;
        unsigned int ctx_header_size;
        unsigned int max_ctx_payload_size;
        enum dma_data_direction dir;
@@ -953,7 +958,13 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
                        max_ctx_payload_size -= IT_PKT_HEADER_SIZE_CIP;
        }
 
-       err = iso_packets_buffer_init(&s->buffer, s->unit, QUEUE_LENGTH,
+       if (events_per_buffer == 0)
+               events_per_buffer = INTERRUPT_INTERVAL * 3;
+
+       s->queue_size = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_buffer,
+                                    amdtp_rate_table[s->sfc]);
+
+       err = iso_packets_buffer_init(&s->buffer, s->unit, s->queue_size,
                                      max_ctx_payload_size, dir);
        if (err < 0)
                goto err_unlock;
@@ -981,7 +992,7 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
        else
                s->tag = TAG_CIP;
 
-       s->pkt_descs = kcalloc(INTERRUPT_INTERVAL, sizeof(*s->pkt_descs),
+       s->pkt_descs = kcalloc(s->queue_size, sizeof(*s->pkt_descs),
                               GFP_KERNEL);
        if (!s->pkt_descs) {
                err = -ENOMEM;
@@ -1196,7 +1207,7 @@ int amdtp_domain_start(struct amdtp_domain *d)
        int err = 0;
 
        list_for_each_entry(s, &d->streams, list) {
-               err = amdtp_stream_start(s, s->channel, s->speed);
+               err = amdtp_stream_start(s, s->channel, s->speed, d);
                if (err < 0)
                        break;
        }
index d95a4ed15f20d5bc24e362b0bd0931ef72c424a3..8d541727e43759b063ab50a93fe6a0b9e20e86c0 100644 (file)
@@ -117,6 +117,7 @@ struct amdtp_stream {
        /* For packet processing. */
        struct fw_iso_context *context;
        struct iso_packets_buffer buffer;
+       unsigned int queue_size;
        int packet_index;
        struct pkt_desc *pkt_descs;
        int tag;
@@ -274,6 +275,7 @@ struct amdtp_domain {
        struct list_head streams;
 
        unsigned int events_per_period;
+       unsigned int events_per_buffer;
 };
 
 int amdtp_domain_init(struct amdtp_domain *d);
@@ -286,9 +288,11 @@ int amdtp_domain_start(struct amdtp_domain *d);
 void amdtp_domain_stop(struct amdtp_domain *d);
 
 static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d,
-                                               unsigned int events_per_period)
+                                               unsigned int events_per_period,
+                                               unsigned int events_per_buffer)
 {
        d->events_per_period = events_per_period;
+       d->events_per_buffer = events_per_buffer;
 
        return 0;
 }
index f1db3ddc3e0046331c30d38307a270c71e6a3faa..e8e9eca6f116604872ce2a4277dbbc4e18fbc0d5 100644 (file)
@@ -610,7 +610,7 @@ int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate,
                }
 
                err = amdtp_domain_set_events_per_period(&bebob->domain,
-                                                        frames_per_period);
+                                                        frames_per_period, 0);
                if (err < 0) {
                        cmp_connection_release(&bebob->out_conn);
                        cmp_connection_release(&bebob->in_conn);
index ef36bf588d11789bcba44eb79a2c0ac6b289b4c9..b4ef08bd7e8f4aaa325512a28fc9b141bf0ddc10 100644 (file)
@@ -327,7 +327,7 @@ int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate,
                        goto error;
 
                err = amdtp_domain_set_events_per_period(&dice->domain,
-                                                        events_per_period);
+                                                        events_per_period, 0);
                if (err < 0)
                        goto error;
        }
index 96d331e47b0781c9544b10fabc8f626fd2fb25f2..83659fc0ef25f7274299d9f31acca96444cf0fc8 100644 (file)
@@ -318,7 +318,7 @@ int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate,
                }
 
                err = amdtp_domain_set_events_per_period(&dg00x->domain,
-                                                        frames_per_period);
+                                                        frames_per_period, 0);
                if (err < 0) {
                        fw_iso_resources_free(&dg00x->rx_resources);
                        fw_iso_resources_free(&dg00x->tx_resources);
index d05e7d3055e155305c1281f7b962603dfbfd5751..cbe0e5087b05e27668ab08b9b2732ece90a73ec3 100644 (file)
@@ -153,7 +153,7 @@ int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate,
                        return err;
 
                err = amdtp_domain_set_events_per_period(&ff->domain,
-                                                        frames_per_period);
+                                                        frames_per_period, 0);
                if (err < 0) {
                        fw_iso_resources_free(&ff->tx_resources);
                        fw_iso_resources_free(&ff->rx_resources);
index 0787d5c3b01bb0ea6a98f3d5bfc355857a635ad3..e4d4dd08c60a9e063b813df3a2d69d07e53e178e 100644 (file)
@@ -231,7 +231,7 @@ int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate,
                }
 
                err = amdtp_domain_set_events_per_period(&efw->domain,
-                                                        frames_per_period);
+                                                        frames_per_period, 0);
                if (err < 0) {
                        cmp_connection_release(&efw->in_conn);
                        cmp_connection_release(&efw->out_conn);
index 52b7c375bb0bd203c5f920eaa3b612a53136e1b3..97245c67073271886baa63ae44589a818d1d9ea5 100644 (file)
@@ -174,7 +174,7 @@ int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate,
                }
 
                err = amdtp_domain_set_events_per_period(&motu->domain,
-                                                        frames_per_period);
+                                                        frames_per_period, 0);
                if (err < 0) {
                        fw_iso_resources_free(&motu->tx_resources);
                        fw_iso_resources_free(&motu->rx_resources);
index 7d2e88c5b73d3fb7a026dab610b579359ca7b82a..318de8217b3ad208214c7c73e32b4b2be0de3a36 100644 (file)
@@ -308,7 +308,7 @@ int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
                }
 
                err = amdtp_domain_set_events_per_period(&oxfw->domain,
-                                                       frames_per_period);
+                                                       frames_per_period, 0);
                if (err < 0) {
                        cmp_connection_release(&oxfw->in_conn);
                        if (oxfw->has_output)
index 8c04a0ad17d9d2c6501274e45057e81e8a7c8513..1e4d44ed8bedc89045eb7e495b0d539710cb9676 100644 (file)
@@ -416,7 +416,7 @@ int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate,
                }
 
                err = amdtp_domain_set_events_per_period(&tscm->domain,
-                                                       frames_per_period);
+                                                       frames_per_period, 0);
                if (err < 0) {
                        fw_iso_resources_free(&tscm->tx_resources);
                        fw_iso_resources_free(&tscm->rx_resources);