summaryrefslogtreecommitdiffstats
path: root/sound/firewire
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2021-05-20 13:01:50 +0900
committerTakashi Iwai <tiwai@suse.de>2021-05-20 14:00:25 +0200
commitda3623abfbef446fc586a49807156d622cf778f6 (patch)
tree018f871b20c3fdc43826c2e69001cc74e75d12b2 /sound/firewire
parent233dbbc7af5d279a5b1cc92ab08f15f7c2d64ad7 (diff)
downloadlinux-da3623abfbef446fc586a49807156d622cf778f6.tar.gz
linux-da3623abfbef446fc586a49807156d622cf778f6.tar.bz2
linux-da3623abfbef446fc586a49807156d622cf778f6.zip
ALSA: firewire-lib: start processing content of packet at the same cycle in several IR contexts
DICE ASICs support several pairs of isochronous packet streaming. It's convenient for drivers to process content of the packet in the same cycle timing. This commit adds structure member to manage the cycle to start processing packet in several IR contexts. The cycle is decided in the first callback of the IR contexts. The content of packet is dropped till the cycle. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Link: https://lore.kernel.org/r/20210520040154.80450-5-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire')
-rw-r--r--sound/firewire/amdtp-stream.c115
-rw-r--r--sound/firewire/amdtp-stream.h4
2 files changed, 113 insertions, 6 deletions
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index 87644cb0d8ab..35925c9666fc 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -958,9 +958,8 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
s->ctx_data.rx.event_count = event_count;
}
-static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
- size_t header_length, void *header,
- void *private_data)
+static void process_tx_packets(struct fw_iso_context *context, u32 tstamp, size_t header_length,
+ void *header, void *private_data)
{
struct amdtp_stream *s = private_data;
__be32 *ctx_header = header;
@@ -996,6 +995,82 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
}
}
+static void drop_tx_packets(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 packets;
+ unsigned int cycle;
+ int i;
+
+ if (s->packet_index < 0)
+ return;
+
+ packets = header_length / s->ctx_data.tx.ctx_header_size;
+
+ ctx_header += (packets - 1) * s->ctx_data.tx.ctx_header_size / sizeof(*ctx_header);
+ cycle = compute_ohci_cycle_count(ctx_header[1]);
+ s->next_cycle = increment_ohci_cycle_count(cycle, 1);
+
+ for (i = 0; i < packets; ++i) {
+ struct fw_iso_packet params = {0};
+
+ if (queue_in_packet(s, &params) < 0) {
+ cancel_stream(s);
+ return;
+ }
+ }
+}
+
+static void process_tx_packets_intermediately(struct fw_iso_context *context, u32 tstamp,
+ size_t header_length, void *header, void *private_data)
+{
+ struct amdtp_stream *s = private_data;
+ struct amdtp_domain *d = s->domain;
+ __be32 *ctx_header;
+ unsigned int packets;
+ unsigned int offset;
+
+ if (s->packet_index < 0)
+ return;
+
+ packets = header_length / s->ctx_data.tx.ctx_header_size;
+
+ offset = 0;
+ ctx_header = header;
+ while (offset < packets) {
+ unsigned int cycle = compute_ohci_cycle_count(ctx_header[1]);
+
+ if (compare_ohci_cycle_count(cycle, d->processing_cycle.tx_start) >= 0)
+ break;
+
+ ctx_header += s->ctx_data.tx.ctx_header_size / sizeof(__be32);
+ ++offset;
+ }
+
+ ctx_header = header;
+
+ if (offset > 0) {
+ size_t length = s->ctx_data.tx.ctx_header_size * offset;
+
+ drop_tx_packets(context, tstamp, length, ctx_header, s);
+ if (amdtp_streaming_error(s))
+ return;
+
+ ctx_header += length / sizeof(*ctx_header);
+ header_length -= length;
+ }
+
+ if (offset < packets) {
+ process_tx_packets(context, tstamp, header_length, ctx_header, s);
+ if (amdtp_streaming_error(s))
+ return;
+
+ context->callback.sc = process_tx_packets;
+ }
+}
+
static void pool_ideal_seq_descs(struct amdtp_domain *d, unsigned int packets)
{
struct amdtp_stream *irq_target = d->irq_target;
@@ -1082,6 +1157,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
void *header, void *private_data)
{
struct amdtp_stream *s = private_data;
+ struct amdtp_domain *d = s->domain;
const __be32 *ctx_header = header;
u32 cycle;
@@ -1094,13 +1170,12 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
if (s->direction == AMDTP_IN_STREAM) {
cycle = compute_ohci_cycle_count(ctx_header[1]);
- s->next_cycle = cycle;
- context->callback.sc = in_stream_callback;
+ context->callback.sc = drop_tx_packets;
} else {
cycle = compute_ohci_it_cycle(*ctx_header, s->queue_size);
- if (s == s->domain->irq_target)
+ if (s == d->irq_target)
context->callback.sc = irq_target_callback;
else
context->callback.sc = out_stream_callback;
@@ -1109,6 +1184,34 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
s->start_cycle = cycle;
context->callback.sc(context, tstamp, header_length, header, s);
+
+ // Decide the cycle count to begin processing content of packet in IR contexts.
+ if (s->direction == AMDTP_IN_STREAM) {
+ unsigned int stream_count = 0;
+ unsigned int callbacked_count = 0;
+
+ list_for_each_entry(s, &d->streams, list) {
+ if (s->direction == AMDTP_IN_STREAM) {
+ ++stream_count;
+ if (s->callbacked)
+ ++callbacked_count;
+ }
+ }
+
+ if (stream_count == callbacked_count) {
+ list_for_each_entry(s, &d->streams, list) {
+ if (s->direction != AMDTP_IN_STREAM)
+ continue;
+
+ if (compare_ohci_cycle_count(s->next_cycle, cycle) > 0)
+ cycle = s->next_cycle;
+
+ s->context->callback.sc = process_tx_packets_intermediately;
+ }
+
+ d->processing_cycle.tx_start = cycle;
+ }
+ }
}
/**
diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h
index 58769ca184a2..6fad113188fe 100644
--- a/sound/firewire/amdtp-stream.h
+++ b/sound/firewire/amdtp-stream.h
@@ -289,6 +289,10 @@ struct amdtp_domain {
struct amdtp_stream *irq_target;
struct {
+ unsigned int tx_start;
+ } processing_cycle;
+
+ struct {
struct seq_desc *descs;
unsigned int size;
unsigned int tail;