lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-id: <1328858388-22384-1-git-send-email-myungjoo.ham@samsung.com>
Date:	Fri, 10 Feb 2012 16:19:48 +0900
From:	MyungJoo Ham <myungjoo.ham@...sung.com>
To:	linux-kernel@...r.kernel.org, linux-pm@...r.kernel.org
Cc:	Kyungmin Park <kyungmin.park@...sung.com>,
	"Rafael J. Wysocki" <rjw@...k.pl>, Kevin Hilman <khilman@...com>,
	Mike Turquette <mturquette@...com>, myungjoo.ham@...il.com
Subject: [PATCH] PM / devfreq: add relation of recommended frequency.

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@...sung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@...sung.com>
---
 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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