diff mbox series

[1/4] ALSA: hda: Refactor codec PM to use direct-complete optimization

Message ID 20201023102340.25494-1-kai.heng.feng@canonical.com (mailing list archive)
State Superseded
Headers show
Series [1/4] ALSA: hda: Refactor codec PM to use direct-complete optimization | expand

Commit Message

Kai-Heng Feng Oct. 23, 2020, 10:23 a.m. UTC
Upon system resume, hda_codec_pm_resume() uses hda_codec_force_resume()
to resume the codec. However, pm_runtime_force_resume() won't really
resume the codec because of pm_runtime_need_not_resume() check.

Hence, hda_codec_force_resume() schedules a jackpoll work, which is to
really power up the codec.

Instead of doing that, we can use direct-complete to make the PM flow
more straightforward, and keep codec always suspended through system PM
flow if conditions are met.

On system suspend, PM core will decide what to do based on
hda_codec_pm_prepare():
- If codec is not runtime-suspended, PM core will suspend and resume the
device as normal.
- If codec is runtime-suspended, PM core will try to keep it suspended.
If it's still suspended after system resume, we use
hda_codec_pm_complete() to resume codec if it's needed.

Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
 sound/pci/hda/hda_codec.c | 45 +++++++++++++++++++++++++--------------
 1 file changed, 29 insertions(+), 16 deletions(-)

Comments

Takashi Iwai Oct. 23, 2020, 11:32 a.m. UTC | #1
On Fri, 23 Oct 2020 12:23:35 +0200,
Kai-Heng Feng wrote:
> 
> +static void hda_codec_pm_complete(struct device *dev)
>  {
>  	struct hda_codec *codec = dev_to_hda_codec(dev);
> -	int ret;
>  
> -	ret = pm_runtime_force_resume(dev);
> -	/* schedule jackpoll work for jack detection update */
> -	if (codec->jackpoll_interval ||
> -	    (pm_runtime_suspended(dev) && hda_codec_need_resume(codec)))
> -		schedule_delayed_work(&codec->jackpoll_work,
> -				      codec->jackpoll_interval);
> -	return ret;
> +	if (pm_runtime_suspended(dev) &&
> +	    (hda_codec_need_resume(codec) || codec->forced_resume))
> +		pm_request_resume(dev);

You shouldn't drop the check of codec->jackpoll_interval.  If this
field is set, the codec driver has to resume no matter what it was, so
that the polling can start up again.


thanks,

Takashi
Kai-Heng Feng Oct. 23, 2020, 12:44 p.m. UTC | #2
> On Oct 23, 2020, at 19:32, Takashi Iwai <tiwai@suse.de> wrote:
> 
> On Fri, 23 Oct 2020 12:23:35 +0200,
> Kai-Heng Feng wrote:
>> 
>> +static void hda_codec_pm_complete(struct device *dev)
>> {
>> 	struct hda_codec *codec = dev_to_hda_codec(dev);
>> -	int ret;
>> 
>> -	ret = pm_runtime_force_resume(dev);
>> -	/* schedule jackpoll work for jack detection update */
>> -	if (codec->jackpoll_interval ||
>> -	    (pm_runtime_suspended(dev) && hda_codec_need_resume(codec)))
>> -		schedule_delayed_work(&codec->jackpoll_work,
>> -				      codec->jackpoll_interval);
>> -	return ret;
>> +	if (pm_runtime_suspended(dev) &&
>> +	    (hda_codec_need_resume(codec) || codec->forced_resume))
>> +		pm_request_resume(dev);
> 
> You shouldn't drop the check of codec->jackpoll_interval.  If this
> field is set, the codec driver has to resume no matter what it was, so
> that the polling can start up again.

Ok, will address in v2.

Kai-Heng

> 
> 
> thanks,
> 
> Takashi
Takashi Iwai Oct. 23, 2020, 1:04 p.m. UTC | #3
On Fri, 23 Oct 2020 14:44:18 +0200,
Kai-Heng Feng wrote:
> 
> 
> 
> > On Oct 23, 2020, at 19:32, Takashi Iwai <tiwai@suse.de> wrote:
> > 
> > On Fri, 23 Oct 2020 12:23:35 +0200,
> > Kai-Heng Feng wrote:
> >> 
> >> +static void hda_codec_pm_complete(struct device *dev)
> >> {
> >> 	struct hda_codec *codec = dev_to_hda_codec(dev);
> >> -	int ret;
> >> 
> >> -	ret = pm_runtime_force_resume(dev);
> >> -	/* schedule jackpoll work for jack detection update */
> >> -	if (codec->jackpoll_interval ||
> >> -	    (pm_runtime_suspended(dev) && hda_codec_need_resume(codec)))
> >> -		schedule_delayed_work(&codec->jackpoll_work,
> >> -				      codec->jackpoll_interval);
> >> -	return ret;
> >> +	if (pm_runtime_suspended(dev) &&
> >> +	    (hda_codec_need_resume(codec) || codec->forced_resume))
> >> +		pm_request_resume(dev);
> > 
> > You shouldn't drop the check of codec->jackpoll_interval.  If this
> > field is set, the codec driver has to resume no matter what it was, so
> > that the polling can start up again.
> 
> Ok, will address in v2.

Thanks.  And, could you submit v2 series with a cover letter?


Takashi
diff mbox series

Patch

diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index a356c21edb90..c2a510cc81bb 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2934,7 +2934,7 @@  static void hda_call_codec_resume(struct hda_codec *codec)
 	snd_hdac_leave_pm(&codec->core);
 }
 
-static int hda_codec_runtime_suspend(struct device *dev)
+static int hda_codec_suspend(struct device *dev)
 {
 	struct hda_codec *codec = dev_to_hda_codec(dev);
 	unsigned int state;
@@ -2953,7 +2953,7 @@  static int hda_codec_runtime_suspend(struct device *dev)
 	return 0;
 }
 
-static int hda_codec_runtime_resume(struct device *dev)
+static int hda_codec_resume(struct device *dev)
 {
 	struct hda_codec *codec = dev_to_hda_codec(dev);
 
@@ -2967,57 +2967,70 @@  static int hda_codec_runtime_resume(struct device *dev)
 	pm_runtime_mark_last_busy(dev);
 	return 0;
 }
+
+static int hda_codec_runtime_suspend(struct device *dev)
+{
+	return hda_codec_suspend(dev);
+}
+
+static int hda_codec_runtime_resume(struct device *dev)
+{
+	return hda_codec_resume(dev);
+}
+
 #endif /* CONFIG_PM */
 
 #ifdef CONFIG_PM_SLEEP
-static int hda_codec_force_resume(struct device *dev)
+static int hda_codec_pm_prepare(struct device *dev)
+{
+	return pm_runtime_suspended(dev);
+}
+
+static void hda_codec_pm_complete(struct device *dev)
 {
 	struct hda_codec *codec = dev_to_hda_codec(dev);
-	int ret;
 
-	ret = pm_runtime_force_resume(dev);
-	/* schedule jackpoll work for jack detection update */
-	if (codec->jackpoll_interval ||
-	    (pm_runtime_suspended(dev) && hda_codec_need_resume(codec)))
-		schedule_delayed_work(&codec->jackpoll_work,
-				      codec->jackpoll_interval);
-	return ret;
+	if (pm_runtime_suspended(dev) &&
+	    (hda_codec_need_resume(codec) || codec->forced_resume))
+		pm_request_resume(dev);
 }
 
 static int hda_codec_pm_suspend(struct device *dev)
 {
 	dev->power.power_state = PMSG_SUSPEND;
-	return pm_runtime_force_suspend(dev);
+	return hda_codec_suspend(dev);
 }
 
 static int hda_codec_pm_resume(struct device *dev)
 {
 	dev->power.power_state = PMSG_RESUME;
-	return hda_codec_force_resume(dev);
+	return hda_codec_resume(dev);
 }
 
 static int hda_codec_pm_freeze(struct device *dev)
 {
 	dev->power.power_state = PMSG_FREEZE;
-	return pm_runtime_force_suspend(dev);
+	return hda_codec_suspend(dev);
 }
 
 static int hda_codec_pm_thaw(struct device *dev)
 {
 	dev->power.power_state = PMSG_THAW;
-	return hda_codec_force_resume(dev);
+	return hda_codec_resume(dev);
 }
 
 static int hda_codec_pm_restore(struct device *dev)
 {
 	dev->power.power_state = PMSG_RESTORE;
-	return hda_codec_force_resume(dev);
+	return hda_codec_resume(dev);
 }
 #endif /* CONFIG_PM_SLEEP */
 
 /* referred in hda_bind.c */
 const struct dev_pm_ops hda_codec_driver_pm = {
 #ifdef CONFIG_PM_SLEEP
+	.prepare = hda_codec_pm_prepare,
+	.complete = hda_codec_pm_complete,
 	.suspend = hda_codec_pm_suspend,
 	.resume = hda_codec_pm_resume,
 	.freeze = hda_codec_pm_freeze,