diff mbox

[v4,2/7] cpufreq: Add boost frequency support in core

Message ID 1371661969-7660-3-git-send-email-l.majewski@samsung.com (mailing list archive)
State Changes Requested, archived
Headers show

Commit Message

Lukasz Majewski June 19, 2013, 5:12 p.m. UTC
This commit adds boost frequency support in cpufreq core (Hardware &
Software).
Some SoC (like Exynos4 - e.g. 4x12) allow setting frequency above
its normal operation limits. Such a mode shall be only used for a short
time.

Overclocking (boost) support is essentially provided by platform
dependent cpufreq driver.

This commit unifies support for SW and HW (Intel) over clocking solutions
in the core cpufreq driver. Previously the "boost" sysfs attribute was
defined at acpi driver code.
Boost sysfs attribute is always exported (to support legacy API). By
default boost is exported as read only. One global attribute is available at:
/sys/devices/system/cpu/cpufreq/boost.

Under the hood frequencies dedicated for boosting are marked with a
special flag (CPUFREQ_BOOST_FREQ) at driver's frequency table.
It is the user's concern to enable/disable overclocking with proper call to
sysfs.

Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Myungjoo Ham <myungjoo.ham@samsung.com>

Changes for v4:
- Remove boost parameter from cpufreq_frequency_table_cpuinfo() function
- Introduce cpufreq_boost_supported() method
- Use of cpufreq_boost_supported() and cpufreq_boost_enabled() to decide
  if frequency shall be skipped
- Rename set_boost_freq() to enable_boost()
- cpufreq_attr_available_freq() moved to freq_table.c
- Use policy list to get access to cpufreq policies
- Rename global boost flag (cpufreq_boost_enabled -> boost_enabled)
- pr_err corrected ( %sable)
- Remove sanity check at cpufreq_boost_trigger_state() entrance [to test if
  boost is supported]
- Use either HW (boost_enable) callback or SW managed boost
- Introduce new cpufreq_boost_trigger_state_sw() method to handle boost
  at SW.
- Protect boost_enabled manipulation with lock
- Always export boost attribute (preserve legacy behaviour). When boost
  is not supported this attribute is read only

Changes for v3:
- Method for reading boost status
- Removal of cpufreq_frequency_table_max()
- Extent cpufreq_frequency_table_cpuinfo() to support boost parameter
- boost_supported flag added to cpufreq_driver struct
- "boost" sysfs attribute control flag removed
- One global flag describing state of the boost defined at cpufreq core
- Rename cpufreq_driver's low_level_boost field to set_boost_freq()
- Usage of cpufreq_sysfs_{remove|add}_file() routines

Changes for v2:
- Removal of cpufreq_boost structure and move its fields to cpufreq_driver
  structure
- Flag to indicate if global boost attribute is already defined
- Extent the pr_{err|debbug} functions to show current function names
---
 drivers/cpufreq/cpufreq.c    |   95 ++++++++++++++++++++++++++++++++++++++++++
 drivers/cpufreq/freq_table.c |   43 +++++++++++++++----
 include/linux/cpufreq.h      |   11 +++++
 3 files changed, 142 insertions(+), 7 deletions(-)

Comments

dirk.brandewie@gmail.com June 19, 2013, 5:48 p.m. UTC | #1
On 06/19/2013 10:12 AM, Lukasz Majewski wrote:
> This commit adds boost frequency support in cpufreq core (Hardware &

> +/*********************************************************************
>    *               REGISTER / UNREGISTER CPUFREQ DRIVER                *
>    *********************************************************************/
>
> @@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
>   	cpufreq_driver = driver_data;
>   	write_unlock_irqrestore(&cpufreq_driver_lock, flags);
>
> +	if (!cpufreq_driver->boost_supported)
> +		boost.attr.mode = 0444;
> +
> +	ret = cpufreq_sysfs_create_file(&(boost.attr));
> +	if (ret) {
> +		pr_err("%s: cannot register global boost sysfs file\n",
> +		       __func__);
> +		goto err_null_driver;
> +	}
> +

I do not think the boost sysfs should be created at all if boost is not
supported.

For intel_pstate the read-only boost would be there for no reason and would
cause confusion on the part of the user IMHO

>   	ret = subsys_interface_register(&cpufreq_interface);
>   	if (ret)
>   		goto err_null_driver;
> @@ -1992,6 +2085,8 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
>   	pr_debug("unregistering driver %s\n", driver->name);
>
>   	subsys_interface_unregister(&cpufreq_interface);
> +
> +	cpufreq_sysfs_remove_file(&(boost.attr));
>   	unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
>

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lukasz Majewski June 19, 2013, 8:31 p.m. UTC | #2
On Wed, 19 Jun 2013 10:48:53 -0700
Dirk Brandewie <dirk.brandewie@gmail.com> wrote:

> On 06/19/2013 10:12 AM, Lukasz Majewski wrote:
> > This commit adds boost frequency support in cpufreq core (Hardware &
> 
> > +/*********************************************************************
> >    *               REGISTER / UNREGISTER CPUFREQ
> > DRIVER                *
> > *********************************************************************/
> >
> > @@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct
> > cpufreq_driver *driver_data) cpufreq_driver = driver_data;
> >   	write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> >
> > +	if (!cpufreq_driver->boost_supported)
> > +		boost.attr.mode = 0444;
> > +
> > +	ret = cpufreq_sysfs_create_file(&(boost.attr));
> > +	if (ret) {
> > +		pr_err("%s: cannot register global boost sysfs
> > file\n",
> > +		       __func__);
> > +		goto err_null_driver;
> > +	}
> > +
> 
> I do not think the boost sysfs should be created at all if boost is
> not supported.

This was my first thought. But unfortunately this "boost" attribute is
always exported at acpi-cpufreq.c and in my opinion is part of a
legacy API.

I totally agree with the idea of exporting boost only when supported,
but I would like to know the community opinion about this (especially
Viresh and Rafael shall speak up).

> 
> For intel_pstate the read-only boost would be there for no reason and
> would cause confusion on the part of the user IMHO

You are probably right here. However I don't know what was the
original rationale behind exporting this attribute as read only. 

> 
> >   	ret = subsys_interface_register(&cpufreq_interface);
> >   	if (ret)
> >   		goto err_null_driver;
> > @@ -1992,6 +2085,8 @@ int cpufreq_unregister_driver(struct
> > cpufreq_driver *driver) pr_debug("unregistering driver %s\n",
> > driver->name);
> >
> >   	subsys_interface_unregister(&cpufreq_interface);
> > +
> > +	cpufreq_sysfs_remove_file(&(boost.attr));
> >   	unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
> >
> 

Best regards,

Lukasz Majewski

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafael Wysocki June 19, 2013, 10:25 p.m. UTC | #3
On Wednesday, June 19, 2013 10:31:02 PM Lukasz Majewski wrote:
> On Wed, 19 Jun 2013 10:48:53 -0700
> Dirk Brandewie <dirk.brandewie@gmail.com> wrote:
> 
> > On 06/19/2013 10:12 AM, Lukasz Majewski wrote:
> > > This commit adds boost frequency support in cpufreq core (Hardware &
> > 
> > > +/*********************************************************************
> > >    *               REGISTER / UNREGISTER CPUFREQ
> > > DRIVER                *
> > > *********************************************************************/
> > >
> > > @@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct
> > > cpufreq_driver *driver_data) cpufreq_driver = driver_data;
> > >   	write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> > >
> > > +	if (!cpufreq_driver->boost_supported)
> > > +		boost.attr.mode = 0444;
> > > +
> > > +	ret = cpufreq_sysfs_create_file(&(boost.attr));
> > > +	if (ret) {
> > > +		pr_err("%s: cannot register global boost sysfs
> > > file\n",
> > > +		       __func__);
> > > +		goto err_null_driver;
> > > +	}
> > > +
> > 
> > I do not think the boost sysfs should be created at all if boost is
> > not supported.
> 
> This was my first thought. But unfortunately this "boost" attribute is
> always exported at acpi-cpufreq.c and in my opinion is part of a
> legacy API.
> 
> I totally agree with the idea of exporting boost only when supported,
> but I would like to know the community opinion about this (especially
> Viresh and Rafael shall speak up).

Simple: Export it only when supported.

Thanks,
Rafael
Viresh Kumar June 20, 2013, 5:13 a.m. UTC | #4
On 19 June 2013 22:42, Lukasz Majewski <l.majewski@samsung.com> wrote:

> Boost sysfs attribute is always exported (to support legacy API). By
> default boost is exported as read only. One global attribute is available at:
> /sys/devices/system/cpu/cpufreq/boost.

You asked me and Rafael a question and posted your next version without
even waiting for our replies? That will waste your time and ours too
reviewing it.
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafael Wysocki June 20, 2013, 8:03 p.m. UTC | #5
On Thursday, June 20, 2013 10:43:08 AM Viresh Kumar wrote:
> On 19 June 2013 22:42, Lukasz Majewski <l.majewski@samsung.com> wrote:
> 
> > Boost sysfs attribute is always exported (to support legacy API). By
> > default boost is exported as read only. One global attribute is available at:
> > /sys/devices/system/cpu/cpufreq/boost.
> 
> You asked me and Rafael a question and posted your next version without
> even waiting for our replies? That will waste your time and ours too
> reviewing it.

I believe I replied to that (in a different branch of the thread).

And the reply was: Do not expose if not supported.

Thanks,
Rafael
Lukasz Majewski June 21, 2013, 6:23 a.m. UTC | #6
On Thu, 20 Jun 2013 22:03:45 +0200, Rafael J. Wysocki wrote:

Hi Rafael,

> On Thursday, June 20, 2013 10:43:08 AM Viresh Kumar wrote:
> > On 19 June 2013 22:42, Lukasz Majewski <l.majewski@samsung.com>
> > wrote:
> > 
> > > Boost sysfs attribute is always exported (to support legacy API).
> > > By default boost is exported as read only. One global attribute
> > > is available at: /sys/devices/system/cpu/cpufreq/boost.
> > 
> > You asked me and Rafael a question and posted your next version
> > without even waiting for our replies? That will waste your time and
> > ours too reviewing it.
> 
> I believe I replied to that (in a different branch of the thread).
> 
> And the reply was: Do not expose if not supported.

Thanks for reply. Understood :-)

