All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tobias Jakobi <tjakobi@math.uni-bielefeld.de>
To: Chanwoo Choi <cw00.choi@samsung.com>,
	Tobias Jakobi <tjakobi@math.uni-bielefeld.de>,
	linux-samsung-soc@vger.kernel.org
Cc: linux-pm@vger.kernel.org, m.reichl@fivetechno.de, myungjoo.ham@gmail.com
Subject: Re: [RFC 1/4] PM / devfreq: Add DevFreq subsystem suspend/resume
Date: Thu, 24 Nov 2016 15:20:44 +0100	[thread overview]
Message-ID: <5836F73C.8040706@math.uni-bielefeld.de> (raw)
In-Reply-To: <5836A2E7.5080504@samsung.com>

Hey Chanwoo,

first of all, thanks for the help!


Chanwoo Choi wrote:
> Hi Tobias,
> 
> On 2016년 11월 24일 10:34, Chanwoo Choi wrote:
>> Hi Tobias,
>>
>> I like your suggestion. But I have some comment on below.
>>
>> On 2016년 11월 23일 22:51, Tobias Jakobi wrote:
>>> This suspend/resume operations works analogous to the
>>> cpufreq_{suspend,resume}() calls in the CPUFreq subsystem.
>>>
>>> Signed-off-by: Tobias Jakobi <tjakobi@math.uni-bielefeld.de>
>>> ---
>>>  drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++
>>>  include/linux/devfreq.h   | 10 +++++++
>>>  2 files changed, 85 insertions(+)
>>>
>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>> index bf3ea76..2f1aa83 100644
>>> --- a/drivers/devfreq/devfreq.c
>>> +++ b/drivers/devfreq/devfreq.c
>>> @@ -785,6 +785,81 @@ int devfreq_resume_device(struct devfreq *devfreq)
>>>  EXPORT_SYMBOL(devfreq_resume_device);
>>>  
>>>  /**
>>> + * devfreq_suspend() - Suspend DevFreq governors
>>> + *
>>> + * Called during system wide Suspend/Hibernate cycles for suspending governors
>>> + * in the same fashion as cpufreq_suspend().
>>> + */
>>> +void devfreq_suspend(void)
>>> +{
>>> +	struct devfreq *devfreq;
>>> +	unsigned long freq;
>>> +	int ret;
>>> +
>>> +	mutex_lock(&devfreq_list_lock);
>>> +
>>> +	list_for_each_entry(devfreq, &devfreq_list, node) {
>>> +		if (!devfreq->suspend_freq)
>>> +			continue;
>>> +
>>> +		ret = devfreq_suspend_device(devfreq);
> 
> The devfreq_suspend_device() stop the monitoring of governors.
> But, this function is exported. It means that each devfreq device.
> can call the devfreq_suspend/resume_device() (e.g., int drivers/scsi/ufs/ufshcd.c)
> 
> So, you should consider following case:
> - case :Before calling the devfreq_suspend() and specific devfreq already call
>   the devfreq_suspend_device(), how to support it?
>   In this case, the specific devfreq device don't want to call
>   the devfreq_resume_device() in the devfreq_resume().
How about this idea?

Introduce a boolean 'devfreq_suspended' (again similar to CPUFreq) and
set it to true (atomically?) once we have entered devfreq_suspend().

At the end of devfreq_suspend() we set it to false again.

We just need to check in devfreq_{suspend,resume}_device() for
'devfreq_suspended' and return some error code (-EBUSY maybe?) to the
caller.

Of course I would inline the devfreq->governor->event_handler() call
into devfreq_{suspend,resume}() first.

Does this look sane?

Also, do you see any other exported calls which we might have to
'protect' during suspended state?


With best wishes,
Tobias


>>> +		if (ret < 0) {
>>> +			dev_warn(&devfreq->dev, "%s: governor suspend failed\n", __func__);
>>> +			continue;
>>> +		}
>>> +
>>> +		devfreq->resume_freq = 0;
>>> +		if (devfreq->profile->get_cur_freq) {
>>> +			ret = devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq);
>>> +			if (ret >= 0)
>>> +				devfreq->resume_freq = freq;
>>> +		}
>>> +
>>> +		freq = devfreq->suspend_freq;
>>> +		ret = devfreq->profile->target(devfreq->dev.parent, &freq, 0);
>>
>>
>> DEVFREQ subsystem has the passive governor[2] and devfreq device using passive[1]
>> governor depends on the parent devfreq device. The passive governor uses
>> 'DEVFREQ_TRANSITION_NOTIFIER' notifier to track the changed state of
>> parent devfreq device.
>>
>> When changing the clock/voltage of parent devfreq device,
>> DEVFREQ subsystem have to notify the changed frequency
>> to the passive devfreq device.
>>
>> So, you should call the devfreq_notifiy_transition()
>> before/after 'devfreq->profile->target' as following:
>> You can refer the update_devfreq() function 
>> that is how to use devfreq_notifiy_transition().
>>
>> For example,
>> 		struct devfreq_freq freqs;
>>  
>> 		if (devfreq->profile->get_cur_freq) {
>> 			ret = devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq);
>> 			if (ret >= 0)
>> 				devfreq->resume_freq = freq;
>> 		} else {
>> 			devfreq->resume_freq = devfreq_previous_freq;
>> 		} 
>>
>> 		freqs.old = devfreq->resume_freq;
>> 		freqs.new = devfreq->suspend_freq;
>> 		devfreq_notify_transition(devfreq, &freqs, DEVFREQ_PRECHANGE);
>>
>>                 freq = devfreq->suspend_freq;
>>                 ret = devfreq->profile->target(devfreq->dev.parent, &freq, 0);
>>  
>> 		freqs.new = freq;
>> 		devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
>>
>>                 if (ret < 0)
>>                         dev_warn(&devfreq->dev, "%s: setting suspend frequency failed\n", __func__);
>>         }
>>
>> [1] DEVFREQ_TRANSITION_NOTIFIER notifier
>> - https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=0fe3a66410a3ba96679be903f1e287d7a0a264a9
>> [2] DEVFREQ passive governor
>> - https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=996133119f57334c38b020dbfaaac5b5eb127e29
>>
>>> +
>>> +		if (ret < 0)
>>> +			dev_warn(&devfreq->dev, "%s: setting suspend frequency failed\n", __func__);
>>> +	}
>>> +
>>> +	mutex_unlock(&devfreq_list_lock);
>>> +}
>>> +
>>> +/**
>>> + * devfreq_resume() - Resume DevFreq governors
>>> + *
>>> + * Called during system wide Suspend/Hibernate cycle for resuming governors that
>>> + * are suspended with devfreq_suspend().
>>> + */
>>> +void devfreq_resume(void)
>>> +{
>>> +	struct devfreq *devfreq;
>>> +	unsigned long freq;
>>> +	int ret;
>>> +
>>> +	mutex_lock(&devfreq_list_lock);
>>> +
>>> +	list_for_each_entry(devfreq, &devfreq_list, node) {
>>> +		if (!devfreq->suspend_freq)
>>> +			continue;
>>> +
>>> +		freq = devfreq->resume_freq;
>>> +		ret = devfreq->profile->target(devfreq->dev.parent, &freq, 0);
>>
>> ditto.
>>
>>> +
>>> +		if (ret < 0) {
>>> +			dev_warn(&devfreq->dev, "%s: setting resume frequency failed\n", __func__);
>>> +			continue;
>>> +		}
>>> +
>>> +		ret = devfreq_resume_device(devfreq);
>>> +		if (ret < 0)
>>> +			dev_warn(&devfreq->dev, "%s: governor resume failed\n", __func__);
>>> +	}
>>> +
>>> +	mutex_unlock(&devfreq_list_lock);
>>> +}
>>> +
>>> +/**
>>>   * devfreq_add_governor() - Add devfreq governor
>>>   * @governor:	the devfreq governor to be added
>>>   */
>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>> index 2de4e2e..555d024 100644
>>> --- a/include/linux/devfreq.h
>>> +++ b/include/linux/devfreq.h
>>> @@ -171,6 +171,9 @@ struct devfreq {
>>>  	struct notifier_block nb;
>>>  	struct delayed_work work;
>>>  
>>> +	unsigned long suspend_freq; /* freq during devfreq suspend */
>>> +	unsigned long resume_freq; /* freq restored after suspend cycle */
>>> +
>>>  	unsigned long previous_freq;
>>>  	struct devfreq_dev_status last_status;
>>>  
>>> @@ -211,6 +214,10 @@ extern void devm_devfreq_remove_device(struct device *dev,
>>>  extern int devfreq_suspend_device(struct devfreq *devfreq);
>>>  extern int devfreq_resume_device(struct devfreq *devfreq);
>>>  
>>> +/* Suspend/resume the entire Devfreq subsystem. */
>>> +void devfreq_suspend(void);
>>> +void devfreq_resume(void);
>>> +
>>>  /* Helper functions for devfreq user device driver with OPP. */
>>>  extern struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
>>>  					   unsigned long *freq, u32 flags);
>>> @@ -410,6 +417,9 @@ static inline int devfreq_update_stats(struct devfreq *df)
>>>  {
>>>  	return -EINVAL;
>>>  }
>>> +
>>> +static inline void devfreq_suspend(void) {}
>>> +static inline void devfreq_resume(void) {}
>>>  #endif /* CONFIG_PM_DEVFREQ */
>>>  
>>>  #endif /* __LINUX_DEVFREQ_H__ */
>>>
>>
>>
> Best Regards,
> Chanwoo Choi
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


  reply	other threads:[~2016-11-24 14:20 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-11-23 13:51 [RFC 0/4] PM / devfreq: draft for OPP suspend impl Tobias Jakobi
2016-11-23 13:51 ` [RFC 1/4] PM / devfreq: Add DevFreq subsystem suspend/resume Tobias Jakobi
2016-11-24  1:34   ` Chanwoo Choi
2016-11-24  8:20     ` Chanwoo Choi
2016-11-24 14:20       ` Tobias Jakobi [this message]
2016-11-23 13:51 ` [RFC 2/4] PM / devfreq: suspend subsystem on system suspend/hibernate Tobias Jakobi
2016-11-24  1:35   ` Chanwoo Choi
2016-11-23 13:51 ` [RFC 3/4] PM / devfreq: exynos-bus: add support for suspend OPP Tobias Jakobi
2016-11-24  1:38   ` Chanwoo Choi
2016-11-24 14:22     ` Tobias Jakobi
2016-11-23 13:51 ` [RFC 4/4] ARM: dts: exynos4x12: add suspend OPP for DMC and leftbus Tobias Jakobi
2016-11-24  1:41   ` Chanwoo Choi
2016-11-24 14:27     ` Tobias Jakobi
2016-11-24 23:44       ` Chanwoo Choi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5836F73C.8040706@math.uni-bielefeld.de \
    --to=tjakobi@math.uni-bielefeld.de \
    --cc=cw00.choi@samsung.com \
    --cc=linux-pm@vger.kernel.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=m.reichl@fivetechno.de \
    --cc=myungjoo.ham@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.