Skip to content

Commit 08fa20a

Browse files
committed
ALSA: hda - Yet another fix for D3 stop-clock refcounting
The call of pm_notify callback in snd_hda_codec_free() should be with the check of the current state whether pm_notify(false) is called or not, instead of codec->power_on check. For improving the code readability and fixing this inconsistency, codec->d3_stop_clk_ok is renamed to codec->pm_down_notified, and this flag is set only when runtime PM down is called. The new name reflects to a more direct purpose of the flag. Signed-off-by: Takashi Iwai <[email protected]>
1 parent 5a79839 commit 08fa20a

File tree

2 files changed

+23
-20
lines changed

2 files changed

+23
-20
lines changed

sound/pci/hda/hda_codec.c

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,7 +1206,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
12061206
if (codec->patch_ops.free)
12071207
codec->patch_ops.free(codec);
12081208
#ifdef CONFIG_PM
1209-
if (codec->power_on)
1209+
if (!codec->pm_down_notified) /* cancel leftover refcounts */
12101210
hda_call_pm_notify(codec->bus, false);
12111211
#endif
12121212
module_put(codec->owner);
@@ -1222,7 +1222,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
12221222
static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
12231223
hda_nid_t fg, unsigned int power_state);
12241224

1225-
static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
1225+
static unsigned int hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
12261226
unsigned int power_state);
12271227

12281228
/**
@@ -3564,18 +3564,14 @@ static unsigned int hda_sync_power_state(struct hda_codec *codec,
35643564
}
35653565

35663566
/*
3567-
* set power state of the codec
3567+
* set power state of the codec, and return the power state
35683568
*/
3569-
static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
3570-
unsigned int power_state)
3569+
static unsigned int hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
3570+
unsigned int power_state)
35713571
{
35723572
int count;
35733573
unsigned int state;
35743574

3575-
#ifdef CONFIG_PM
3576-
codec->d3_stop_clk_ok = 0;
3577-
#endif
3578-
35793575
/* this delay seems necessary to avoid click noise at power-down */
35803576
if (power_state == AC_PWRST_D3) {
35813577
/* transition time less than 10ms for power down */
@@ -3599,11 +3595,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
35993595
break;
36003596
}
36013597

3602-
#ifdef CONFIG_PM
3603-
if (!codec->bus->power_keep_link_on && power_state == AC_PWRST_D3
3604-
&& codec->d3_stop_clk && (state & AC_PWRST_CLK_STOP_OK))
3605-
codec->d3_stop_clk_ok = 1;
3606-
#endif
3598+
return state;
36073599
}
36083600

36093601
#ifdef CONFIG_SND_HDA_HWDEP
@@ -3620,13 +3612,16 @@ static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
36203612
#ifdef CONFIG_PM
36213613
/*
36223614
* call suspend and power-down; used both from PM and power-save
3615+
* this function returns the power state in the end
36233616
*/
3624-
static void hda_call_codec_suspend(struct hda_codec *codec)
3617+
static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
36253618
{
3619+
unsigned int state;
3620+
36263621
if (codec->patch_ops.suspend)
36273622
codec->patch_ops.suspend(codec);
36283623
hda_cleanup_all_streams(codec);
3629-
hda_set_power_state(codec,
3624+
state = hda_set_power_state(codec,
36303625
codec->afg ? codec->afg : codec->mfg,
36313626
AC_PWRST_D3);
36323627
cancel_delayed_work(&codec->power_work);
@@ -3637,6 +3632,7 @@ static void hda_call_codec_suspend(struct hda_codec *codec)
36373632
codec->power_transition = 0;
36383633
codec->power_jiffies = jiffies;
36393634
spin_unlock(&codec->power_lock);
3635+
return state;
36403636
}
36413637

36423638
/*
@@ -4438,6 +4434,7 @@ static void hda_power_work(struct work_struct *work)
44384434
struct hda_codec *codec =
44394435
container_of(work, struct hda_codec, power_work.work);
44404436
struct hda_bus *bus = codec->bus;
4437+
unsigned int state;
44414438

44424439
spin_lock(&codec->power_lock);
44434440
if (codec->power_transition > 0) { /* during power-up sequence? */
@@ -4451,9 +4448,12 @@ static void hda_power_work(struct work_struct *work)
44514448
}
44524449
spin_unlock(&codec->power_lock);
44534450

4454-
hda_call_codec_suspend(codec);
4455-
if (codec->d3_stop_clk_ok)
4451+
state = hda_call_codec_suspend(codec);
4452+
codec->pm_down_notified = 0;
4453+
if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) {
4454+
codec->pm_down_notified = 1;
44564455
hda_call_pm_notify(bus, false);
4456+
}
44574457
}
44584458

44594459
static void hda_keep_power_on(struct hda_codec *codec)
@@ -4510,8 +4510,11 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
45104510
codec->power_transition = 1; /* avoid reentrance */
45114511
spin_unlock(&codec->power_lock);
45124512

4513-
if (codec->d3_stop_clk_ok) /* flag set at suspend */
4513+
if (codec->pm_down_notified) {
4514+
codec->pm_down_notified = 0;
45144515
hda_call_pm_notify(bus, true);
4516+
}
4517+
45154518
hda_call_codec_resume(codec);
45164519

45174520
spin_lock(&codec->power_lock);

sound/pci/hda/hda_codec.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,7 @@ struct hda_codec {
868868
#ifdef CONFIG_PM
869869
unsigned int power_on :1; /* current (global) power-state */
870870
unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */
871-
unsigned int d3_stop_clk_ok:1; /* BCLK can stop */
871+
unsigned int pm_down_notified:1; /* PM notified to controller */
872872
int power_transition; /* power-state in transition */
873873
int power_count; /* current (global) power refcount */
874874
struct delayed_work power_work; /* delayed task for powerdown */

0 commit comments

Comments
 (0)