summaryrefslogtreecommitdiff
path: root/sound/firewire/amdtp-stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/firewire/amdtp-stream.c')
-rw-r--r--sound/firewire/amdtp-stream.c150
1 files changed, 61 insertions, 89 deletions
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index 7e763f46e5a4..cf4fbbd18756 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -441,6 +441,30 @@ static unsigned int calculate_syt_offset(unsigned int *last_syt_offset,
return syt_offset;
}
+static void pool_ideal_seq_descs(struct amdtp_stream *s, unsigned int count)
+{
+ unsigned int seq_tail = s->ctx_data.rx.seq.tail;
+ const unsigned int seq_size = s->ctx_data.rx.seq.size;
+ const unsigned int syt_interval = s->syt_interval;
+ const enum cip_sfc sfc = s->sfc;
+ const bool is_blocking = !!(s->flags & CIP_BLOCKING);
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ struct seq_desc *desc = s->ctx_data.rx.seq.descs + seq_tail;
+
+ desc->syt_offset = calculate_syt_offset(&s->ctx_data.rx.last_syt_offset,
+ &s->ctx_data.rx.syt_offset_state, sfc);
+ desc->data_blocks = calculate_data_blocks(&s->ctx_data.rx.data_block_state,
+ is_blocking, desc->syt_offset == CIP_SYT_NO_INFO,
+ syt_interval, sfc);
+
+ seq_tail = (seq_tail + 1) % seq_size;
+ }
+
+ s->ctx_data.rx.seq.tail = seq_tail;
+}
+
static void update_pcm_pointers(struct amdtp_stream *s,
struct snd_pcm_substream *pcm,
unsigned int frames)
@@ -833,14 +857,14 @@ static void generate_pkt_descs(struct amdtp_stream *s, struct pkt_desc *descs,
unsigned int seq_size)
{
unsigned int dbc = s->data_block_counter;
- unsigned int seq_index = s->ctx_data.rx.seq_index;
+ unsigned int seq_head = s->ctx_data.rx.seq.head;
bool aware_syt = !(s->flags & CIP_UNAWARE_SYT);
int i;
for (i = 0; i < packets; ++i) {
struct pkt_desc *desc = descs + i;
unsigned int index = (s->packet_index + i) % s->queue_size;
- const struct seq_desc *seq = seq_descs + seq_index;
+ const struct seq_desc *seq = seq_descs + seq_head;
desc->cycle = compute_ohci_it_cycle(*ctx_header, s->queue_size);
@@ -863,13 +887,13 @@ static void generate_pkt_descs(struct amdtp_stream *s, struct pkt_desc *descs,
desc->ctx_payload = s->buffer.packets[index].buffer;
- seq_index = (seq_index + 1) % seq_size;
+ seq_head = (seq_head + 1) % seq_size;
++ctx_header;
}
s->data_block_counter = dbc;
- s->ctx_data.rx.seq_index = seq_index;
+ s->ctx_data.rx.seq.head = seq_head;
}
static inline void cancel_stream(struct amdtp_stream *s)
@@ -911,8 +935,10 @@ static void process_rx_packets(struct fw_iso_context *context, u32 tstamp, size_
// Calculate the number of packets in buffer and check XRUN.
packets = header_length / sizeof(*ctx_header);
- generate_pkt_descs(s, s->pkt_descs, ctx_header, packets, d->seq.descs,
- d->seq.size);
+ pool_ideal_seq_descs(s, packets);
+
+ generate_pkt_descs(s, s->pkt_descs, ctx_header, packets, s->ctx_data.rx.seq.descs,
+ s->ctx_data.rx.seq.size);
process_ctx_payloads(s, s->pkt_descs, packets);
@@ -1152,51 +1178,6 @@ static void process_tx_packets_intermediately(struct fw_iso_context *context, u3
}
}
-static void pool_ideal_seq_descs(struct amdtp_domain *d, unsigned int packets)
-{
- struct amdtp_stream *irq_target = d->irq_target;
- unsigned int seq_tail = d->seq.tail;
- unsigned int seq_size = d->seq.size;
- unsigned int min_avail;
- struct amdtp_stream *s;
-
- min_avail = d->seq.size;
- list_for_each_entry(s, &d->streams, list) {
- unsigned int seq_index;
- unsigned int avail;
-
- if (s->direction == AMDTP_IN_STREAM)
- continue;
-
- seq_index = s->ctx_data.rx.seq_index;
- avail = d->seq.tail;
- if (seq_index > avail)
- avail += d->seq.size;
- avail -= seq_index;
-
- if (avail < min_avail)
- min_avail = avail;
- }
-
- while (min_avail < packets) {
- struct seq_desc *desc = d->seq.descs + seq_tail;
-
- desc->syt_offset = calculate_syt_offset(&d->last_syt_offset,
- &d->syt_offset_state, irq_target->sfc);
- desc->data_blocks = calculate_data_blocks(&d->data_block_state,
- !!(irq_target->flags & CIP_BLOCKING),
- desc->syt_offset == CIP_SYT_NO_INFO,
- irq_target->syt_interval, irq_target->sfc);
-
- ++seq_tail;
- seq_tail %= seq_size;
-
- ++min_avail;
- }
-
- d->seq.tail = seq_tail;
-}
-
static void process_ctxs_in_domain(struct amdtp_domain *d)
{
struct amdtp_stream *s;
@@ -1225,9 +1206,6 @@ static void irq_target_callback(struct fw_iso_context *context, u32 tstamp, size
{
struct amdtp_stream *s = private_data;
struct amdtp_domain *d = s->domain;
- unsigned int packets = header_length / sizeof(__be32);
-
- pool_ideal_seq_descs(d, packets);
process_rx_packets(context, tstamp, header_length, header, private_data);
process_ctxs_in_domain(d);
@@ -1238,9 +1216,6 @@ static void irq_target_callback_intermediately(struct fw_iso_context *context, u
{
struct amdtp_stream *s = private_data;
struct amdtp_domain *d = s->domain;
- unsigned int packets = header_length / sizeof(__be32);
-
- pool_ideal_seq_descs(d, packets);
process_rx_packets_intermediately(context, tstamp, header_length, header, private_data);
process_ctxs_in_domain(d);
@@ -1415,7 +1390,31 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
s->ctx_data.tx.max_ctx_payload_length = max_ctx_payload_size;
s->ctx_data.tx.ctx_header_size = ctx_header_size;
} else {
- s->ctx_data.rx.seq_index = 0;
+ static const struct {
+ unsigned int data_block;
+ unsigned int syt_offset;
+ } *entry, initial_state[] = {
+ [CIP_SFC_32000] = { 4, 3072 },
+ [CIP_SFC_48000] = { 6, 1024 },
+ [CIP_SFC_96000] = { 12, 1024 },
+ [CIP_SFC_192000] = { 24, 1024 },
+ [CIP_SFC_44100] = { 0, 67 },
+ [CIP_SFC_88200] = { 0, 67 },
+ [CIP_SFC_176400] = { 0, 67 },
+ };
+
+ s->ctx_data.rx.seq.descs = kcalloc(queue_size, sizeof(*s->ctx_data.rx.seq.descs), GFP_KERNEL);
+ if (!s->ctx_data.rx.seq.descs)
+ goto err_context;
+ s->ctx_data.rx.seq.size = queue_size;
+ s->ctx_data.rx.seq.tail = 0;
+ s->ctx_data.rx.seq.head = 0;
+
+ entry = &initial_state[s->sfc];
+ s->ctx_data.rx.data_block_state = entry->data_block;
+ s->ctx_data.rx.syt_offset_state = entry->syt_offset;
+ s->ctx_data.rx.last_syt_offset = TICKS_PER_CYCLE;
+
s->ctx_data.rx.event_count = 0;
}
@@ -1471,6 +1470,8 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
err_pkt_descs:
kfree(s->pkt_descs);
err_context:
+ if (s->direction == AMDTP_OUT_STREAM)
+ kfree(s->ctx_data.rx.seq.descs);
fw_iso_context_destroy(s->context);
s->context = ERR_PTR(-1);
err_buffer:
@@ -1581,7 +1582,8 @@ static void amdtp_stream_stop(struct amdtp_stream *s)
iso_packets_buffer_destroy(&s->buffer, s->unit);
kfree(s->pkt_descs);
- s->callbacked = false;
+ if (s->direction == AMDTP_OUT_STREAM)
+ kfree(s->ctx_data.rx.seq.descs);
mutex_unlock(&s->mutex);
}
@@ -1613,8 +1615,6 @@ int amdtp_domain_init(struct amdtp_domain *d)
d->events_per_period = 0;
- d->seq.descs = NULL;
-
return 0;
}
EXPORT_SYMBOL_GPL(amdtp_domain_init);
@@ -1665,18 +1665,6 @@ EXPORT_SYMBOL_GPL(amdtp_domain_add_stream);
*/
int amdtp_domain_start(struct amdtp_domain *d, unsigned int tx_init_skip_cycles)
{
- static const struct {
- unsigned int data_block;
- unsigned int syt_offset;
- } *entry, initial_state[] = {
- [CIP_SFC_32000] = { 4, 3072 },
- [CIP_SFC_48000] = { 6, 1024 },
- [CIP_SFC_96000] = { 12, 1024 },
- [CIP_SFC_192000] = { 24, 1024 },
- [CIP_SFC_44100] = { 0, 67 },
- [CIP_SFC_88200] = { 0, 67 },
- [CIP_SFC_176400] = { 0, 67 },
- };
unsigned int events_per_buffer = d->events_per_buffer;
unsigned int events_per_period = d->events_per_period;
unsigned int queue_size;
@@ -1705,17 +1693,6 @@ int amdtp_domain_start(struct amdtp_domain *d, unsigned int tx_init_skip_cycles)
queue_size = DIV_ROUND_UP(CYCLES_PER_SECOND * events_per_buffer,
amdtp_rate_table[d->irq_target->sfc]);
- d->seq.descs = kcalloc(queue_size, sizeof(*d->seq.descs), GFP_KERNEL);
- if (!d->seq.descs)
- return -ENOMEM;
- d->seq.size = queue_size;
- d->seq.tail = 0;
-
- entry = &initial_state[s->sfc];
- d->data_block_state = entry->data_block;
- d->syt_offset_state = entry->syt_offset;
- d->last_syt_offset = TICKS_PER_CYCLE;
-
list_for_each_entry(s, &d->streams, list) {
unsigned int idle_irq_interval = 0;
@@ -1734,8 +1711,6 @@ int amdtp_domain_start(struct amdtp_domain *d, unsigned int tx_init_skip_cycles)
error:
list_for_each_entry(s, &d->streams, list)
amdtp_stream_stop(s);
- kfree(d->seq.descs);
- d->seq.descs = NULL;
return err;
}
EXPORT_SYMBOL_GPL(amdtp_domain_start);
@@ -1760,8 +1735,5 @@ void amdtp_domain_stop(struct amdtp_domain *d)
d->events_per_period = 0;
d->irq_target = NULL;
-
- kfree(d->seq.descs);
- d->seq.descs = NULL;
}
EXPORT_SYMBOL_GPL(amdtp_domain_stop);