ALSA: firewire-lib: add context information to tracepoints
[cascardo/linux.git] / sound / firewire / amdtp-stream.c
index f1ebb7b..bf10ca3 100644 (file)
@@ -251,7 +251,6 @@ void amdtp_stream_pcm_prepare(struct amdtp_stream *s)
        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);
 
@@ -356,7 +355,6 @@ static void update_pcm_pointers(struct amdtp_stream *s,
        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);
        }
 }
@@ -411,15 +409,19 @@ static inline int queue_in_packet(struct amdtp_stream *s)
                            amdtp_stream_get_max_payload(s), false);
 }
 
-static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks,
-                            unsigned int cycle, unsigned int syt)
+static int handle_out_packet(struct amdtp_stream *s, unsigned int cycle,
+                            unsigned int index)
 {
        __be32 *buffer;
+       unsigned int syt;
+       unsigned int data_blocks;
        unsigned int payload_length;
        unsigned int pcm_frames;
        struct snd_pcm_substream *pcm;
 
        buffer = s->buffer.packets[s->packet_index].buffer;
+       syt = calculate_syt(s, cycle);
+       data_blocks = calculate_data_blocks(s, syt);
        pcm_frames = s->process_data_blocks(s, buffer + 2, data_blocks, &syt);
 
        buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) |
@@ -433,7 +435,7 @@ static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks,
        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;
@@ -447,7 +449,8 @@ static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks,
 }
 
 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];
@@ -462,7 +465,7 @@ static int handle_in_packet(struct amdtp_stream *s,
        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'.
@@ -588,8 +591,7 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
                                void *private_data)
 {
        struct amdtp_stream *s = private_data;
-       unsigned int i, syt, packets = header_length / 4;
-       unsigned int data_blocks;
+       unsigned int i, packets = header_length / 4;
        u32 cycle;
 
        if (s->packet_index < 0)
@@ -602,10 +604,7 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
 
        for (i = 0; i < packets; ++i) {
                cycle = increment_cycle_count(cycle, 1);
-               syt = calculate_syt(s, cycle);
-               data_blocks = calculate_data_blocks(s, syt);
-
-               if (handle_out_packet(s, data_blocks, cycle, syt) < 0) {
+               if (handle_out_packet(s, cycle, i) < 0) {
                        s->packet_index = -1;
                        amdtp_stream_pcm_abort(s);
                        return;
@@ -652,7 +651,7 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
                        break;
                }
 
-               if (handle_in_packet(s, payload_quadlets, cycle) < 0)
+               if (handle_in_packet(s, payload_quadlets, cycle, i) < 0)
                        break;
        }
 
@@ -724,8 +723,7 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
                goto err_unlock;
        }
 
-       if (s->direction == AMDTP_IN_STREAM &&
-           s->flags & CIP_SKIP_INIT_DBC_CHECK)
+       if (s->direction == AMDTP_IN_STREAM)
                s->data_block_counter = UINT_MAX;
        else
                s->data_block_counter = 0;
@@ -805,11 +803,24 @@ EXPORT_SYMBOL(amdtp_stream_start);
  */
 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);
 }