Re: [PATCH v6 4/4] PM / DEVFREQ: add sysfs interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Aug 19, 2011 at 12:15 PM, Turquette, Mike <mturquette@xxxxxx> wrote:
> On Thu, Aug 18, 2011 at 3:27 AM, MyungJoo Ham <myungjoo.ham@xxxxxxxxxxx> wrote:
>> Device specific sysfs interface /sys/devices/.../power/devfreq_*
>> - governor      R: name of governor
>> - cur_freq      R: current frequency
>> - max_freq      R: maximum operable frequency
>> - min_freq      R: minimum operable frequency
>> - set_freq      R: read user specified frequency (0 if not specified yet)
>>                W: set user specified frequency
>> - polling_interval      R: polling interval in ms given with devfreq profile
>
> This code still does not export up_threshold/down_threshold entries
> for simple-ondemand which I requested in V5.  However there is a much
> bigger issue here brought out in patch 3.  Those values shouldn't be
> global, since devices might want different thresholds.
>
> The solution is not to put those tunables in struct devfreq.
> up_threshold and down_threshold must be parameters of the governor,
> and there must be a per-device instance of the governor.
>
> Regards,
> Mike

As in the example in the reply to the thread of patch 3/4 of v6
patchset, we do not need to create another per-device object in
DEVFREQ in order to allow governors to be tuned per device. The global
values you've mentioned are only used as default and each instance of
devfreq (per device) can specify its own tuneable values and they can
alter the values in run-time.

For the sysfs interfaces of governor-specific tunable values, I'd like
to see that as a "future work" and that would be implemented
per-governor basis; i.e., probably under
/sysfs/devices/.../power/NAME_OF_GOVERNOR/variable_name. Or should I
regard the sysfs interface to tune governors at userland is somewhat
essential and critical for the initial release?



Cheers!

MyungJoo

>
>>
>> Signed-off-by: MyungJoo Ham <myungjoo.ham@xxxxxxxxxxx>
>> Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx>
>>
>> --
>> Changed from v5
>> - updated devferq_update usage.
>>
>> Changed from v4
>> - removed system-wide sysfs interface
>> - removed tickling sysfs interface
>> - added set_freq for userspace governor (and any other governors that
>>  require user input)
>>
>> Changed from v3
>> - corrected sysfs API usage
>> - corrected error messages
>> - moved sysfs entry location
>> - added sysfs entries
>>
>> Changed from v2
>> - add ABI entries for devfreq sysfs interface
>> ---
>>  Documentation/ABI/testing/sysfs-devices-power |   45 +++++++
>>  drivers/devfreq/devfreq.c                     |  152 +++++++++++++++++++++++++
>>  2 files changed, 197 insertions(+), 0 deletions(-)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power
>> index 8ffbc25..6e77604 100644
>> --- a/Documentation/ABI/testing/sysfs-devices-power
>> +++ b/Documentation/ABI/testing/sysfs-devices-power
>> @@ -165,3 +165,48 @@ Description:
>>
>>                Not all drivers support this attribute.  If it isn't supported,
>>                attempts to read or write it will yield I/O errors.
>> +
>> +What:          /sys/devices/.../power/devfreq_governor
>> +Date:          July 2011
>> +Contact:       MyungJoo Ham <myungjoo.ham@xxxxxxxxxxx>
>> +Description:
>> +               The /sys/devices/.../power/devfreq_governor shows the name
>> +               of the governor used by the corresponding device.
>> +
>> +What:          /sys/devices/.../power/devfreq_cur_freq
>> +Date:          July 2011
>> +Contact:       MyungJoo Ham <myungjoo.ham@xxxxxxxxxxx>
>> +Description:
>> +               The /sys/devices/.../power/devfreq_cur_freq shows the current
>> +               frequency of the corresponding device.
>> +
>> +What:          /sys/devices/.../power/devfreq_max_freq
>> +Date:          July 2011
>> +Contact:       MyungJoo Ham <myungjoo.ham@xxxxxxxxxxx>
>> +Description:
>> +               The /sys/devices/.../power/devfreq_cur_freq shows the
>> +               maximum operable frequency of the corresponding device.
>> +
>> +What:          /sys/devices/.../power/devfreq_min_freq
>> +Date:          July 2011
>> +Contact:       MyungJoo Ham <myungjoo.ham@xxxxxxxxxxx>
>> +Description:
>> +               The /sys/devices/.../power/devfreq_cur_freq shows the
>> +               minimum operable frequency of the corresponding device.
>> +
>> +What:          /sys/devices/.../power/devfreq_set_freq
>> +Date:          August 2011
>> +Contact:       MyungJoo Ham <myungjoo.ham@xxxxxxxxxxx>
>> +Description:
>> +               The /sys/devices/.../power/devfreq_set_freq sets and shows
>> +               the user specified desired frequency of the device. The
>> +               governor may and may not use the value. With the basic
>> +               governors given with devfreq.c, userspace governor is
>> +               using the value.
>> +
>> +What:          /sys/devices/.../power/devfreq_polling_interval
>> +Date:          July 2011
>> +Contact:       MyungJoo Ham <myungjoo.ham@xxxxxxxxxxx>
>> +Description:
>> +               The /sys/devices/.../power/devfreq_polling_interval shows the
>> +               requested polling interval of the corresponding device.
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index 2036f2c..13b422f 100644
>> --- a/drivers/devfreq/devfreq.c
>> +++ b/drivers/devfreq/devfreq.c
>> @@ -37,6 +37,8 @@ static struct delayed_work devfreq_work;
>>  static LIST_HEAD(devfreq_list);
>>  static DEFINE_MUTEX(devfreq_list_lock);
>>
>> +static struct attribute_group dev_attr_group;
>> +
>>  /**
>>  * find_device_devfreq() - find devfreq struct using device pointer
>>  * @dev:       device pointer used to lookup device devfreq.
>> @@ -154,6 +156,8 @@ static void devfreq_monitor(struct work_struct *work)
>>                                dev_err(devfreq->dev, "Due to devfreq_do error(%d), devfreq(%s) is removed from the device\n",
>>                                        error, devfreq->governor->name);
>>
>> +                               sysfs_unmerge_group(&devfreq->dev->kobj,
>> +                                                   &dev_attr_group);
>>                                list_del(&devfreq->node);
>>                                kfree(devfreq);
>>
>> @@ -244,6 +248,8 @@ int devfreq_add_device(struct device *dev, struct devfreq_dev_profile *profile,
>>                queue_delayed_work(devfreq_wq, &devfreq_work,
>>                                   devfreq->next_polling);
>>        }
>> +
>> +       sysfs_merge_group(&dev->kobj, &dev_attr_group);
>>  out:
>>        mutex_unlock(&devfreq_list_lock);
>>
>> @@ -276,6 +282,8 @@ int devfreq_remove_device(struct device *dev)
>>                goto out;
>>        }
>>
>> +       sysfs_unmerge_group(&dev->kobj, &dev_attr_group);
>> +
>>        list_del(&devfreq->node);
>>        srcu_notifier_chain_unregister(nh, &devfreq->nb);
>>        kfree(devfreq);
>> @@ -284,6 +292,150 @@ out:
>>        return 0;
>>  }
>>
>> +static ssize_t show_governor(struct device *dev,
>> +                            struct device_attribute *attr, char *buf)
>> +{
>> +       struct devfreq *df = find_device_devfreq(dev);
>> +
>> +       if (IS_ERR(df))
>> +               return PTR_ERR(df);
>> +       if (!df->governor)
>> +               return -EINVAL;
>> +
>> +       return sprintf(buf, "%s\n", df->governor->name);
>> +}
>> +
>> +static ssize_t show_freq(struct device *dev,
>> +                        struct device_attribute *attr, char *buf)
>> +{
>> +       struct devfreq *df = find_device_devfreq(dev);
>> +
>> +       if (IS_ERR(df))
>> +               return PTR_ERR(df);
>> +
>> +       return sprintf(buf, "%lu\n", df->previous_freq);
>> +}
>> +
>> +static ssize_t show_max_freq(struct device *dev,
>> +                            struct device_attribute *attr, char *buf)
>> +{
>> +       struct devfreq *df = find_device_devfreq(dev);
>> +       unsigned long freq = ULONG_MAX;
>> +       struct opp *opp;
>> +
>> +       if (IS_ERR(df))
>> +               return PTR_ERR(df);
>> +       if (!df->dev)
>> +               return -EINVAL;
>> +
>> +       opp = opp_find_freq_floor(df->dev, &freq);
>> +       if (IS_ERR(opp))
>> +               return PTR_ERR(opp);
>> +
>> +       return sprintf(buf, "%lu\n", freq);
>> +}
>> +
>> +static ssize_t show_min_freq(struct device *dev,
>> +                            struct device_attribute *attr, char *buf)
>> +{
>> +       struct devfreq *df = find_device_devfreq(dev);
>> +       unsigned long freq = 0;
>> +       struct opp *opp;
>> +
>> +       if (IS_ERR(df))
>> +               return PTR_ERR(df);
>> +       if (!df->dev)
>> +               return -EINVAL;
>> +
>> +       opp = opp_find_freq_ceil(df->dev, &freq);
>> +       if (IS_ERR(opp))
>> +               return PTR_ERR(opp);
>> +
>> +       return sprintf(buf, "%lu\n", freq);
>> +}
>> +
>> +static ssize_t show_polling_interval(struct device *dev,
>> +                                    struct device_attribute *attr, char *buf)
>> +{
>> +       struct devfreq *df = find_device_devfreq(dev);
>> +
>> +       if (IS_ERR(df))
>> +               return PTR_ERR(df);
>> +       if (!df->profile)
>> +               return -EINVAL;
>> +
>> +       return sprintf(buf, "%d\n", df->profile->polling_ms);
>> +}
>> +
>> +static ssize_t set_user_frequency(struct device *dev,
>> +                                 struct device_attribute *attr,
>> +                                 const char *buf, size_t count)
>> +{
>> +       struct devfreq *devfreq;
>> +       unsigned long wanted;
>> +       int err = 0;
>> +
>> +       sscanf(buf, "%lu", &wanted);
>> +
>> +       mutex_lock(&devfreq_list_lock);
>> +       devfreq = find_device_devfreq(dev);
>> +
>> +       if (IS_ERR(devfreq)) {
>> +               err = PTR_ERR(devfreq);
>> +               goto out;
>> +       }
>> +
>> +       devfreq->user_set_freq = wanted;
>> +       err = count;
>> +out:
>> +       mutex_unlock(&devfreq_list_lock);
>> +       if (err >= 0)
>> +               devfreq_update(&devfreq->nb, 0, NULL);
>> +       return err;
>> +}
>> +
>> +static ssize_t show_user_frequency(struct device *dev,
>> +                                  struct device_attribute *attr, char *buf)
>> +{
>> +       struct devfreq *devfreq;
>> +       int err = 0;
>> +
>> +       mutex_lock(&devfreq_list_lock);
>> +       devfreq = find_device_devfreq(dev);
>> +
>> +       if (IS_ERR(devfreq)) {
>> +               err = PTR_ERR(devfreq);
>> +               goto out;
>> +       }
>> +
>> +       err = sprintf(buf, "%lu\n", devfreq->user_set_freq);
>> +out:
>> +       mutex_unlock(&devfreq_list_lock);
>> +       return err;
>> +
>> +}
>> +
>> +static DEVICE_ATTR(devfreq_governor, 0444, show_governor, NULL);
>> +static DEVICE_ATTR(devfreq_cur_freq, 0444, show_freq, NULL);
>> +static DEVICE_ATTR(devfreq_max_freq, 0444, show_max_freq, NULL);
>> +static DEVICE_ATTR(devfreq_min_freq, 0444, show_min_freq, NULL);
>> +static DEVICE_ATTR(devfreq_polling_interval, 0444, show_polling_interval, NULL);
>> +static DEVICE_ATTR(devfreq_set_freq, 0644, show_user_frequency,
>> +                  set_user_frequency);
>> +static struct attribute *dev_entries[] = {
>> +       &dev_attr_devfreq_governor.attr,
>> +       &dev_attr_devfreq_cur_freq.attr,
>> +       &dev_attr_devfreq_max_freq.attr,
>> +       &dev_attr_devfreq_min_freq.attr,
>> +       &dev_attr_devfreq_polling_interval.attr,
>> +       &dev_attr_devfreq_set_freq.attr,
>> +       NULL,
>> +};
>> +static struct attribute_group dev_attr_group = {
>> +       .name   = power_group_name,
>> +       .attrs  = dev_entries,
>> +};
>> +
>>  /**
>>  * devfreq_init() - Initialize data structure for devfreq framework and
>>  *               start polling registered devfreq devices.
>> --
>> 1.7.4.1
>>
>>
>



-- 
MyungJoo Ham (함명주), Ph.D.
Mobile Software Platform Lab,
Digital Media and Communications (DMC) Business
Samsung Electronics
cell: 82-10-6714-2858
_______________________________________________
linux-pm mailing list
linux-pm@xxxxxxxxxxxxxxxxxxxxxxxxxx
https://lists.linux-foundation.org/mailman/listinfo/linux-pm



[Index of Archives]     [Linux ACPI]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [CPU Freq]     [Kernel Newbies]     [Fedora Kernel]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux