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);
}
}
*/
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);
}