diff mbox

[v2,3/3] PM / DEVFREQ: add sysfs interface (including user tickling)

Message ID 1305100723-29161-3-git-send-email-myungjoo.ham@samsung.com (mailing list archive)
State Superseded, archived
Headers show

Commit Message

MyungJoo Ham May 11, 2011, 7:58 a.m. UTC
1. System-wide sysfs interface
- tickle_all	R: number of tickle_all execution
		W: tickle all devfreq devices
- min_interval	R: devfreq monitoring base interval in ms
- monitoring	R: shows whether devfreq monitoring is active or
  not.

2. Device specific sysfs interface
- tickle	R: number of tickle execution for the device
		W: tickle the device

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/base/power/devfreq.c |  191 ++++++++++++++++++++++++++++++++++++-----
 include/linux/devfreq.h      |    3 +
 2 files changed, 170 insertions(+), 24 deletions(-)

Comments

Greg Kroah-Hartman May 11, 2011, 10:55 p.m. UTC | #1
On Wed, May 11, 2011 at 04:58:43PM +0900, MyungJoo Ham wrote:
> 1. System-wide sysfs interface
> - tickle_all	R: number of tickle_all execution
> 		W: tickle all devfreq devices
> - min_interval	R: devfreq monitoring base interval in ms
> - monitoring	R: shows whether devfreq monitoring is active or
>   not.
> 
> 2. Device specific sysfs interface
> - tickle	R: number of tickle execution for the device
> 		W: tickle the device

Any sysfs file change/addition/removal needs to have a
Documentation/ABI/ entry as well.  Please add that to this patch instead
of burying it in the changelog entry, where no one will be able to find
it in the future.

thanks,

greg k-h
MyungJoo Ham May 17, 2011, 5:04 a.m. UTC | #2
On Thu, May 12, 2011 at 7:55 AM, Greg KH <gregkh@suse.de> wrote:
> On Wed, May 11, 2011 at 04:58:43PM +0900, MyungJoo Ham wrote:
>> 1. System-wide sysfs interface
>> - tickle_all  R: number of tickle_all execution
>>               W: tickle all devfreq devices
>> - min_interval        R: devfreq monitoring base interval in ms
>> - monitoring  R: shows whether devfreq monitoring is active or
>>   not.
>>
>> 2. Device specific sysfs interface
>> - tickle      R: number of tickle execution for the device
>>               W: tickle the device
>
> Any sysfs file change/addition/removal needs to have a
> Documentation/ABI/ entry as well.  Please add that to this patch instead
> of burying it in the changelog entry, where no one will be able to find
> it in the future.
>
> thanks,
>
> greg k-h
>

Sure, I'll add Documentation/ABI/testing/* entries.

However, would it be appropriate for "1. System-wide sysfs interface"
to be in "sysfs-class-power" and for "2. Device specific sysfs
interface" to be in "sysfs-devices-devfreq"?

