Re: [PATCH] PM / devfreq: add relation of recommended frequency.

From: MyungJoo Ham
Date: Fri Mar 09 2012 - 02:10:03 EST


On Thu, Mar 8, 2012 at 2:45 AM, Turquette, Mike <mturquette@xxxxxx> wrote:
> On Thu, Feb 9, 2012 at 11:19 PM, MyungJoo Ham <myungjoo.ham@xxxxxxxxxxx> wrote:
>> The semantics of "target frequency" given to devfreq driver from
>> devfreq framework has always been interpretted as "at least" or GLB
>> (greatest lower bound). However, the framework might want the
>> device driver to limit its max frequency (LUB: least upper bound),
>> especially if it is given by thermal framework (it's too hot).
>>
>> Thus, the target fuction should have another parameter to express
>> whether the framework wants GLB or LUB. And, the additional parameter,
>> "u32 options", does it.
>
> Nitpick: changelog still refers to "options" but code reads "flags".
>
> Regards,
> Mike
>

Thanks. That is updated in the git.infradead.org repository to be
requested to pull.
http://git.infradead.org/users/kmpark/linux-samsung/shortlog/refs/heads/devfreq-for-next

As soon as infradead server gets synched, you can see the commit
message updated.


Cheers!
MyungJoo.

>>
>> With the update, devfreq_recommended_opp() is also updated.
>>
>> Signed-off-by: MyungJoo Ham <myungjoo.ham@xxxxxxxxxxx>
>> Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx>
>> ---
>>  drivers/devfreq/devfreq.c     |   44 ++++++++++++++++++++++++++++++----------
>>  drivers/devfreq/exynos4_bus.c |   16 +++++++++++---
>>  include/linux/devfreq.h       |   18 ++++++++++++++--
>>  3 files changed, 60 insertions(+), 18 deletions(-)
>>
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index a33fc6c..83392a6 100644
>> --- a/drivers/devfreq/devfreq.c
>> +++ b/drivers/devfreq/devfreq.c
>> @@ -84,6 +84,7 @@ int update_devfreq(struct devfreq *devfreq)
>>  {
>>        unsigned long freq;
>>        int err = 0;
>> +       u32 options = 0;
>>
>>        if (!mutex_is_locked(&devfreq->lock)) {
>>                WARN(true, "devfreq->lock must be locked by the caller.\n");
>> @@ -104,18 +105,23 @@ int update_devfreq(struct devfreq *devfreq)
>>         * qos_min_freq
>>         */
>>
>> -       if (devfreq->qos_min_freq && freq < devfreq->qos_min_freq)
>> +       if (devfreq->qos_min_freq && freq < devfreq->qos_min_freq) {
>>                freq = devfreq->qos_min_freq;
>> -       if (devfreq->max_freq && freq > devfreq->max_freq)
>> +               options &= ~(1 << 0);
>> +               options |= DEVFREQ_OPTION_FREQ_LUB;
>> +       }
>> +       if (devfreq->max_freq && freq > devfreq->max_freq) {
>>                freq = devfreq->max_freq;
>> -       if (devfreq->min_freq && freq < devfreq->min_freq)
>> +               options &= ~(1 << 0);
>> +               options |= DEVFREQ_OPTION_FREQ_GLB;
>> +       }
>> +       if (devfreq->min_freq && freq < devfreq->min_freq) {
>>                freq = devfreq->min_freq;
>> +               options &= ~(1 << 0);
>> +               options |= DEVFREQ_OPTION_FREQ_LUB;
>> +       }
>>
>> -       /*
>> -        * TODO in the devfreq-next:
>> -        * add relation or use rance (freq_min, freq_max)
>> -        */
>> -       err = devfreq->profile->target(devfreq->dev.parent, &freq);
>> +       err = devfreq->profile->target(devfreq->dev.parent, &freq, options);
>>        if (err)
>>                return err;
>>
>> @@ -771,14 +777,30 @@ module_exit(devfreq_exit);
>>  *                          freq value given to target callback.
>>  * @dev                The devfreq user device. (parent of devfreq)
>>  * @freq       The frequency given to target function
>> + * @floor      false: find LUB first and use GLB if LUB not available.
>> + *             true:  find GLB first and use LUB if GLB not available.
>> + *
>> + * LUB: least upper bound (at least this freq or above, but the least)
>> + * GLB: greatest lower bound (at most this freq or below, but the most)
>>  *
>>  */
>> -struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq)
>> +struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq,
>> +                                   bool floor)
>>  {
>> -       struct opp *opp = opp_find_freq_ceil(dev, freq);
>> +       struct opp *opp;
>>
>> -       if (opp == ERR_PTR(-ENODEV))
>> +       if (floor) {
>>                opp = opp_find_freq_floor(dev, freq);
>> +
>> +               if (opp == ERR_PTR(-ENODEV))
>> +                       opp = opp_find_freq_ceil(dev, freq);
>> +       } else {
>> +               opp = opp_find_freq_ceil(dev, freq);
>> +
>> +               if (opp == ERR_PTR(-ENODEV))
>> +                       opp = opp_find_freq_floor(dev, freq);
>> +       }
>> +
>>        return opp;
>>  }
>>
>> diff --git a/drivers/devfreq/exynos4_bus.c b/drivers/devfreq/exynos4_bus.c
>> index 590d686..c0a78da 100644
>> --- a/drivers/devfreq/exynos4_bus.c
>> +++ b/drivers/devfreq/exynos4_bus.c
>> @@ -619,13 +619,21 @@ static int exynos4_bus_setvolt(struct busfreq_data *data, struct opp *opp,
>>        return err;
>>  }
>>
>> -static int exynos4_bus_target(struct device *dev, unsigned long *_freq)
>> +static int exynos4_bus_target(struct device *dev, unsigned long *_freq,
>> +                             u32 options)
>>  {
>>        int err = 0;
>> -       struct busfreq_data *data = dev_get_drvdata(dev);
>> -       struct opp *opp = devfreq_recommended_opp(dev, _freq);
>> -       unsigned long old_freq = opp_get_freq(data->curr_opp);
>> +       unsigned long def = *_freq;
>> +       struct platform_device *pdev = container_of(dev, struct platform_device,
>> +                                                   dev);
>> +       struct busfreq_data *data = platform_get_drvdata(pdev);
>> +       struct opp *opp = devfreq_recommended_opp(dev, _freq, options &
>> +                                                 DEVFREQ_OPTION_FREQ_GLB);
>>        unsigned long freq = opp_get_freq(opp);
>> +       unsigned long old_freq = opp_get_freq(data->curr_opp);
>> +
>> +       if (IS_ERR(opp))
>> +               return PTR_ERR(opp);
>>
>>        if (old_freq == freq)
>>                return 0;
>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>> index b853379..1aff012 100644
>> --- a/include/linux/devfreq.h
>> +++ b/include/linux/devfreq.h
>> @@ -59,6 +59,16 @@ struct devfreq_pm_qos_table {
>>        s32 qos_value;
>>  };
>>
>> +/*
>> + * target callback, which is to provide additional information to the
>> + * devfreq driver.
>> + */
>> +
>> +/* The resulting frequency should be at least this. (least upper bound) */
>> +#define DEVFREQ_OPTION_FREQ_LUB        0x0
>> +/* The resulting frequency should be at most this. (greatest lower bound) */
>> +#define DEVFREQ_OPTION_FREQ_GLB 0x1
>> +
>>  /**
>>  * struct devfreq_dev_profile - Devfreq's user device profile
>>  * @initial_freq       The operating frequency when devfreq_add_device() is
>> @@ -76,6 +86,8 @@ struct devfreq_pm_qos_table {
>>  *                     higher than any operable frequency, set maximum.
>>  *                     Before returning, target function should set
>>  *                     freq at the current frequency.
>> + *                     The "option" parameter's possible values are
>> + *                     explained above with "DEVFREQ_OPTION_*" macros.
>>  * @get_dev_status     The device should provide the current performance
>>  *                     status to devfreq, which is used by governors.
>>  * @exit               An optional callback that is called when devfreq
>> @@ -95,7 +107,7 @@ struct devfreq_dev_profile {
>>        bool qos_use_max;
>>        struct devfreq_pm_qos_table *qos_list;
>>
>> -       int (*target)(struct device *dev, unsigned long *freq);
>> +       int (*target)(struct device *dev, unsigned long *freq, u32 options);
>>        int (*get_dev_status)(struct device *dev,
>>                              struct devfreq_dev_status *stat);
>>        void (*exit)(struct device *dev);
>> @@ -198,7 +210,7 @@ extern int devfreq_remove_device(struct devfreq *devfreq);
>>
>>  /* Helper functions for devfreq user device driver with OPP. */
>>  extern struct opp *devfreq_recommended_opp(struct device *dev,
>> -                                          unsigned long *freq);
>> +                                          unsigned long *freq, bool floor);
>>  extern int devfreq_register_opp_notifier(struct device *dev,
>>                                         struct devfreq *devfreq);
>>  extern int devfreq_unregister_opp_notifier(struct device *dev,
>> @@ -253,7 +265,7 @@ static int devfreq_remove_device(struct devfreq *devfreq)
>>  }
>>
>>  static struct opp *devfreq_recommended_opp(struct device *dev,
>> -                                          unsigned long *freq)
>> +                                          unsigned long *freq, bool floor)
>>  {
>>        return -EINVAL;
>>  }
>> --
>> 1.7.4.1
>>



--
MyungJoo Ham, Ph.D.
Mobile Software Platform Lab, DMC Business, Samsung Electronics
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/