Commit 6abce9e6 authored by Clemens Ladisch's avatar Clemens Ladisch

ALSA: dice: optimize bus reset handling

After a bus reset, do not stop the stream completely to avoid having to
reconfigure the device when restarting the stream.
Signed-off-by: default avatarClemens Ladisch <clemens@ladisch.de>
parent 82fbb4f7
...@@ -559,24 +559,92 @@ static int dice_close(struct snd_pcm_substream *substream) ...@@ -559,24 +559,92 @@ static int dice_close(struct snd_pcm_substream *substream)
return 0; return 0;
} }
static void dice_stop_stream(struct dice *dice) static int dice_stream_start_packets(struct dice *dice)
{ {
__be32 channel; int err;
if (dice->stream_running)
return 0;
if (dice->stream_running) { err = amdtp_out_stream_start(&dice->stream, dice->resources.channel,
dice_enable_clear(dice); fw_parent_device(dice->unit)->max_speed);
if (err < 0)
return err;
err = dice_enable_set(dice);
if (err < 0) {
amdtp_out_stream_stop(&dice->stream); amdtp_out_stream_stop(&dice->stream);
return err;
}
channel = cpu_to_be32((u32)-1); dice->stream_running = true;
snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
rx_address(dice, RX_ISOCHRONOUS),
&channel, 4);
fw_iso_resources_free(&dice->resources); return 0;
}
dice->stream_running = false; static int dice_stream_start(struct dice *dice)
{
__be32 channel;
int err;
if (!dice->resources.allocated) {
err = fw_iso_resources_allocate(&dice->resources,
amdtp_out_stream_get_max_payload(&dice->stream),
fw_parent_device(dice->unit)->max_speed);
if (err < 0)
goto error;
channel = cpu_to_be32(dice->resources.channel);
err = snd_fw_transaction(dice->unit,
TCODE_WRITE_QUADLET_REQUEST,
rx_address(dice, RX_ISOCHRONOUS),
&channel, 4);
if (err < 0)
goto err_resources;
} }
err = dice_stream_start_packets(dice);
if (err < 0)
goto err_rx_channel;
return 0;
err_rx_channel:
channel = cpu_to_be32((u32)-1);
snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
rx_address(dice, RX_ISOCHRONOUS), &channel, 4);
err_resources:
fw_iso_resources_free(&dice->resources);
error:
return err;
}
static void dice_stream_stop_packets(struct dice *dice)
{
if (!dice->stream_running)
return;
dice_enable_clear(dice);
amdtp_out_stream_stop(&dice->stream);
dice->stream_running = false;
}
static void dice_stream_stop(struct dice *dice)
{
__be32 channel;
dice_stream_stop_packets(dice);
if (!dice->resources.allocated)
return;
channel = cpu_to_be32((u32)-1);
snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
rx_address(dice, RX_ISOCHRONOUS), &channel, 4);
fw_iso_resources_free(&dice->resources);
} }
static int dice_hw_params(struct snd_pcm_substream *substream, static int dice_hw_params(struct snd_pcm_substream *substream,
...@@ -586,7 +654,7 @@ static int dice_hw_params(struct snd_pcm_substream *substream, ...@@ -586,7 +654,7 @@ static int dice_hw_params(struct snd_pcm_substream *substream,
int err; int err;
mutex_lock(&dice->mutex); mutex_lock(&dice->mutex);
dice_stop_stream(dice); dice_stream_stop(dice);
mutex_unlock(&dice->mutex); mutex_unlock(&dice->mutex);
err = snd_pcm_lib_alloc_vmalloc_buffer(substream, err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
...@@ -608,7 +676,7 @@ static int dice_hw_free(struct snd_pcm_substream *substream) ...@@ -608,7 +676,7 @@ static int dice_hw_free(struct snd_pcm_substream *substream)
struct dice *dice = substream->private_data; struct dice *dice = substream->private_data;
mutex_lock(&dice->mutex); mutex_lock(&dice->mutex);
dice_stop_stream(dice); dice_stream_stop(dice);
mutex_unlock(&dice->mutex); mutex_unlock(&dice->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream); return snd_pcm_lib_free_vmalloc_buffer(substream);
...@@ -617,42 +685,17 @@ static int dice_hw_free(struct snd_pcm_substream *substream) ...@@ -617,42 +685,17 @@ static int dice_hw_free(struct snd_pcm_substream *substream)
static int dice_prepare(struct snd_pcm_substream *substream) static int dice_prepare(struct snd_pcm_substream *substream)
{ {
struct dice *dice = substream->private_data; struct dice *dice = substream->private_data;
struct fw_device *device = fw_parent_device(dice->unit);
__be32 channel;
int err; int err;
mutex_lock(&dice->mutex); mutex_lock(&dice->mutex);
if (amdtp_out_streaming_error(&dice->stream)) if (amdtp_out_streaming_error(&dice->stream))
dice_stop_stream(dice); dice_stream_stop_packets(dice);
if (!dice->stream_running) {
err = fw_iso_resources_allocate(&dice->resources,
amdtp_out_stream_get_max_payload(&dice->stream),
device->max_speed);
if (err < 0)
goto error;
//TODO: RX_SEQ_START
channel = cpu_to_be32(dice->resources.channel);
err = snd_fw_transaction(dice->unit,
TCODE_WRITE_QUADLET_REQUEST,
rx_address(dice, RX_ISOCHRONOUS),
&channel, 4);
if (err < 0)
goto err_resources;
err = amdtp_out_stream_start(&dice->stream,
dice->resources.channel,
device->max_speed);
if (err < 0)
goto err_resources;
err = dice_enable_set(dice);
if (err < 0)
goto err_stream;
dice->stream_running = true; err = dice_stream_start(dice);
if (err < 0) {
mutex_unlock(&dice->mutex);
return err;
} }
mutex_unlock(&dice->mutex); mutex_unlock(&dice->mutex);
...@@ -660,15 +703,6 @@ static int dice_prepare(struct snd_pcm_substream *substream) ...@@ -660,15 +703,6 @@ static int dice_prepare(struct snd_pcm_substream *substream)
amdtp_out_stream_pcm_prepare(&dice->stream); amdtp_out_stream_pcm_prepare(&dice->stream);
return 0; return 0;
err_stream:
amdtp_out_stream_stop(&dice->stream);
err_resources:
fw_iso_resources_free(&dice->resources);
error:
mutex_unlock(&dice->mutex);
return err;
} }
static int dice_trigger(struct snd_pcm_substream *substream, int cmd) static int dice_trigger(struct snd_pcm_substream *substream, int cmd)
...@@ -941,7 +975,7 @@ static void dice_remove(struct fw_unit *unit) ...@@ -941,7 +975,7 @@ static void dice_remove(struct fw_unit *unit)
mutex_lock(&dice->mutex); mutex_lock(&dice->mutex);
amdtp_out_stream_pcm_abort(&dice->stream); amdtp_out_stream_pcm_abort(&dice->stream);
dice_stop_stream(dice); dice_stream_stop(dice);
dice_owner_clear(dice); dice_owner_clear(dice);
mutex_unlock(&dice->mutex); mutex_unlock(&dice->mutex);
...@@ -953,8 +987,8 @@ static void dice_bus_reset(struct fw_unit *unit) ...@@ -953,8 +987,8 @@ static void dice_bus_reset(struct fw_unit *unit)
struct dice *dice = dev_get_drvdata(&unit->device); struct dice *dice = dev_get_drvdata(&unit->device);
mutex_lock(&dice->mutex); mutex_lock(&dice->mutex);
/* /*
* XXX is the following true?
* On a bus reset, the DICE firmware disables streaming and then goes * On a bus reset, the DICE firmware disables streaming and then goes
* off contemplating its own navel for hundreds of milliseconds before * off contemplating its own navel for hundreds of milliseconds before
* it can react to any of our attempts to reenable streaming. This * it can react to any of our attempts to reenable streaming. This
...@@ -962,9 +996,13 @@ static void dice_bus_reset(struct fw_unit *unit) ...@@ -962,9 +996,13 @@ static void dice_bus_reset(struct fw_unit *unit)
* to stop so that the application can restart them in an orderly * to stop so that the application can restart them in an orderly
* manner. * manner.
*/ */
dice_owner_update(dice);
amdtp_out_stream_pcm_abort(&dice->stream); amdtp_out_stream_pcm_abort(&dice->stream);
dice_stop_stream(dice); dice_stream_stop_packets(dice);
dice_owner_update(dice);
fw_iso_resources_update(&dice->resources);
mutex_unlock(&dice->mutex); mutex_unlock(&dice->mutex);
} }
......
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