> 
> Thanks,
> Rafael
> 
>
Viresh Kumar June 26, 2013, 10:54 a.m. UTC | #7
On 19 June 2013 22:42, Lukasz Majewski <l.majewski@samsung.com> wrote:
> Boost sysfs attribute is always exported (to support legacy API). By
> default boost is exported as read only. One global attribute is available at:
> /sys/devices/system/cpu/cpufreq/boost.

I assume you are going to fix this as discussed in other threads.

> Changes for v4:
> - Remove boost parameter from cpufreq_frequency_table_cpuinfo() function
> - Introduce cpufreq_boost_supported() method
> - Use of cpufreq_boost_supported() and cpufreq_boost_enabled() to decide
>   if frequency shall be skipped
> - Rename set_boost_freq() to enable_boost()
> - cpufreq_attr_available_freq() moved to freq_table.c
> - Use policy list to get access to cpufreq policies
> - Rename global boost flag (cpufreq_boost_enabled -> boost_enabled)
> - pr_err corrected ( %sable)
> - Remove sanity check at cpufreq_boost_trigger_state() entrance [to test if
>   boost is supported]
> - Use either HW (boost_enable) callback or SW managed boost
> - Introduce new cpufreq_boost_trigger_state_sw() method to handle boost
>   at SW.
> - Protect boost_enabled manipulation with lock
> - Always export boost attribute (preserve legacy behaviour). When boost
>   is not supported this attribute is read only

Very well written changelog. But write it after ---

> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> index 665e641..9141d33 100644
> --- a/drivers/cpufreq/cpufreq.c
> +++ b/drivers/cpufreq/cpufreq.c
> @@ -40,6 +40,7 @@
>   * also protects the cpufreq_cpu_data array.
>   */
>  static struct cpufreq_driver *cpufreq_driver;
> +static bool boost_enabled;
>  static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
>  #ifdef CONFIG_HOTPLUG_CPU
>  /* This one keeps track of the previously set governor of a removed CPU */
> @@ -316,6 +317,29 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
>  /*********************************************************************
>   *                          SYSFS INTERFACE                          *
>   *********************************************************************/
> +ssize_t show_boost(struct kobject *kobj,
> +                                struct attribute *attr, char *buf)
> +{
> +       return sprintf(buf, "%d\n", boost_enabled);
> +}
> +
> +static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
> +                                 const char *buf, size_t count)
> +{
> +       int ret, enable;
> +
> +       ret = sscanf(buf, "%d", &enable);
> +       if (ret != 1 || enable < 0 || enable > 1)
> +               return -EINVAL;
> +
> +       if (cpufreq_boost_trigger_state(enable)) {
> +               pr_err("%s: Cannot enable boost!\n", __func__);
> +               return -EINVAL;
> +       }

Probably do boost_enabled = true here.

> +       return count;
> +}
> +define_one_global_rw(boost);

>  /*********************************************************************
> + *               BOOST                                              *
> + *********************************************************************/
> +static int cpufreq_boost_trigger_state_sw(void)
> +{
> +       struct cpufreq_frequency_table *freq_table;
> +       struct cpufreq_policy *policy;
> +       int ret = -EINVAL;
> +
> +       list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
> +               freq_table = cpufreq_frequency_get_table(policy->cpu);
> +               if (freq_table)
> +                       ret = cpufreq_frequency_table_cpuinfo(policy,
> +                                                       freq_table);
> +       }
> +
> +       return ret;
> +
> +}

add blank line here.

> +int cpufreq_boost_trigger_state(int state)
> +{
> +       unsigned long flags;
> +       int ret = 0;
> +
> +       if (boost_enabled != state) {
> +               write_lock_irqsave(&cpufreq_driver_lock, flags);
> +               boost_enabled = state;
> +               if (cpufreq_driver->enable_boost)
> +                       ret = cpufreq_driver->enable_boost(state);
> +               else
> +                       ret = cpufreq_boost_trigger_state_sw();
> +
> +               if (ret) {
> +                       boost_enabled = 0;
> +                       write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> +                       pr_err("%s: BOOST cannot enable (%d)\n",
> +                              __func__, ret);
> +
> +                       return ret;
> +               }
> +               write_unlock_irqrestore(&cpufreq_driver_lock, flags);

You can rewrite if (ret) and unlock() code to make it less redundant.
unlock and return ret at the end and write other stuff before it.

> +               pr_debug("%s: cpufreq BOOST %s\n", __func__,
> +                        state ? "enabled" : "disabled");
> +       }
> +
> +       return 0;
> +}
> +
> +int cpufreq_boost_supported(void)
> +{
> +       return cpufreq_driver->boost_supported;
> +}
> +
> +int cpufreq_boost_enabled(void)
> +{
> +       return boost_enabled;
> +}

EXPORT_SYMBOL_GPL ??

> +/*********************************************************************
>   *               REGISTER / UNREGISTER CPUFREQ DRIVER                *
>   *********************************************************************/
>
> @@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
>         cpufreq_driver = driver_data;
>         write_unlock_irqrestore(&cpufreq_driver_lock, flags);
>
> +       if (!cpufreq_driver->boost_supported)
> +               boost.attr.mode = 0444;
> +
> +       ret = cpufreq_sysfs_create_file(&(boost.attr));
> +       if (ret) {
> +               pr_err("%s: cannot register global boost sysfs file\n",
> +                      __func__);
> +               goto err_null_driver;
> +       }

