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

From: MyungJoo Ham
Date: Sun Mar 11 2012 - 22:13:01 EST


2012/3/11 Rafael J. Wysocki <rjw@xxxxxxx>:
> On Wednesday, March 07, 2012, MyungJoo Ham 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.
>>
>> 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>
>
> This one looks good.
>
> Do you want me to take it as a patch, or to pull it from your tree?
>
> Rafael

Hello Rafael,


Please pull it from the tree
(http://git.infradead.org/users/kmpark/linux-samsung/shortlog/refs/heads/devfreq-for-next)
as the change log has been corrected.

git://git.infradead.org/users/kmpark/linux-samsung devfreq-for-next



Thank you.


Cheers!
MyungJoo.

>
>
>> ---
>> Changes from v1
>> - Style update.
>> ---
>>  drivers/devfreq/devfreq.c     |   41 ++++++++++++++++++++++++++++++-----------
>>  drivers/devfreq/exynos4_bus.c |   14 ++++++++++----
>>  include/linux/devfreq.h       |   16 +++++++++++++---
>>  3 files changed, 53 insertions(+), 18 deletions(-)
>>
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index 0b49f59..13794d1 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 flags = 0;
>>
>>       if (!mutex_is_locked(&devfreq->lock)) {
>>               WARN(true, "devfreq->lock must be locked by the caller.\n");
>> @@ -104,18 +105,20 @@ 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)
>> +             flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
>> +     }
>> +     if (devfreq->max_freq && freq > devfreq->max_freq) {
>>               freq = devfreq->max_freq;
>> -     if (devfreq->min_freq && freq < devfreq->min_freq)
>> +             flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */
>> +     }
>> +     if (devfreq->min_freq && freq < devfreq->min_freq) {
>>               freq = devfreq->min_freq;
>> +             flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
>> +     }
>>
>> -     /*
>> -      * 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, flags);
>>       if (err)
>>               return err;
>>
>> @@ -773,14 +776,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
>> + * @flags    Flags handed from devfreq framework.
>>   *
>>   */
>> -struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq)
>> +struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq,
>> +                                 u32 flags)
>>  {
>> -     struct opp *opp = opp_find_freq_ceil(dev, freq);
>> +     struct opp *opp;
>>
>> -     if (opp == ERR_PTR(-ENODEV))
>> +     if (flags & DEVFREQ_FLAG_LEAST_UPPER_BOUND) {
>> +             /* The freq is an upper bound. opp should be lower */
>>               opp = opp_find_freq_floor(dev, freq);
>> +
>> +             /* If not available, use the closest opp */
>> +             if (opp == ERR_PTR(-ENODEV))
>> +                     opp = opp_find_freq_ceil(dev, freq);
>> +     } else {
>> +             /* The freq is an lower bound. opp should be higher */
>> +             opp = opp_find_freq_ceil(dev, freq);
>> +
>> +             /* If not available, use the closest opp */
>> +             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..1a361e9 100644
>> --- a/drivers/devfreq/exynos4_bus.c
>> +++ b/drivers/devfreq/exynos4_bus.c
>> @@ -619,13 +619,19 @@ 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 flags)
>>  {
>>       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);
>> +     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, flags);
>>       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 f27d511..85d4b0f 100644
>> --- a/include/linux/devfreq.h
>> +++ b/include/linux/devfreq.h
>> @@ -59,6 +59,14 @@ struct devfreq_pm_qos_table {
>>       s32 qos_value;
>>  };
>>
>> +/*
>> + * The resulting frequency should be at most this. (this bound is the
>> + * least upper bound; thus, the resulting freq should be lower or same)
>> + * If the flag is not set, the resulting frequency should be at most the
>> + * bound (greatest lower bound)
>> + */
>> +#define DEVFREQ_FLAG_LEAST_UPPER_BOUND               0x1
>> +
>>  /**
>>   * struct devfreq_dev_profile - Devfreq's user device profile
>>   * @initial_freq     The operating frequency when devfreq_add_device() is
>> @@ -74,6 +82,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 "flags" parameter's possible values are
>> + *                   explained above with "DEVFREQ_FLAG_*" 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
>> @@ -92,7 +102,7 @@ struct devfreq_dev_profile {
>>       int qos_type;
>>       struct devfreq_pm_qos_table *qos_list;
>>
>> -     int (*target)(struct device *dev, unsigned long *freq);
>> +     int (*target)(struct device *dev, unsigned long *freq, u32 flags);
>>       int (*get_dev_status)(struct device *dev,
>>                             struct devfreq_dev_status *stat);
>>       void (*exit)(struct device *dev);
>> @@ -198,7 +208,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, u32 flags);
>>  extern int devfreq_register_opp_notifier(struct device *dev,
>>                                        struct devfreq *devfreq);
>>  extern int devfreq_unregister_opp_notifier(struct device *dev,
>> @@ -253,7 +263,7 @@ static int devfreq_remove_device(struct devfreq *devfreq)
>>  }
>>
>>  static struct opp *devfreq_recommended_opp(struct device *dev,
>> -                                        unsigned long *freq)
>> +                                        unsigned long *freq, u32 flags)
>>  {
>>       return -EINVAL;
>>  }
>>
>



--
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/