Commit bdaedca7 authored by Takashi Sakamoto's avatar Takashi Sakamoto Committed by Takashi Iwai

ALSA: firewire-lib: change waking up timing to process packets

When starting AMDTP domain, tasks in process context yields running CPU
till all of isochronous context get callback, with an assumption that
it's OK to process content of packet.

However several isochronous cycles are skipped to transfer rx packets, or
the content of rx packets are dropped, to manage the timing to start
processing the packets.

This commit changes the timing for tasks in process context to wake up
when processing content of packet is actually ready.
Signed-off-by: default avatarTakashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20210520040154.80450-9-o-takashi@sakamocchi.jpSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 9b1fcd9b
......@@ -107,7 +107,7 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
INIT_WORK(&s->period_work, pcm_period_work);
s->packet_index = 0;
init_waitqueue_head(&s->callback_wait);
init_waitqueue_head(&s->ready_wait);
s->callbacked = false;
s->fmt = fmt;
......@@ -1029,6 +1029,9 @@ static void process_rx_packets_intermediately(struct fw_iso_context *context, u3
}
if (offset < packets) {
s->ready_processing = true;
wake_up(&s->ready_wait);
process_rx_packets(context, tstamp, header_length, ctx_header, private_data);
if (amdtp_streaming_error(s))
return;
......@@ -1145,6 +1148,9 @@ static void process_tx_packets_intermediately(struct fw_iso_context *context, u3
}
if (offset < packets) {
s->ready_processing = true;
wake_up(&s->ready_wait);
process_tx_packets(context, tstamp, header_length, ctx_header, s);
if (amdtp_streaming_error(s))
return;
......@@ -1286,12 +1292,9 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
const __be32 *ctx_header = header;
u32 cycle;
/*
* For in-stream, first packet has come.
* For out-stream, prepared to transmit first packet
*/
// For in-stream, first packet has come.
// For out-stream, prepared to transmit first packet
s->callbacked = true;
wake_up(&s->callback_wait);
if (s->direction == AMDTP_IN_STREAM) {
cycle = compute_ohci_cycle_count(ctx_header[1]);
......@@ -1464,6 +1467,7 @@ static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed,
tag |= FW_ISO_CONTEXT_MATCH_TAG0;
s->callbacked = false;
s->ready_processing = false;
err = fw_iso_context_start(s->context, -1, 0, tag);
if (err < 0)
goto err_pkt_descs;
......
......@@ -167,9 +167,11 @@ struct amdtp_stream {
snd_pcm_uframes_t pcm_buffer_pointer;
unsigned int pcm_period_pointer;
/* To wait for first packet. */
bool callbacked;
wait_queue_head_t callback_wait;
// To start processing content of packets at the same cycle in several contexts for
// each direction.
bool callbacked:1;
bool ready_processing:1;
wait_queue_head_t ready_wait;
unsigned int next_cycle;
/* For backends to process data blocks. */
......@@ -259,21 +261,6 @@ static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc)
return sfc & 1;
}
/**
* amdtp_stream_wait_callback - sleep till callbacked or timeout
* @s: the AMDTP stream
* @timeout: msec till timeout
*
* If this function return false, the AMDTP stream should be stopped.
*/
static inline bool amdtp_stream_wait_callback(struct amdtp_stream *s,
unsigned int timeout)
{
return wait_event_timeout(s->callback_wait,
s->callbacked,
msecs_to_jiffies(timeout)) > 0;
}
struct seq_desc {
unsigned int syt_offset;
unsigned int data_blocks;
......@@ -327,4 +314,25 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d,
struct amdtp_stream *s);
int amdtp_domain_stream_pcm_ack(struct amdtp_domain *d, struct amdtp_stream *s);
/**
* amdtp_domain_wait_ready - sleep till being ready to process packets or timeout
* @d: the AMDTP domain
* @timeout_ms: msec till timeout
*
* If this function return false, the AMDTP domain should be stopped.
*/
static inline bool amdtp_domain_wait_ready(struct amdtp_domain *d, unsigned int timeout_ms)
{
struct amdtp_stream *s;
list_for_each_entry(s, &d->streams, list) {
unsigned int j = msecs_to_jiffies(timeout_ms);
if (wait_event_interruptible_timeout(s->ready_wait, s->ready_processing, j) <= 0)
return false;
}
return true;
}
#endif
......@@ -7,8 +7,7 @@
#include "./bebob.h"
#define CALLBACK_TIMEOUT 2500
#define FW_ISO_RESOURCE_DELAY 1000
#define READY_TIMEOUT_MS 2500
/*
* NOTE;
......@@ -679,10 +678,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
// Some devices postpone start of transmission mostly for 1 sec after receives
// packets firstly.
if (!amdtp_stream_wait_callback(&bebob->rx_stream,
CALLBACK_TIMEOUT) ||
!amdtp_stream_wait_callback(&bebob->tx_stream,
CALLBACK_TIMEOUT)) {
if (!amdtp_domain_wait_ready(&bebob->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}
......
......@@ -8,7 +8,7 @@
#include "dice.h"
#define CALLBACK_TIMEOUT 200
#define READY_TIMEOUT_MS 200
#define NOTIFICATION_TIMEOUT_MS (2 * MSEC_PER_SEC)
struct reg_params {
......@@ -463,16 +463,9 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice)
if (err < 0)
goto error;
for (i = 0; i < MAX_STREAMS; i++) {
if ((i < tx_params.count &&
!amdtp_stream_wait_callback(&dice->tx_stream[i],
CALLBACK_TIMEOUT)) ||
(i < rx_params.count &&
!amdtp_stream_wait_callback(&dice->rx_stream[i],
CALLBACK_TIMEOUT))) {
err = -ETIMEDOUT;
goto error;
}
if (!amdtp_domain_wait_ready(&dice->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}
}
......
......@@ -7,7 +7,7 @@
#include "digi00x.h"
#define CALLBACK_TIMEOUT 500
#define READY_TIMEOUT_MS 500
const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT] = {
[SND_DG00X_RATE_44100] = 44100,
......@@ -379,10 +379,7 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
if (err < 0)
goto error;
if (!amdtp_stream_wait_callback(&dg00x->rx_stream,
CALLBACK_TIMEOUT) ||
!amdtp_stream_wait_callback(&dg00x->tx_stream,
CALLBACK_TIMEOUT)) {
if (!amdtp_domain_wait_ready(&dg00x->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}
......
......@@ -7,7 +7,7 @@
#include "ff.h"
#define CALLBACK_TIMEOUT_MS 200
#define READY_TIMEOUT_MS 200
int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
enum snd_ff_stream_mode *mode)
......@@ -203,10 +203,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
if (err < 0)
goto error;
if (!amdtp_stream_wait_callback(&ff->rx_stream,
CALLBACK_TIMEOUT_MS) ||
!amdtp_stream_wait_callback(&ff->tx_stream,
CALLBACK_TIMEOUT_MS)) {
if (!amdtp_domain_wait_ready(&ff->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}
......
......@@ -6,7 +6,7 @@
*/
#include "./fireworks.h"
#define CALLBACK_TIMEOUT 100
#define READY_TIMEOUT_MS 100
static int init_stream(struct snd_efw *efw, struct amdtp_stream *stream)
{
......@@ -276,11 +276,7 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw)
if (err < 0)
goto error;
// Wait first callback.
if (!amdtp_stream_wait_callback(&efw->rx_stream,
CALLBACK_TIMEOUT) ||
!amdtp_stream_wait_callback(&efw->tx_stream,
CALLBACK_TIMEOUT)) {
if (!amdtp_domain_wait_ready(&efw->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}
......
......@@ -7,7 +7,7 @@
#include "motu.h"
#define CALLBACK_TIMEOUT 200
#define READY_TIMEOUT_MS 200
#define ISOC_COMM_CONTROL_OFFSET 0x0b00
#define ISOC_COMM_CONTROL_MASK 0xffff0000
......@@ -264,10 +264,7 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu)
if (err < 0)
goto stop_streams;
if (!amdtp_stream_wait_callback(&motu->tx_stream,
CALLBACK_TIMEOUT) ||
!amdtp_stream_wait_callback(&motu->rx_stream,
CALLBACK_TIMEOUT)) {
if (!amdtp_domain_wait_ready(&motu->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto stop_streams;
}
......
......@@ -9,7 +9,7 @@
#include <linux/delay.h>
#define AVC_GENERIC_FRAME_MAXIMUM_BYTES 512
#define CALLBACK_TIMEOUT 200
#define READY_TIMEOUT_MS 200
/*
* According to datasheet of Oxford Semiconductor:
......@@ -358,20 +358,10 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
if (err < 0)
goto error;
// Wait first packet.
if (!amdtp_stream_wait_callback(&oxfw->rx_stream,
CALLBACK_TIMEOUT)) {
if (!amdtp_domain_wait_ready(&oxfw->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}
if (oxfw->has_output) {
if (!amdtp_stream_wait_callback(&oxfw->tx_stream,
CALLBACK_TIMEOUT)) {
err = -ETIMEDOUT;
goto error;
}
}
}
return 0;
......
......@@ -11,7 +11,7 @@
#define CLOCK_STATUS_MASK 0xffff0000
#define CLOCK_CONFIG_MASK 0x0000ffff
#define CALLBACK_TIMEOUT 500
#define READY_TIMEOUT_MS 500
static int get_clock(struct snd_tscm *tscm, u32 *data)
{
......@@ -477,10 +477,7 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
if (err < 0)
return err;
if (!amdtp_stream_wait_callback(&tscm->rx_stream,
CALLBACK_TIMEOUT) ||
!amdtp_stream_wait_callback(&tscm->tx_stream,
CALLBACK_TIMEOUT)) {
if (!amdtp_domain_wait_ready(&tscm->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}
......
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