System-wide sysfs interface is in /sys/class/power/devfreq/* and
Device specific sysfs interface is in /sys/...DEVICE.../devfreq/* .

Thank you.


- MyungJoo
Greg Kroah-Hartman May 17, 2011, 6:32 p.m. UTC | #3
On Tue, May 17, 2011 at 02:04:52PM +0900, MyungJoo Ham wrote:
> On Thu, May 12, 2011 at 7:55 AM, Greg KH <gregkh@suse.de> wrote:
> > On Wed, May 11, 2011 at 04:58:43PM +0900, MyungJoo Ham wrote:
> >> 1. System-wide sysfs interface
> >> - tickle_all  R: number of tickle_all execution
> >>               W: tickle all devfreq devices
> >> - min_interval        R: devfreq monitoring base interval in ms
> >> - monitoring  R: shows whether devfreq monitoring is active or
> >>   not.
> >>
> >> 2. Device specific sysfs interface
> >> - tickle      R: number of tickle execution for the device
> >>               W: tickle the device
> >
> > Any sysfs file change/addition/removal needs to have a
> > Documentation/ABI/ entry as well.  Please add that to this patch instead
> > of burying it in the changelog entry, where no one will be able to find
> > it in the future.
> >
> > thanks,
> >
> > greg k-h
> >
> 
> Sure, I'll add Documentation/ABI/testing/* entries.
> 
> However, would it be appropriate for "1. System-wide sysfs interface"
> to be in "sysfs-class-power" and for "2. Device specific sysfs
> interface" to be in "sysfs-devices-devfreq"?
> 
> System-wide sysfs interface is in /sys/class/power/devfreq/* and
> Device specific sysfs interface is in /sys/...DEVICE.../devfreq/* .

That makes sense.

thanks,

greg k-h
Rafael Wysocki May 17, 2011, 10:41 p.m. UTC | #4
On Tuesday, May 17, 2011, MyungJoo Ham wrote:
> On Thu, May 12, 2011 at 7:55 AM, Greg KH <gregkh@suse.de> wrote:
> > On Wed, May 11, 2011 at 04:58:43PM +0900, MyungJoo Ham wrote:
> >> 1. System-wide sysfs interface
> >> - tickle_all  R: number of tickle_all execution
> >>               W: tickle all devfreq devices
> >> - min_interval        R: devfreq monitoring base interval in ms
> >> - monitoring  R: shows whether devfreq monitoring is active or
> >>   not.
> >>
> >> 2. Device specific sysfs interface
> >> - tickle      R: number of tickle execution for the device
> >>               W: tickle the device
> >
> > Any sysfs file change/addition/removal needs to have a
> > Documentation/ABI/ entry as well.  Please add that to this patch instead
> > of burying it in the changelog entry, where no one will be able to find
> > it in the future.
> >
> > thanks,
> >
> > greg k-h
> >
> 
> Sure, I'll add Documentation/ABI/testing/* entries.
> 
> However, would it be appropriate for "1. System-wide sysfs interface"
> to be in "sysfs-class-power" and for "2. Device specific sysfs
> interface" to be in "sysfs-devices-devfreq"?
> 
> System-wide sysfs interface is in /sys/class/power/devfreq/* and

Hmm.  Why not to use /sys/power/ that's already there?

> Device specific sysfs interface is in /sys/...DEVICE.../devfreq/* .

Thanks,
Rafael
MyungJoo Ham May 18, 2011, 12:43 a.m. UTC | #5
On Wed, May 18, 2011 at 7:41 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> On Tuesday, May 17, 2011, MyungJoo Ham wrote:
>> On Thu, May 12, 2011 at 7:55 AM, Greg KH <gregkh@suse.de> wrote:
>> > On Wed, May 11, 2011 at 04:58:43PM +0900, MyungJoo Ham wrote:
>> >> 1. System-wide sysfs interface
>> >> - tickle_all  R: number of tickle_all execution
>> >>               W: tickle all devfreq devices
>> >> - min_interval        R: devfreq monitoring base interval in ms
>> >> - monitoring  R: shows whether devfreq monitoring is active or
>> >>   not.
>> >>
>> >> 2. Device specific sysfs interface
>> >> - tickle      R: number of tickle execution for the device
>> >>               W: tickle the device
>> >
>> > Any sysfs file change/addition/removal needs to have a
>> > Documentation/ABI/ entry as well.  Please add that to this patch instead
>> > of burying it in the changelog entry, where no one will be able to find
>> > it in the future.
>> >
>> > thanks,
>> >
>> > greg k-h
>> >
>>
>> Sure, I'll add Documentation/ABI/testing/* entries.
>>
>> However, would it be appropriate for "1. System-wide sysfs interface"
>> to be in "sysfs-class-power" and for "2. Device specific sysfs
>> interface" to be in "sysfs-devices-devfreq"?
>>
>> System-wide sysfs interface is in /sys/class/power/devfreq/* and
>
> Hmm.  Why not to use /sys/power/ that's already there?

Ah.. that was my mistake. I'd put it at /sys/power/devfreq/*.

Thank you for cleaning that up.

>
>> Device specific sysfs interface is in /sys/...DEVICE.../devfreq/* .
>
> Thanks,
> Rafael
>

Cheers!
- MyungJoo
diff mbox

Patch

diff --git a/drivers/base/power/devfreq.c b/drivers/base/power/devfreq.c
index 251d761..ba1b606 100644
--- a/drivers/base/power/devfreq.c
+++ b/drivers/base/power/devfreq.c
@@ -40,6 +40,9 @@  static LIST_HEAD(devfreq_list);
 /* Exclusive access to devfreq_list and its elements */
 static DEFINE_MUTEX(devfreq_list_lock);
 
+static struct kobject *devfreq_kobj;
+static struct attribute_group dev_attr_group;
+
 /**
  * find_device_devfreq() - find devfreq struct using device pointer
  * @dev:	device pointer used to lookup device DEVFREQ.
@@ -211,6 +214,8 @@  int devfreq_add_device(struct device *dev, struct devfreq_dev_profile *profile,
 		queue_delayed_work(devfreq_wq, &devfreq_work,
 				   msecs_to_jiffies(DEVFREQ_INTERVAL));
 	}
+
+	sysfs_update_group(&dev->kobj, &dev_attr_group);
 out:
 	mutex_unlock(&devfreq_list_lock);
 
@@ -237,6 +242,8 @@  int devfreq_remove_device(struct device *dev)
 		return -EINVAL;
 	}
 
+	sysfs_remove_group(&dev->kobj, &dev_attr_group);
+
 	list_del(&devfreq->node);
 
 	kfree(devfreq);
@@ -286,6 +293,38 @@  out:
 	return err;
 }
 
+int _devfreq_tickle_device(struct devfreq *df, unsigned long delay)
+{
+	int err = 0;
+	unsigned long freq;
+	struct opp *opp;
+
+	freq = df->profile->max_freq;
+	opp = opp_find_freq_floor(df->dev, &freq);
+	if (IS_ERR(opp))
+		return PTR_ERR(opp);
+
+	freq = opp_get_freq(opp);
+	if (df->previous_freq != freq) {
+		err = df->profile->target(df->dev, opp);
+		if (!err)
+			df->previous_freq = freq;
+	}
+	if (err) {
+		dev_err(df->dev, "%s: Cannot set frequency.\n", __func__);
+	} else {
+		df->tickle = delay;
+		df->num_tickle++;
+	}
+
+	if (devfreq_wq && !monitoring) {
+		monitoring = true;
+		queue_delayed_work(devfreq_wq, &devfreq_work,
+				   msecs_to_jiffies(DEVFREQ_INTERVAL));
+	}
+
+	return err;
+}
 /**
  * devfreq_tickle_device() - Guarantee maximum operation speed for a while
  *			instaneously.
@@ -301,43 +340,133 @@  out:
 int devfreq_tickle_device(struct device *dev, unsigned long duration_ms)
 {
 	struct devfreq *devfreq;
-	struct opp *opp;
-	unsigned long freq;
 	int err = 0;
+	unsigned long delay; /* in num DEVFREQ_INTERVAL */
 
 	mutex_lock(&devfreq_list_lock);
 	devfreq = find_device_devfreq(dev);
-	if (!IS_ERR(devfreq)) {
-		freq = devfreq->profile->max_freq;
-		opp = opp_find_freq_floor(devfreq->dev, &freq);
-		freq = opp_get_freq(opp);
-		if (devfreq->previous_freq != freq) {
-			err = devfreq->profile->target(devfreq->dev, opp);
-			if (!err)
-				devfreq->previous_freq = freq;
-		}
-		if (err)
-			dev_err(dev, "%s: Cannot set frequency.\n", __func__);
-		else
-			devfreq->tickle = DIV_ROUND_UP(duration_ms,
-						       DEVFREQ_INTERVAL);
+	delay = DIV_ROUND_UP(duration_ms, DEVFREQ_INTERVAL);
+
+	if (IS_ERR(devfreq))
+		err = PTR_ERR(devfreq);
+	else
+		err = _devfreq_tickle_device(devfreq, delay);
+
+	mutex_unlock(&devfreq_list_lock);
+
+	return err;
+}
+
+static int num_tickle_all;
+static ssize_t tickle_all(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	int duration;
+	struct devfreq *tmp;
+	unsigned long delay;
+
+	sscanf(buf, "%d", &duration);
+	if (duration < DEVFREQ_INTERVAL)
+		duration = DEVFREQ_INTERVAL;
+
+	if (unlikely(IS_ERR_OR_NULL(dev))) {
+		pr_err("%s: Invalid parameters\n", __func__);
+		return -EINVAL;
 	}
 
-	if (devfreq_wq && !monitoring) {
-		monitoring = true;
-		queue_delayed_work(devfreq_wq, &devfreq_work,
-				   msecs_to_jiffies(DEVFREQ_INTERVAL));
+	delay = DIV_ROUND_UP(duration, DEVFREQ_INTERVAL);
+
+	mutex_lock(&devfreq_list_lock);
+	list_for_each_entry(tmp, &devfreq_list, node) {
+		_devfreq_tickle_device(tmp, delay);
 	}
 	mutex_unlock(&devfreq_list_lock);
 
-	if (IS_ERR(devfreq)) {
-		dev_err(dev, "%s: Cannot find devfreq.\n", __func__);
-		err = PTR_ERR(devfreq);
+	num_tickle_all++;
+	return count;
+}
+
+static ssize_t show_num_tickle_all(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", num_tickle_all);
+}
+
+static ssize_t show_min_interval(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", DEVFREQ_INTERVAL);
+}
+
+static ssize_t show_monitoring(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", monitoring ? 1 : 0);
+}
+
+static DEVICE_ATTR(tickle_all, 0644, show_num_tickle_all, tickle_all);
+static DEVICE_ATTR(min_interval, 0444, show_min_interval, NULL);
+static DEVICE_ATTR(monitoring, 0444, show_monitoring, NULL);
+static struct attribute *devfreq_entries[] = {
+	&dev_attr_tickle_all.attr,
+	&dev_attr_min_interval.attr,
+	&dev_attr_monitoring.attr,
+	NULL,
+};
+static struct attribute_group devfreq_attr_group = {
+	.name	= "devfreq",
+	.attrs	= devfreq_entries,
+};
+
+static ssize_t tickle(struct device *dev, struct device_attribute *attr,
+		      const char *buf, size_t count)
+{
+	int duration;
+	struct devfreq *df;
+	unsigned long delay;
+
+	sscanf(buf, "%d", &duration);
+	if (duration < DEVFREQ_INTERVAL)
+		duration = DEVFREQ_INTERVAL;
+
+	if (unlikely(IS_ERR_OR_NULL(dev))) {
+		pr_err("%s: Invalid parameters\n", __func__);
+		return -EINVAL;
 	}
 
-	return err;
+	delay = DIV_ROUND_UP(duration, DEVFREQ_INTERVAL);
+
+	mutex_lock(&devfreq_list_lock);
+	df = find_device_devfreq(dev);
+	_devfreq_tickle_device(df, delay);
+	mutex_unlock(&devfreq_list_lock);
+
+	return count;
 }
 
+static ssize_t show_num_tickle(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct devfreq *df;
+
+	df = find_device_devfreq(dev);
+
+	if (!IS_ERR(df))
+		return sprintf(buf, "%d\n", df->num_tickle);
+
+	return PTR_ERR(df);
+}
+
+static DEVICE_ATTR(tickle, 0644, show_num_tickle, tickle);
+static struct attribute *dev_entries[] = {
+	&dev_attr_tickle.attr,
+	NULL,
+};
+static struct attribute_group dev_attr_group = {
+	.name	= NULL,
+	.attrs	= dev_entries,
+};
+
 static int __init devfreq_init(void)
 {
 	mutex_lock(&devfreq_list_lock);
@@ -345,6 +474,20 @@  static int __init devfreq_init(void)
 	monitoring = false;
 	devfreq_wq = create_freezable_workqueue("devfreq_wq");
 	INIT_DELAYED_WORK_DEFERRABLE(&devfreq_work, devfreq_monitor);
+
+	/* Create sysfs */
+#ifdef CONFIG_PM
+	devfreq_kobj = kobject_create_and_add("devfreq", power_kobj);
+	if (!devfreq_kobj) {
+		pr_err("Unable to create DEVFREQ kobject.\n");
+		goto out;
+	}
+	if (sysfs_create_group(devfreq_kobj, &devfreq_attr_group)) {
+		pr_err("Unable to create DEVFREQ sysfs entries.\n");
+		goto out;
+	}
+#endif
+out:
 	mutex_unlock(&devfreq_list_lock);
 
 	devfreq_monitor(&devfreq_work.work);
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index ec41ba6..f6e38ee 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -59,6 +59,7 @@  struct devfreq_governor {
  *		at each executino of devfreq_monitor, tickle is decremented.
  *		User may tickle a device-devfreq in order to set maximum
  *		frequency instaneously with some guaranteed duration.
+ * @num_tickle	number of tickle calls.
  *
  * This structure stores the DEVFREQ information for a give device.
  */
@@ -72,6 +73,8 @@  struct devfreq {
 	unsigned long previous_freq;
 	unsigned int next_polling;
 	unsigned int tickle;
+
+	unsigned int num_tickle;
 };
 
 #if defined(CONFIG_PM_DEVFREQ)