diff options
author | Takashi Iwai <tiwai@suse.de> | 2015-04-13 12:01:14 +0300 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-04-13 12:07:20 +0300 |
commit | c3aeda62878f09da91329693a60a1f08ec97e0b8 (patch) | |
tree | 5b07fb0e0aeddc6cfb5b4b0b5f0151a679e62c4d /include | |
parent | eacf6e0a238923dfce0626450adcb6d486072f28 (diff) | |
download | linux-c3aeda62878f09da91329693a60a1f08ec97e0b8.tar.xz |
ALSA: hda - Fix another race in runtime PM refcounting
Although some races in runtime PM refcount was fixed by the commit
[664c715573c2: ALSA: hda - Work around races of power up/down with
runtime PM], there is still a race in the following case:
CPU0: CPU1 :
runtime suspend:
codec->in_pm = 1
snd_hdac_power_up_pm():
pm_runtime_get_sync() skipped
suspend finished:
codec->in_pm = 0
snd_hdac_power_down_pm():
pm_runtime_put_*() is called!
For avoiding this situation, increment in_pm flag atomically when it's
non-zero, and decrement accordingly, to ensure that in_pm is set
consistently for the whole concurrent operations.
Also, since atomic_inc_not_zero() and atomic_dec_if_positive() are
lengthy inline functions, move snd_hdac_power_up_pm() and _down_pm()
to sound/hda/hdac_device.c as no inline functions.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'include')
-rw-r--r-- | include/sound/hdaudio.h | 32 |
1 files changed, 4 insertions, 28 deletions
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 30446f17c6a6..2a8aa9dfb83d 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -139,39 +139,15 @@ static inline int snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, #ifdef CONFIG_PM void snd_hdac_power_up(struct hdac_device *codec); void snd_hdac_power_down(struct hdac_device *codec); +void snd_hdac_power_up_pm(struct hdac_device *codec); +void snd_hdac_power_down_pm(struct hdac_device *codec); #else static inline void snd_hdac_power_up(struct hdac_device *codec) {} static inline void snd_hdac_power_down(struct hdac_device *codec) {} +static inline void snd_hdac_power_up_pm(struct hdac_device *codec) {} +static inline void snd_hdac_power_down_pm(struct hdac_device *codec) {} #endif -/** - * snd_hdac_power_up_pm - power up the codec - * @codec: the codec object - * - * This function can be called in a recursive code path like init code - * which may be called by PM suspend/resume again. OTOH, if a power-up - * call must wake up the sleeper (e.g. in a kctl callback), use - * snd_hdac_power_up() instead. - */ -static inline void snd_hdac_power_up_pm(struct hdac_device *codec) -{ - if (!atomic_read(&codec->in_pm)) - snd_hdac_power_up(codec); -} - -/** - * snd_hdac_power_down_pm - power down the codec - * @codec: the codec object - * - * Like snd_hdac_power_up_pm(), this function is used in a recursive - * code path like init code which may be called by PM suspend/resume again. - */ -static inline void snd_hdac_power_down_pm(struct hdac_device *codec) -{ - if (!atomic_read(&codec->in_pm)) - snd_hdac_power_down(codec); -} - /* * HD-audio codec base driver */ |