aboutsummaryrefslogtreecommitdiffstats
path: root/sound/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-04-13 05:01:14 -0400
committerTakashi Iwai <tiwai@suse.de>2015-04-13 05:07:20 -0400
commitc3aeda62878f09da91329693a60a1f08ec97e0b8 (patch)
tree5b07fb0e0aeddc6cfb5b4b0b5f0151a679e62c4d /sound/hda
parenteacf6e0a238923dfce0626450adcb6d486072f28 (diff)
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 'sound/hda')
-rw-r--r--sound/hda/hdac_device.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c
index 92604bbcee5f..f75bf5622687 100644
--- a/sound/hda/hdac_device.c
+++ b/sound/hda/hdac_device.c
@@ -519,6 +519,36 @@ void snd_hdac_power_down(struct hdac_device *codec)
519 pm_runtime_put_autosuspend(dev); 519 pm_runtime_put_autosuspend(dev);
520} 520}
521EXPORT_SYMBOL_GPL(snd_hdac_power_down); 521EXPORT_SYMBOL_GPL(snd_hdac_power_down);
522
523/**
524 * snd_hdac_power_up_pm - power up the codec
525 * @codec: the codec object
526 *
527 * This function can be called in a recursive code path like init code
528 * which may be called by PM suspend/resume again. OTOH, if a power-up
529 * call must wake up the sleeper (e.g. in a kctl callback), use
530 * snd_hdac_power_up() instead.
531 */
532void snd_hdac_power_up_pm(struct hdac_device *codec)
533{
534 if (!atomic_inc_not_zero(&codec->in_pm))
535 snd_hdac_power_up(codec);
536}
537EXPORT_SYMBOL_GPL(snd_hdac_power_up_pm);
538
539/**
540 * snd_hdac_power_down_pm - power down the codec
541 * @codec: the codec object
542 *
543 * Like snd_hdac_power_up_pm(), this function is used in a recursive
544 * code path like init code which may be called by PM suspend/resume again.
545 */
546void snd_hdac_power_down_pm(struct hdac_device *codec)
547{
548 if (atomic_dec_if_positive(&codec->in_pm) < 0)
549 snd_hdac_power_down(codec);
550}
551EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm);
522#endif 552#endif
523 553
524/* codec vendor labels */ 554/* codec vendor labels */