aboutsummaryrefslogtreecommitdiffstats
path: root/include/sound/hdaudio.h
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-04-08 05:43:14 -0400
committerTakashi Iwai <tiwai@suse.de>2015-04-08 07:50:42 -0400
commit664c715573c2c116c2d8f5de7d59ce85a98a1751 (patch)
tree78629587a6d0ddfc478fa59d0248baa815f7132f /include/sound/hdaudio.h
parent142267c9e026827ca5fa622f1f13780b6db26cf8 (diff)
ALSA: hda - Work around races of power up/down with runtime PM
Currently, snd_hdac_power_up()/down() helpers checks whether the codec is being in pm (suspend/resume), and skips the call of runtime get/put during it. This is needed as there are lots of power up/down sequences called in the paths that are also used in the PM itself. An example is found in hda_codec.c::codec_exec_verb(), where this can power up the codec while it may be called again in its power up sequence, too. The above works in most cases, but sometimes we really want to wait for the real power up. For example, the control element get/put may want explicit power up so that the value change is assured to reach to the hardware. Using the current snd_hdac_power_up(), however, results in a race, e.g. when it's called during the runtime suspend is being performed. In the worst case, as found in patch_ca0132.c, it can even lead to the deadlock because the code assumes the power up while it was skipped due to the check above. For dealing with such cases, this patch makes snd_hdac_power_up() and _down() to two variants: with and without in_pm flag check. The version with pm flag check is named as snd_hdac_power_up_pm() while the version without pm flag check is still kept as snd_hdac_power_up(). (Just because the usage of the former is fewer.) Then finally, the patch replaces each call potentially done in PM with the new _pm() variant. In theory, we can implement a unified version -- if we can distinguish the current context whether it's in the pm path. But such an implementation is cumbersome, so leave the code like this a bit messy way for now... Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=96271 Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'include/sound/hdaudio.h')
-rw-r--r--include/sound/hdaudio.h28
1 files changed, 28 insertions, 0 deletions
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 95acc337aea5..30446f17c6a6 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -144,6 +144,34 @@ static inline void snd_hdac_power_up(struct hdac_device *codec) {}
144static inline void snd_hdac_power_down(struct hdac_device *codec) {} 144static inline void snd_hdac_power_down(struct hdac_device *codec) {}
145#endif 145#endif
146 146
147/**
148 * snd_hdac_power_up_pm - power up the codec
149 * @codec: the codec object
150 *
151 * This function can be called in a recursive code path like init code
152 * which may be called by PM suspend/resume again. OTOH, if a power-up
153 * call must wake up the sleeper (e.g. in a kctl callback), use
154 * snd_hdac_power_up() instead.
155 */
156static inline void snd_hdac_power_up_pm(struct hdac_device *codec)
157{
158 if (!atomic_read(&codec->in_pm))
159 snd_hdac_power_up(codec);
160}
161
162/**
163 * snd_hdac_power_down_pm - power down the codec
164 * @codec: the codec object
165 *
166 * Like snd_hdac_power_up_pm(), this function is used in a recursive
167 * code path like init code which may be called by PM suspend/resume again.
168 */
169static inline void snd_hdac_power_down_pm(struct hdac_device *codec)
170{
171 if (!atomic_read(&codec->in_pm))
172 snd_hdac_power_down(codec);
173}
174
147/* 175/*
148 * HD-audio codec base driver 176 * HD-audio codec base driver
149 */ 177 */