aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core
diff options
context:
space:
mode:
authorCharles Keepax <ckeepax@opensource.wolfsonmicro.com>2016-06-13 09:17:10 -0400
committerMark Brown <broonie@kernel.org>2016-06-13 11:45:37 -0400
commita4f2d87c63571d4cd9467d369f2fbf2362646043 (patch)
tree9ba1c814757a52c9f18c2be6bf0fd85f3c0d0e2a /sound/core
parent1a695a905c18548062509178b98bc91e67510864 (diff)
ALSA: compress: Add function to indicate the stream has gone bad
Currently, the avail IOCTL doesn't pass any error status, which means typically on error it simply shows no data available. This can lead to situations where user-space is waiting indefinitely for data that will never come as the DSP has suffered an unrecoverable error. Add snd_compr_stop_error which end drivers can call to indicate the stream has suffered an unrecoverable error and stop it. The avail and poll IOCTLs are then updated to report if the stream is in an error state to user-space. Allowing the error to propagate out. Processing of the actual snd_compr_stop needs to be deferred to a worker thread as the end driver may detect the errors during an existing operation callback. Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> Acked-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/compress_offload.c67
1 files changed, 65 insertions, 2 deletions
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index 9b3334be9df2..2c498488af6c 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -67,6 +67,8 @@ struct snd_compr_file {
67 struct snd_compr_stream stream; 67 struct snd_compr_stream stream;
68}; 68};
69 69
70static void error_delayed_work(struct work_struct *work);
71
70/* 72/*
71 * a note on stream states used: 73 * a note on stream states used:
72 * we use following states in the compressed core 74 * we use following states in the compressed core
@@ -123,6 +125,9 @@ static int snd_compr_open(struct inode *inode, struct file *f)
123 snd_card_unref(compr->card); 125 snd_card_unref(compr->card);
124 return -ENOMEM; 126 return -ENOMEM;
125 } 127 }
128
129 INIT_DELAYED_WORK(&data->stream.error_work, error_delayed_work);
130
126 data->stream.ops = compr->ops; 131 data->stream.ops = compr->ops;
127 data->stream.direction = dirn; 132 data->stream.direction = dirn;
128 data->stream.private_data = compr->private_data; 133 data->stream.private_data = compr->private_data;
@@ -153,6 +158,8 @@ static int snd_compr_free(struct inode *inode, struct file *f)
153 struct snd_compr_file *data = f->private_data; 158 struct snd_compr_file *data = f->private_data;
154 struct snd_compr_runtime *runtime = data->stream.runtime; 159 struct snd_compr_runtime *runtime = data->stream.runtime;
155 160
161 cancel_delayed_work_sync(&data->stream.error_work);
162
156 switch (runtime->state) { 163 switch (runtime->state) {
157 case SNDRV_PCM_STATE_RUNNING: 164 case SNDRV_PCM_STATE_RUNNING:
158 case SNDRV_PCM_STATE_DRAINING: 165 case SNDRV_PCM_STATE_DRAINING:
@@ -237,6 +244,15 @@ snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
237 avail = snd_compr_calc_avail(stream, &ioctl_avail); 244 avail = snd_compr_calc_avail(stream, &ioctl_avail);
238 ioctl_avail.avail = avail; 245 ioctl_avail.avail = avail;
239 246
247 switch (stream->runtime->state) {
248 case SNDRV_PCM_STATE_OPEN:
249 return -EBADFD;
250 case SNDRV_PCM_STATE_XRUN:
251 return -EPIPE;
252 default:
253 break;
254 }
255
240 if (copy_to_user((__u64 __user *)arg, 256 if (copy_to_user((__u64 __user *)arg,
241 &ioctl_avail, sizeof(ioctl_avail))) 257 &ioctl_avail, sizeof(ioctl_avail)))
242 return -EFAULT; 258 return -EFAULT;
@@ -346,11 +362,13 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
346 switch (stream->runtime->state) { 362 switch (stream->runtime->state) {
347 case SNDRV_PCM_STATE_OPEN: 363 case SNDRV_PCM_STATE_OPEN:
348 case SNDRV_PCM_STATE_PREPARED: 364 case SNDRV_PCM_STATE_PREPARED:
349 case SNDRV_PCM_STATE_XRUN:
350 case SNDRV_PCM_STATE_SUSPENDED: 365 case SNDRV_PCM_STATE_SUSPENDED:
351 case SNDRV_PCM_STATE_DISCONNECTED: 366 case SNDRV_PCM_STATE_DISCONNECTED:
352 retval = -EBADFD; 367 retval = -EBADFD;
353 goto out; 368 goto out;
369 case SNDRV_PCM_STATE_XRUN:
370 retval = -EPIPE;
371 goto out;
354 } 372 }
355 373
356 avail = snd_compr_get_avail(stream); 374 avail = snd_compr_get_avail(stream);
@@ -399,10 +417,16 @@ static unsigned int snd_compr_poll(struct file *f, poll_table *wait)
399 stream = &data->stream; 417 stream = &data->stream;
400 418
401 mutex_lock(&stream->device->lock); 419 mutex_lock(&stream->device->lock);
402 if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) { 420
421 switch (stream->runtime->state) {
422 case SNDRV_PCM_STATE_OPEN:
423 case SNDRV_PCM_STATE_XRUN:
403 retval = snd_compr_get_poll(stream) | POLLERR; 424 retval = snd_compr_get_poll(stream) | POLLERR;
404 goto out; 425 goto out;
426 default:
427 break;
405 } 428 }
429
406 poll_wait(f, &stream->runtime->sleep, wait); 430 poll_wait(f, &stream->runtime->sleep, wait);
407 431
408 avail = snd_compr_get_avail(stream); 432 avail = snd_compr_get_avail(stream);
@@ -697,6 +721,45 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
697 return retval; 721 return retval;
698} 722}
699 723
724static void error_delayed_work(struct work_struct *work)
725{
726 struct snd_compr_stream *stream;
727
728 stream = container_of(work, struct snd_compr_stream, error_work.work);
729
730 mutex_lock(&stream->device->lock);
731
732 stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
733 wake_up(&stream->runtime->sleep);
734
735 mutex_unlock(&stream->device->lock);
736}
737
738/*
739 * snd_compr_stop_error: Report a fatal error on a stream
740 * @stream: pointer to stream
741 * @state: state to transition the stream to
742 *
743 * Stop the stream and set its state.
744 *
745 * Should be called with compressed device lock held.
746 */
747int snd_compr_stop_error(struct snd_compr_stream *stream,
748 snd_pcm_state_t state)
749{
750 if (stream->runtime->state == state)
751 return 0;
752
753 stream->runtime->state = state;
754
755 pr_debug("Changing state to: %d\n", state);
756
757 queue_delayed_work(system_power_efficient_wq, &stream->error_work, 0);
758
759 return 0;
760}
761EXPORT_SYMBOL_GPL(snd_compr_stop_error);
762
700static int snd_compress_wait_for_drain(struct snd_compr_stream *stream) 763static int snd_compress_wait_for_drain(struct snd_compr_stream *stream)
701{ 764{
702 int ret; 765 int ret;