This would change.

>         ret = subsys_interface_register(&cpufreq_interface);
>         if (ret)
>                 goto err_null_driver;
> @@ -1992,6 +2085,8 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
>         pr_debug("unregistering driver %s\n", driver->name);
>
>         subsys_interface_unregister(&cpufreq_interface);
> +
> +       cpufreq_sysfs_remove_file(&(boost.attr));
>         unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
>
>         list_del(&cpufreq_policy_list);
> diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
> index d7a7966..9c8e71e 100644
> --- a/drivers/cpufreq/freq_table.c
> +++ b/drivers/cpufreq/freq_table.c
> @@ -34,6 +34,11 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
>
>                         continue;
>                 }
> +               if (cpufreq_boost_supported())

Probably remove this check. Assume somebody while testing exynos,
just sent boost_supported as false. Then you will not skip this frequency
and may burn your chip :)

> +                       if (!cpufreq_boost_enabled()
> +                           && table[i].index == CPUFREQ_BOOST_FREQ)
> +                               continue;

This should be enough.

>                 pr_debug("table entry %u: %u kHz, %u index\n",
>                                         i, freq, table[i].index);
>                 if (freq < min_freq)
> @@ -171,7 +176,8 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
>  /**
>   * show_available_freqs - show available frequencies for the specified CPU
>   */
> -static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
> +static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
> +                                   int show_boost)
>  {
>         unsigned int i = 0;
>         unsigned int cpu = policy->cpu;
> @@ -186,6 +192,9 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
>         for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
>                 if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
>                         continue;

Add a comment here describing your complex logic.

> +               if (show_boost ^ (table[i].index == CPUFREQ_BOOST_FREQ))
> +                       continue;
> +
>                 count += sprintf(&buf[count], "%d ", table[i].frequency);
>         }
>         count += sprintf(&buf[count], "\n");
> @@ -194,14 +203,34 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
>
>  }
>
> -struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
> -       .attr = { .name = "scaling_available_frequencies",
> -                 .mode = 0444,
> -               },
> -       .show = show_available_freqs,
> -};
> +#define cpufreq_attr_available_freq(_name)       \
> +struct freq_attr cpufreq_freq_attr_##_name##_freqs =     \
> +__ATTR_RO(_name##_frequencies)
> +
> +/**
> + * show_scaling_available_frequencies - show normal boost frequencies for

You missed this comment earlier. boost??

> + * the specified CPU
> + */
> +static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
> +                                                 char *buf)
> +{
> +       return show_available_freqs(policy, buf, 0);
> +}
> +cpufreq_attr_available_freq(scaling_available);
>  EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
>
> +/**
> + * show_available_boost_freqs - show available boost frequencies for
> + * the specified CPU
> + */
> +static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
> +                                             char *buf)
> +{
> +       return show_available_freqs(policy, buf, 1);
> +}
> +cpufreq_attr_available_freq(scaling_boost);
> +EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
> +
>  /*
>   * if you use these, you must assure that the frequency table is valid
>   * all the time between get_attr and put_attr!
> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> index 5348981..4783c4c 100644
> --- a/include/linux/cpufreq.h
> +++ b/include/linux/cpufreq.h
> @@ -267,6 +267,10 @@ struct cpufreq_driver {
>         int     (*suspend)      (struct cpufreq_policy *policy);
>         int     (*resume)       (struct cpufreq_policy *policy);
>         struct freq_attr        **attr;
> +
> +       /* platform specific boost support code */
> +       bool                    boost_supported;
> +       int (*enable_boost)    (int state);
>  };
>
>  /* flags */
> @@ -408,6 +412,9 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
>  #define CPUFREQ_ENTRY_INVALID ~0
>  #define CPUFREQ_TABLE_END     ~1
>
> +/* Define index for boost frequency */
> +#define CPUFREQ_BOOST_FREQ    ~2
> +
>  struct cpufreq_frequency_table {
>         unsigned int    index;     /* any */
>         unsigned int    frequency; /* kHz - doesn't need to be in ascending
> @@ -426,11 +433,15 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
>                                    unsigned int relation,
>                                    unsigned int *index);
>
> +int cpufreq_boost_trigger_state(int state);

Why is this present here?
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lukasz Majewski June 26, 2013, 12:54 p.m. UTC | #8
On Wed, 26 Jun 2013 16:24:32 +0530, Viresh Kumar wrote:
> On 19 June 2013 22:42, Lukasz Majewski <l.majewski@samsung.com> wrote:
> > Boost sysfs attribute is always exported (to support legacy API). By
> > default boost is exported as read only. One global attribute is
> > available at: /sys/devices/system/cpu/cpufreq/boost.
> 
> I assume you are going to fix this as discussed in other threads.
Yes. Boost attribute will be visible only when boost is supported.

> 
> > Changes for v4:
> > - Remove boost parameter from cpufreq_frequency_table_cpuinfo()
> > function
> > - Introduce cpufreq_boost_supported() method
> > - Use of cpufreq_boost_supported() and cpufreq_boost_enabled() to
> > decide if frequency shall be skipped
> > - Rename set_boost_freq() to enable_boost()
> > - cpufreq_attr_available_freq() moved to freq_table.c
> > - Use policy list to get access to cpufreq policies
> > - Rename global boost flag (cpufreq_boost_enabled -> boost_enabled)
> > - pr_err corrected ( %sable)
> > - Remove sanity check at cpufreq_boost_trigger_state() entrance [to
> > test if boost is supported]
> > - Use either HW (boost_enable) callback or SW managed boost
> > - Introduce new cpufreq_boost_trigger_state_sw() method to handle
> > boost at SW.
> > - Protect boost_enabled manipulation with lock
> > - Always export boost attribute (preserve legacy behaviour). When
> > boost is not supported this attribute is read only
> 
> Very well written changelog. But write it after ---

I will stick to the rule proposed at patch 1/4, ver 4.

> 
> > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> > index 665e641..9141d33 100644
> > --- a/drivers/cpufreq/cpufreq.c
> > +++ b/drivers/cpufreq/cpufreq.c
> > @@ -40,6 +40,7 @@
> >   * also protects the cpufreq_cpu_data array.
> >   */
> >  static struct cpufreq_driver *cpufreq_driver;
> > +static bool boost_enabled;
> >  static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
> >  #ifdef CONFIG_HOTPLUG_CPU
> >  /* This one keeps track of the previously set governor of a
> > removed CPU */ @@ -316,6 +317,29 @@
> > EXPORT_SYMBOL_GPL(cpufreq_notify_transition); /*********************************************************************
> >   *                          SYSFS
> > INTERFACE                          *
> > *********************************************************************/
> > +ssize_t show_boost(struct kobject *kobj,
> > +                                struct attribute *attr, char *buf)
> > +{
> > +       return sprintf(buf, "%d\n", boost_enabled);
> > +}
> > +
> > +static ssize_t store_boost(struct kobject *kobj, struct attribute
> > *attr,
> > +                                 const char *buf, size_t count)
> > +{
> > +       int ret, enable;
> > +
> > +       ret = sscanf(buf, "%d", &enable);
> > +       if (ret != 1 || enable < 0 || enable > 1)
> > +               return -EINVAL;
> > +
> > +       if (cpufreq_boost_trigger_state(enable)) {
> > +               pr_err("%s: Cannot enable boost!\n", __func__);
> > +               return -EINVAL;
> > +       }
> 
> Probably do boost_enabled = true here.

I would prefer to set boot_enabled at
cpufreq_boost_trigger_state() method. It is closer to the 
cpufreq_driver->enable_boost and cpufreq_boost_trigger_state_sw();
functions, which do change the freq.

> 
> > +       return count;
> > +}
> > +define_one_global_rw(boost);
> 
> >  /*********************************************************************
> > + *
> > BOOST                                              *
> > +
> > *********************************************************************/
> > +static int cpufreq_boost_trigger_state_sw(void) +{
> > +       struct cpufreq_frequency_table *freq_table;
> > +       struct cpufreq_policy *policy;
> > +       int ret = -EINVAL;
> > +
> > +       list_for_each_entry(policy, &cpufreq_policy_list,
> > policy_list) {
> > +               freq_table =
> > cpufreq_frequency_get_table(policy->cpu);
> > +               if (freq_table)
> > +                       ret =
> > cpufreq_frequency_table_cpuinfo(policy,
> > +                                                       freq_table);
> > +       }
> > +
> > +       return ret;
> > +
> > +}
> 
> add blank line here.

OK.

> 
> > +int cpufreq_boost_trigger_state(int state)
> > +{
> > +       unsigned long flags;
> > +       int ret = 0;
> > +
> > +       if (boost_enabled != state) {
> > +               write_lock_irqsave(&cpufreq_driver_lock, flags);
> > +               boost_enabled = state;
> > +               if (cpufreq_driver->enable_boost)
> > +                       ret = cpufreq_driver->enable_boost(state);
						  ^^^^^^^^^^^^^
					I would prefer to change this
					name to enable_boost_hw
It is more informative, since it is tailored to hw based boost (Intel).

> > +               else
> > +                       ret = cpufreq_boost_trigger_state_sw();
> > +
> > +               if (ret) {
> > +                       boost_enabled = 0;
> > +
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> > +                       pr_err("%s: BOOST cannot enable (%d)\n",
> > +                              __func__, ret);
> > +
> > +                       return ret;
> > +               }
> > +               write_unlock_irqrestore(&cpufreq_driver_lock,
> > flags);
> 
> You can rewrite if (ret) and unlock() code to make it less redundant.
> unlock and return ret at the end and write other stuff before it.

I will rewrite it as follow:

if (ret)
	boost_enabled = 0;
		
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
pr_debug("%s: cpufreq BOOST %s\n", __func__,
		 state ? "enabled" : "disabled");

return ret;

> 
> > +               pr_debug("%s: cpufreq BOOST %s\n", __func__,
> > +                        state ? "enabled" : "disabled");
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +int cpufreq_boost_supported(void)
> > +{
> > +       return cpufreq_driver->boost_supported;
> > +}
> > +
> > +int cpufreq_boost_enabled(void)
> > +{
> > +       return boost_enabled;
> > +}
> 
> EXPORT_SYMBOL_GPL ??

I will export cpufreq_boost_enabled() and cpufreq_boost_supported()

> 
> > +/*********************************************************************
> >   *               REGISTER / UNREGISTER CPUFREQ
> > DRIVER                *
> > *********************************************************************/
> >
> > @@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct
> > cpufreq_driver *driver_data) cpufreq_driver = driver_data;
> >         write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> >
> > +       if (!cpufreq_driver->boost_supported)
> > +               boost.attr.mode = 0444;
            Will be removed ^^^^^^^^^^^^^^^
> > +
> > +       ret = cpufreq_sysfs_create_file(&(boost.attr));
> > +       if (ret) {
> > +               pr_err("%s: cannot register global boost sysfs
> > file\n",
> > +                      __func__);
> > +               goto err_null_driver;
> > +       }
> 
> This would change.

This will be only exported when cpufreq_boost_supported() is true.

> 
> >         ret = subsys_interface_register(&cpufreq_interface);
> >         if (ret)
> >                 goto err_null_driver;
> > @@ -1992,6 +2085,8 @@ int cpufreq_unregister_driver(struct
> > cpufreq_driver *driver) pr_debug("unregistering driver %s\n",
> > driver->name);
> >
> >         subsys_interface_unregister(&cpufreq_interface);
> > +
> > +       cpufreq_sysfs_remove_file(&(boost.attr));
> >         unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
> >
> >         list_del(&cpufreq_policy_list);
> > diff --git a/drivers/cpufreq/freq_table.c
> > b/drivers/cpufreq/freq_table.c index d7a7966..9c8e71e 100644
> > --- a/drivers/cpufreq/freq_table.c
> > +++ b/drivers/cpufreq/freq_table.c
> > @@ -34,6 +34,11 @@ int cpufreq_frequency_table_cpuinfo(struct
> > cpufreq_policy *policy,
> >
> >                         continue;
> >                 }
> > +               if (cpufreq_boost_supported())
> 
> Probably remove this check. Assume somebody while testing exynos,
> just sent boost_supported as false. Then you will not skip this
> frequency and may burn your chip :)

OK.

> 
> > +                       if (!cpufreq_boost_enabled()
> > +                           && table[i].index == CPUFREQ_BOOST_FREQ)
> > +                               continue;
> 
> This should be enough.

Let's only rely on the cpufreq_boost_enabled() test here.

> 
> >                 pr_debug("table entry %u: %u kHz, %u index\n",
> >                                         i, freq, table[i].index);
> >                 if (freq < min_freq)
> > @@ -171,7 +176,8 @@ static DEFINE_PER_CPU(struct
> > cpufreq_frequency_table *, cpufreq_show_table); /**
> >   * show_available_freqs - show available frequencies for the
> > specified CPU */
> > -static ssize_t show_available_freqs(struct cpufreq_policy *policy,
> > char *buf) +static ssize_t show_available_freqs(struct
> > cpufreq_policy *policy, char *buf,
> > +                                   int show_boost)
> >  {
> >         unsigned int i = 0;
> >         unsigned int cpu = policy->cpu;
> > @@ -186,6 +192,9 @@ static ssize_t show_available_freqs(struct
> > cpufreq_policy *policy, char *buf) for (i = 0;
> > (table[i].frequency != CPUFREQ_TABLE_END); i++) { if
> > (table[i].frequency == CPUFREQ_ENTRY_INVALID) continue;
> 
> Add a comment here describing your complex logic.

OK.

> 
> > +               if (show_boost ^ (table[i].index ==
> > CPUFREQ_BOOST_FREQ))
> > +                       continue;
> > +
> >                 count += sprintf(&buf[count], "%d ",
> > table[i].frequency); }
> >         count += sprintf(&buf[count], "\n");
> > @@ -194,14 +203,34 @@ static ssize_t show_available_freqs(struct
> > cpufreq_policy *policy, char *buf)
> >
> >  }
> >
> > -struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
> > -       .attr = { .name = "scaling_available_frequencies",
> > -                 .mode = 0444,
> > -               },
> > -       .show = show_available_freqs,
> > -};
> > +#define cpufreq_attr_available_freq(_name)       \
> > +struct freq_attr cpufreq_freq_attr_##_name##_freqs =     \
> > +__ATTR_RO(_name##_frequencies)
> > +
> > +/**
> > + * show_scaling_available_frequencies - show normal boost
> > frequencies for
> 
> You missed this comment earlier. boost??

My mistake. This will be corrected.

> 
> > + * the specified CPU
> > + */
> > +static ssize_t scaling_available_frequencies_show(struct
> > cpufreq_policy *policy,
> > +                                                 char *buf)
> > +{
> > +       return show_available_freqs(policy, buf, 0);
> > +}
> > +cpufreq_attr_available_freq(scaling_available);
> >  EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
> >
> > +/**
> > + * show_available_boost_freqs - show available boost frequencies
> > for
> > + * the specified CPU
> > + */
> > +static ssize_t scaling_boost_frequencies_show(struct
> > cpufreq_policy *policy,
> > +                                             char *buf)
> > +{
> > +       return show_available_freqs(policy, buf, 1);
> > +}
> > +cpufreq_attr_available_freq(scaling_boost);
> > +EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
> > +
> >  /*
> >   * if you use these, you must assure that the frequency table is
> > valid
> >   * all the time between get_attr and put_attr!
> > diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> > index 5348981..4783c4c 100644
> > --- a/include/linux/cpufreq.h
> > +++ b/include/linux/cpufreq.h
> > @@ -267,6 +267,10 @@ struct cpufreq_driver {
> >         int     (*suspend)      (struct cpufreq_policy *policy);
> >         int     (*resume)       (struct cpufreq_policy *policy);
> >         struct freq_attr        **attr;
> > +
> > +       /* platform specific boost support code */
> > +       bool                    boost_supported;
> > +       int (*enable_boost)    (int state);
> >  };
> >
> >  /* flags */
> > @@ -408,6 +412,9 @@ extern struct cpufreq_governor
> > cpufreq_gov_conservative; #define CPUFREQ_ENTRY_INVALID ~0
> >  #define CPUFREQ_TABLE_END     ~1
> >
> > +/* Define index for boost frequency */
> > +#define CPUFREQ_BOOST_FREQ    ~2
> > +
> >  struct cpufreq_frequency_table {
> >         unsigned int    index;     /* any */
> >         unsigned int    frequency; /* kHz - doesn't need to be in
> > ascending @@ -426,11 +433,15 @@ int
> > cpufreq_frequency_table_target(struct cpufreq_policy *policy,
> > unsigned int relation, unsigned int *index);
> >
> > +int cpufreq_boost_trigger_state(int state);
> 
> Why is this present here?

We had agreed to talk only about cpufreq :-).

This declaration will be removed.
Lukasz Majewski June 26, 2013, 2:02 p.m. UTC | #9
On Wed, 26 Jun 2013 14:54:12 +0200, Lukasz Majewski wrote:
> > >
> > > +int cpufreq_boost_trigger_state(int state);  
> > 
> > Why is this present here?  
> 
> We had agreed to talk only about cpufreq :-).
> 
> This declaration will be removed.

Correction:

This declaration is needed for allowing disabling cpufreq boost at
thermal subsystem (please refer to [PATCH v4 7/7]).
Viresh Kumar June 27, 2013, 9:02 a.m. UTC | #10
On 26 June 2013 18:24, Lukasz Majewski <l.majewski@samsung.com> wrote:
> On Wed, 26 Jun 2013 16:24:32 +0530, Viresh Kumar wrote:
>> On 19 June 2013 22:42, Lukasz Majewski <l.majewski@samsung.com> wrote:

>> > +static ssize_t store_boost(struct kobject *kobj, struct attribute
>> > *attr,
>> > +                                 const char *buf, size_t count)
>> > +{
>> > +       int ret, enable;
>> > +
>> > +       ret = sscanf(buf, "%d", &enable);
>> > +       if (ret != 1 || enable < 0 || enable > 1)
>> > +               return -EINVAL;
>> > +
>> > +       if (cpufreq_boost_trigger_state(enable)) {
>> > +               pr_err("%s: Cannot enable boost!\n", __func__);
>> > +               return -EINVAL;
>> > +       }
>>
>> Probably do boost_enabled = true here.
>
> I would prefer to set boot_enabled at
> cpufreq_boost_trigger_state() method. It is closer to the
> cpufreq_driver->enable_boost and cpufreq_boost_trigger_state_sw();
> functions, which do change the freq.

I said that as this will be more inclined towards the purpose of
this routine. This routine should store boost as show_boost()
is returning it. So, what would be better is if you just return
0 or err from cpufreq_boost_trigger_state() and then set boost
here. This will also solve your problem where you revert back
to older boost value for failure cases.

>> > +                       ret = cpufreq_driver->enable_boost(state);
>                                                   ^^^^^^^^^^^^^
>                                         I would prefer to change this
>                                         name to enable_boost_hw
> It is more informative, since it is tailored to hw based boost (Intel).

Ok

>> > +               else
>> > +                       ret = cpufreq_boost_trigger_state_sw();

then why not enable_boost_sw() here? that would be more
relevant.

> I will rewrite it as follow:
>
> if (ret)
>         boost_enabled = 0;
>
> write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> pr_debug("%s: cpufreq BOOST %s\n", __func__,
>                  state ? "enabled" : "disabled");

So, you will not print error but current state? Probably
printing error is better.
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lukasz Majewski June 27, 2013, 9:48 a.m. UTC | #11
On Thu, 27 Jun 2013 14:32:57 +0530, Viresh Kumar wrote:
> On 26 June 2013 18:24, Lukasz Majewski <l.majewski@samsung.com> wrote:
> > On Wed, 26 Jun 2013 16:24:32 +0530, Viresh Kumar wrote:
> >> On 19 June 2013 22:42, Lukasz Majewski <l.majewski@samsung.com>
> >> wrote:
> 
> >> > +static ssize_t store_boost(struct kobject *kobj, struct
> >> > attribute *attr,
> >> > +                                 const char *buf, size_t count)
> >> > +{
> >> > +       int ret, enable;
> >> > +
> >> > +       ret = sscanf(buf, "%d", &enable);
> >> > +       if (ret != 1 || enable < 0 || enable > 1)
> >> > +               return -EINVAL;
> >> > +
> >> > +       if (cpufreq_boost_trigger_state(enable)) {
> >> > +               pr_err("%s: Cannot enable boost!\n", __func__);
> >> > +               return -EINVAL;
> >> > +       }
> >>
> >> Probably do boost_enabled = true here.
> >
> > I would prefer to set boot_enabled at
> > cpufreq_boost_trigger_state() method. It is closer to the
> > cpufreq_driver->enable_boost and cpufreq_boost_trigger_state_sw();
> > functions, which do change the freq.
> 
> I said that as this will be more inclined towards the purpose of
> this routine. This routine should store boost as show_boost()
> is returning it. So, what would be better is if you just return
> 0 or err from cpufreq_boost_trigger_state() and then set boost
> here. This will also solve your problem where you revert back
> to older boost value for failure cases.

I thought about this idea, but at cpufreq_boost_trigger_state_sw()
I iterate through all available policies and call
cpufreq_frequency_table_cpuinfo()[*] on them. In this routine [*] I use 
cpufreq_boost_enabled() [**] route to search for maximal (boost)
frequency.
The [**] reads boost_enabled flag, which shall be updated before. When
this search fails, then I restore the old value of boost_enabled. 

> 
> >> > +                       ret =
> >> > cpufreq_driver->enable_boost(state);
> >                                                   ^^^^^^^^^^^^^
> >                                         I would prefer to change
> > this name to enable_boost_hw
> > It is more informative, since it is tailored to hw based boost
> > (Intel).
> 
> Ok

OK.

> 
> >> > +               else
> >> > +                       ret = cpufreq_boost_trigger_state_sw();
> 
> then why not enable_boost_sw() here? that would be more
> relevant.

Could you be more specific here?

The distinction here is done on purpose:

You can either call cpufreq_driver->enable_boost for HW controlled
boost or cpufreq_boost_trigger_state_sw() for SW controlled one.

I could write:
	if (cpufreq_driver->enable_boost)
		ret = cpufreq_driver->enable_boost(state);

	ret = cpufreq_boost_trigger_state_sw();

But then for Intel CPUs I will iterate over its policies to seek for
CPUFREQ_BOOST_FREQ marked frequencies without any purpose, since HW is
taking care of boosting. 

> 
> > I will rewrite it as follow:
> >
> > if (ret)
> >         boost_enabled = 0;
> >
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> > pr_debug("%s: cpufreq BOOST %s\n", __func__,
> >                  state ? "enabled" : "disabled");
> 
> So, you will not print error but current state? Probably
> printing error is better.

I will change it to:

write_unlock_irqrestore(&cpufreq_driver_lock, flags);
if (ret)
	pr_err("%s: BOOST cannot enable (%d)\n",
			       __func__, ret);

return ret;

I want to avoid time consuming operations (like print) with holding
lock (and boost_enabled shall be modified under lock).
Viresh Kumar June 27, 2013, 10:25 a.m. UTC | #12
On 27 June 2013 15:18, Lukasz Majewski <l.majewski@samsung.com> wrote:
> On Thu, 27 Jun 2013 14:32:57 +0530, Viresh Kumar wrote:

> I thought about this idea, but at cpufreq_boost_trigger_state_sw()
> I iterate through all available policies and call
> cpufreq_frequency_table_cpuinfo()[*] on them. In this routine [*] I use
> cpufreq_boost_enabled() [**] route to search for maximal (boost)
> frequency.
> The [**] reads boost_enabled flag, which shall be updated before. When
> this search fails, then I restore the old value of boost_enabled.

Ok.

>> >> > +               else
>> >> > +                       ret = cpufreq_boost_trigger_state_sw();
>>
>> then why not enable_boost_sw() here? that would be more
>> relevant.
>
> Could you be more specific here?

I meant rename cpufreq_boost_trigger_state_sw() to
enable_boost_sw() :)
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lukasz Majewski June 27, 2013, 11:07 a.m. UTC | #13
On Thu, 27 Jun 2013 15:55:26 +0530, Viresh Kumar wrote:
> On 27 June 2013 15:18, Lukasz Majewski <l.majewski@samsung.com> wrote:
> > On Thu, 27 Jun 2013 14:32:57 +0530, Viresh Kumar wrote:
> 
> > I thought about this idea, but at cpufreq_boost_trigger_state_sw()
> > I iterate through all available policies and call
> > cpufreq_frequency_table_cpuinfo()[*] on them. In this routine [*] I
> > use cpufreq_boost_enabled() [**] route to search for maximal (boost)
> > frequency.
> > The [**] reads boost_enabled flag, which shall be updated before.
> > When this search fails, then I restore the old value of
> > boost_enabled.
> 
> Ok.

OK
> 
> >> >> > +               else
> >> >> > +                       ret =
> >> >> > cpufreq_boost_trigger_state_sw();
> >>
> >> then why not enable_boost_sw() here? that would be more
> >> relevant.
> >
> > Could you be more specific here?
> 
> I meant rename cpufreq_boost_trigger_state_sw() to
> enable_boost_sw() :)

No problem:
- For SW there will be 
	cpufreq_boost_trigger_state_sw() renamed to enable_boost_sw()

- For HW:
	cpufreq_driver->enable_boost(state) renamed to
		cpufreq_driver->enable_boost_hw();
Lukasz Majewski June 27, 2013, 3:55 p.m. UTC | #14
On Wed, 26 Jun 2013 16:24:32 +0530, Viresh Kumar wrote:

> > +int cpufreq_boost_trigger_state(int state)
> > +{
> > +       unsigned long flags;
> > +       int ret = 0;
> > +
> > +       if (boost_enabled != state) {
> > +               write_lock_irqsave(&cpufreq_driver_lock, flags);
> > +               boost_enabled = state;
> > +               if (cpufreq_driver->enable_boost)
> > +                       ret = cpufreq_driver->enable_boost(state);
> > +               else
> > +                       ret = cpufreq_boost_trigger_state_sw();

I will use only one call to cpufreq_driver->enable_boost(state) [*] with
either cpufreq_boost_enable_sw() (function with SW boost handling) or
 the one provided by cpufreq driver.

Only when cpufreq driver doesn't provide [*], it will be filled with
"default" cpufreq_boost_enable_sw().

> > +
> > +               if (ret) {
> > +                       boost_enabled = 0;
> > +
> > write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> > +                       pr_err("%s: BOOST cannot enable (%d)\n",
> > +                              __func__, ret);
> > +
> > +                       return ret;
> > +               }
> > +               write_unlock_irqrestore(&cpufreq_driver_lock,
> > flags);
Viresh Kumar June 28, 2013, 3:40 a.m. UTC | #15
On 27 June 2013 21:25, Lukasz Majewski <l.majewski@samsung.com> wrote:
> On Wed, 26 Jun 2013 16:24:32 +0530, Viresh Kumar wrote:
>> > +       if (boost_enabled != state) {
>> > +               write_lock_irqsave(&cpufreq_driver_lock, flags);
>> > +               boost_enabled = state;
>> > +               if (cpufreq_driver->enable_boost)
>> > +                       ret = cpufreq_driver->enable_boost(state);
>> > +               else
>> > +                       ret = cpufreq_boost_trigger_state_sw();
>
> I will use only one call to cpufreq_driver->enable_boost(state) [*] with
> either cpufreq_boost_enable_sw() (function with SW boost handling) or
>  the one provided by cpufreq driver.
>
> Only when cpufreq driver doesn't provide [*], it will be filled with
> "default" cpufreq_boost_enable_sw().

I didn't get it completely. You are saying you will send a function pointer
now?
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lukasz Majewski June 28, 2013, 6:49 a.m. UTC | #16
On Fri, 28 Jun 2013 09:10:53 +0530, Viresh Kumar wrote:
> On 27 June 2013 21:25, Lukasz Majewski <l.majewski@samsung.com> wrote:
> > On Wed, 26 Jun 2013 16:24:32 +0530, Viresh Kumar wrote:
> >> > +       if (boost_enabled != state) {
> >> > +               write_lock_irqsave(&cpufreq_driver_lock, flags);
> >> > +               boost_enabled = state;
> >> > +               if (cpufreq_driver->enable_boost)
> >> > +                       ret =
> >> > cpufreq_driver->enable_boost(state);
> >> > +               else
> >> > +                       ret = cpufreq_boost_trigger_state_sw();
> >
> > I will use only one call to cpufreq_driver->enable_boost(state) [*]
> > with either cpufreq_boost_enable_sw() (function with SW boost
> > handling) or the one provided by cpufreq driver.
> >
> > Only when cpufreq driver doesn't provide [*], it will be filled with
> > "default" cpufreq_boost_enable_sw().
> 
> I didn't get it completely. You are saying you will send a function
> pointer now?

No, I will use:

if (boost_enabled != state) {
	write_lock_irqsave(&cpufreq_driver_lock, flags);
	boost_enabled = state;

	ret = cpufreq_driver->enable_boost(state);
	^^^^^^^^^^^^^^^^^^^^ only one callback call
	if (ret)
		boost_enabled = 0;

	write_unlock_irqrestore(&cpufreq_driver_lock, flags);

	if (ret)
		pr_err("%s: BOOST cannot enable (%d)\n",
		       __func__, ret);
}

and @ cpufreq_register_driver() I will add following line:

if (!cpufreq_driver->enable_boost)
	cpufreq_driver->enable_boost = &cpufreq_boost_enable_sw;

When cpufreq driver doesn't define callback for enable_boost it will be
filled with default SW cpufreq_boost_enable_sw callback.
Viresh Kumar June 28, 2013, 6:51 a.m. UTC | #17
On 28 June 2013 12:19, Lukasz Majewski <l.majewski@samsung.com> wrote:
> No, I will use:
>
> if (boost_enabled != state) {
>         write_lock_irqsave(&cpufreq_driver_lock, flags);
>         boost_enabled = state;
>
>         ret = cpufreq_driver->enable_boost(state);
>         ^^^^^^^^^^^^^^^^^^^^ only one callback call
>         if (ret)
>                 boost_enabled = 0;
>
>         write_unlock_irqrestore(&cpufreq_driver_lock, flags);
>
>         if (ret)
>                 pr_err("%s: BOOST cannot enable (%d)\n",
>                        __func__, ret);
> }
>
> and @ cpufreq_register_driver() I will add following line:
>
> if (!cpufreq_driver->enable_boost)
>         cpufreq_driver->enable_boost = &cpufreq_boost_enable_sw;
>
> When cpufreq driver doesn't define callback for enable_boost it will be
> filled with default SW cpufreq_boost_enable_sw callback.

That's some smart  code. Good. :)
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lukasz Majewski June 28, 2013, 7:31 a.m. UTC | #18
On Fri, 28 Jun 2013 12:21:21 +0530, Viresh Kumar wrote:

> On 28 June 2013 12:19, Lukasz Majewski <l.majewski@samsung.com> wrote:
> > No, I will use:
> >
> > if (boost_enabled != state) {
> >         write_lock_irqsave(&cpufreq_driver_lock, flags);
> >         boost_enabled = state;
> >
> >         ret = cpufreq_driver->enable_boost(state);
> >         ^^^^^^^^^^^^^^^^^^^^ only one callback call
> >         if (ret)
> >                 boost_enabled = 0;
> >
> >         write_unlock_irqrestore(&cpufreq_driver_lock, flags);
> >
> >         if (ret)
> >                 pr_err("%s: BOOST cannot enable (%d)\n",
> >                        __func__, ret);
> > }
> >
> > and @ cpufreq_register_driver() I will add following line:
> >
> > if (!cpufreq_driver->enable_boost)
> >         cpufreq_driver->enable_boost = &cpufreq_boost_enable_sw;
> >
> > When cpufreq driver doesn't define callback for enable_boost it
> > will be filled with default SW cpufreq_boost_enable_sw callback.
> 
> That's some smart  code. Good. :)

OK
Viresh Kumar July 17, 2013, 7:58 a.m. UTC | #19
On 20 June 2013 03:55, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> On Wednesday, June 19, 2013 10:31:02 PM Lukasz Majewski wrote:
>> On Wed, 19 Jun 2013 10:48:53 -0700
>> Dirk Brandewie <dirk.brandewie@gmail.com> wrote:
>>
>> > On 06/19/2013 10:12 AM, Lukasz Majewski wrote:

>> > > @@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct
>> > > + if (!cpufreq_driver->boost_supported)
>> > > +         boost.attr.mode = 0444;
>> > > +
>> > > + ret = cpufreq_sysfs_create_file(&(boost.attr));
>> > > + if (ret) {
>> > > +         pr_err("%s: cannot register global boost sysfs
>> > > file\n",
>> > > +                __func__);
>> > > +         goto err_null_driver;
>> > > + }
>> > > +
>> >
>> > I do not think the boost sysfs should be created at all if boost is
>> > not supported.
>>
>> This was my first thought. But unfortunately this "boost" attribute is
>> always exported at acpi-cpufreq.c and in my opinion is part of a
>> legacy API.
>>
>> I totally agree with the idea of exporting boost only when supported,
>> but I would like to know the community opinion about this (especially
>> Viresh and Rafael shall speak up).
>
> Simple: Export it only when supported.

Guys,

I got confused here. We originally decided to keep this feature as is
for acpi-cpufreq.

So, For acpi-cpufreq:
- when boost isn't supported: create sysfs boost with ro permissions
- when boost is supported: create sysfs boost with rw permissions

So, For others:
- create sysfs boost with rw permissions only when boost is supported

.

Do you want something else? or do you want to change behavior of
acpi-cpufreq driver? I don't why it was designed this way and what
applications use it.
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafael Wysocki July 17, 2013, 11:31 a.m. UTC | #20
On Wednesday, July 17, 2013 01:28:29 PM Viresh Kumar wrote:
> On 20 June 2013 03:55, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > On Wednesday, June 19, 2013 10:31:02 PM Lukasz Majewski wrote:
> >> On Wed, 19 Jun 2013 10:48:53 -0700
> >> Dirk Brandewie <dirk.brandewie@gmail.com> wrote:
> >>
> >> > On 06/19/2013 10:12 AM, Lukasz Majewski wrote:
> 
> >> > > @@ -1936,6 +2019,16 @@ int cpufreq_register_driver(struct
> >> > > + if (!cpufreq_driver->boost_supported)
> >> > > +         boost.attr.mode = 0444;
> >> > > +
> >> > > + ret = cpufreq_sysfs_create_file(&(boost.attr));
> >> > > + if (ret) {
> >> > > +         pr_err("%s: cannot register global boost sysfs
> >> > > file\n",
> >> > > +                __func__);
> >> > > +         goto err_null_driver;
> >> > > + }
> >> > > +
> >> >
> >> > I do not think the boost sysfs should be created at all if boost is
> >> > not supported.
> >>
> >> This was my first thought. But unfortunately this "boost" attribute is
> >> always exported at acpi-cpufreq.c and in my opinion is part of a
> >> legacy API.
> >>
> >> I totally agree with the idea of exporting boost only when supported,
> >> but I would like to know the community opinion about this (especially
> >> Viresh and Rafael shall speak up).
> >
> > Simple: Export it only when supported.
> 
> Guys,
> 
> I got confused here. We originally decided to keep this feature as is
> for acpi-cpufreq.
> 
> So, For acpi-cpufreq:
> - when boost isn't supported: create sysfs boost with ro permissions
> - when boost is supported: create sysfs boost with rw permissions
> 
> So, For others:
> - create sysfs boost with rw permissions only when boost is supported
> 
> .
> 
> Do you want something else? or do you want to change behavior of
> acpi-cpufreq driver? I don't why it was designed this way and what
> applications use it.

First off, I'm not sure how many applications actually use it and I think,
if any, they should be able cope with the attribute not being present.

Of course, if it turns out that yes, there are applications using it and no,
they cannot cope with the missing attribute, we'll need to address this.
That said such applications wouldn't work with earlier kernels in which that
attribute wasn't present at all, so I suppose this is really unlikely.

So, do whichever makes more sense to you: Design things to preserve the old
behavior (which is sightly confusing) or design them to expose the attribute
if the feature is actually supported and be prepared to address the (unlikely)
case when some hypothetical applications break because of that.

Thanks,
Rafael
Viresh Kumar July 17, 2013, 1:01 p.m. UTC | #21
On 17 July 2013 17:01, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> First off, I'm not sure how many applications actually use it and I think,
> if any, they should be able cope with the attribute not being present.
>
> Of course, if it turns out that yes, there are applications using it and no,
> they cannot cope with the missing attribute, we'll need to address this.
> That said such applications wouldn't work with earlier kernels in which that
> attribute wasn't present at all, so I suppose this is really unlikely.
>
> So, do whichever makes more sense to you: Design things to preserve the old
> behavior (which is sightly confusing) or design them to expose the attribute
> if the feature is actually supported and be prepared to address the (unlikely)
> case when some hypothetical applications break because of that.

Okay. Its better to keep it the way Lukasz designed it in his last patchset.
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lukasz Majewski July 17, 2013, 2:59 p.m. UTC | #22
On Wed, 17 Jul 2013 18:31:19 +0530 Viresh Kumar viresh.kumar@linaro.org
wrote,
> On 17 July 2013 17:01, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > First off, I'm not sure how many applications actually use it and I
> > think, if any, they should be able cope with the attribute not
> > being present.
> >
> > Of course, if it turns out that yes, there are applications using
> > it and no, they cannot cope with the missing attribute, we'll need
> > to address this. That said such applications wouldn't work with
> > earlier kernels in which that attribute wasn't present at all, so I
> > suppose this is really unlikely.
> >
> > So, do whichever makes more sense to you: Design things to preserve
> > the old behavior (which is sightly confusing) or design them to
> > expose the attribute if the feature is actually supported and be
> > prepared to address the (unlikely) case when some hypothetical
> > applications break because of that.
> 
> Okay. Its better to keep it the way Lukasz designed it in his last
> patchset.

To be 100% sure - we export boost only when supported (as proposed at v5).
Viresh Kumar July 18, 2013, 7:51 a.m. UTC | #23
On 17 July 2013 20:29, Lukasz Majewski <l.majewski@samsung.com> wrote:
> To be 100% sure - we export boost only when supported (as proposed at v5).

Yes.
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 665e641..9141d33 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -40,6 +40,7 @@ 
  * also protects the cpufreq_cpu_data array.
  */
 static struct cpufreq_driver *cpufreq_driver;
+static bool boost_enabled;
 static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
 #ifdef CONFIG_HOTPLUG_CPU
 /* This one keeps track of the previously set governor of a removed CPU */
@@ -316,6 +317,29 @@  EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
 /*********************************************************************
  *                          SYSFS INTERFACE                          *
  *********************************************************************/
+ssize_t show_boost(struct kobject *kobj,
+				 struct attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", boost_enabled);
+}
+
+static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
+				  const char *buf, size_t count)
+{
+	int ret, enable;
+
+	ret = sscanf(buf, "%d", &enable);
+	if (ret != 1 || enable < 0 || enable > 1)
+		return -EINVAL;
+
+	if (cpufreq_boost_trigger_state(enable)) {
+		pr_err("%s: Cannot enable boost!\n", __func__);
+		return -EINVAL;
+	}
+
+	return count;
+}
+define_one_global_rw(boost);
 
 static struct cpufreq_governor *__find_governor(const char *str_governor)
 {
@@ -1898,6 +1922,65 @@  static struct notifier_block __refdata cpufreq_cpu_notifier = {
 };
 
 /*********************************************************************
+ *               BOOST						     *
+ *********************************************************************/
+static int cpufreq_boost_trigger_state_sw(void)
+{
+	struct cpufreq_frequency_table *freq_table;
+	struct cpufreq_policy *policy;
+	int ret = -EINVAL;
+
+	list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+		freq_table = cpufreq_frequency_get_table(policy->cpu);
+		if (freq_table)
+			ret = cpufreq_frequency_table_cpuinfo(policy,
+							freq_table);
+	}
+
+	return ret;
+
+}
+int cpufreq_boost_trigger_state(int state)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	if (boost_enabled != state) {
+		write_lock_irqsave(&cpufreq_driver_lock, flags);
+		boost_enabled = state;
+		if (cpufreq_driver->enable_boost)
+			ret = cpufreq_driver->enable_boost(state);
+		else
+			ret = cpufreq_boost_trigger_state_sw();
+
+		if (ret) {
+			boost_enabled = 0;
+			write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+			pr_err("%s: BOOST cannot enable (%d)\n",
+			       __func__, ret);
+
+			return ret;
+		}
+		write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+		pr_debug("%s: cpufreq BOOST %s\n", __func__,
+			 state ? "enabled" : "disabled");
+	}
+
+	return 0;
+}
+
+int cpufreq_boost_supported(void)
+{
+	return cpufreq_driver->boost_supported;
+}
+
+int cpufreq_boost_enabled(void)
+{
+	return boost_enabled;
+}
+
+/*********************************************************************
  *               REGISTER / UNREGISTER CPUFREQ DRIVER                *
  *********************************************************************/
 
