tasklet_kill(&s->period_tasklet);
s->pcm_buffer_pointer = 0;
s->pcm_period_pointer = 0;
- s->pointer_flush = true;
}
EXPORT_SYMBOL(amdtp_stream_pcm_prepare);
s->pcm_period_pointer += frames;
if (s->pcm_period_pointer >= pcm->runtime->period_size) {
s->pcm_period_pointer -= pcm->runtime->period_size;
- s->pointer_flush = false;
tasklet_hi_schedule(&s->period_tasklet);
}
}
amdtp_stream_get_max_payload(s), false);
}
-static int handle_out_packet(struct amdtp_stream *s, unsigned int cycle)
+static int handle_out_packet(struct amdtp_stream *s, unsigned int cycle,
+ unsigned int index)
{
__be32 *buffer;
unsigned int syt;
s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
payload_length = 8 + data_blocks * 4 * s->data_block_quadlets;
- trace_out_packet(s, cycle, buffer, payload_length);
+ trace_out_packet(s, cycle, buffer, payload_length, index);
if (queue_out_packet(s, payload_length, false) < 0)
return -EIO;
}
static int handle_in_packet(struct amdtp_stream *s,
- unsigned int payload_quadlets, unsigned int cycle)
+ unsigned int payload_quadlets, unsigned int cycle,
+ unsigned int index)
{
__be32 *buffer;
u32 cip_header[2];
cip_header[0] = be32_to_cpu(buffer[0]);
cip_header[1] = be32_to_cpu(buffer[1]);
- trace_in_packet(s, cycle, cip_header, payload_quadlets);
+ trace_in_packet(s, cycle, cip_header, payload_quadlets, index);
/*
* This module supports 'Two-quadlet CIP header with SYT field'.
for (i = 0; i < packets; ++i) {
cycle = increment_cycle_count(cycle, 1);
- if (handle_out_packet(s, cycle) < 0) {
+ if (handle_out_packet(s, cycle, i) < 0) {
s->packet_index = -1;
amdtp_stream_pcm_abort(s);
return;
break;
}
- if (handle_in_packet(s, payload_quadlets, cycle) < 0)
+ if (handle_in_packet(s, payload_quadlets, cycle, i) < 0)
break;
}
*/
unsigned long amdtp_stream_pcm_pointer(struct amdtp_stream *s)
{
- /* this optimization is allowed to be racy */
- if (s->pointer_flush && amdtp_stream_running(s))
+ /*
+ * This function is called in software IRQ context of period_tasklet or
+ * process context.
+ *
+ * When the software IRQ context was scheduled by software IRQ context
+ * of IR/IT contexts, queued packets were already handled. Therefore,
+ * no need to flush the queue in buffer anymore.
+ *
+ * When the process context reach here, some packets will be already
+ * queued in the buffer. These packets should be handled immediately
+ * to keep better granularity of PCM pointer.
+ *
+ * Later, the process context will sometimes schedules software IRQ
+ * context of the period_tasklet. Then, no need to flush the queue by
+ * the same reason as described for IR/IT contexts.
+ */
+ if (!in_interrupt() && amdtp_stream_running(s))
fw_iso_context_flush_completions(s->context);
- else
- s->pointer_flush = true;
return ACCESS_ONCE(s->pcm_buffer_pointer);
}