aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2014-09-08 05:01:10 -0400
committerTakashi Iwai <tiwai@suse.de>2014-09-08 05:01:44 -0400
commit7fd4394dfe1db02ba904dfa1048f718cbca822d1 (patch)
tree902d159ced8c873ee8f58c3301c30f674f099a03 /sound/core
parentd6cc58e127a0b7df78d869a29ff073da6fb899bb (diff)
parent7af142f752116e86adbe2073f2922d8265a77709 (diff)
Merge branch 'topic/pcm-nonatomic' into for-next
This is a merge for exending PCM ops to be non-atomic.
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/pcm.c1
-rw-r--r--sound/core/pcm_native.c136
2 files changed, 128 insertions, 9 deletions
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 43932e8dce66..afccdc553ef9 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -698,6 +698,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
698 } 698 }
699 substream->group = &substream->self_group; 699 substream->group = &substream->self_group;
700 spin_lock_init(&substream->self_group.lock); 700 spin_lock_init(&substream->self_group.lock);
701 mutex_init(&substream->self_group.mutex);
701 INIT_LIST_HEAD(&substream->self_group.substreams); 702 INIT_LIST_HEAD(&substream->self_group.substreams);
702 list_add_tail(&substream->link_list, &substream->self_group.substreams); 703 list_add_tail(&substream->link_list, &substream->self_group.substreams);
703 atomic_set(&substream->mmap_count, 0); 704 atomic_set(&substream->mmap_count, 0);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 8cd2f930ad0b..85fe1a216225 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -74,11 +74,68 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
74 * 74 *
75 */ 75 */
76 76
77DEFINE_RWLOCK(snd_pcm_link_rwlock); 77static DEFINE_RWLOCK(snd_pcm_link_rwlock);
78EXPORT_SYMBOL(snd_pcm_link_rwlock);
79
80static DECLARE_RWSEM(snd_pcm_link_rwsem); 78static DECLARE_RWSEM(snd_pcm_link_rwsem);
81 79
80void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
81{
82 if (substream->pcm->nonatomic) {
83 down_read(&snd_pcm_link_rwsem);
84 mutex_lock(&substream->self_group.mutex);
85 } else {
86 read_lock(&snd_pcm_link_rwlock);
87 spin_lock(&substream->self_group.lock);
88 }
89}
90EXPORT_SYMBOL_GPL(snd_pcm_stream_lock);
91
92void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
93{
94 if (substream->pcm->nonatomic) {
95 mutex_unlock(&substream->self_group.mutex);
96 up_read(&snd_pcm_link_rwsem);
97 } else {
98 spin_unlock(&substream->self_group.lock);
99 read_unlock(&snd_pcm_link_rwlock);
100 }
101}
102EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock);
103
104void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
105{
106 if (!substream->pcm->nonatomic)
107 local_irq_disable();
108 snd_pcm_stream_lock(substream);
109}
110EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq);
111
112void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream)
113{
114 snd_pcm_stream_unlock(substream);
115 if (!substream->pcm->nonatomic)
116 local_irq_enable();
117}
118EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq);
119
120unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream)
121{
122 unsigned long flags = 0;
123 if (!substream->pcm->nonatomic)
124 local_irq_save(flags);
125 snd_pcm_stream_lock(substream);
126 return flags;
127}
128EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave);
129
130void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
131 unsigned long flags)
132{
133 snd_pcm_stream_unlock(substream);
134 if (!substream->pcm->nonatomic)
135 local_irq_restore(flags);
136}
137EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore);
138
82static inline mm_segment_t snd_enter_user(void) 139static inline mm_segment_t snd_enter_user(void)
83{ 140{
84 mm_segment_t fs = get_fs(); 141 mm_segment_t fs = get_fs();
@@ -727,9 +784,14 @@ static int snd_pcm_action_group(struct action_ops *ops,
727 int res = 0; 784 int res = 0;
728 785
729 snd_pcm_group_for_each_entry(s, substream) { 786 snd_pcm_group_for_each_entry(s, substream) {
730 if (do_lock && s != substream) 787 if (do_lock && s != substream) {
731 spin_lock_nested(&s->self_group.lock, 788 if (s->pcm->nonatomic)
732 SINGLE_DEPTH_NESTING); 789 mutex_lock_nested(&s->self_group.mutex,
790 SINGLE_DEPTH_NESTING);
791 else
792 spin_lock_nested(&s->self_group.lock,
793 SINGLE_DEPTH_NESTING);
794 }
733 res = ops->pre_action(s, state); 795 res = ops->pre_action(s, state);
734 if (res < 0) 796 if (res < 0)
735 goto _unlock; 797 goto _unlock;
@@ -755,8 +817,12 @@ static int snd_pcm_action_group(struct action_ops *ops,
755 if (do_lock) { 817 if (do_lock) {
756 /* unlock streams */ 818 /* unlock streams */
757 snd_pcm_group_for_each_entry(s1, substream) { 819 snd_pcm_group_for_each_entry(s1, substream) {
758 if (s1 != substream) 820 if (s1 != substream) {
759 spin_unlock(&s1->self_group.lock); 821 if (s->pcm->nonatomic)
822 mutex_unlock(&s1->self_group.mutex);
823 else
824 spin_unlock(&s1->self_group.lock);
825 }
760 if (s1 == s) /* end */ 826 if (s1 == s) /* end */
761 break; 827 break;
762 } 828 }
@@ -784,6 +850,27 @@ static int snd_pcm_action_single(struct action_ops *ops,
784 return res; 850 return res;
785} 851}
786 852
853/* call in mutex-protected context */
854static int snd_pcm_action_mutex(struct action_ops *ops,
855 struct snd_pcm_substream *substream,
856 int state)
857{
858 int res;
859
860 if (snd_pcm_stream_linked(substream)) {
861 if (!mutex_trylock(&substream->group->mutex)) {
862 mutex_unlock(&substream->self_group.mutex);
863 mutex_lock(&substream->group->mutex);
864 mutex_lock(&substream->self_group.mutex);
865 }
866 res = snd_pcm_action_group(ops, substream, state, 1);
867 mutex_unlock(&substream->group->mutex);
868 } else {
869 res = snd_pcm_action_single(ops, substream, state);
870 }
871 return res;
872}
873
787/* 874/*
788 * Note: call with stream lock 875 * Note: call with stream lock
789 */ 876 */
@@ -793,6 +880,9 @@ static int snd_pcm_action(struct action_ops *ops,
793{ 880{
794 int res; 881 int res;
795 882
883 if (substream->pcm->nonatomic)
884 return snd_pcm_action_mutex(ops, substream, state);
885
796 if (snd_pcm_stream_linked(substream)) { 886 if (snd_pcm_stream_linked(substream)) {
797 if (!spin_trylock(&substream->group->lock)) { 887 if (!spin_trylock(&substream->group->lock)) {
798 spin_unlock(&substream->self_group.lock); 888 spin_unlock(&substream->self_group.lock);
@@ -807,6 +897,29 @@ static int snd_pcm_action(struct action_ops *ops,
807 return res; 897 return res;
808} 898}
809 899
900static int snd_pcm_action_lock_mutex(struct action_ops *ops,
901 struct snd_pcm_substream *substream,
902 int state)
903{
904 int res;
905
906 down_read(&snd_pcm_link_rwsem);
907 if (snd_pcm_stream_linked(substream)) {
908 mutex_lock(&substream->group->mutex);
909 mutex_lock_nested(&substream->self_group.mutex,
910 SINGLE_DEPTH_NESTING);
911 res = snd_pcm_action_group(ops, substream, state, 1);
912 mutex_unlock(&substream->self_group.mutex);
913 mutex_unlock(&substream->group->mutex);
914 } else {
915 mutex_lock(&substream->self_group.mutex);
916 res = snd_pcm_action_single(ops, substream, state);
917 mutex_unlock(&substream->self_group.mutex);
918 }
919 up_read(&snd_pcm_link_rwsem);
920 return res;
921}
922
810/* 923/*
811 * Note: don't use any locks before 924 * Note: don't use any locks before
812 */ 925 */
@@ -816,6 +929,9 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops,
816{ 929{
817 int res; 930 int res;
818 931
932 if (substream->pcm->nonatomic)
933 return snd_pcm_action_lock_mutex(ops, substream, state);
934
819 read_lock_irq(&snd_pcm_link_rwlock); 935 read_lock_irq(&snd_pcm_link_rwlock);
820 if (snd_pcm_stream_linked(substream)) { 936 if (snd_pcm_stream_linked(substream)) {
821 spin_lock(&substream->group->lock); 937 spin_lock(&substream->group->lock);
@@ -1634,7 +1750,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
1634 down_write(&snd_pcm_link_rwsem); 1750 down_write(&snd_pcm_link_rwsem);
1635 write_lock_irq(&snd_pcm_link_rwlock); 1751 write_lock_irq(&snd_pcm_link_rwlock);
1636 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || 1752 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN ||
1637 substream->runtime->status->state != substream1->runtime->status->state) { 1753 substream->runtime->status->state != substream1->runtime->status->state ||
1754 substream->pcm->nonatomic != substream1->pcm->nonatomic) {
1638 res = -EBADFD; 1755 res = -EBADFD;
1639 goto _end; 1756 goto _end;
1640 } 1757 }
@@ -1646,6 +1763,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
1646 substream->group = group; 1763 substream->group = group;
1647 group = NULL; 1764 group = NULL;
1648 spin_lock_init(&substream->group->lock); 1765 spin_lock_init(&substream->group->lock);
1766 mutex_init(&substream->group->mutex);
1649 INIT_LIST_HEAD(&substream->group->substreams); 1767 INIT_LIST_HEAD(&substream->group->substreams);
1650 list_add_tail(&substream->link_list, &substream->group->substreams); 1768 list_add_tail(&substream->link_list, &substream->group->substreams);
1651 substream->group->count = 1; 1769 substream->group->count = 1;