Commit ec00f5e4 authored by Clemens Ladisch's avatar Clemens Ladisch Committed by Takashi Iwai

ALSA: firewire-lib, firewire-speakers: handle packet queueing errors

Add an AMDTP stream error state that occurs when we fail to queue
another packet.  In this case, the stream is stopped, and the error can
be reported when the application tries to restart the PCM stream.
Signed-off-by: default avatarClemens Ladisch <clemens@ladisch.de>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 5b2599a0
...@@ -47,6 +47,7 @@ int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit, ...@@ -47,6 +47,7 @@ int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit,
s->flags = flags; s->flags = flags;
s->context = ERR_PTR(-1); s->context = ERR_PTR(-1);
mutex_init(&s->mutex); mutex_init(&s->mutex);
s->packet_index = 0;
return 0; return 0;
} }
...@@ -316,15 +317,19 @@ static void amdtp_fill_midi(struct amdtp_out_stream *s, ...@@ -316,15 +317,19 @@ static void amdtp_fill_midi(struct amdtp_out_stream *s,
static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle) static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle)
{ {
__be32 *buffer; __be32 *buffer;
unsigned int data_blocks, syt, ptr; unsigned int index, data_blocks, syt, ptr;
struct snd_pcm_substream *pcm; struct snd_pcm_substream *pcm;
struct fw_iso_packet packet; struct fw_iso_packet packet;
int err; int err;
if (s->packet_index < 0)
return;
index = s->packet_index;
data_blocks = calculate_data_blocks(s); data_blocks = calculate_data_blocks(s);
syt = calculate_syt(s, cycle); syt = calculate_syt(s, cycle);
buffer = s->buffer.packets[s->packet_counter].buffer; buffer = s->buffer.packets[index].buffer;
buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) |
(s->data_block_quadlets << 16) | (s->data_block_quadlets << 16) |
s->data_block_counter); s->data_block_counter);
...@@ -343,20 +348,24 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle) ...@@ -343,20 +348,24 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle)
s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff; s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
packet.payload_length = 8 + data_blocks * 4 * s->data_block_quadlets; packet.payload_length = 8 + data_blocks * 4 * s->data_block_quadlets;
packet.interrupt = IS_ALIGNED(s->packet_counter + 1, packet.interrupt = IS_ALIGNED(index + 1, INTERRUPT_INTERVAL);
INTERRUPT_INTERVAL);
packet.skip = 0; packet.skip = 0;
packet.tag = TAG_CIP; packet.tag = TAG_CIP;
packet.sy = 0; packet.sy = 0;
packet.header_length = 0; packet.header_length = 0;
err = fw_iso_context_queue(s->context, &packet, &s->buffer.iso_buffer, err = fw_iso_context_queue(s->context, &packet, &s->buffer.iso_buffer,
s->buffer.packets[s->packet_counter].offset); s->buffer.packets[index].offset);
if (err < 0) if (err < 0) {
dev_err(&s->unit->device, "queueing error: %d\n", err); dev_err(&s->unit->device, "queueing error: %d\n", err);
s->packet_index = -1;
amdtp_out_stream_pcm_abort(s);
return;
}
if (++s->packet_counter >= QUEUE_LENGTH) if (++index >= QUEUE_LENGTH)
s->packet_counter = 0; index = 0;
s->packet_index = index;
if (pcm) { if (pcm) {
ptr = s->pcm_buffer_pointer + data_blocks; ptr = s->pcm_buffer_pointer + data_blocks;
...@@ -398,13 +407,13 @@ static int queue_initial_skip_packets(struct amdtp_out_stream *s) ...@@ -398,13 +407,13 @@ static int queue_initial_skip_packets(struct amdtp_out_stream *s)
int err; int err;
for (i = 0; i < QUEUE_LENGTH; ++i) { for (i = 0; i < QUEUE_LENGTH; ++i) {
skip_packet.interrupt = IS_ALIGNED(s->packet_counter + 1, skip_packet.interrupt = IS_ALIGNED(s->packet_index + 1,
INTERRUPT_INTERVAL); INTERRUPT_INTERVAL);
err = fw_iso_context_queue(s->context, &skip_packet, NULL, 0); err = fw_iso_context_queue(s->context, &skip_packet, NULL, 0);
if (err < 0) if (err < 0)
return err; return err;
if (++s->packet_counter >= QUEUE_LENGTH) if (++s->packet_index >= QUEUE_LENGTH)
s->packet_counter = 0; s->packet_index = 0;
} }
return 0; return 0;
...@@ -469,7 +478,7 @@ int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed) ...@@ -469,7 +478,7 @@ int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed)
amdtp_out_stream_update(s); amdtp_out_stream_update(s);
s->packet_counter = 0; s->packet_index = 0;
s->data_block_counter = 0; s->data_block_counter = 0;
err = queue_initial_skip_packets(s); err = queue_initial_skip_packets(s);
if (err < 0) if (err < 0)
......
...@@ -56,7 +56,7 @@ struct amdtp_out_stream { ...@@ -56,7 +56,7 @@ struct amdtp_out_stream {
struct snd_pcm_substream *pcm; struct snd_pcm_substream *pcm;
unsigned int packet_counter; int packet_index;
unsigned int data_block_counter; unsigned int data_block_counter;
unsigned int data_block_state; unsigned int data_block_state;
...@@ -110,6 +110,18 @@ static inline void amdtp_out_stream_set_midi(struct amdtp_out_stream *s, ...@@ -110,6 +110,18 @@ static inline void amdtp_out_stream_set_midi(struct amdtp_out_stream *s,
s->midi_ports = midi_ports; s->midi_ports = midi_ports;
} }
/**
* amdtp_out_streaming_error - check for streaming error
* @s: the AMDTP output stream
*
* If this function returns true, the stream's packet queue has stopped due to
* an asynchronous error.
*/
static inline bool amdtp_out_streaming_error(struct amdtp_out_stream *s)
{
return s->packet_index < 0;
}
/** /**
* amdtp_out_stream_pcm_prepare - prepare PCM device for running * amdtp_out_stream_pcm_prepare - prepare PCM device for running
* @s: the AMDTP output stream * @s: the AMDTP output stream
......
...@@ -283,6 +283,9 @@ static int fwspk_prepare(struct snd_pcm_substream *substream) ...@@ -283,6 +283,9 @@ static int fwspk_prepare(struct snd_pcm_substream *substream)
mutex_lock(&fwspk->mutex); mutex_lock(&fwspk->mutex);
if (amdtp_out_streaming_error(&fwspk->stream))
fwspk_stop_stream(fwspk);
if (!fwspk->stream_running) { if (!fwspk->stream_running) {
err = cmp_connection_establish(&fwspk->connection, err = cmp_connection_establish(&fwspk->connection,
amdtp_out_stream_get_max_payload(&fwspk->stream)); amdtp_out_stream_get_max_payload(&fwspk->stream));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment