diff options
author | Andres Salomon <dilinger@debian.org> | 2007-09-03 09:42:16 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2007-10-16 09:59:52 -0400 |
commit | 222fa0b0d2fdb2373a71d532c2cabd2ec920b3b3 (patch) | |
tree | fff88e0f8be8540b1fd74cc7f7d7b9fec783a8f4 /sound/pci/cs5535audio/cs5535audio_pm.c | |
parent | 7abcacb09ac0f9c6848f1e7d86b284427fa83cee (diff) |
[ALSA] cs5535audio: fix PRD register save/restore power management race
In the suspend path, we currently save the PRD registers and then disable DMA.
This is racy; the sound hardware might update the PRD register as it finishes
processing some DMA pages between when we've saved the PRD registers and
when DMA actually gets disabled. Furthermore, we actively check whether or
not DMA is enabled before saving PRD registers; there's no reason to do that,
as the PRD registers should not update when we twiddle the ACC_BM[x]_CMD
register(s). Worst case, we save the PRD registers twice; even powering
down the ACC shouldn't mess with the PRD registers (according to the 5536
data sheet, section 5.3.7.4, power-down procedure). This patch reworks
all that to first disable DMA, and then save PRD registers.
Signed-off-by: Andres Salomon <dilinger@debian.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/pci/cs5535audio/cs5535audio_pm.c')
-rw-r--r-- | sound/pci/cs5535audio/cs5535audio_pm.c | 14 |
1 files changed, 7 insertions, 7 deletions
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c index 3e4d198a4502..9a4e84aa3e04 100644 --- a/sound/pci/cs5535audio/cs5535audio_pm.c +++ b/sound/pci/cs5535audio/cs5535audio_pm.c | |||
@@ -64,13 +64,13 @@ int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state) | |||
64 | int i; | 64 | int i; |
65 | 65 | ||
66 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 66 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
67 | snd_pcm_suspend_all(cs5535au->pcm); | ||
68 | snd_ac97_suspend(cs5535au->ac97); | ||
67 | for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { | 69 | for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { |
68 | struct cs5535audio_dma *dma = &cs5535au->dmas[i]; | 70 | struct cs5535audio_dma *dma = &cs5535au->dmas[i]; |
69 | if (dma && dma->substream && !dma->suspended) | 71 | if (dma && dma->substream) |
70 | dma->saved_prd = dma->ops->read_prd(cs5535au); | 72 | dma->saved_prd = dma->ops->read_prd(cs5535au); |
71 | } | 73 | } |
72 | snd_pcm_suspend_all(cs5535au->pcm); | ||
73 | snd_ac97_suspend(cs5535au->ac97); | ||
74 | /* save important regs, then disable aclink in hw */ | 74 | /* save important regs, then disable aclink in hw */ |
75 | snd_cs5535audio_stop_hardware(cs5535au); | 75 | snd_cs5535audio_stop_hardware(cs5535au); |
76 | 76 | ||
@@ -112,17 +112,17 @@ int snd_cs5535audio_resume(struct pci_dev *pci) | |||
112 | if (!timeout) | 112 | if (!timeout) |
113 | snd_printk(KERN_ERR "Failure getting AC Link ready\n"); | 113 | snd_printk(KERN_ERR "Failure getting AC Link ready\n"); |
114 | 114 | ||
115 | /* we depend on ac97 to perform the codec power up */ | ||
116 | snd_ac97_resume(cs5535au->ac97); | ||
117 | /* set up rate regs, dma. actual initiation is done in trig */ | 115 | /* set up rate regs, dma. actual initiation is done in trig */ |
118 | for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { | 116 | for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { |
119 | struct cs5535audio_dma *dma = &cs5535au->dmas[i]; | 117 | struct cs5535audio_dma *dma = &cs5535au->dmas[i]; |
120 | if (dma && dma->substream && dma->suspended) { | 118 | if (dma && dma->substream) { |
121 | dma->substream->ops->prepare(dma->substream); | 119 | dma->substream->ops->prepare(dma->substream); |
122 | dma->ops->setup_prd(cs5535au, dma->saved_prd); | 120 | dma->ops->setup_prd(cs5535au, dma->saved_prd); |
123 | } | 121 | } |
124 | } | 122 | } |
125 | 123 | ||
124 | /* we depend on ac97 to perform the codec power up */ | ||
125 | snd_ac97_resume(cs5535au->ac97); | ||
126 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | 126 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); |
127 | 127 | ||
128 | return 0; | 128 | return 0; |