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>
This commit is contained in:
parent
eacf6e0a23
commit
c3aeda6287
|
@ -139,39 +139,15 @@ static inline int snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid,
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
void snd_hdac_power_up(struct hdac_device *codec);
|
void snd_hdac_power_up(struct hdac_device *codec);
|
||||||
void snd_hdac_power_down(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
|
#else
|
||||||
static inline void snd_hdac_power_up(struct hdac_device *codec) {}
|
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_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
|
#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
|
* HD-audio codec base driver
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -519,6 +519,36 @@ void snd_hdac_power_down(struct hdac_device *codec)
|
||||||
pm_runtime_put_autosuspend(dev);
|
pm_runtime_put_autosuspend(dev);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(snd_hdac_power_down);
|
EXPORT_SYMBOL_GPL(snd_hdac_power_down);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
void snd_hdac_power_up_pm(struct hdac_device *codec)
|
||||||
|
{
|
||||||
|
if (!atomic_inc_not_zero(&codec->in_pm))
|
||||||
|
snd_hdac_power_up(codec);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(snd_hdac_power_up_pm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
void snd_hdac_power_down_pm(struct hdac_device *codec)
|
||||||
|
{
|
||||||
|
if (atomic_dec_if_positive(&codec->in_pm) < 0)
|
||||||
|
snd_hdac_power_down(codec);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* codec vendor labels */
|
/* codec vendor labels */
|
||||||
|
|
Loading…
Reference in New Issue