diff options
author | Takashi Iwai <tiwai@suse.de> | 2014-09-08 05:01:10 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-09-08 05:01:44 -0400 |
commit | 7fd4394dfe1db02ba904dfa1048f718cbca822d1 (patch) | |
tree | 902d159ced8c873ee8f58c3301c30f674f099a03 /sound/core | |
parent | d6cc58e127a0b7df78d869a29ff073da6fb899bb (diff) | |
parent | 7af142f752116e86adbe2073f2922d8265a77709 (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.c | 1 | ||||
-rw-r--r-- | sound/core/pcm_native.c | 136 |
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 | ||
77 | DEFINE_RWLOCK(snd_pcm_link_rwlock); | 77 | static DEFINE_RWLOCK(snd_pcm_link_rwlock); |
78 | EXPORT_SYMBOL(snd_pcm_link_rwlock); | ||
79 | |||
80 | static DECLARE_RWSEM(snd_pcm_link_rwsem); | 78 | static DECLARE_RWSEM(snd_pcm_link_rwsem); |
81 | 79 | ||
80 | void 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 | } | ||
90 | EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); | ||
91 | |||
92 | void 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 | } | ||
102 | EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); | ||
103 | |||
104 | void 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 | } | ||
110 | EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); | ||
111 | |||
112 | void 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 | } | ||
118 | EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq); | ||
119 | |||
120 | unsigned 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 | } | ||
128 | EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); | ||
129 | |||
130 | void 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 | } | ||
137 | EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); | ||
138 | |||
82 | static inline mm_segment_t snd_enter_user(void) | 139 | static 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 */ | ||
854 | static 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 | ||
900 | static 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; |