@@ -1936,6 +2019,16 @@  int cpufreq_register_driver(struct cpufreq_driver *driver_data)
 	cpufreq_driver = driver_data;
 	write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
+	if (!cpufreq_driver->boost_supported)
+		boost.attr.mode = 0444;
+
+	ret = cpufreq_sysfs_create_file(&(boost.attr));
+	if (ret) {
+		pr_err("%s: cannot register global boost sysfs file\n",
+		       __func__);
+		goto err_null_driver;
+	}
+
 	ret = subsys_interface_register(&cpufreq_interface);
 	if (ret)
 		goto err_null_driver;
@@ -1992,6 +2085,8 @@  int cpufreq_unregister_driver(struct cpufreq_driver *driver)
 	pr_debug("unregistering driver %s\n", driver->name);
 
 	subsys_interface_unregister(&cpufreq_interface);
+
+	cpufreq_sysfs_remove_file(&(boost.attr));
 	unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
 
 	list_del(&cpufreq_policy_list);
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index d7a7966..9c8e71e 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -34,6 +34,11 @@  int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
 
 			continue;
 		}
+		if (cpufreq_boost_supported())
+			if (!cpufreq_boost_enabled()
+			    && table[i].index == CPUFREQ_BOOST_FREQ)
+				continue;
+
 		pr_debug("table entry %u: %u kHz, %u index\n",
 					i, freq, table[i].index);
 		if (freq < min_freq)
