diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 838f695b20de..1f38729c8e74 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -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; } diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index d95a4ed15f20..8d541727e437 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -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; } diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index f1db3ddc3e00..e8e9eca6f116 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -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); diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index ef36bf588d11..b4ef08bd7e8f 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -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; } diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c index 96d331e47b07..83659fc0ef25 100644 --- a/sound/firewire/digi00x/digi00x-stream.c +++ b/sound/firewire/digi00x/digi00x-stream.c @@ -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); diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index d05e7d3055e1..cbe0e5087b05 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -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); diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 0787d5c3b01b..e4d4dd08c60a 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -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); diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c index 52b7c375bb0b..97245c670732 100644 --- a/sound/firewire/motu/motu-stream.c +++ b/sound/firewire/motu/motu-stream.c @@ -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); diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 7d2e88c5b73d..318de8217b3a 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -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) diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index 8c04a0ad17d9..1e4d44ed8bed 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -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);