aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core
diff options
context:
space:
mode:
authorVinod Koul <vinod.koul@intel.com>2013-10-24 07:07:31 -0400
committerTakashi Iwai <tiwai@suse.de>2013-10-24 08:50:37 -0400
commit917f4b5cba78980a527098a910d94139d3e82c8d (patch)
treee84f98c5c5ea708b205e1ef34684b778d16c5a67 /sound/core
parenta5606f85611267047206d8ba055bc0e4ba166ad3 (diff)
ALSA: compress: fix drain calls blocking other compress functions
The drain and drain_notify callback were blocked by low level driver untill the draining was complete. Due to this being invoked with big fat mutex held, others ops like reading timestamp, calling pause, drop were blocked. So to fix this we add a new snd_compr_drain_notify() API. This would be required to be invoked by low level driver when drain or partial drain has been completed by the DSP. Thus we make the drain and partial_drain callback as non blocking and driver returns immediately after notifying DSP. The waiting is done while relasing the lock so that other ops can go ahead. Signed-off-by: Vinod Koul <vinod.koul@intel.com> CC: stable@vger.kernel.org Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/compress_offload.c41
1 files changed, 38 insertions, 3 deletions
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index bea523a5d852..3eb47d0006a7 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -123,6 +123,7 @@ static int snd_compr_open(struct inode *inode, struct file *f)
123 } 123 }
124 runtime->state = SNDRV_PCM_STATE_OPEN; 124 runtime->state = SNDRV_PCM_STATE_OPEN;
125 init_waitqueue_head(&runtime->sleep); 125 init_waitqueue_head(&runtime->sleep);
126 init_waitqueue_head(&runtime->wait);
126 data->stream.runtime = runtime; 127 data->stream.runtime = runtime;
127 f->private_data = (void *)data; 128 f->private_data = (void *)data;
128 mutex_lock(&compr->lock); 129 mutex_lock(&compr->lock);
@@ -682,12 +683,34 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
682 if (!retval) { 683 if (!retval) {
683 stream->runtime->state = SNDRV_PCM_STATE_SETUP; 684 stream->runtime->state = SNDRV_PCM_STATE_SETUP;
684 wake_up(&stream->runtime->sleep); 685 wake_up(&stream->runtime->sleep);
686 snd_compr_drain_notify(stream);
685 stream->runtime->total_bytes_available = 0; 687 stream->runtime->total_bytes_available = 0;
686 stream->runtime->total_bytes_transferred = 0; 688 stream->runtime->total_bytes_transferred = 0;
687 } 689 }
688 return retval; 690 return retval;
689} 691}
690 692
693static int snd_compress_wait_for_drain(struct snd_compr_stream *stream)
694{
695 /*
696 * We are called with lock held. So drop the lock while we wait for
697 * drain complete notfication from the driver
698 *
699 * It is expected that driver will notify the drain completion and then
700 * stream will be moved to SETUP state, even if draining resulted in an
701 * error. We can trigger next track after this.
702 */
703 stream->runtime->state = SNDRV_PCM_STATE_DRAINING;
704 mutex_unlock(&stream->device->lock);
705
706 wait_event(stream->runtime->wait, stream->runtime->drain_wake);
707
708 wake_up(&stream->runtime->sleep);
709 mutex_lock(&stream->device->lock);
710
711 return 0;
712}
713
691static int snd_compr_drain(struct snd_compr_stream *stream) 714static int snd_compr_drain(struct snd_compr_stream *stream)
692{ 715{
693 int retval; 716 int retval;
@@ -695,11 +718,17 @@ static int snd_compr_drain(struct snd_compr_stream *stream)
695 if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED || 718 if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
696 stream->runtime->state == SNDRV_PCM_STATE_SETUP) 719 stream->runtime->state == SNDRV_PCM_STATE_SETUP)
697 return -EPERM; 720 return -EPERM;
721
722 stream->runtime->drain_wake = 0;
698 retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN); 723 retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);
699 if (!retval) { 724 if (retval) {
700 stream->runtime->state = SNDRV_PCM_STATE_DRAINING; 725 pr_err("SND_COMPR_TRIGGER_DRAIN failed %d\n", retval);
701 wake_up(&stream->runtime->sleep); 726 wake_up(&stream->runtime->sleep);
727 return retval;
702 } 728 }
729
730 retval = snd_compress_wait_for_drain(stream);
731 stream->runtime->state = SNDRV_PCM_STATE_SETUP;
703 return retval; 732 return retval;
704} 733}
705 734
@@ -735,10 +764,16 @@ static int snd_compr_partial_drain(struct snd_compr_stream *stream)
735 if (stream->next_track == false) 764 if (stream->next_track == false)
736 return -EPERM; 765 return -EPERM;
737 766
767 stream->runtime->drain_wake = 0;
738 retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN); 768 retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN);
769 if (retval) {
770 pr_err("Partial drain returned failure\n");
771 wake_up(&stream->runtime->sleep);
772 return retval;
773 }
739 774
740 stream->next_track = false; 775 stream->next_track = false;
741 return retval; 776 return snd_compress_wait_for_drain(stream);
742} 777}
743 778
744static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) 779static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)