Commit 68467f51 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Fix runtime PM leftover refcounts

When the HD-audio is removed, it leaves the refcounts when codecs are
powered up (usually yes) in the destructor.  For fixing the unbalance,
and cleaning up the code mess, this patch changes the following:
- change pm_notify callback to take the explicit power on/off state,
- check of D3 stop-clock and keep_link_on flags is moved to the caller
  side,
- call pm_notify callback in snd_hda_codec_new() and snd_hda_codec_free()
  so that the refcounts are proprely updated.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 48ee7cb8
...@@ -98,9 +98,15 @@ EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset); ...@@ -98,9 +98,15 @@ EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset);
static void hda_power_work(struct work_struct *work); static void hda_power_work(struct work_struct *work);
static void hda_keep_power_on(struct hda_codec *codec); static void hda_keep_power_on(struct hda_codec *codec);
#define hda_codec_is_power_on(codec) ((codec)->power_on) #define hda_codec_is_power_on(codec) ((codec)->power_on)
static inline void hda_call_pm_notify(struct hda_bus *bus, bool power_up)
{
if (bus->ops.pm_notify)
bus->ops.pm_notify(bus, power_up);
}
#else #else
static inline void hda_keep_power_on(struct hda_codec *codec) {} static inline void hda_keep_power_on(struct hda_codec *codec) {}
#define hda_codec_is_power_on(codec) 1 #define hda_codec_is_power_on(codec) 1
#define hda_call_pm_notify(bus, state) {}
#endif #endif
/** /**
...@@ -1199,6 +1205,10 @@ static void snd_hda_codec_free(struct hda_codec *codec) ...@@ -1199,6 +1205,10 @@ static void snd_hda_codec_free(struct hda_codec *codec)
codec->bus->caddr_tbl[codec->addr] = NULL; codec->bus->caddr_tbl[codec->addr] = NULL;
if (codec->patch_ops.free) if (codec->patch_ops.free)
codec->patch_ops.free(codec); codec->patch_ops.free(codec);
#ifdef CONFIG_SND_HDA_POWER_SAVE
if (codec->power_on)
hda_call_pm_notify(codec->bus, false);
#endif
module_put(codec->owner); module_put(codec->owner);
free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->amp_cache);
free_hda_cache(&codec->cmd_cache); free_hda_cache(&codec->cmd_cache);
...@@ -1271,6 +1281,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, ...@@ -1271,6 +1281,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
* phase. * phase.
*/ */
hda_keep_power_on(codec); hda_keep_power_on(codec);
hda_call_pm_notify(bus, true);
#endif #endif
if (codec->bus->modelname) { if (codec->bus->modelname) {
...@@ -3576,7 +3587,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, ...@@ -3576,7 +3587,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
} }
#ifdef CONFIG_SND_HDA_POWER_SAVE #ifdef CONFIG_SND_HDA_POWER_SAVE
if ((power_state == AC_PWRST_D3) if (!codec->bus->power_keep_link_on && power_state == AC_PWRST_D3
&& codec->d3_stop_clk && (state & AC_PWRST_CLK_STOP_OK)) && codec->d3_stop_clk && (state & AC_PWRST_CLK_STOP_OK))
codec->d3_stop_clk_ok = 1; codec->d3_stop_clk_ok = 1;
#endif #endif
...@@ -4430,8 +4441,8 @@ static void hda_power_work(struct work_struct *work) ...@@ -4430,8 +4441,8 @@ static void hda_power_work(struct work_struct *work)
spin_unlock(&codec->power_lock); spin_unlock(&codec->power_lock);
hda_call_codec_suspend(codec); hda_call_codec_suspend(codec);
if (bus->ops.pm_notify) if (codec->d3_stop_clk_ok)
bus->ops.pm_notify(bus, codec); hda_call_pm_notify(bus, false);
} }
static void hda_keep_power_on(struct hda_codec *codec) static void hda_keep_power_on(struct hda_codec *codec)
...@@ -4488,8 +4499,8 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) ...@@ -4488,8 +4499,8 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
codec->power_transition = 1; /* avoid reentrance */ codec->power_transition = 1; /* avoid reentrance */
spin_unlock(&codec->power_lock); spin_unlock(&codec->power_lock);
if (bus->ops.pm_notify) if (codec->d3_stop_clk_ok) /* flag set at suspend */
bus->ops.pm_notify(bus, codec); hda_call_pm_notify(bus, true);
hda_call_codec_resume(codec); hda_call_codec_resume(codec);
spin_lock(&codec->power_lock); spin_lock(&codec->power_lock);
......
...@@ -616,7 +616,7 @@ struct hda_bus_ops { ...@@ -616,7 +616,7 @@ struct hda_bus_ops {
void (*bus_reset)(struct hda_bus *bus); void (*bus_reset)(struct hda_bus *bus);
#ifdef CONFIG_SND_HDA_POWER_SAVE #ifdef CONFIG_SND_HDA_POWER_SAVE
/* notify power-up/down from codec to controller */ /* notify power-up/down from codec to controller */
void (*pm_notify)(struct hda_bus *bus, struct hda_codec *codec); void (*pm_notify)(struct hda_bus *bus, bool power_up);
#endif #endif
}; };
......
...@@ -1033,7 +1033,7 @@ static unsigned int azx_get_response(struct hda_bus *bus, ...@@ -1033,7 +1033,7 @@ static unsigned int azx_get_response(struct hda_bus *bus,
} }
#ifdef CONFIG_SND_HDA_POWER_SAVE #ifdef CONFIG_SND_HDA_POWER_SAVE
static void azx_power_notify(struct hda_bus *bus, struct hda_codec *codec); static void azx_power_notify(struct hda_bus *bus, bool power_up);
#endif #endif
/* reset codec link */ /* reset codec link */
...@@ -2406,14 +2406,11 @@ static void azx_stop_chip(struct azx *chip) ...@@ -2406,14 +2406,11 @@ static void azx_stop_chip(struct azx *chip)
#ifdef CONFIG_SND_HDA_POWER_SAVE #ifdef CONFIG_SND_HDA_POWER_SAVE
/* power-up/down the controller */ /* power-up/down the controller */
static void azx_power_notify(struct hda_bus *bus, struct hda_codec *codec) static void azx_power_notify(struct hda_bus *bus, bool power_up)
{ {
struct azx *chip = bus->private_data; struct azx *chip = bus->private_data;
if (bus->power_keep_link_on || !codec->d3_stop_clk_ok) if (power_up)
return;
if (codec->power_on)
pm_runtime_get_sync(&chip->pci->dev); pm_runtime_get_sync(&chip->pci->dev);
else else
pm_runtime_put_sync(&chip->pci->dev); pm_runtime_put_sync(&chip->pci->dev);
...@@ -3273,15 +3270,6 @@ static void azx_firmware_cb(const struct firmware *fw, void *context) ...@@ -3273,15 +3270,6 @@ static void azx_firmware_cb(const struct firmware *fw, void *context)
} }
#endif #endif
static void rpm_get_all_codecs(struct azx *chip)
{
struct hda_codec *codec;
list_for_each_entry(codec, &chip->bus->codec_list, list) {
pm_runtime_get_noresume(&chip->pci->dev);
}
}
static int __devinit azx_probe(struct pci_dev *pci, static int __devinit azx_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id) const struct pci_device_id *pci_id)
{ {
...@@ -3388,7 +3376,6 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip) ...@@ -3388,7 +3376,6 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip)
goto out_free; goto out_free;
chip->running = 1; chip->running = 1;
rpm_get_all_codecs(chip); /* all codecs are active */
power_down_all_codecs(chip); power_down_all_codecs(chip);
azx_notifier_register(chip); azx_notifier_register(chip);
azx_add_card_list(chip); azx_add_card_list(chip);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment