diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-12-18 12:48:50 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-12-18 14:31:13 -0500 |
commit | d6a89fefa50feda5516cd5210ad0008a44632b52 (patch) | |
tree | 58d21a68c34ad2d85b1f3fc3b7eb3bc1c3009a89 | |
parent | a08d56583f6b87e2981d1b6e9ee891bdc741cc44 (diff) |
ALSA: AACI: switch to per-pcm locking
We can use finer-grained locking, which makes things easier when
we gain DMA support.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/arm/aaci.c | 49 | ||||
-rw-r--r-- | sound/arm/aaci.h | 2 |
2 files changed, 30 insertions, 21 deletions
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index b377370af2d7..c5699863643b 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c | |||
@@ -172,14 +172,15 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | |||
172 | return v; | 172 | return v; |
173 | } | 173 | } |
174 | 174 | ||
175 | static inline void aaci_chan_wait_ready(struct aaci_runtime *aacirun) | 175 | static inline void |
176 | aaci_chan_wait_ready(struct aaci_runtime *aacirun, unsigned long mask) | ||
176 | { | 177 | { |
177 | u32 val; | 178 | u32 val; |
178 | int timeout = 5000; | 179 | int timeout = 5000; |
179 | 180 | ||
180 | do { | 181 | do { |
181 | val = readl(aacirun->base + AACI_SR); | 182 | val = readl(aacirun->base + AACI_SR); |
182 | } while (val & (SR_TXB|SR_RXB) && timeout--); | 183 | } while (val & mask && timeout--); |
183 | } | 184 | } |
184 | 185 | ||
185 | 186 | ||
@@ -208,8 +209,10 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) | |||
208 | writel(0, aacirun->base + AACI_IE); | 209 | writel(0, aacirun->base + AACI_IE); |
209 | return; | 210 | return; |
210 | } | 211 | } |
211 | ptr = aacirun->ptr; | ||
212 | 212 | ||
213 | spin_lock(&aacirun->lock); | ||
214 | |||
215 | ptr = aacirun->ptr; | ||
213 | do { | 216 | do { |
214 | unsigned int len = aacirun->fifosz; | 217 | unsigned int len = aacirun->fifosz; |
215 | u32 val; | 218 | u32 val; |
@@ -217,9 +220,9 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) | |||
217 | if (aacirun->bytes <= 0) { | 220 | if (aacirun->bytes <= 0) { |
218 | aacirun->bytes += aacirun->period; | 221 | aacirun->bytes += aacirun->period; |
219 | aacirun->ptr = ptr; | 222 | aacirun->ptr = ptr; |
220 | spin_unlock(&aaci->lock); | 223 | spin_unlock(&aacirun->lock); |
221 | snd_pcm_period_elapsed(aacirun->substream); | 224 | snd_pcm_period_elapsed(aacirun->substream); |
222 | spin_lock(&aaci->lock); | 225 | spin_lock(&aacirun->lock); |
223 | } | 226 | } |
224 | if (!(aacirun->cr & CR_EN)) | 227 | if (!(aacirun->cr & CR_EN)) |
225 | break; | 228 | break; |
@@ -245,7 +248,10 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) | |||
245 | ptr = aacirun->start; | 248 | ptr = aacirun->start; |
246 | } | 249 | } |
247 | } while(1); | 250 | } while(1); |
251 | |||
248 | aacirun->ptr = ptr; | 252 | aacirun->ptr = ptr; |
253 | |||
254 | spin_unlock(&aacirun->lock); | ||
249 | } | 255 | } |
250 | 256 | ||
251 | if (mask & ISR_URINTR) { | 257 | if (mask & ISR_URINTR) { |
@@ -263,6 +269,8 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) | |||
263 | return; | 269 | return; |
264 | } | 270 | } |
265 | 271 | ||
272 | spin_lock(&aacirun->lock); | ||
273 | |||
266 | ptr = aacirun->ptr; | 274 | ptr = aacirun->ptr; |
267 | do { | 275 | do { |
268 | unsigned int len = aacirun->fifosz; | 276 | unsigned int len = aacirun->fifosz; |
@@ -271,9 +279,9 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) | |||
271 | if (aacirun->bytes <= 0) { | 279 | if (aacirun->bytes <= 0) { |
272 | aacirun->bytes += aacirun->period; | 280 | aacirun->bytes += aacirun->period; |
273 | aacirun->ptr = ptr; | 281 | aacirun->ptr = ptr; |
274 | spin_unlock(&aaci->lock); | 282 | spin_unlock(&aacirun->lock); |
275 | snd_pcm_period_elapsed(aacirun->substream); | 283 | snd_pcm_period_elapsed(aacirun->substream); |
276 | spin_lock(&aaci->lock); | 284 | spin_lock(&aacirun->lock); |
277 | } | 285 | } |
278 | if (!(aacirun->cr & CR_EN)) | 286 | if (!(aacirun->cr & CR_EN)) |
279 | break; | 287 | break; |
@@ -301,6 +309,8 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) | |||
301 | } while (1); | 309 | } while (1); |
302 | 310 | ||
303 | aacirun->ptr = ptr; | 311 | aacirun->ptr = ptr; |
312 | |||
313 | spin_unlock(&aacirun->lock); | ||
304 | } | 314 | } |
305 | } | 315 | } |
306 | 316 | ||
@@ -310,7 +320,6 @@ static irqreturn_t aaci_irq(int irq, void *devid) | |||
310 | u32 mask; | 320 | u32 mask; |
311 | int i; | 321 | int i; |
312 | 322 | ||
313 | spin_lock(&aaci->lock); | ||
314 | mask = readl(aaci->base + AACI_ALLINTS); | 323 | mask = readl(aaci->base + AACI_ALLINTS); |
315 | if (mask) { | 324 | if (mask) { |
316 | u32 m = mask; | 325 | u32 m = mask; |
@@ -320,7 +329,6 @@ static irqreturn_t aaci_irq(int irq, void *devid) | |||
320 | } | 329 | } |
321 | } | 330 | } |
322 | } | 331 | } |
323 | spin_unlock(&aaci->lock); | ||
324 | 332 | ||
325 | return mask ? IRQ_HANDLED : IRQ_NONE; | 333 | return mask ? IRQ_HANDLED : IRQ_NONE; |
326 | } | 334 | } |
@@ -580,7 +588,7 @@ static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun) | |||
580 | ie &= ~(IE_URIE|IE_TXIE); | 588 | ie &= ~(IE_URIE|IE_TXIE); |
581 | writel(ie, aacirun->base + AACI_IE); | 589 | writel(ie, aacirun->base + AACI_IE); |
582 | aacirun->cr &= ~CR_EN; | 590 | aacirun->cr &= ~CR_EN; |
583 | aaci_chan_wait_ready(aacirun); | 591 | aaci_chan_wait_ready(aacirun, SR_TXB); |
584 | writel(aacirun->cr, aacirun->base + AACI_TXCR); | 592 | writel(aacirun->cr, aacirun->base + AACI_TXCR); |
585 | } | 593 | } |
586 | 594 | ||
@@ -588,7 +596,7 @@ static void aaci_pcm_playback_start(struct aaci_runtime *aacirun) | |||
588 | { | 596 | { |
589 | u32 ie; | 597 | u32 ie; |
590 | 598 | ||
591 | aaci_chan_wait_ready(aacirun); | 599 | aaci_chan_wait_ready(aacirun, SR_TXB); |
592 | aacirun->cr |= CR_EN; | 600 | aacirun->cr |= CR_EN; |
593 | 601 | ||
594 | ie = readl(aacirun->base + AACI_IE); | 602 | ie = readl(aacirun->base + AACI_IE); |
@@ -599,12 +607,12 @@ static void aaci_pcm_playback_start(struct aaci_runtime *aacirun) | |||
599 | 607 | ||
600 | static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) | 608 | static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) |
601 | { | 609 | { |
602 | struct aaci *aaci = substream->private_data; | ||
603 | struct aaci_runtime *aacirun = substream->runtime->private_data; | 610 | struct aaci_runtime *aacirun = substream->runtime->private_data; |
604 | unsigned long flags; | 611 | unsigned long flags; |
605 | int ret = 0; | 612 | int ret = 0; |
606 | 613 | ||
607 | spin_lock_irqsave(&aaci->lock, flags); | 614 | spin_lock_irqsave(&aacirun->lock, flags); |
615 | |||
608 | switch (cmd) { | 616 | switch (cmd) { |
609 | case SNDRV_PCM_TRIGGER_START: | 617 | case SNDRV_PCM_TRIGGER_START: |
610 | aaci_pcm_playback_start(aacirun); | 618 | aaci_pcm_playback_start(aacirun); |
@@ -631,7 +639,8 @@ static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cm | |||
631 | default: | 639 | default: |
632 | ret = -EINVAL; | 640 | ret = -EINVAL; |
633 | } | 641 | } |
634 | spin_unlock_irqrestore(&aaci->lock, flags); | 642 | |
643 | spin_unlock_irqrestore(&aacirun->lock, flags); | ||
635 | 644 | ||
636 | return ret; | 645 | return ret; |
637 | } | 646 | } |
@@ -666,7 +675,7 @@ static void aaci_pcm_capture_stop(struct aaci_runtime *aacirun) | |||
666 | { | 675 | { |
667 | u32 ie; | 676 | u32 ie; |
668 | 677 | ||
669 | aaci_chan_wait_ready(aacirun); | 678 | aaci_chan_wait_ready(aacirun, SR_RXB); |
670 | 679 | ||
671 | ie = readl(aacirun->base + AACI_IE); | 680 | ie = readl(aacirun->base + AACI_IE); |
672 | ie &= ~(IE_ORIE | IE_RXIE); | 681 | ie &= ~(IE_ORIE | IE_RXIE); |
@@ -681,7 +690,7 @@ static void aaci_pcm_capture_start(struct aaci_runtime *aacirun) | |||
681 | { | 690 | { |
682 | u32 ie; | 691 | u32 ie; |
683 | 692 | ||
684 | aaci_chan_wait_ready(aacirun); | 693 | aaci_chan_wait_ready(aacirun, SR_RXB); |
685 | 694 | ||
686 | #ifdef DEBUG | 695 | #ifdef DEBUG |
687 | /* RX Timeout value: bits 28:17 in RXCR */ | 696 | /* RX Timeout value: bits 28:17 in RXCR */ |
@@ -698,12 +707,11 @@ static void aaci_pcm_capture_start(struct aaci_runtime *aacirun) | |||
698 | 707 | ||
699 | static int aaci_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) | 708 | static int aaci_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) |
700 | { | 709 | { |
701 | struct aaci *aaci = substream->private_data; | ||
702 | struct aaci_runtime *aacirun = substream->runtime->private_data; | 710 | struct aaci_runtime *aacirun = substream->runtime->private_data; |
703 | unsigned long flags; | 711 | unsigned long flags; |
704 | int ret = 0; | 712 | int ret = 0; |
705 | 713 | ||
706 | spin_lock_irqsave(&aaci->lock, flags); | 714 | spin_lock_irqsave(&aacirun->lock, flags); |
707 | 715 | ||
708 | switch (cmd) { | 716 | switch (cmd) { |
709 | case SNDRV_PCM_TRIGGER_START: | 717 | case SNDRV_PCM_TRIGGER_START: |
@@ -732,7 +740,7 @@ static int aaci_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd | |||
732 | ret = -EINVAL; | 740 | ret = -EINVAL; |
733 | } | 741 | } |
734 | 742 | ||
735 | spin_unlock_irqrestore(&aaci->lock, flags); | 743 | spin_unlock_irqrestore(&aacirun->lock, flags); |
736 | 744 | ||
737 | return ret; | 745 | return ret; |
738 | } | 746 | } |
@@ -933,7 +941,6 @@ static struct aaci * __devinit aaci_init_card(struct amba_device *dev) | |||
933 | 941 | ||
934 | aaci = card->private_data; | 942 | aaci = card->private_data; |
935 | mutex_init(&aaci->ac97_sem); | 943 | mutex_init(&aaci->ac97_sem); |
936 | spin_lock_init(&aaci->lock); | ||
937 | aaci->card = card; | 944 | aaci->card = card; |
938 | aaci->dev = dev; | 945 | aaci->dev = dev; |
939 | 946 | ||
@@ -1020,12 +1027,14 @@ static int __devinit aaci_probe(struct amba_device *dev, struct amba_id *id) | |||
1020 | /* | 1027 | /* |
1021 | * Playback uses AACI channel 0 | 1028 | * Playback uses AACI channel 0 |
1022 | */ | 1029 | */ |
1030 | spin_lock_init(&aaci->playback.lock); | ||
1023 | aaci->playback.base = aaci->base + AACI_CSCH1; | 1031 | aaci->playback.base = aaci->base + AACI_CSCH1; |
1024 | aaci->playback.fifo = aaci->base + AACI_DR1; | 1032 | aaci->playback.fifo = aaci->base + AACI_DR1; |
1025 | 1033 | ||
1026 | /* | 1034 | /* |
1027 | * Capture uses AACI channel 0 | 1035 | * Capture uses AACI channel 0 |
1028 | */ | 1036 | */ |
1037 | spin_lock_init(&aaci->capture.lock); | ||
1029 | aaci->capture.base = aaci->base + AACI_CSCH1; | 1038 | aaci->capture.base = aaci->base + AACI_CSCH1; |
1030 | aaci->capture.fifo = aaci->base + AACI_DR1; | 1039 | aaci->capture.fifo = aaci->base + AACI_DR1; |
1031 | 1040 | ||
diff --git a/sound/arm/aaci.h b/sound/arm/aaci.h index 924f69c1c44c..6a4a2eebdda1 100644 --- a/sound/arm/aaci.h +++ b/sound/arm/aaci.h | |||
@@ -202,6 +202,7 @@ | |||
202 | struct aaci_runtime { | 202 | struct aaci_runtime { |
203 | void __iomem *base; | 203 | void __iomem *base; |
204 | void __iomem *fifo; | 204 | void __iomem *fifo; |
205 | spinlock_t lock; | ||
205 | 206 | ||
206 | struct ac97_pcm *pcm; | 207 | struct ac97_pcm *pcm; |
207 | int pcm_open; | 208 | int pcm_open; |
@@ -232,7 +233,6 @@ struct aaci { | |||
232 | struct snd_ac97 *ac97; | 233 | struct snd_ac97 *ac97; |
233 | 234 | ||
234 | u32 maincr; | 235 | u32 maincr; |
235 | spinlock_t lock; | ||
236 | 236 | ||
237 | struct aaci_runtime playback; | 237 | struct aaci_runtime playback; |
238 | struct aaci_runtime capture; | 238 | struct aaci_runtime capture; |