@@ -171,7 +176,8 @@  static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
 /**
  * show_available_freqs - show available frequencies for the specified CPU
  */
-static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
+				    int show_boost)
 {
 	unsigned int i = 0;
 	unsigned int cpu = policy->cpu;
@@ -186,6 +192,9 @@  static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
 	for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
 		if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
 			continue;
+		if (show_boost ^ (table[i].index == CPUFREQ_BOOST_FREQ))
+			continue;
+
 		count += sprintf(&buf[count], "%d ", table[i].frequency);
 	}
 	count += sprintf(&buf[count], "\n");
@@ -194,14 +203,34 @@  static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
 
 }
 
-struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
-	.attr = { .name = "scaling_available_frequencies",
-		  .mode = 0444,
-		},
-	.show = show_available_freqs,
-};
+#define cpufreq_attr_available_freq(_name)	  \
+struct freq_attr cpufreq_freq_attr_##_name##_freqs =     \
+__ATTR_RO(_name##_frequencies)
+
+/**
+ * show_scaling_available_frequencies - show normal boost frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
+						  char *buf)
+{
+	return show_available_freqs(policy, buf, 0);
+}
+cpufreq_attr_available_freq(scaling_available);
 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
 
+/**
+ * show_available_boost_freqs - show available boost frequencies for
+ * the specified CPU
+ */
+static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
+					      char *buf)
+{
+	return show_available_freqs(policy, buf, 1);
+}
+cpufreq_attr_available_freq(scaling_boost);
+EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
+
 /*
  * if you use these, you must assure that the frequency table is valid
  * all the time between get_attr and put_attr!
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 5348981..4783c4c 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -267,6 +267,10 @@  struct cpufreq_driver {
 	int	(*suspend)	(struct cpufreq_policy *policy);
 	int	(*resume)	(struct cpufreq_policy *policy);
 	struct freq_attr	**attr;
+
+	/* platform specific boost support code */
+	bool                    boost_supported;
+	int (*enable_boost)    (int state);
 };
 
 /* flags */
@@ -408,6 +412,9 @@  extern struct cpufreq_governor cpufreq_gov_conservative;
 #define CPUFREQ_ENTRY_INVALID ~0
 #define CPUFREQ_TABLE_END     ~1
 
+/* Define index for boost frequency */
+#define CPUFREQ_BOOST_FREQ    ~2
+
 struct cpufreq_frequency_table {
 	unsigned int	index;     /* any */
 	unsigned int	frequency; /* kHz - doesn't need to be in ascending
@@ -426,11 +433,15 @@  int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
 				   unsigned int relation,
 				   unsigned int *index);
 
+int cpufreq_boost_trigger_state(int state);
+int cpufreq_boost_supported(void);
+int cpufreq_boost_enabled(void);
 /* the following 3 funtions are for cpufreq core use only */
 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
 
 /* the following are really really optional */
 extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
+extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs;
 
 void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
 				      unsigned int cpu);