All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v8 0/6] PM / devfreq: Add dev_pm_qos support
@ 2019-09-24 10:11   ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 10:11 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Chanwoo Choi, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

Add dev_pm_qos notifiers to devfreq core in order to support frequency
limits via dev_pm_qos_add_request.

Unlike the rest of devfreq the dev_pm_qos frequency is measured in Khz,
this is consistent with current dev_pm_qos usage for cpufreq and
allows frequencies above 2Ghz (pm_qos expresses limits as s32).

Like with cpufreq the handling of min_freq/max_freq is moved to the
dev_pm_qos mechanism. Constraints from userspace are no longer clamped on
store, instead all values can be written and we only check against OPPs in a
new devfreq_get_freq_range function. This is consistent with the design of
dev_pm_qos.

Notifiers from pm_qos are executed under a single global dev_pm_qos_mtx and
need to take devfreq->lock. Notifier registration takes the same dev_pm_qos_mtx
so in order to prevent lockdep warnings it must be done outside devfreq->lock.
Current devfreq_add_device does all initialization under devfreq->lock and that
needs to be relaxed.

---
Changes since v7:
* Only #define HZ_PER_KHZ in patch where it's used.
* Drop devfreq_ prefix for some internal functions.
* Improve qos update error message.
* Remove some unnecessary comments.
* Collect reviews
Link to v7: https://patchwork.kernel.org/cover/11157649/

Changes since v6:
* Don't return errno from devfreq_qos_notifier_call, return NOTIFY_DONE
and print the error.
* More spelling and punctuation nits
Link to v6: https://patchwork.kernel.org/cover/11157201/

Changes since v5:
* Drop patches which are not strictly related to PM QoS.
* Add a comment explaining why devfreq_add_device needs two cleanup paths.
* Remove {} for single line.
* Rename {min,max}_freq_req to user_{min,max}_freq_req
* Collect reviews
Link to v5: https://patchwork.kernel.org/cover/11149497/

Sorry for forgetting to properly label v5. I know this is inside the
merge window but review would still be appreciated.

Changes since v4:
* Move more devfreq_add_device init ahead of device_register.
* Make devfreq_dev_release cleanup devices not yet in devfreq_list. This is
simpler than previous attempt to add to devfreq_list sonner.
* Take devfreq->lock in trans_stat_show
* Register dev_pm_opp notifier on devfreq parent dev (which has OPPs)
Link to v4: https://patchwork.kernel.org/cover/11114657/

Changes since v4:
* Move more devfreq_add_device init ahead of device_register.
* Make devfreq_dev_release cleanup devices not yet in devfreq_list. This is
simpler than previous attempt to add to devfreq_list sonner.
* Take devfreq->lock in trans_stat_show
* Register dev_pm_opp notifier on devfreq parent dev (which has OPPs)
Like to v4: https://patchwork.kernel.org/cover/11114657/

Changes since v3:
* Cleanup locking and error-handling in devfreq_add_device
* Register notifiers after device registration but before governor start
* Keep the initialization of min_req/max_req ahead of device_register
because it's used for sysfs handling
* Use HZ_PER_KHZ instead of 1000
* Add kernel-doc comments
* Move OPP notifier to core
Link to v3: https://patchwork.kernel.org/cover/11104061/

Changes since v2:
* Handle sysfs via dev_pm_qos (in separate patch)
* Add locking to {min,max}_freq_show
* Fix checkpatch issues (long lines etc)
Link to v2: https://patchwork.kernel.org/patch/11084279/

Changes since v1:
* Add doxygen comments for min_nb/max_nb
* Remove notifiers on error/cleanup paths. Keep gotos simple by relying on
dev_pm_qos_remove_notifier ignoring notifiers which were not added.
Link to v1: https://patchwork.kernel.org/patch/11078475/

Leonard Crestez (6):
  PM / devfreq: Don't fail devfreq_dev_release if not in list
  PM / devfreq: Move more initialization before registration
  PM / devfreq: Don't take lock in devfreq_add_device
  PM / devfreq: Introduce get_freq_range helper
  PM / devfreq: Add PM QoS support
  PM / devfreq: Use PM QoS for sysfs min/max_freq

 drivers/devfreq/devfreq.c | 268 +++++++++++++++++++++++++-------------
 include/linux/devfreq.h   |  14 +-
 2 files changed, 191 insertions(+), 91 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH v8 0/6] PM / devfreq: Add dev_pm_qos support
@ 2019-09-24 10:11   ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 10:11 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba, Chanwoo Choi,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

Add dev_pm_qos notifiers to devfreq core in order to support frequency
limits via dev_pm_qos_add_request.

Unlike the rest of devfreq the dev_pm_qos frequency is measured in Khz,
this is consistent with current dev_pm_qos usage for cpufreq and
allows frequencies above 2Ghz (pm_qos expresses limits as s32).

Like with cpufreq the handling of min_freq/max_freq is moved to the
dev_pm_qos mechanism. Constraints from userspace are no longer clamped on
store, instead all values can be written and we only check against OPPs in a
new devfreq_get_freq_range function. This is consistent with the design of
dev_pm_qos.

Notifiers from pm_qos are executed under a single global dev_pm_qos_mtx and
need to take devfreq->lock. Notifier registration takes the same dev_pm_qos_mtx
so in order to prevent lockdep warnings it must be done outside devfreq->lock.
Current devfreq_add_device does all initialization under devfreq->lock and that
needs to be relaxed.

---
Changes since v7:
* Only #define HZ_PER_KHZ in patch where it's used.
* Drop devfreq_ prefix for some internal functions.
* Improve qos update error message.
* Remove some unnecessary comments.
* Collect reviews
Link to v7: https://patchwork.kernel.org/cover/11157649/

Changes since v6:
* Don't return errno from devfreq_qos_notifier_call, return NOTIFY_DONE
and print the error.
* More spelling and punctuation nits
Link to v6: https://patchwork.kernel.org/cover/11157201/

Changes since v5:
* Drop patches which are not strictly related to PM QoS.
* Add a comment explaining why devfreq_add_device needs two cleanup paths.
* Remove {} for single line.
* Rename {min,max}_freq_req to user_{min,max}_freq_req
* Collect reviews
Link to v5: https://patchwork.kernel.org/cover/11149497/

Sorry for forgetting to properly label v5. I know this is inside the
merge window but review would still be appreciated.

Changes since v4:
* Move more devfreq_add_device init ahead of device_register.
* Make devfreq_dev_release cleanup devices not yet in devfreq_list. This is
simpler than previous attempt to add to devfreq_list sonner.
* Take devfreq->lock in trans_stat_show
* Register dev_pm_opp notifier on devfreq parent dev (which has OPPs)
Link to v4: https://patchwork.kernel.org/cover/11114657/

Changes since v4:
* Move more devfreq_add_device init ahead of device_register.
* Make devfreq_dev_release cleanup devices not yet in devfreq_list. This is
simpler than previous attempt to add to devfreq_list sonner.
* Take devfreq->lock in trans_stat_show
* Register dev_pm_opp notifier on devfreq parent dev (which has OPPs)
Like to v4: https://patchwork.kernel.org/cover/11114657/

Changes since v3:
* Cleanup locking and error-handling in devfreq_add_device
* Register notifiers after device registration but before governor start
* Keep the initialization of min_req/max_req ahead of device_register
because it's used for sysfs handling
* Use HZ_PER_KHZ instead of 1000
* Add kernel-doc comments
* Move OPP notifier to core
Link to v3: https://patchwork.kernel.org/cover/11104061/

Changes since v2:
* Handle sysfs via dev_pm_qos (in separate patch)
* Add locking to {min,max}_freq_show
* Fix checkpatch issues (long lines etc)
Link to v2: https://patchwork.kernel.org/patch/11084279/

Changes since v1:
* Add doxygen comments for min_nb/max_nb
* Remove notifiers on error/cleanup paths. Keep gotos simple by relying on
dev_pm_qos_remove_notifier ignoring notifiers which were not added.
Link to v1: https://patchwork.kernel.org/patch/11078475/

Leonard Crestez (6):
  PM / devfreq: Don't fail devfreq_dev_release if not in list
  PM / devfreq: Move more initialization before registration
  PM / devfreq: Don't take lock in devfreq_add_device
  PM / devfreq: Introduce get_freq_range helper
  PM / devfreq: Add PM QoS support
  PM / devfreq: Use PM QoS for sysfs min/max_freq

 drivers/devfreq/devfreq.c | 268 +++++++++++++++++++++++++-------------
 include/linux/devfreq.h   |  14 +-
 2 files changed, 191 insertions(+), 91 deletions(-)

-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH v8 1/6] PM / devfreq: Don't fail devfreq_dev_release if not in list
  2019-09-24 10:11   ` Leonard Crestez
@ 2019-09-24 10:11     ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 10:11 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Chanwoo Choi, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

Right now devfreq_dev_release will print a warning and abort the rest of
the cleanup if the devfreq instance is not part of the global
devfreq_list. But this is a valid scenario, for example it can happen if
the governor can't be found or on any other init error that happens
after device_register.

Initialize devfreq->node to an empty list head in devfreq_add_device so
that list_del becomes a safe noop inside devfreq_dev_release and we can
continue the rest of the cleanup.

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
---
 drivers/devfreq/devfreq.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index a2a045e117f0..12c4bcdc1f17 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -582,15 +582,10 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
 static void devfreq_dev_release(struct device *dev)
 {
 	struct devfreq *devfreq = to_devfreq(dev);
 
 	mutex_lock(&devfreq_list_lock);
-	if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) {
-		mutex_unlock(&devfreq_list_lock);
-		dev_warn(&devfreq->dev, "releasing devfreq which doesn't exist\n");
-		return;
-	}
 	list_del(&devfreq->node);
 	mutex_unlock(&devfreq_list_lock);
 
 	if (devfreq->profile->exit)
 		devfreq->profile->exit(devfreq->dev.parent);
@@ -641,10 +636,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
 	mutex_init(&devfreq->lock);
 	mutex_lock(&devfreq->lock);
 	devfreq->dev.parent = dev;
 	devfreq->dev.class = devfreq_class;
 	devfreq->dev.release = devfreq_dev_release;
+	INIT_LIST_HEAD(&devfreq->node);
 	devfreq->profile = profile;
 	strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN);
 	devfreq->previous_freq = profile->initial_freq;
 	devfreq->last_status.current_frequency = profile->initial_freq;
 	devfreq->data = data;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 82+ messages in thread

* [PATCH v8 1/6] PM / devfreq: Don't fail devfreq_dev_release if not in list
@ 2019-09-24 10:11     ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 10:11 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba, Chanwoo Choi,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

Right now devfreq_dev_release will print a warning and abort the rest of
the cleanup if the devfreq instance is not part of the global
devfreq_list. But this is a valid scenario, for example it can happen if
the governor can't be found or on any other init error that happens
after device_register.

Initialize devfreq->node to an empty list head in devfreq_add_device so
that list_del becomes a safe noop inside devfreq_dev_release and we can
continue the rest of the cleanup.

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
---
 drivers/devfreq/devfreq.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index a2a045e117f0..12c4bcdc1f17 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -582,15 +582,10 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
 static void devfreq_dev_release(struct device *dev)
 {
 	struct devfreq *devfreq = to_devfreq(dev);
 
 	mutex_lock(&devfreq_list_lock);
-	if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) {
-		mutex_unlock(&devfreq_list_lock);
-		dev_warn(&devfreq->dev, "releasing devfreq which doesn't exist\n");
-		return;
-	}
 	list_del(&devfreq->node);
 	mutex_unlock(&devfreq_list_lock);
 
 	if (devfreq->profile->exit)
 		devfreq->profile->exit(devfreq->dev.parent);
@@ -641,10 +636,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
 	mutex_init(&devfreq->lock);
 	mutex_lock(&devfreq->lock);
 	devfreq->dev.parent = dev;
 	devfreq->dev.class = devfreq_class;
 	devfreq->dev.release = devfreq_dev_release;
+	INIT_LIST_HEAD(&devfreq->node);
 	devfreq->profile = profile;
 	strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN);
 	devfreq->previous_freq = profile->initial_freq;
 	devfreq->last_status.current_frequency = profile->initial_freq;
 	devfreq->data = data;
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 82+ messages in thread

* [PATCH v8 2/6] PM / devfreq: Move more initialization before registration
  2019-09-24 10:11   ` Leonard Crestez
@ 2019-09-24 10:11     ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 10:11 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Chanwoo Choi, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

In general it is a better to initialize an object before making it
accessible externally (through device_register).

This makes it possible to avoid relying on locking a partially
initialized object.

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
---
 drivers/devfreq/devfreq.c | 43 +++++++++++++++++++++++----------------
 1 file changed, 25 insertions(+), 18 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 12c4bcdc1f17..dbc6dc882aba 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -588,10 +588,12 @@ static void devfreq_dev_release(struct device *dev)
 	mutex_unlock(&devfreq_list_lock);
 
 	if (devfreq->profile->exit)
 		devfreq->profile->exit(devfreq->dev.parent);
 
+	kfree(devfreq->time_in_state);
+	kfree(devfreq->trans_table);
 	mutex_destroy(&devfreq->lock);
 	kfree(devfreq);
 }
 
 /**
@@ -671,44 +673,43 @@ struct devfreq *devfreq_add_device(struct device *dev,
 	devfreq->max_freq = devfreq->scaling_max_freq;
 
 	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
 	atomic_set(&devfreq->suspend_count, 0);
 
-	dev_set_name(&devfreq->dev, "devfreq%d",
-				atomic_inc_return(&devfreq_no));
-	err = device_register(&devfreq->dev);
-	if (err) {
-		mutex_unlock(&devfreq->lock);
-		put_device(&devfreq->dev);
-		goto err_out;
-	}
-
-	devfreq->trans_table = devm_kzalloc(&devfreq->dev,
+	devfreq->trans_table = kzalloc(
 			array3_size(sizeof(unsigned int),
 				    devfreq->profile->max_state,
 				    devfreq->profile->max_state),
 			GFP_KERNEL);
 	if (!devfreq->trans_table) {
 		mutex_unlock(&devfreq->lock);
 		err = -ENOMEM;
-		goto err_devfreq;
+		goto err_dev;
 	}
 
-	devfreq->time_in_state = devm_kcalloc(&devfreq->dev,
-			devfreq->profile->max_state,
-			sizeof(unsigned long),
-			GFP_KERNEL);
+	devfreq->time_in_state = kcalloc(devfreq->profile->max_state,
+					 sizeof(unsigned long),
+					 GFP_KERNEL);
 	if (!devfreq->time_in_state) {
 		mutex_unlock(&devfreq->lock);
 		err = -ENOMEM;
-		goto err_devfreq;
+		goto err_dev;
 	}
 
 	devfreq->last_stat_updated = jiffies;
 
 	srcu_init_notifier_head(&devfreq->transition_notifier_list);
 
+	dev_set_name(&devfreq->dev, "devfreq%d",
+				atomic_inc_return(&devfreq_no));
+	err = device_register(&devfreq->dev);
+	if (err) {
+		mutex_unlock(&devfreq->lock);
+		put_device(&devfreq->dev);
+		goto err_out;
+	}
+
 	mutex_unlock(&devfreq->lock);
 
 	mutex_lock(&devfreq_list_lock);
 
 	governor = try_then_request_governor(devfreq->governor_name);
@@ -734,14 +735,20 @@ struct devfreq *devfreq_add_device(struct device *dev,
 
 	return devfreq;
 
 err_init:
 	mutex_unlock(&devfreq_list_lock);
-err_devfreq:
 	devfreq_remove_device(devfreq);
-	devfreq = NULL;
+	return ERR_PTR(err);
+
 err_dev:
+	/*
+	 * Cleanup path for errors that happen before registration.
+	 * Otherwise we rely on devfreq_dev_release.
+	 */
+	kfree(devfreq->time_in_state);
+	kfree(devfreq->trans_table);
 	kfree(devfreq);
 err_out:
 	return ERR_PTR(err);
 }
 EXPORT_SYMBOL(devfreq_add_device);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 82+ messages in thread

* [PATCH v8 2/6] PM / devfreq: Move more initialization before registration
@ 2019-09-24 10:11     ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 10:11 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba, Chanwoo Choi,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

In general it is a better to initialize an object before making it
accessible externally (through device_register).

This makes it possible to avoid relying on locking a partially
initialized object.

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
---
 drivers/devfreq/devfreq.c | 43 +++++++++++++++++++++++----------------
 1 file changed, 25 insertions(+), 18 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 12c4bcdc1f17..dbc6dc882aba 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -588,10 +588,12 @@ static void devfreq_dev_release(struct device *dev)
 	mutex_unlock(&devfreq_list_lock);
 
 	if (devfreq->profile->exit)
 		devfreq->profile->exit(devfreq->dev.parent);
 
+	kfree(devfreq->time_in_state);
+	kfree(devfreq->trans_table);
 	mutex_destroy(&devfreq->lock);
 	kfree(devfreq);
 }
 
 /**
@@ -671,44 +673,43 @@ struct devfreq *devfreq_add_device(struct device *dev,
 	devfreq->max_freq = devfreq->scaling_max_freq;
 
 	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
 	atomic_set(&devfreq->suspend_count, 0);
 
-	dev_set_name(&devfreq->dev, "devfreq%d",
-				atomic_inc_return(&devfreq_no));
-	err = device_register(&devfreq->dev);
-	if (err) {
-		mutex_unlock(&devfreq->lock);
-		put_device(&devfreq->dev);
-		goto err_out;
-	}
-
-	devfreq->trans_table = devm_kzalloc(&devfreq->dev,
+	devfreq->trans_table = kzalloc(
 			array3_size(sizeof(unsigned int),
 				    devfreq->profile->max_state,
 				    devfreq->profile->max_state),
 			GFP_KERNEL);
 	if (!devfreq->trans_table) {
 		mutex_unlock(&devfreq->lock);
 		err = -ENOMEM;
-		goto err_devfreq;
+		goto err_dev;
 	}
 
-	devfreq->time_in_state = devm_kcalloc(&devfreq->dev,
-			devfreq->profile->max_state,
-			sizeof(unsigned long),
-			GFP_KERNEL);
+	devfreq->time_in_state = kcalloc(devfreq->profile->max_state,
+					 sizeof(unsigned long),
+					 GFP_KERNEL);
 	if (!devfreq->time_in_state) {
 		mutex_unlock(&devfreq->lock);
 		err = -ENOMEM;
-		goto err_devfreq;
+		goto err_dev;
 	}
 
 	devfreq->last_stat_updated = jiffies;
 
 	srcu_init_notifier_head(&devfreq->transition_notifier_list);
 
+	dev_set_name(&devfreq->dev, "devfreq%d",
+				atomic_inc_return(&devfreq_no));
+	err = device_register(&devfreq->dev);
+	if (err) {
+		mutex_unlock(&devfreq->lock);
+		put_device(&devfreq->dev);
+		goto err_out;
+	}
+
 	mutex_unlock(&devfreq->lock);
 
 	mutex_lock(&devfreq_list_lock);
 
 	governor = try_then_request_governor(devfreq->governor_name);
@@ -734,14 +735,20 @@ struct devfreq *devfreq_add_device(struct device *dev,
 
 	return devfreq;
 
 err_init:
 	mutex_unlock(&devfreq_list_lock);
-err_devfreq:
 	devfreq_remove_device(devfreq);
-	devfreq = NULL;
+	return ERR_PTR(err);
+
 err_dev:
+	/*
+	 * Cleanup path for errors that happen before registration.
+	 * Otherwise we rely on devfreq_dev_release.
+	 */
+	kfree(devfreq->time_in_state);
+	kfree(devfreq->trans_table);
 	kfree(devfreq);
 err_out:
 	return ERR_PTR(err);
 }
 EXPORT_SYMBOL(devfreq_add_device);
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 82+ messages in thread

* [PATCH v8 3/6] PM / devfreq: Don't take lock in devfreq_add_device
  2019-09-24 10:11   ` Leonard Crestez
@ 2019-09-24 10:11     ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 10:11 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Chanwoo Choi, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

A device usually doesn't need to lock itself during initialization
because it is not yet reachable from other threads.

This simplifies the code and helps avoid recursive lock warnings.

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
---
 drivers/devfreq/devfreq.c | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index dbc6dc882aba..4a878baa809e 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -634,11 +634,10 @@ struct devfreq *devfreq_add_device(struct device *dev,
 		err = -ENOMEM;
 		goto err_out;
 	}
 
 	mutex_init(&devfreq->lock);
-	mutex_lock(&devfreq->lock);
 	devfreq->dev.parent = dev;
 	devfreq->dev.class = devfreq_class;
 	devfreq->dev.release = devfreq_dev_release;
 	INIT_LIST_HEAD(&devfreq->node);
 	devfreq->profile = profile;
@@ -647,28 +646,24 @@ struct devfreq *devfreq_add_device(struct device *dev,
 	devfreq->last_status.current_frequency = profile->initial_freq;
 	devfreq->data = data;
 	devfreq->nb.notifier_call = devfreq_notifier_call;
 
 	if (!devfreq->profile->max_state && !devfreq->profile->freq_table) {
-		mutex_unlock(&devfreq->lock);
 		err = set_freq_table(devfreq);
 		if (err < 0)
 			goto err_dev;
-		mutex_lock(&devfreq->lock);
 	}
 
 	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
 	if (!devfreq->scaling_min_freq) {
-		mutex_unlock(&devfreq->lock);
 		err = -EINVAL;
 		goto err_dev;
 	}
 	devfreq->min_freq = devfreq->scaling_min_freq;
 
 	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
 	if (!devfreq->scaling_max_freq) {
-		mutex_unlock(&devfreq->lock);
 		err = -EINVAL;
 		goto err_dev;
 	}
 	devfreq->max_freq = devfreq->scaling_max_freq;
 
@@ -679,20 +674,18 @@ struct devfreq *devfreq_add_device(struct device *dev,
 			array3_size(sizeof(unsigned int),
 				    devfreq->profile->max_state,
 				    devfreq->profile->max_state),
 			GFP_KERNEL);
 	if (!devfreq->trans_table) {
-		mutex_unlock(&devfreq->lock);
 		err = -ENOMEM;
 		goto err_dev;
 	}
 
 	devfreq->time_in_state = kcalloc(devfreq->profile->max_state,
 					 sizeof(unsigned long),
 					 GFP_KERNEL);
 	if (!devfreq->time_in_state) {
-		mutex_unlock(&devfreq->lock);
 		err = -ENOMEM;
 		goto err_dev;
 	}
 
 	devfreq->last_stat_updated = jiffies;
@@ -701,17 +694,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
 
 	dev_set_name(&devfreq->dev, "devfreq%d",
 				atomic_inc_return(&devfreq_no));
 	err = device_register(&devfreq->dev);
 	if (err) {
-		mutex_unlock(&devfreq->lock);
 		put_device(&devfreq->dev);
 		goto err_out;
 	}
 
-	mutex_unlock(&devfreq->lock);
-
 	mutex_lock(&devfreq_list_lock);
 
 	governor = try_then_request_governor(devfreq->governor_name);
 	if (IS_ERR(governor)) {
 		dev_err(dev, "%s: Unable to find governor for the device\n",
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 82+ messages in thread

* [PATCH v8 3/6] PM / devfreq: Don't take lock in devfreq_add_device
@ 2019-09-24 10:11     ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 10:11 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba, Chanwoo Choi,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

A device usually doesn't need to lock itself during initialization
because it is not yet reachable from other threads.

This simplifies the code and helps avoid recursive lock warnings.

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
---
 drivers/devfreq/devfreq.c | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index dbc6dc882aba..4a878baa809e 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -634,11 +634,10 @@ struct devfreq *devfreq_add_device(struct device *dev,
 		err = -ENOMEM;
 		goto err_out;
 	}
 
 	mutex_init(&devfreq->lock);
-	mutex_lock(&devfreq->lock);
 	devfreq->dev.parent = dev;
 	devfreq->dev.class = devfreq_class;
 	devfreq->dev.release = devfreq_dev_release;
 	INIT_LIST_HEAD(&devfreq->node);
 	devfreq->profile = profile;
@@ -647,28 +646,24 @@ struct devfreq *devfreq_add_device(struct device *dev,
 	devfreq->last_status.current_frequency = profile->initial_freq;
 	devfreq->data = data;
 	devfreq->nb.notifier_call = devfreq_notifier_call;
 
 	if (!devfreq->profile->max_state && !devfreq->profile->freq_table) {
-		mutex_unlock(&devfreq->lock);
 		err = set_freq_table(devfreq);
 		if (err < 0)
 			goto err_dev;
-		mutex_lock(&devfreq->lock);
 	}
 
 	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
 	if (!devfreq->scaling_min_freq) {
-		mutex_unlock(&devfreq->lock);
 		err = -EINVAL;
 		goto err_dev;
 	}
 	devfreq->min_freq = devfreq->scaling_min_freq;
 
 	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
 	if (!devfreq->scaling_max_freq) {
-		mutex_unlock(&devfreq->lock);
 		err = -EINVAL;
 		goto err_dev;
 	}
 	devfreq->max_freq = devfreq->scaling_max_freq;
 
@@ -679,20 +674,18 @@ struct devfreq *devfreq_add_device(struct device *dev,
 			array3_size(sizeof(unsigned int),
 				    devfreq->profile->max_state,
 				    devfreq->profile->max_state),
 			GFP_KERNEL);
 	if (!devfreq->trans_table) {
-		mutex_unlock(&devfreq->lock);
 		err = -ENOMEM;
 		goto err_dev;
 	}
 
 	devfreq->time_in_state = kcalloc(devfreq->profile->max_state,
 					 sizeof(unsigned long),
 					 GFP_KERNEL);
 	if (!devfreq->time_in_state) {
-		mutex_unlock(&devfreq->lock);
 		err = -ENOMEM;
 		goto err_dev;
 	}
 
 	devfreq->last_stat_updated = jiffies;
@@ -701,17 +694,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
 
 	dev_set_name(&devfreq->dev, "devfreq%d",
 				atomic_inc_return(&devfreq_no));
 	err = device_register(&devfreq->dev);
 	if (err) {
-		mutex_unlock(&devfreq->lock);
 		put_device(&devfreq->dev);
 		goto err_out;
 	}
 
-	mutex_unlock(&devfreq->lock);
-
 	mutex_lock(&devfreq_list_lock);
 
 	governor = try_then_request_governor(devfreq->governor_name);
 	if (IS_ERR(governor)) {
 		dev_err(dev, "%s: Unable to find governor for the device\n",
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 82+ messages in thread

* [PATCH v8 4/6] PM / devfreq: Introduce get_freq_range helper
  2019-09-24 10:11   ` Leonard Crestez
@ 2019-09-24 10:11     ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 10:11 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Chanwoo Choi, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

Moving handling of min/max freq to a single function and call it from
update_devfreq and for printing min/max freq values in sysfs.

This changes the behavior of out-of-range min_freq/max_freq: clamping
is now done at evaluation time. This means that if an out-of-range
constraint is imposed by sysfs and it later becomes valid then it will
be enforced.

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
---
 drivers/devfreq/devfreq.c | 112 ++++++++++++++++++++++----------------
 1 file changed, 64 insertions(+), 48 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 4a878baa809e..eee403e70c84 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -96,10 +96,54 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
 		dev_pm_opp_put(opp);
 
 	return max_freq;
 }
 
+/**
+ * get_freq_range() - Get the current freq range
+ * @devfreq:	the devfreq instance
+ * @min_freq:	the min frequency
+ * @max_freq:	the max frequency
+ *
+ * This takes into consideration all constraints.
+ */
+static void get_freq_range(struct devfreq *devfreq,
+			   unsigned long *min_freq,
+			   unsigned long *max_freq)
+{
+	unsigned long *freq_table = devfreq->profile->freq_table;
+
+	lockdep_assert_held(&devfreq->lock);
+
+	/*
+	 * Init min/max frequency from freq table.
+	 * Drivers can initialize this in either ascending or descending order
+	 * and devfreq core supports both.
+	 */
+	if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
+		*min_freq = freq_table[0];
+		*max_freq = freq_table[devfreq->profile->max_state - 1];
+	} else {
+		*min_freq = freq_table[devfreq->profile->max_state - 1];
+		*max_freq = freq_table[0];
+	}
+
+	/* constraints from sysfs */
+	*min_freq = max(*min_freq, devfreq->min_freq);
+	*max_freq = min(*max_freq, devfreq->max_freq);
+
+	/* constraints from OPP interface */
+	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
+	/* scaling_max_freq can be zero on error */
+	if (devfreq->scaling_max_freq)
+		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
+
+	/* max_freq takes precedence over min_freq */
+	if (*min_freq > *max_freq)
+		*min_freq = *max_freq;
+}
+
 /**
  * devfreq_get_freq_level() - Lookup freq_table for the frequency
  * @devfreq:	the devfreq instance
  * @freq:	the target frequency
  */
@@ -349,20 +393,11 @@ int update_devfreq(struct devfreq *devfreq)
 
 	/* Reevaluate the proper frequency */
 	err = devfreq->governor->get_target_freq(devfreq, &freq);
 	if (err)
 		return err;
-
-	/*
-	 * Adjust the frequency with user freq, QoS and available freq.
-	 *
-	 * List from the highest priority
-	 * max_freq
-	 * min_freq
-	 */
-	max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
-	min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
+	get_freq_range(devfreq, &min_freq, &max_freq);
 
 	if (freq < min_freq) {
 		freq = min_freq;
 		flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
 	}
@@ -1298,40 +1333,28 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
 	ret = sscanf(buf, "%lu", &value);
 	if (ret != 1)
 		return -EINVAL;
 
 	mutex_lock(&df->lock);
-
-	if (value) {
-		if (value > df->max_freq) {
-			ret = -EINVAL;
-			goto unlock;
-		}
-	} else {
-		unsigned long *freq_table = df->profile->freq_table;
-
-		/* Get minimum frequency according to sorting order */
-		if (freq_table[0] < freq_table[df->profile->max_state - 1])
-			value = freq_table[0];
-		else
-			value = freq_table[df->profile->max_state - 1];
-	}
-
 	df->min_freq = value;
 	update_devfreq(df);
-	ret = count;
-unlock:
 	mutex_unlock(&df->lock);
-	return ret;
+
+	return count;
 }
 
 static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
 			     char *buf)
 {
 	struct devfreq *df = to_devfreq(dev);
+	unsigned long min_freq, max_freq;
+
+	mutex_lock(&df->lock);
+	get_freq_range(df, &min_freq, &max_freq);
+	mutex_unlock(&df->lock);
 
-	return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
+	return sprintf(buf, "%lu\n", min_freq);
 }
 
 static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
 			      const char *buf, size_t count)
 {
@@ -1343,40 +1366,33 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
 	if (ret != 1)
 		return -EINVAL;
 
 	mutex_lock(&df->lock);
 
-	if (value) {
-		if (value < df->min_freq) {
-			ret = -EINVAL;
-			goto unlock;
-		}
-	} else {
-		unsigned long *freq_table = df->profile->freq_table;
-
-		/* Get maximum frequency according to sorting order */
-		if (freq_table[0] < freq_table[df->profile->max_state - 1])
-			value = freq_table[df->profile->max_state - 1];
-		else
-			value = freq_table[0];
-	}
+	/* Interpret zero as "don't care" */
+	if (!value)
+		value = ULONG_MAX;
 
 	df->max_freq = value;
 	update_devfreq(df);
-	ret = count;
-unlock:
 	mutex_unlock(&df->lock);
-	return ret;
+
+	return count;
 }
 static DEVICE_ATTR_RW(min_freq);
 
 static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
 			     char *buf)
 {
 	struct devfreq *df = to_devfreq(dev);
+	unsigned long min_freq, max_freq;
+
+	mutex_lock(&df->lock);
+	get_freq_range(df, &min_freq, &max_freq);
+	mutex_unlock(&df->lock);
 
-	return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
+	return sprintf(buf, "%lu\n", max_freq);
 }
 static DEVICE_ATTR_RW(max_freq);
 
 static ssize_t available_frequencies_show(struct device *d,
 					  struct device_attribute *attr,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 82+ messages in thread

* [PATCH v8 4/6] PM / devfreq: Introduce get_freq_range helper
@ 2019-09-24 10:11     ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 10:11 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba, Chanwoo Choi,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

Moving handling of min/max freq to a single function and call it from
update_devfreq and for printing min/max freq values in sysfs.

This changes the behavior of out-of-range min_freq/max_freq: clamping
is now done at evaluation time. This means that if an out-of-range
constraint is imposed by sysfs and it later becomes valid then it will
be enforced.

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
---
 drivers/devfreq/devfreq.c | 112 ++++++++++++++++++++++----------------
 1 file changed, 64 insertions(+), 48 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 4a878baa809e..eee403e70c84 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -96,10 +96,54 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
 		dev_pm_opp_put(opp);
 
 	return max_freq;
 }
 
+/**
+ * get_freq_range() - Get the current freq range
+ * @devfreq:	the devfreq instance
+ * @min_freq:	the min frequency
+ * @max_freq:	the max frequency
+ *
+ * This takes into consideration all constraints.
+ */
+static void get_freq_range(struct devfreq *devfreq,
+			   unsigned long *min_freq,
+			   unsigned long *max_freq)
+{
+	unsigned long *freq_table = devfreq->profile->freq_table;
+
+	lockdep_assert_held(&devfreq->lock);
+
+	/*
+	 * Init min/max frequency from freq table.
+	 * Drivers can initialize this in either ascending or descending order
+	 * and devfreq core supports both.
+	 */
+	if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
+		*min_freq = freq_table[0];
+		*max_freq = freq_table[devfreq->profile->max_state - 1];
+	} else {
+		*min_freq = freq_table[devfreq->profile->max_state - 1];
+		*max_freq = freq_table[0];
+	}
+
+	/* constraints from sysfs */
+	*min_freq = max(*min_freq, devfreq->min_freq);
+	*max_freq = min(*max_freq, devfreq->max_freq);
+
+	/* constraints from OPP interface */
+	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
+	/* scaling_max_freq can be zero on error */
+	if (devfreq->scaling_max_freq)
+		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
+
+	/* max_freq takes precedence over min_freq */
+	if (*min_freq > *max_freq)
+		*min_freq = *max_freq;
+}
+
 /**
  * devfreq_get_freq_level() - Lookup freq_table for the frequency
  * @devfreq:	the devfreq instance
  * @freq:	the target frequency
  */
@@ -349,20 +393,11 @@ int update_devfreq(struct devfreq *devfreq)
 
 	/* Reevaluate the proper frequency */
 	err = devfreq->governor->get_target_freq(devfreq, &freq);
 	if (err)
 		return err;
-
-	/*
-	 * Adjust the frequency with user freq, QoS and available freq.
-	 *
-	 * List from the highest priority
-	 * max_freq
-	 * min_freq
-	 */
-	max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
-	min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
+	get_freq_range(devfreq, &min_freq, &max_freq);
 
 	if (freq < min_freq) {
 		freq = min_freq;
 		flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
 	}
@@ -1298,40 +1333,28 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
 	ret = sscanf(buf, "%lu", &value);
 	if (ret != 1)
 		return -EINVAL;
 
 	mutex_lock(&df->lock);
-
-	if (value) {
-		if (value > df->max_freq) {
-			ret = -EINVAL;
-			goto unlock;
-		}
-	} else {
-		unsigned long *freq_table = df->profile->freq_table;
-
-		/* Get minimum frequency according to sorting order */
-		if (freq_table[0] < freq_table[df->profile->max_state - 1])
-			value = freq_table[0];
-		else
-			value = freq_table[df->profile->max_state - 1];
-	}
-
 	df->min_freq = value;
 	update_devfreq(df);
-	ret = count;
-unlock:
 	mutex_unlock(&df->lock);
-	return ret;
+
+	return count;
 }
 
 static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
 			     char *buf)
 {
 	struct devfreq *df = to_devfreq(dev);
+	unsigned long min_freq, max_freq;
+
+	mutex_lock(&df->lock);
+	get_freq_range(df, &min_freq, &max_freq);
+	mutex_unlock(&df->lock);
 
-	return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
+	return sprintf(buf, "%lu\n", min_freq);
 }
 
 static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
 			      const char *buf, size_t count)
 {
@@ -1343,40 +1366,33 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
 	if (ret != 1)
 		return -EINVAL;
 
 	mutex_lock(&df->lock);
 
-	if (value) {
-		if (value < df->min_freq) {
-			ret = -EINVAL;
-			goto unlock;
-		}
-	} else {
-		unsigned long *freq_table = df->profile->freq_table;
-
-		/* Get maximum frequency according to sorting order */
-		if (freq_table[0] < freq_table[df->profile->max_state - 1])
-			value = freq_table[df->profile->max_state - 1];
-		else
-			value = freq_table[0];
-	}
+	/* Interpret zero as "don't care" */
+	if (!value)
+		value = ULONG_MAX;
 
 	df->max_freq = value;
 	update_devfreq(df);
-	ret = count;
-unlock:
 	mutex_unlock(&df->lock);
-	return ret;
+
+	return count;
 }
 static DEVICE_ATTR_RW(min_freq);
 
 static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
 			     char *buf)
 {
 	struct devfreq *df = to_devfreq(dev);
+	unsigned long min_freq, max_freq;
+
+	mutex_lock(&df->lock);
+	get_freq_range(df, &min_freq, &max_freq);
+	mutex_unlock(&df->lock);
 
-	return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
+	return sprintf(buf, "%lu\n", max_freq);
 }
 static DEVICE_ATTR_RW(max_freq);
 
 static ssize_t available_frequencies_show(struct device *d,
 					  struct device_attribute *attr,
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 82+ messages in thread

* [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-24 10:11   ` Leonard Crestez
@ 2019-09-24 10:11     ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 10:11 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Chanwoo Choi, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

Register notifiers with the PM QoS framework in order to respond to
requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.

No notifiers are added by this patch but PM QoS constraints can be
imposed externally (for example from other devices).

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
---
 drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
 include/linux/devfreq.h   |  5 +++
 2 files changed, 80 insertions(+)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index eee403e70c84..784f3e40536a 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -22,15 +22,18 @@
 #include <linux/platform_device.h>
 #include <linux/list.h>
 #include <linux/printk.h>
 #include <linux/hrtimer.h>
 #include <linux/of.h>
+#include <linux/pm_qos.h>
 #include "governor.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/devfreq.h>
 
+#define HZ_PER_KHZ	1000
+
 static struct class *devfreq_class;
 
 /*
  * devfreq core provides delayed work based load monitoring helper
  * functions. Governors can use these or can implement their own
@@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
 static void get_freq_range(struct devfreq *devfreq,
 			   unsigned long *min_freq,
 			   unsigned long *max_freq)
 {
 	unsigned long *freq_table = devfreq->profile->freq_table;
+	unsigned long qos_min_freq, qos_max_freq;
 
 	lockdep_assert_held(&devfreq->lock);
 
 	/*
 	 * Init min/max frequency from freq table.
@@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
 	} else {
 		*min_freq = freq_table[devfreq->profile->max_state - 1];
 		*max_freq = freq_table[0];
 	}
 
+	/* constraints from PM QoS */
+	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
+					     DEV_PM_QOS_MIN_FREQUENCY);
+	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
+					     DEV_PM_QOS_MIN_FREQUENCY);
+	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
+	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
+
 	/* constraints from sysfs */
 	*min_freq = max(*min_freq, devfreq->min_freq);
 	*max_freq = min(*max_freq, devfreq->max_freq);
 
 	/* constraints from OPP interface */
@@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
 	mutex_unlock(&devfreq->lock);
 
 	return ret;
 }
 
+/**
+ * qos_notifier_call() - Common handler for QoS constraints.
+ * @devfreq:    the devfreq instance.
+ */
+static int qos_notifier_call(struct devfreq *devfreq)
+{
+	int err;
+
+	mutex_lock(&devfreq->lock);
+	err = update_devfreq(devfreq);
+	mutex_unlock(&devfreq->lock);
+	if (err)
+		dev_err(devfreq->dev.parent,
+				"failed to update frequency for PM QoS constraints (%d)\n",
+				err);
+
+	return NOTIFY_OK;
+}
+
+/**
+ * qos_min_notifier_call() - Callback for QoS min_freq changes.
+ * @nb:		Should be devfreq->nb_min
+ */
+static int qos_min_notifier_call(struct notifier_block *nb,
+					 unsigned long val, void *ptr)
+{
+	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
+}
+
+/**
+ * qos_max_notifier_call() - Callback for QoS max_freq changes.
+ * @nb:		Should be devfreq->nb_max
+ */
+static int qos_max_notifier_call(struct notifier_block *nb,
+					 unsigned long val, void *ptr)
+{
+	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
+}
+
 /**
  * devfreq_dev_release() - Callback for struct device to release the device.
  * @dev:	the devfreq device
  *
  * Remove devfreq from the list and release its resources.
@@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
 
 	mutex_lock(&devfreq_list_lock);
 	list_del(&devfreq->node);
 	mutex_unlock(&devfreq_list_lock);
 
+	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
+			DEV_PM_QOS_MAX_FREQUENCY);
+	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
+			DEV_PM_QOS_MIN_FREQUENCY);
+
 	if (devfreq->profile->exit)
 		devfreq->profile->exit(devfreq->dev.parent);
 
 	kfree(devfreq->time_in_state);
 	kfree(devfreq->trans_table);
@@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
 	if (err) {
 		put_device(&devfreq->dev);
 		goto err_out;
 	}
 
+	/*
+	 * Register notifiers for updates to min/max_freq after device is
+	 * initialized (and we can handle notifications) but before the
+	 * governor is started (which should do an initial enforcement of
+	 * constraints).
+	 */
+	devfreq->nb_min.notifier_call = qos_min_notifier_call;
+	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
+				      DEV_PM_QOS_MIN_FREQUENCY);
+	if (err)
+		goto err_devfreq;
+
+	devfreq->nb_max.notifier_call = qos_max_notifier_call;
+	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
+				      DEV_PM_QOS_MAX_FREQUENCY);
+	if (err)
+		goto err_devfreq;
+
 	mutex_lock(&devfreq_list_lock);
 
 	governor = try_then_request_governor(devfreq->governor_name);
 	if (IS_ERR(governor)) {
 		dev_err(dev, "%s: Unable to find governor for the device\n",
@@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
 
 	return devfreq;
 
 err_init:
 	mutex_unlock(&devfreq_list_lock);
+err_devfreq:
 	devfreq_remove_device(devfreq);
 	return ERR_PTR(err);
 
 err_dev:
 	/*
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index c3cbc15fdf08..dac0dffeabb4 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -134,10 +134,12 @@ struct devfreq_dev_profile {
  * @total_trans:	Number of devfreq transitions
  * @trans_table:	Statistics of devfreq transitions
  * @time_in_state:	Statistics of devfreq states
  * @last_stat_updated:	The last time stat updated
  * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
+ * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
+ * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
  *
  * This structure stores the devfreq information for a give device.
  *
  * Note that when a governor accesses entries in struct devfreq in its
  * functions except for the context of callbacks defined in struct
@@ -176,10 +178,13 @@ struct devfreq {
 	unsigned int *trans_table;
 	unsigned long *time_in_state;
 	unsigned long last_stat_updated;
 
 	struct srcu_notifier_head transition_notifier_list;
+
+	struct notifier_block nb_min;
+	struct notifier_block nb_max;
 };
 
 struct devfreq_freqs {
 	unsigned long old;
 	unsigned long new;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 82+ messages in thread

* [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-24 10:11     ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 10:11 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba, Chanwoo Choi,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

Register notifiers with the PM QoS framework in order to respond to
requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.

No notifiers are added by this patch but PM QoS constraints can be
imposed externally (for example from other devices).

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
---
 drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
 include/linux/devfreq.h   |  5 +++
 2 files changed, 80 insertions(+)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index eee403e70c84..784f3e40536a 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -22,15 +22,18 @@
 #include <linux/platform_device.h>
 #include <linux/list.h>
 #include <linux/printk.h>
 #include <linux/hrtimer.h>
 #include <linux/of.h>
+#include <linux/pm_qos.h>
 #include "governor.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/devfreq.h>
 
+#define HZ_PER_KHZ	1000
+
 static struct class *devfreq_class;
 
 /*
  * devfreq core provides delayed work based load monitoring helper
  * functions. Governors can use these or can implement their own
@@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
 static void get_freq_range(struct devfreq *devfreq,
 			   unsigned long *min_freq,
 			   unsigned long *max_freq)
 {
 	unsigned long *freq_table = devfreq->profile->freq_table;
+	unsigned long qos_min_freq, qos_max_freq;
 
 	lockdep_assert_held(&devfreq->lock);
 
 	/*
 	 * Init min/max frequency from freq table.
@@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
 	} else {
 		*min_freq = freq_table[devfreq->profile->max_state - 1];
 		*max_freq = freq_table[0];
 	}
 
+	/* constraints from PM QoS */
+	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
+					     DEV_PM_QOS_MIN_FREQUENCY);
+	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
+					     DEV_PM_QOS_MIN_FREQUENCY);
+	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
+	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
+
 	/* constraints from sysfs */
 	*min_freq = max(*min_freq, devfreq->min_freq);
 	*max_freq = min(*max_freq, devfreq->max_freq);
 
 	/* constraints from OPP interface */
@@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
 	mutex_unlock(&devfreq->lock);
 
 	return ret;
 }
 
+/**
+ * qos_notifier_call() - Common handler for QoS constraints.
+ * @devfreq:    the devfreq instance.
+ */
+static int qos_notifier_call(struct devfreq *devfreq)
+{
+	int err;
+
+	mutex_lock(&devfreq->lock);
+	err = update_devfreq(devfreq);
+	mutex_unlock(&devfreq->lock);
+	if (err)
+		dev_err(devfreq->dev.parent,
+				"failed to update frequency for PM QoS constraints (%d)\n",
+				err);
+
+	return NOTIFY_OK;
+}
+
+/**
+ * qos_min_notifier_call() - Callback for QoS min_freq changes.
+ * @nb:		Should be devfreq->nb_min
+ */
+static int qos_min_notifier_call(struct notifier_block *nb,
+					 unsigned long val, void *ptr)
+{
+	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
+}
+
+/**
+ * qos_max_notifier_call() - Callback for QoS max_freq changes.
+ * @nb:		Should be devfreq->nb_max
+ */
+static int qos_max_notifier_call(struct notifier_block *nb,
+					 unsigned long val, void *ptr)
+{
+	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
+}
+
 /**
  * devfreq_dev_release() - Callback for struct device to release the device.
  * @dev:	the devfreq device
  *
  * Remove devfreq from the list and release its resources.
@@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
 
 	mutex_lock(&devfreq_list_lock);
 	list_del(&devfreq->node);
 	mutex_unlock(&devfreq_list_lock);
 
+	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
+			DEV_PM_QOS_MAX_FREQUENCY);
+	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
+			DEV_PM_QOS_MIN_FREQUENCY);
+
 	if (devfreq->profile->exit)
 		devfreq->profile->exit(devfreq->dev.parent);
 
 	kfree(devfreq->time_in_state);
 	kfree(devfreq->trans_table);
@@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
 	if (err) {
 		put_device(&devfreq->dev);
 		goto err_out;
 	}
 
+	/*
+	 * Register notifiers for updates to min/max_freq after device is
+	 * initialized (and we can handle notifications) but before the
+	 * governor is started (which should do an initial enforcement of
+	 * constraints).
+	 */
+	devfreq->nb_min.notifier_call = qos_min_notifier_call;
+	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
+				      DEV_PM_QOS_MIN_FREQUENCY);
+	if (err)
+		goto err_devfreq;
+
+	devfreq->nb_max.notifier_call = qos_max_notifier_call;
+	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
+				      DEV_PM_QOS_MAX_FREQUENCY);
+	if (err)
+		goto err_devfreq;
+
 	mutex_lock(&devfreq_list_lock);
 
 	governor = try_then_request_governor(devfreq->governor_name);
 	if (IS_ERR(governor)) {
 		dev_err(dev, "%s: Unable to find governor for the device\n",
@@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
 
 	return devfreq;
 
 err_init:
 	mutex_unlock(&devfreq_list_lock);
+err_devfreq:
 	devfreq_remove_device(devfreq);
 	return ERR_PTR(err);
 
 err_dev:
 	/*
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index c3cbc15fdf08..dac0dffeabb4 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -134,10 +134,12 @@ struct devfreq_dev_profile {
  * @total_trans:	Number of devfreq transitions
  * @trans_table:	Statistics of devfreq transitions
  * @time_in_state:	Statistics of devfreq states
  * @last_stat_updated:	The last time stat updated
  * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
+ * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
+ * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
  *
  * This structure stores the devfreq information for a give device.
  *
  * Note that when a governor accesses entries in struct devfreq in its
  * functions except for the context of callbacks defined in struct
@@ -176,10 +178,13 @@ struct devfreq {
 	unsigned int *trans_table;
 	unsigned long *time_in_state;
 	unsigned long last_stat_updated;
 
 	struct srcu_notifier_head transition_notifier_list;
+
+	struct notifier_block nb_min;
+	struct notifier_block nb_max;
 };
 
 struct devfreq_freqs {
 	unsigned long old;
 	unsigned long new;
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 82+ messages in thread

* [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
  2019-09-24 10:11   ` Leonard Crestez
@ 2019-09-24 10:11     ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 10:11 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Chanwoo Choi, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

Switch the handling of min_freq and max_freq from sysfs to use the
dev_pm_qos_request interface.

Since PM QoS handles frequencies as kHz this change reduces the
precision of min_freq and max_freq. This shouldn't introduce problems
because frequencies which are not an integer number of kHz are likely
not an integer number of Hz either.

Try to ensure compatibility by rounding min values down and rounding
max values up.

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
---
 drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
 include/linux/devfreq.h   |  9 ++++----
 2 files changed, 33 insertions(+), 22 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 784f3e40536a..8bb7efd821ab 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
 	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
 					     DEV_PM_QOS_MIN_FREQUENCY);
 	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
 	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
 
-	/* constraints from sysfs */
-	*min_freq = max(*min_freq, devfreq->min_freq);
-	*max_freq = min(*max_freq, devfreq->max_freq);
-
 	/* constraints from OPP interface */
 	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
 	/* scaling_max_freq can be zero on error */
 	if (devfreq->scaling_max_freq)
 		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
@@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
 			DEV_PM_QOS_MIN_FREQUENCY);
 
 	if (devfreq->profile->exit)
 		devfreq->profile->exit(devfreq->dev.parent);
 
+	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
+	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
 	kfree(devfreq->time_in_state);
 	kfree(devfreq->trans_table);
 	mutex_destroy(&devfreq->lock);
 	kfree(devfreq);
 }
@@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
 	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
 	if (!devfreq->scaling_min_freq) {
 		err = -EINVAL;
 		goto err_dev;
 	}
-	devfreq->min_freq = devfreq->scaling_min_freq;
 
 	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
 	if (!devfreq->scaling_max_freq) {
 		err = -EINVAL;
 		goto err_dev;
 	}
-	devfreq->max_freq = devfreq->scaling_max_freq;
+
+	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
+				     DEV_PM_QOS_MIN_FREQUENCY, 0);
+	if (err < 0)
+		goto err_dev;
+	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
+				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
+	if (err < 0)
+		goto err_dev;
 
 	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
 	atomic_set(&devfreq->suspend_count, 0);
 
 	devfreq->trans_table = kzalloc(
@@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
 err_dev:
 	/*
 	 * Cleanup path for errors that happen before registration.
 	 * Otherwise we rely on devfreq_dev_release.
 	 */
+	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
+		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
+	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
+		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
 	kfree(devfreq->time_in_state);
 	kfree(devfreq->trans_table);
 	kfree(devfreq);
 err_out:
 	return ERR_PTR(err);
@@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
 
 	ret = sscanf(buf, "%lu", &value);
 	if (ret != 1)
 		return -EINVAL;
 
-	mutex_lock(&df->lock);
-	df->min_freq = value;
-	update_devfreq(df);
-	mutex_unlock(&df->lock);
+	/* round down to kHz for PM QoS */
+	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
+					value / HZ_PER_KHZ);
+	if (ret < 0)
+		return ret;
 
 	return count;
 }
 
 static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
@@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
 
 	ret = sscanf(buf, "%lu", &value);
 	if (ret != 1)
 		return -EINVAL;
 
-	mutex_lock(&df->lock);
-
-	/* Interpret zero as "don't care" */
-	if (!value)
-		value = ULONG_MAX;
+	/* round up to kHz for PM QoS and interpret zero as "don't care" */
+	if (value)
+		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
+	else
+		value = S32_MAX;
 
-	df->max_freq = value;
-	update_devfreq(df);
-	mutex_unlock(&df->lock);
+	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
+	if (ret < 0)
+		return ret;
 
 	return count;
 }
 static DEVICE_ATTR_RW(min_freq);
 
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index dac0dffeabb4..7849fe4c666d 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -11,10 +11,11 @@
 #define __LINUX_DEVFREQ_H__
 
 #include <linux/device.h>
 #include <linux/notifier.h>
 #include <linux/pm_opp.h>
+#include <linux/pm_qos.h>
 
 #define DEVFREQ_NAME_LEN 16
 
 /* DEVFREQ governor name */
 #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
@@ -121,12 +122,12 @@ struct devfreq_dev_profile {
  *		devfreq.nb to the corresponding register notifier call chain.
  * @work:	delayed work for load monitoring.
  * @previous_freq:	previously configured frequency value.
  * @data:	Private data of the governor. The devfreq framework does not
  *		touch this.
- * @min_freq:	Limit minimum frequency requested by user (0: none)
- * @max_freq:	Limit maximum frequency requested by user (0: none)
+ * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)
+ * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)
  * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
  * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
  * @stop_polling:	 devfreq polling status of a device.
  * @suspend_freq:	 frequency of a device set during suspend phase.
  * @resume_freq:	 frequency of a device set in resume phase.
@@ -161,12 +162,12 @@ struct devfreq {
 	unsigned long previous_freq;
 	struct devfreq_dev_status last_status;
 
 	void *data; /* private data for governors */
 
-	unsigned long min_freq;
-	unsigned long max_freq;
+	struct dev_pm_qos_request user_min_freq_req;
+	struct dev_pm_qos_request user_max_freq_req;
 	unsigned long scaling_min_freq;
 	unsigned long scaling_max_freq;
 	bool stop_polling;
 
 	unsigned long suspend_freq;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 82+ messages in thread

* [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
@ 2019-09-24 10:11     ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 10:11 UTC (permalink / raw)
  To: MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba, Chanwoo Choi,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

Switch the handling of min_freq and max_freq from sysfs to use the
dev_pm_qos_request interface.

Since PM QoS handles frequencies as kHz this change reduces the
precision of min_freq and max_freq. This shouldn't introduce problems
because frequencies which are not an integer number of kHz are likely
not an integer number of Hz either.

Try to ensure compatibility by rounding min values down and rounding
max values up.

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
---
 drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
 include/linux/devfreq.h   |  9 ++++----
 2 files changed, 33 insertions(+), 22 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 784f3e40536a..8bb7efd821ab 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
 	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
 					     DEV_PM_QOS_MIN_FREQUENCY);
 	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
 	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
 
-	/* constraints from sysfs */
-	*min_freq = max(*min_freq, devfreq->min_freq);
-	*max_freq = min(*max_freq, devfreq->max_freq);
-
 	/* constraints from OPP interface */
 	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
 	/* scaling_max_freq can be zero on error */
 	if (devfreq->scaling_max_freq)
 		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
@@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
 			DEV_PM_QOS_MIN_FREQUENCY);
 
 	if (devfreq->profile->exit)
 		devfreq->profile->exit(devfreq->dev.parent);
 
+	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
+	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
 	kfree(devfreq->time_in_state);
 	kfree(devfreq->trans_table);
 	mutex_destroy(&devfreq->lock);
 	kfree(devfreq);
 }
@@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
 	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
 	if (!devfreq->scaling_min_freq) {
 		err = -EINVAL;
 		goto err_dev;
 	}
-	devfreq->min_freq = devfreq->scaling_min_freq;
 
 	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
 	if (!devfreq->scaling_max_freq) {
 		err = -EINVAL;
 		goto err_dev;
 	}
-	devfreq->max_freq = devfreq->scaling_max_freq;
+
+	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
+				     DEV_PM_QOS_MIN_FREQUENCY, 0);
+	if (err < 0)
+		goto err_dev;
+	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
+				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
+	if (err < 0)
+		goto err_dev;
 
 	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
 	atomic_set(&devfreq->suspend_count, 0);
 
 	devfreq->trans_table = kzalloc(
@@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
 err_dev:
 	/*
 	 * Cleanup path for errors that happen before registration.
 	 * Otherwise we rely on devfreq_dev_release.
 	 */
+	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
+		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
+	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
+		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
 	kfree(devfreq->time_in_state);
 	kfree(devfreq->trans_table);
 	kfree(devfreq);
 err_out:
 	return ERR_PTR(err);
@@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
 
 	ret = sscanf(buf, "%lu", &value);
 	if (ret != 1)
 		return -EINVAL;
 
-	mutex_lock(&df->lock);
-	df->min_freq = value;
-	update_devfreq(df);
-	mutex_unlock(&df->lock);
+	/* round down to kHz for PM QoS */
+	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
+					value / HZ_PER_KHZ);
+	if (ret < 0)
+		return ret;
 
 	return count;
 }
 
 static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
@@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
 
 	ret = sscanf(buf, "%lu", &value);
 	if (ret != 1)
 		return -EINVAL;
 
-	mutex_lock(&df->lock);
-
-	/* Interpret zero as "don't care" */
-	if (!value)
-		value = ULONG_MAX;
+	/* round up to kHz for PM QoS and interpret zero as "don't care" */
+	if (value)
+		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
+	else
+		value = S32_MAX;
 
-	df->max_freq = value;
-	update_devfreq(df);
-	mutex_unlock(&df->lock);
+	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
+	if (ret < 0)
+		return ret;
 
 	return count;
 }
 static DEVICE_ATTR_RW(min_freq);
 
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index dac0dffeabb4..7849fe4c666d 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -11,10 +11,11 @@
 #define __LINUX_DEVFREQ_H__
 
 #include <linux/device.h>
 #include <linux/notifier.h>
 #include <linux/pm_opp.h>
+#include <linux/pm_qos.h>
 
 #define DEVFREQ_NAME_LEN 16
 
 /* DEVFREQ governor name */
 #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
@@ -121,12 +122,12 @@ struct devfreq_dev_profile {
  *		devfreq.nb to the corresponding register notifier call chain.
  * @work:	delayed work for load monitoring.
  * @previous_freq:	previously configured frequency value.
  * @data:	Private data of the governor. The devfreq framework does not
  *		touch this.
- * @min_freq:	Limit minimum frequency requested by user (0: none)
- * @max_freq:	Limit maximum frequency requested by user (0: none)
+ * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)
+ * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)
  * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
  * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
  * @stop_polling:	 devfreq polling status of a device.
  * @suspend_freq:	 frequency of a device set during suspend phase.
  * @resume_freq:	 frequency of a device set in resume phase.
@@ -161,12 +162,12 @@ struct devfreq {
 	unsigned long previous_freq;
 	struct devfreq_dev_status last_status;
 
 	void *data; /* private data for governors */
 
-	unsigned long min_freq;
-	unsigned long max_freq;
+	struct dev_pm_qos_request user_min_freq_req;
+	struct dev_pm_qos_request user_max_freq_req;
 	unsigned long scaling_min_freq;
 	unsigned long scaling_max_freq;
 	bool stop_polling;
 
 	unsigned long suspend_freq;
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-24 10:11     ` Leonard Crestez
@ 2019-09-24 19:11       ` Matthias Kaehlcke
  -1 siblings, 0 replies; 82+ messages in thread
From: Matthias Kaehlcke @ 2019-09-24 19:11 UTC (permalink / raw)
  To: Leonard Crestez
  Cc: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

On Tue, Sep 24, 2019 at 01:11:29PM +0300, Leonard Crestez wrote:
> Register notifiers with the PM QoS framework in order to respond to
> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
> 
> No notifiers are added by this patch but PM QoS constraints can be
> imposed externally (for example from other devices).
> 
> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> ---
>  drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>  include/linux/devfreq.h   |  5 +++
>  2 files changed, 80 insertions(+)
> 
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index eee403e70c84..784f3e40536a 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -22,15 +22,18 @@
>  #include <linux/platform_device.h>
>  #include <linux/list.h>
>  #include <linux/printk.h>
>  #include <linux/hrtimer.h>
>  #include <linux/of.h>
> +#include <linux/pm_qos.h>
>  #include "governor.h"
>  
>  #define CREATE_TRACE_POINTS
>  #include <trace/events/devfreq.h>
>  
> +#define HZ_PER_KHZ	1000
> +
>  static struct class *devfreq_class;
>  
>  /*
>   * devfreq core provides delayed work based load monitoring helper
>   * functions. Governors can use these or can implement their own
> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>  static void get_freq_range(struct devfreq *devfreq,
>  			   unsigned long *min_freq,
>  			   unsigned long *max_freq)
>  {
>  	unsigned long *freq_table = devfreq->profile->freq_table;
> +	unsigned long qos_min_freq, qos_max_freq;
>  
>  	lockdep_assert_held(&devfreq->lock);
>  
>  	/*
>  	 * Init min/max frequency from freq table.
> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>  	} else {
>  		*min_freq = freq_table[devfreq->profile->max_state - 1];
>  		*max_freq = freq_table[0];
>  	}
>  
> +	/* constraints from PM QoS */
> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> +					     DEV_PM_QOS_MIN_FREQUENCY);
> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> +					     DEV_PM_QOS_MIN_FREQUENCY);

This needs to be DEV_PM_QOS_MAX_FREQUENCY. I missed this in the earlier
reviews, but stumbled across it when testing.

!Reviewed-by: Matthias Kaehlcke <mka@chromium.org>

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-24 19:11       ` Matthias Kaehlcke
  0 siblings, 0 replies; 82+ messages in thread
From: Matthias Kaehlcke @ 2019-09-24 19:11 UTC (permalink / raw)
  To: Leonard Crestez
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba, Chanwoo Choi,
	Kyungmin Park, MyungJoo Ham, Alexandre Bailon, Georgi Djakov,
	linux-arm-kernel, Jacky Bai

On Tue, Sep 24, 2019 at 01:11:29PM +0300, Leonard Crestez wrote:
> Register notifiers with the PM QoS framework in order to respond to
> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
> 
> No notifiers are added by this patch but PM QoS constraints can be
> imposed externally (for example from other devices).
> 
> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> ---
>  drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>  include/linux/devfreq.h   |  5 +++
>  2 files changed, 80 insertions(+)
> 
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index eee403e70c84..784f3e40536a 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -22,15 +22,18 @@
>  #include <linux/platform_device.h>
>  #include <linux/list.h>
>  #include <linux/printk.h>
>  #include <linux/hrtimer.h>
>  #include <linux/of.h>
> +#include <linux/pm_qos.h>
>  #include "governor.h"
>  
>  #define CREATE_TRACE_POINTS
>  #include <trace/events/devfreq.h>
>  
> +#define HZ_PER_KHZ	1000
> +
>  static struct class *devfreq_class;
>  
>  /*
>   * devfreq core provides delayed work based load monitoring helper
>   * functions. Governors can use these or can implement their own
> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>  static void get_freq_range(struct devfreq *devfreq,
>  			   unsigned long *min_freq,
>  			   unsigned long *max_freq)
>  {
>  	unsigned long *freq_table = devfreq->profile->freq_table;
> +	unsigned long qos_min_freq, qos_max_freq;
>  
>  	lockdep_assert_held(&devfreq->lock);
>  
>  	/*
>  	 * Init min/max frequency from freq table.
> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>  	} else {
>  		*min_freq = freq_table[devfreq->profile->max_state - 1];
>  		*max_freq = freq_table[0];
>  	}
>  
> +	/* constraints from PM QoS */
> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> +					     DEV_PM_QOS_MIN_FREQUENCY);
> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> +					     DEV_PM_QOS_MIN_FREQUENCY);

This needs to be DEV_PM_QOS_MAX_FREQUENCY. I missed this in the earlier
reviews, but stumbled across it when testing.

!Reviewed-by: Matthias Kaehlcke <mka@chromium.org>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-24 19:11       ` Matthias Kaehlcke
@ 2019-09-24 19:22         ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 19:22 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 24.09.2019 22:11, Matthias Kaehlcke wrote:
> On Tue, Sep 24, 2019 at 01:11:29PM +0300, Leonard Crestez wrote:
>> Register notifiers with the PM QoS framework in order to respond to
>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>
>> No notifiers are added by this patch but PM QoS constraints can be
>> imposed externally (for example from other devices).
>>
>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>> ---
>>   drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>   include/linux/devfreq.h   |  5 +++
>>   2 files changed, 80 insertions(+)
>>
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index eee403e70c84..784f3e40536a 100644
>> --- a/drivers/devfreq/devfreq.c
>> +++ b/drivers/devfreq/devfreq.c
>> @@ -22,15 +22,18 @@
>>   #include <linux/platform_device.h>
>>   #include <linux/list.h>
>>   #include <linux/printk.h>
>>   #include <linux/hrtimer.h>
>>   #include <linux/of.h>
>> +#include <linux/pm_qos.h>
>>   #include "governor.h"
>>   
>>   #define CREATE_TRACE_POINTS
>>   #include <trace/events/devfreq.h>
>>   
>> +#define HZ_PER_KHZ	1000
>> +
>>   static struct class *devfreq_class;
>>   
>>   /*
>>    * devfreq core provides delayed work based load monitoring helper
>>    * functions. Governors can use these or can implement their own
>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>   static void get_freq_range(struct devfreq *devfreq,
>>   			   unsigned long *min_freq,
>>   			   unsigned long *max_freq)
>>   {
>>   	unsigned long *freq_table = devfreq->profile->freq_table;
>> +	unsigned long qos_min_freq, qos_max_freq;
>>   
>>   	lockdep_assert_held(&devfreq->lock);
>>   
>>   	/*
>>   	 * Init min/max frequency from freq table.
>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>   	} else {
>>   		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>   		*max_freq = freq_table[0];
>>   	}
>>   
>> +	/* constraints from PM QoS */
>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>> +					     DEV_PM_QOS_MIN_FREQUENCY); >
> This needs to be DEV_PM_QOS_MAX_FREQUENCY. I missed this in the earlier
> reviews, but stumbled across it when testing.
> 
> !Reviewed-by: Matthias Kaehlcke <mka@chromium.org>

I broke it in v8 while processing comments. Thanks for catching it.

--
Regards,
Leonard

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-24 19:22         ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-24 19:22 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Chanwoo Choi, Kyungmin Park,
	MyungJoo Ham, Alexandre Bailon, Georgi Djakov, linux-arm-kernel,
	Jacky Bai

On 24.09.2019 22:11, Matthias Kaehlcke wrote:
> On Tue, Sep 24, 2019 at 01:11:29PM +0300, Leonard Crestez wrote:
>> Register notifiers with the PM QoS framework in order to respond to
>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>
>> No notifiers are added by this patch but PM QoS constraints can be
>> imposed externally (for example from other devices).
>>
>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>> ---
>>   drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>   include/linux/devfreq.h   |  5 +++
>>   2 files changed, 80 insertions(+)
>>
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index eee403e70c84..784f3e40536a 100644
>> --- a/drivers/devfreq/devfreq.c
>> +++ b/drivers/devfreq/devfreq.c
>> @@ -22,15 +22,18 @@
>>   #include <linux/platform_device.h>
>>   #include <linux/list.h>
>>   #include <linux/printk.h>
>>   #include <linux/hrtimer.h>
>>   #include <linux/of.h>
>> +#include <linux/pm_qos.h>
>>   #include "governor.h"
>>   
>>   #define CREATE_TRACE_POINTS
>>   #include <trace/events/devfreq.h>
>>   
>> +#define HZ_PER_KHZ	1000
>> +
>>   static struct class *devfreq_class;
>>   
>>   /*
>>    * devfreq core provides delayed work based load monitoring helper
>>    * functions. Governors can use these or can implement their own
>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>   static void get_freq_range(struct devfreq *devfreq,
>>   			   unsigned long *min_freq,
>>   			   unsigned long *max_freq)
>>   {
>>   	unsigned long *freq_table = devfreq->profile->freq_table;
>> +	unsigned long qos_min_freq, qos_max_freq;
>>   
>>   	lockdep_assert_held(&devfreq->lock);
>>   
>>   	/*
>>   	 * Init min/max frequency from freq table.
>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>   	} else {
>>   		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>   		*max_freq = freq_table[0];
>>   	}
>>   
>> +	/* constraints from PM QoS */
>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>> +					     DEV_PM_QOS_MIN_FREQUENCY); >
> This needs to be DEV_PM_QOS_MAX_FREQUENCY. I missed this in the earlier
> reviews, but stumbled across it when testing.
> 
> !Reviewed-by: Matthias Kaehlcke <mka@chromium.org>

I broke it in v8 while processing comments. Thanks for catching it.

--
Regards,
Leonard

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 4/6] PM / devfreq: Introduce get_freq_range helper
  2019-09-24 10:11     ` Leonard Crestez
@ 2019-09-25  1:37       ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-25  1:37 UTC (permalink / raw)
  To: Leonard Crestez, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> Moving handling of min/max freq to a single function and call it from
> update_devfreq and for printing min/max freq values in sysfs.
> 
> This changes the behavior of out-of-range min_freq/max_freq: clamping
> is now done at evaluation time. This means that if an out-of-range
> constraint is imposed by sysfs and it later becomes valid then it will
> be enforced.
> 
> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> ---
>  drivers/devfreq/devfreq.c | 112 ++++++++++++++++++++++----------------
>  1 file changed, 64 insertions(+), 48 deletions(-)
> 
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 4a878baa809e..eee403e70c84 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -96,10 +96,54 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>  		dev_pm_opp_put(opp);
>  
>  	return max_freq;
>  }
>  
> +/**
> + * get_freq_range() - Get the current freq range
> + * @devfreq:	the devfreq instance
> + * @min_freq:	the min frequency
> + * @max_freq:	the max frequency
> + *
> + * This takes into consideration all constraints.
> + */
> +static void get_freq_range(struct devfreq *devfreq,
> +			   unsigned long *min_freq,
> +			   unsigned long *max_freq)
> +{
> +	unsigned long *freq_table = devfreq->profile->freq_table;
> +
> +	lockdep_assert_held(&devfreq->lock);
> +
> +	/*
> +	 * Init min/max frequency from freq table.

Init -> Initialize
min/max -> minimum/maximum 

> +	 * Drivers can initialize this in either ascending or descending order

Drivers -> devfreq drivers

> +	 * and devfreq core supports both.
> +	 */


In result, I prefer to change the comments as following: 
	/*
	 * Initialize the minimum/maximum frequency from freq_table.
 	 * The devfreq drivers can initialize freq_table in either
	 * ascending or descending order and devfreq core supports both.
	 */

> +	if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
> +		*min_freq = freq_table[0];
> +		*max_freq = freq_table[devfreq->profile->max_state - 1];
> +	} else {
> +		*min_freq = freq_table[devfreq->profile->max_state - 1];
> +		*max_freq = freq_table[0];
> +	}
> +
> +	/* constraints from sysfs */

'constraints' -> Constraint because first verb have to be used
as the sigular verbs. Also, I think that have to enhance the comments
I prefer to use following comments: 

	 /* Constraint minimum/maximum frequency from user input via sysfs */



> +	*min_freq = max(*min_freq, devfreq->min_freq);
> +	*max_freq = min(*max_freq, devfreq->max_freq);
> +
> +	/* constraints from OPP interface */

ditto. I prefer to use following comments: 

	/* Constraint minimum/maximum frequency from OPP interface */


> +	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
> +	/* scaling_max_freq can be zero on error */

Please remove it.

> +	if (devfreq->scaling_max_freq)

As I knew, devfreq->scaling_max_freq is never zero.
So, it is always true. This if statement is needed.

> +		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
> +
> +	/* max_freq takes precedence over min_freq */

As I said, almost people know that min_freq have be under than max_freq.
Please remove it. And until finishing the discussion on mailing list,
please don't send the next version. If you just replied from my comment
and then wait my next comment, we can save the time without replying
the repetitive and same comment for same point.

> +	if (*min_freq > *max_freq)
> +		*min_freq = *max_freq;
> +}
> +
>  /**
>   * devfreq_get_freq_level() - Lookup freq_table for the frequency
>   * @devfreq:	the devfreq instance
>   * @freq:	the target frequency
>   */
> @@ -349,20 +393,11 @@ int update_devfreq(struct devfreq *devfreq)
>  
>  	/* Reevaluate the proper frequency */
>  	err = devfreq->governor->get_target_freq(devfreq, &freq);
>  	if (err)
>  		return err;
> -
> -	/*
> -	 * Adjust the frequency with user freq, QoS and available freq.
> -	 *
> -	 * List from the highest priority
> -	 * max_freq
> -	 * min_freq
> -	 */
> -	max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
> -	min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
> +	get_freq_range(devfreq, &min_freq, &max_freq);
>  
>  	if (freq < min_freq) {
>  		freq = min_freq;
>  		flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
>  	}
> @@ -1298,40 +1333,28 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>  	ret = sscanf(buf, "%lu", &value);
>  	if (ret != 1)
>  		return -EINVAL;
>  
>  	mutex_lock(&df->lock);
> -
> -	if (value) {
> -		if (value > df->max_freq) {
> -			ret = -EINVAL;
> -			goto unlock;
> -		}
> -	} else {
> -		unsigned long *freq_table = df->profile->freq_table;
> -
> -		/* Get minimum frequency according to sorting order */
> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
> -			value = freq_table[0];
> -		else
> -			value = freq_table[df->profile->max_state - 1];
> -	}
> -
>  	df->min_freq = value;
>  	update_devfreq(df);
> -	ret = count;
> -unlock:
>  	mutex_unlock(&df->lock);
> -	return ret;
> +
> +	return count;
>  }
>  
>  static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>  			     char *buf)
>  {
>  	struct devfreq *df = to_devfreq(dev);
> +	unsigned long min_freq, max_freq;
> +
> +	mutex_lock(&df->lock);
> +	get_freq_range(df, &min_freq, &max_freq);
> +	mutex_unlock(&df->lock);
>  
> -	return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
> +	return sprintf(buf, "%lu\n", min_freq);
>  }
>  
>  static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>  			      const char *buf, size_t count)
>  {
> @@ -1343,40 +1366,33 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>  	if (ret != 1)
>  		return -EINVAL;
>  
>  	mutex_lock(&df->lock);
>  
> -	if (value) {
> -		if (value < df->min_freq) {
> -			ret = -EINVAL;
> -			goto unlock;
> -		}
> -	} else {
> -		unsigned long *freq_table = df->profile->freq_table;
> -
> -		/* Get maximum frequency according to sorting order */
> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
> -			value = freq_table[df->profile->max_state - 1];
> -		else
> -			value = freq_table[0];
> -	}
> +	/* Interpret zero as "don't care" */

Please remove it. Also, the detailed comment for user have to add
the documentation file. 

> +	if (!value)
> +		value = ULONG_MAX;
>  
>  	df->max_freq = value;
>  	update_devfreq(df);
> -	ret = count;
> -unlock:
>  	mutex_unlock(&df->lock);
> -	return ret;
> +
> +	return count;
>  }
>  static DEVICE_ATTR_RW(min_freq);
>  
>  static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
>  			     char *buf)
>  {
>  	struct devfreq *df = to_devfreq(dev);
> +	unsigned long min_freq, max_freq;
> +
> +	mutex_lock(&df->lock);
> +	get_freq_range(df, &min_freq, &max_freq);
> +	mutex_unlock(&df->lock);
>  
> -	return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
> +	return sprintf(buf, "%lu\n", max_freq);
>  }
>  static DEVICE_ATTR_RW(max_freq);
>  
>  static ssize_t available_frequencies_show(struct device *d,
>  					  struct device_attribute *attr,
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 4/6] PM / devfreq: Introduce get_freq_range helper
@ 2019-09-25  1:37       ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-25  1:37 UTC (permalink / raw)
  To: Leonard Crestez, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> Moving handling of min/max freq to a single function and call it from
> update_devfreq and for printing min/max freq values in sysfs.
> 
> This changes the behavior of out-of-range min_freq/max_freq: clamping
> is now done at evaluation time. This means that if an out-of-range
> constraint is imposed by sysfs and it later becomes valid then it will
> be enforced.
> 
> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> ---
>  drivers/devfreq/devfreq.c | 112 ++++++++++++++++++++++----------------
>  1 file changed, 64 insertions(+), 48 deletions(-)
> 
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 4a878baa809e..eee403e70c84 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -96,10 +96,54 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>  		dev_pm_opp_put(opp);
>  
>  	return max_freq;
>  }
>  
> +/**
> + * get_freq_range() - Get the current freq range
> + * @devfreq:	the devfreq instance
> + * @min_freq:	the min frequency
> + * @max_freq:	the max frequency
> + *
> + * This takes into consideration all constraints.
> + */
> +static void get_freq_range(struct devfreq *devfreq,
> +			   unsigned long *min_freq,
> +			   unsigned long *max_freq)
> +{
> +	unsigned long *freq_table = devfreq->profile->freq_table;
> +
> +	lockdep_assert_held(&devfreq->lock);
> +
> +	/*
> +	 * Init min/max frequency from freq table.

Init -> Initialize
min/max -> minimum/maximum 

> +	 * Drivers can initialize this in either ascending or descending order

Drivers -> devfreq drivers

> +	 * and devfreq core supports both.
> +	 */


In result, I prefer to change the comments as following: 
	/*
	 * Initialize the minimum/maximum frequency from freq_table.
 	 * The devfreq drivers can initialize freq_table in either
	 * ascending or descending order and devfreq core supports both.
	 */

> +	if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
> +		*min_freq = freq_table[0];
> +		*max_freq = freq_table[devfreq->profile->max_state - 1];
> +	} else {
> +		*min_freq = freq_table[devfreq->profile->max_state - 1];
> +		*max_freq = freq_table[0];
> +	}
> +
> +	/* constraints from sysfs */

'constraints' -> Constraint because first verb have to be used
as the sigular verbs. Also, I think that have to enhance the comments
I prefer to use following comments: 

	 /* Constraint minimum/maximum frequency from user input via sysfs */



> +	*min_freq = max(*min_freq, devfreq->min_freq);
> +	*max_freq = min(*max_freq, devfreq->max_freq);
> +
> +	/* constraints from OPP interface */

ditto. I prefer to use following comments: 

	/* Constraint minimum/maximum frequency from OPP interface */


> +	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
> +	/* scaling_max_freq can be zero on error */

Please remove it.

> +	if (devfreq->scaling_max_freq)

As I knew, devfreq->scaling_max_freq is never zero.
So, it is always true. This if statement is needed.

> +		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
> +
> +	/* max_freq takes precedence over min_freq */

As I said, almost people know that min_freq have be under than max_freq.
Please remove it. And until finishing the discussion on mailing list,
please don't send the next version. If you just replied from my comment
and then wait my next comment, we can save the time without replying
the repetitive and same comment for same point.

> +	if (*min_freq > *max_freq)
> +		*min_freq = *max_freq;
> +}
> +
>  /**
>   * devfreq_get_freq_level() - Lookup freq_table for the frequency
>   * @devfreq:	the devfreq instance
>   * @freq:	the target frequency
>   */
> @@ -349,20 +393,11 @@ int update_devfreq(struct devfreq *devfreq)
>  
>  	/* Reevaluate the proper frequency */
>  	err = devfreq->governor->get_target_freq(devfreq, &freq);
>  	if (err)
>  		return err;
> -
> -	/*
> -	 * Adjust the frequency with user freq, QoS and available freq.
> -	 *
> -	 * List from the highest priority
> -	 * max_freq
> -	 * min_freq
> -	 */
> -	max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
> -	min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
> +	get_freq_range(devfreq, &min_freq, &max_freq);
>  
>  	if (freq < min_freq) {
>  		freq = min_freq;
>  		flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
>  	}
> @@ -1298,40 +1333,28 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>  	ret = sscanf(buf, "%lu", &value);
>  	if (ret != 1)
>  		return -EINVAL;
>  
>  	mutex_lock(&df->lock);
> -
> -	if (value) {
> -		if (value > df->max_freq) {
> -			ret = -EINVAL;
> -			goto unlock;
> -		}
> -	} else {
> -		unsigned long *freq_table = df->profile->freq_table;
> -
> -		/* Get minimum frequency according to sorting order */
> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
> -			value = freq_table[0];
> -		else
> -			value = freq_table[df->profile->max_state - 1];
> -	}
> -
>  	df->min_freq = value;
>  	update_devfreq(df);
> -	ret = count;
> -unlock:
>  	mutex_unlock(&df->lock);
> -	return ret;
> +
> +	return count;
>  }
>  
>  static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>  			     char *buf)
>  {
>  	struct devfreq *df = to_devfreq(dev);
> +	unsigned long min_freq, max_freq;
> +
> +	mutex_lock(&df->lock);
> +	get_freq_range(df, &min_freq, &max_freq);
> +	mutex_unlock(&df->lock);
>  
> -	return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
> +	return sprintf(buf, "%lu\n", min_freq);
>  }
>  
>  static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>  			      const char *buf, size_t count)
>  {
> @@ -1343,40 +1366,33 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>  	if (ret != 1)
>  		return -EINVAL;
>  
>  	mutex_lock(&df->lock);
>  
> -	if (value) {
> -		if (value < df->min_freq) {
> -			ret = -EINVAL;
> -			goto unlock;
> -		}
> -	} else {
> -		unsigned long *freq_table = df->profile->freq_table;
> -
> -		/* Get maximum frequency according to sorting order */
> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
> -			value = freq_table[df->profile->max_state - 1];
> -		else
> -			value = freq_table[0];
> -	}
> +	/* Interpret zero as "don't care" */

Please remove it. Also, the detailed comment for user have to add
the documentation file. 

> +	if (!value)
> +		value = ULONG_MAX;
>  
>  	df->max_freq = value;
>  	update_devfreq(df);
> -	ret = count;
> -unlock:
>  	mutex_unlock(&df->lock);
> -	return ret;
> +
> +	return count;
>  }
>  static DEVICE_ATTR_RW(min_freq);
>  
>  static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
>  			     char *buf)
>  {
>  	struct devfreq *df = to_devfreq(dev);
> +	unsigned long min_freq, max_freq;
> +
> +	mutex_lock(&df->lock);
> +	get_freq_range(df, &min_freq, &max_freq);
> +	mutex_unlock(&df->lock);
>  
> -	return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
> +	return sprintf(buf, "%lu\n", max_freq);
>  }
>  static DEVICE_ATTR_RW(max_freq);
>  
>  static ssize_t available_frequencies_show(struct device *d,
>  					  struct device_attribute *attr,
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 0/6] PM / devfreq: Add dev_pm_qos support
  2019-09-24 10:11   ` Leonard Crestez
@ 2019-09-25  1:44     ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-25  1:44 UTC (permalink / raw)
  To: Leonard Crestez, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

Hi Leonard,

Basically, I think that these series are very important.

But, you better to send the next version patch
after finishing the review/discussion on previous version.

I reviewed the v7 and then you replied your comment.
It is OK. But, you just send v8 without waiting my comment
from your reply. It is not efficient discussion method.

If we finish the review of some point in the v7,
it doesn't need to discuss the same comment on v8. 

Please wait the reply for review. I think that
it can save the our time for the review and contribution.


On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> Add dev_pm_qos notifiers to devfreq core in order to support frequency
> limits via dev_pm_qos_add_request.
> 
> Unlike the rest of devfreq the dev_pm_qos frequency is measured in Khz,
> this is consistent with current dev_pm_qos usage for cpufreq and
> allows frequencies above 2Ghz (pm_qos expresses limits as s32).
> 
> Like with cpufreq the handling of min_freq/max_freq is moved to the
> dev_pm_qos mechanism. Constraints from userspace are no longer clamped on
> store, instead all values can be written and we only check against OPPs in a
> new devfreq_get_freq_range function. This is consistent with the design of
> dev_pm_qos.
> 
> Notifiers from pm_qos are executed under a single global dev_pm_qos_mtx and
> need to take devfreq->lock. Notifier registration takes the same dev_pm_qos_mtx
> so in order to prevent lockdep warnings it must be done outside devfreq->lock.
> Current devfreq_add_device does all initialization under devfreq->lock and that
> needs to be relaxed.
> 
> ---
> Changes since v7:
> * Only #define HZ_PER_KHZ in patch where it's used.
> * Drop devfreq_ prefix for some internal functions.
> * Improve qos update error message.
> * Remove some unnecessary comments.
> * Collect reviews
> Link to v7: https://patchwork.kernel.org/cover/11157649/
> 
> Changes since v6:
> * Don't return errno from devfreq_qos_notifier_call, return NOTIFY_DONE
> and print the error.
> * More spelling and punctuation nits
> Link to v6: https://patchwork.kernel.org/cover/11157201/
> 
> Changes since v5:
> * Drop patches which are not strictly related to PM QoS.
> * Add a comment explaining why devfreq_add_device needs two cleanup paths.
> * Remove {} for single line.
> * Rename {min,max}_freq_req to user_{min,max}_freq_req
> * Collect reviews
> Link to v5: https://patchwork.kernel.org/cover/11149497/
> 
> Sorry for forgetting to properly label v5. I know this is inside the
> merge window but review would still be appreciated.
> 
> Changes since v4:
> * Move more devfreq_add_device init ahead of device_register.
> * Make devfreq_dev_release cleanup devices not yet in devfreq_list. This is
> simpler than previous attempt to add to devfreq_list sonner.
> * Take devfreq->lock in trans_stat_show
> * Register dev_pm_opp notifier on devfreq parent dev (which has OPPs)
> Link to v4: https://patchwork.kernel.org/cover/11114657/
> 
> Changes since v4:
> * Move more devfreq_add_device init ahead of device_register.
> * Make devfreq_dev_release cleanup devices not yet in devfreq_list. This is
> simpler than previous attempt to add to devfreq_list sonner.
> * Take devfreq->lock in trans_stat_show
> * Register dev_pm_opp notifier on devfreq parent dev (which has OPPs)
> Like to v4: https://patchwork.kernel.org/cover/11114657/
> 
> Changes since v3:
> * Cleanup locking and error-handling in devfreq_add_device
> * Register notifiers after device registration but before governor start
> * Keep the initialization of min_req/max_req ahead of device_register
> because it's used for sysfs handling
> * Use HZ_PER_KHZ instead of 1000
> * Add kernel-doc comments
> * Move OPP notifier to core
> Link to v3: https://patchwork.kernel.org/cover/11104061/
> 
> Changes since v2:
> * Handle sysfs via dev_pm_qos (in separate patch)
> * Add locking to {min,max}_freq_show
> * Fix checkpatch issues (long lines etc)
> Link to v2: https://patchwork.kernel.org/patch/11084279/
> 
> Changes since v1:
> * Add doxygen comments for min_nb/max_nb
> * Remove notifiers on error/cleanup paths. Keep gotos simple by relying on
> dev_pm_qos_remove_notifier ignoring notifiers which were not added.
> Link to v1: https://patchwork.kernel.org/patch/11078475/
> 
> Leonard Crestez (6):
>   PM / devfreq: Don't fail devfreq_dev_release if not in list
>   PM / devfreq: Move more initialization before registration
>   PM / devfreq: Don't take lock in devfreq_add_device
>   PM / devfreq: Introduce get_freq_range helper
>   PM / devfreq: Add PM QoS support
>   PM / devfreq: Use PM QoS for sysfs min/max_freq
> 
>  drivers/devfreq/devfreq.c | 268 +++++++++++++++++++++++++-------------
>  include/linux/devfreq.h   |  14 +-
>  2 files changed, 191 insertions(+), 91 deletions(-)
> 

-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 0/6] PM / devfreq: Add dev_pm_qos support
@ 2019-09-25  1:44     ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-25  1:44 UTC (permalink / raw)
  To: Leonard Crestez, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

Hi Leonard,

Basically, I think that these series are very important.

But, you better to send the next version patch
after finishing the review/discussion on previous version.

I reviewed the v7 and then you replied your comment.
It is OK. But, you just send v8 without waiting my comment
from your reply. It is not efficient discussion method.

If we finish the review of some point in the v7,
it doesn't need to discuss the same comment on v8. 

Please wait the reply for review. I think that
it can save the our time for the review and contribution.


On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> Add dev_pm_qos notifiers to devfreq core in order to support frequency
> limits via dev_pm_qos_add_request.
> 
> Unlike the rest of devfreq the dev_pm_qos frequency is measured in Khz,
> this is consistent with current dev_pm_qos usage for cpufreq and
> allows frequencies above 2Ghz (pm_qos expresses limits as s32).
> 
> Like with cpufreq the handling of min_freq/max_freq is moved to the
> dev_pm_qos mechanism. Constraints from userspace are no longer clamped on
> store, instead all values can be written and we only check against OPPs in a
> new devfreq_get_freq_range function. This is consistent with the design of
> dev_pm_qos.
> 
> Notifiers from pm_qos are executed under a single global dev_pm_qos_mtx and
> need to take devfreq->lock. Notifier registration takes the same dev_pm_qos_mtx
> so in order to prevent lockdep warnings it must be done outside devfreq->lock.
> Current devfreq_add_device does all initialization under devfreq->lock and that
> needs to be relaxed.
> 
> ---
> Changes since v7:
> * Only #define HZ_PER_KHZ in patch where it's used.
> * Drop devfreq_ prefix for some internal functions.
> * Improve qos update error message.
> * Remove some unnecessary comments.
> * Collect reviews
> Link to v7: https://patchwork.kernel.org/cover/11157649/
> 
> Changes since v6:
> * Don't return errno from devfreq_qos_notifier_call, return NOTIFY_DONE
> and print the error.
> * More spelling and punctuation nits
> Link to v6: https://patchwork.kernel.org/cover/11157201/
> 
> Changes since v5:
> * Drop patches which are not strictly related to PM QoS.
> * Add a comment explaining why devfreq_add_device needs two cleanup paths.
> * Remove {} for single line.
> * Rename {min,max}_freq_req to user_{min,max}_freq_req
> * Collect reviews
> Link to v5: https://patchwork.kernel.org/cover/11149497/
> 
> Sorry for forgetting to properly label v5. I know this is inside the
> merge window but review would still be appreciated.
> 
> Changes since v4:
> * Move more devfreq_add_device init ahead of device_register.
> * Make devfreq_dev_release cleanup devices not yet in devfreq_list. This is
> simpler than previous attempt to add to devfreq_list sonner.
> * Take devfreq->lock in trans_stat_show
> * Register dev_pm_opp notifier on devfreq parent dev (which has OPPs)
> Link to v4: https://patchwork.kernel.org/cover/11114657/
> 
> Changes since v4:
> * Move more devfreq_add_device init ahead of device_register.
> * Make devfreq_dev_release cleanup devices not yet in devfreq_list. This is
> simpler than previous attempt to add to devfreq_list sonner.
> * Take devfreq->lock in trans_stat_show
> * Register dev_pm_opp notifier on devfreq parent dev (which has OPPs)
> Like to v4: https://patchwork.kernel.org/cover/11114657/
> 
> Changes since v3:
> * Cleanup locking and error-handling in devfreq_add_device
> * Register notifiers after device registration but before governor start
> * Keep the initialization of min_req/max_req ahead of device_register
> because it's used for sysfs handling
> * Use HZ_PER_KHZ instead of 1000
> * Add kernel-doc comments
> * Move OPP notifier to core
> Link to v3: https://patchwork.kernel.org/cover/11104061/
> 
> Changes since v2:
> * Handle sysfs via dev_pm_qos (in separate patch)
> * Add locking to {min,max}_freq_show
> * Fix checkpatch issues (long lines etc)
> Link to v2: https://patchwork.kernel.org/patch/11084279/
> 
> Changes since v1:
> * Add doxygen comments for min_nb/max_nb
> * Remove notifiers on error/cleanup paths. Keep gotos simple by relying on
> dev_pm_qos_remove_notifier ignoring notifiers which were not added.
> Link to v1: https://patchwork.kernel.org/patch/11078475/
> 
> Leonard Crestez (6):
>   PM / devfreq: Don't fail devfreq_dev_release if not in list
>   PM / devfreq: Move more initialization before registration
>   PM / devfreq: Don't take lock in devfreq_add_device
>   PM / devfreq: Introduce get_freq_range helper
>   PM / devfreq: Add PM QoS support
>   PM / devfreq: Use PM QoS for sysfs min/max_freq
> 
>  drivers/devfreq/devfreq.c | 268 +++++++++++++++++++++++++-------------
>  include/linux/devfreq.h   |  14 +-
>  2 files changed, 191 insertions(+), 91 deletions(-)
> 

-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 2/6] PM / devfreq: Move more initialization before registration
  2019-09-24 10:11     ` Leonard Crestez
@ 2019-09-25  1:46       ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-25  1:46 UTC (permalink / raw)
  To: Leonard Crestez, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

Hi Leonard,

I copied and pasted my comments as following:
because you send new v8 version without waiting any reply.
In my case, I don't prefer to remove 'devm_' feature.

v7's comment.
I'm not sure that it is necessary. Because, mainline kernel
provides the resource-managed feature with 'devm_*'
in order to reduce the memory leak by user.

It's like going back to a time when 'devm_*' feature wasn't there.
I think just it depends on the coding style of author.

I leave the final decision of this patch to Myungjoo.

On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> In general it is a better to initialize an object before making it
> accessible externally (through device_register).
> 
> This makes it possible to avoid relying on locking a partially
> initialized object.
> 
> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> ---
>  drivers/devfreq/devfreq.c | 43 +++++++++++++++++++++++----------------
>  1 file changed, 25 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 12c4bcdc1f17..dbc6dc882aba 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -588,10 +588,12 @@ static void devfreq_dev_release(struct device *dev)
>  	mutex_unlock(&devfreq_list_lock);
>  
>  	if (devfreq->profile->exit)
>  		devfreq->profile->exit(devfreq->dev.parent);
>  
> +	kfree(devfreq->time_in_state);
> +	kfree(devfreq->trans_table);
>  	mutex_destroy(&devfreq->lock);
>  	kfree(devfreq);
>  }
>  
>  /**
> @@ -671,44 +673,43 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  	devfreq->max_freq = devfreq->scaling_max_freq;
>  
>  	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
>  	atomic_set(&devfreq->suspend_count, 0);
>  
> -	dev_set_name(&devfreq->dev, "devfreq%d",
> -				atomic_inc_return(&devfreq_no));
> -	err = device_register(&devfreq->dev);
> -	if (err) {
> -		mutex_unlock(&devfreq->lock);
> -		put_device(&devfreq->dev);
> -		goto err_out;
> -	}
> -
> -	devfreq->trans_table = devm_kzalloc(&devfreq->dev,
> +	devfreq->trans_table = kzalloc(
>  			array3_size(sizeof(unsigned int),
>  				    devfreq->profile->max_state,
>  				    devfreq->profile->max_state),
>  			GFP_KERNEL);
>  	if (!devfreq->trans_table) {
>  		mutex_unlock(&devfreq->lock);
>  		err = -ENOMEM;
> -		goto err_devfreq;
> +		goto err_dev;
>  	}
>  
> -	devfreq->time_in_state = devm_kcalloc(&devfreq->dev,
> -			devfreq->profile->max_state,
> -			sizeof(unsigned long),
> -			GFP_KERNEL);
> +	devfreq->time_in_state = kcalloc(devfreq->profile->max_state,
> +					 sizeof(unsigned long),
> +					 GFP_KERNEL);
>  	if (!devfreq->time_in_state) {
>  		mutex_unlock(&devfreq->lock);
>  		err = -ENOMEM;
> -		goto err_devfreq;
> +		goto err_dev;
>  	}
>  
>  	devfreq->last_stat_updated = jiffies;
>  
>  	srcu_init_notifier_head(&devfreq->transition_notifier_list);
>  
> +	dev_set_name(&devfreq->dev, "devfreq%d",
> +				atomic_inc_return(&devfreq_no));
> +	err = device_register(&devfreq->dev);
> +	if (err) {
> +		mutex_unlock(&devfreq->lock);
> +		put_device(&devfreq->dev);
> +		goto err_out;
> +	}
> +
>  	mutex_unlock(&devfreq->lock);
>  
>  	mutex_lock(&devfreq_list_lock);
>  
>  	governor = try_then_request_governor(devfreq->governor_name);
> @@ -734,14 +735,20 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  
>  	return devfreq;
>  
>  err_init:
>  	mutex_unlock(&devfreq_list_lock);
> -err_devfreq:
>  	devfreq_remove_device(devfreq);
> -	devfreq = NULL;
> +	return ERR_PTR(err);
> +
>  err_dev:
> +	/*
> +	 * Cleanup path for errors that happen before registration.
> +	 * Otherwise we rely on devfreq_dev_release.
> +	 */
> +	kfree(devfreq->time_in_state);
> +	kfree(devfreq->trans_table);
>  	kfree(devfreq);
>  err_out:
>  	return ERR_PTR(err);
>  }
>  EXPORT_SYMBOL(devfreq_add_device);
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 2/6] PM / devfreq: Move more initialization before registration
@ 2019-09-25  1:46       ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-25  1:46 UTC (permalink / raw)
  To: Leonard Crestez, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

Hi Leonard,

I copied and pasted my comments as following:
because you send new v8 version without waiting any reply.
In my case, I don't prefer to remove 'devm_' feature.

v7's comment.
I'm not sure that it is necessary. Because, mainline kernel
provides the resource-managed feature with 'devm_*'
in order to reduce the memory leak by user.

It's like going back to a time when 'devm_*' feature wasn't there.
I think just it depends on the coding style of author.

I leave the final decision of this patch to Myungjoo.

On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> In general it is a better to initialize an object before making it
> accessible externally (through device_register).
> 
> This makes it possible to avoid relying on locking a partially
> initialized object.
> 
> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> ---
>  drivers/devfreq/devfreq.c | 43 +++++++++++++++++++++++----------------
>  1 file changed, 25 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 12c4bcdc1f17..dbc6dc882aba 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -588,10 +588,12 @@ static void devfreq_dev_release(struct device *dev)
>  	mutex_unlock(&devfreq_list_lock);
>  
>  	if (devfreq->profile->exit)
>  		devfreq->profile->exit(devfreq->dev.parent);
>  
> +	kfree(devfreq->time_in_state);
> +	kfree(devfreq->trans_table);
>  	mutex_destroy(&devfreq->lock);
>  	kfree(devfreq);
>  }
>  
>  /**
> @@ -671,44 +673,43 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  	devfreq->max_freq = devfreq->scaling_max_freq;
>  
>  	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
>  	atomic_set(&devfreq->suspend_count, 0);
>  
> -	dev_set_name(&devfreq->dev, "devfreq%d",
> -				atomic_inc_return(&devfreq_no));
> -	err = device_register(&devfreq->dev);
> -	if (err) {
> -		mutex_unlock(&devfreq->lock);
> -		put_device(&devfreq->dev);
> -		goto err_out;
> -	}
> -
> -	devfreq->trans_table = devm_kzalloc(&devfreq->dev,
> +	devfreq->trans_table = kzalloc(
>  			array3_size(sizeof(unsigned int),
>  				    devfreq->profile->max_state,
>  				    devfreq->profile->max_state),
>  			GFP_KERNEL);
>  	if (!devfreq->trans_table) {
>  		mutex_unlock(&devfreq->lock);
>  		err = -ENOMEM;
> -		goto err_devfreq;
> +		goto err_dev;
>  	}
>  
> -	devfreq->time_in_state = devm_kcalloc(&devfreq->dev,
> -			devfreq->profile->max_state,
> -			sizeof(unsigned long),
> -			GFP_KERNEL);
> +	devfreq->time_in_state = kcalloc(devfreq->profile->max_state,
> +					 sizeof(unsigned long),
> +					 GFP_KERNEL);
>  	if (!devfreq->time_in_state) {
>  		mutex_unlock(&devfreq->lock);
>  		err = -ENOMEM;
> -		goto err_devfreq;
> +		goto err_dev;
>  	}
>  
>  	devfreq->last_stat_updated = jiffies;
>  
>  	srcu_init_notifier_head(&devfreq->transition_notifier_list);
>  
> +	dev_set_name(&devfreq->dev, "devfreq%d",
> +				atomic_inc_return(&devfreq_no));
> +	err = device_register(&devfreq->dev);
> +	if (err) {
> +		mutex_unlock(&devfreq->lock);
> +		put_device(&devfreq->dev);
> +		goto err_out;
> +	}
> +
>  	mutex_unlock(&devfreq->lock);
>  
>  	mutex_lock(&devfreq_list_lock);
>  
>  	governor = try_then_request_governor(devfreq->governor_name);
> @@ -734,14 +735,20 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  
>  	return devfreq;
>  
>  err_init:
>  	mutex_unlock(&devfreq_list_lock);
> -err_devfreq:
>  	devfreq_remove_device(devfreq);
> -	devfreq = NULL;
> +	return ERR_PTR(err);
> +
>  err_dev:
> +	/*
> +	 * Cleanup path for errors that happen before registration.
> +	 * Otherwise we rely on devfreq_dev_release.
> +	 */
> +	kfree(devfreq->time_in_state);
> +	kfree(devfreq->trans_table);
>  	kfree(devfreq);
>  err_out:
>  	return ERR_PTR(err);
>  }
>  EXPORT_SYMBOL(devfreq_add_device);
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* RE: [PATCH v8 2/6] PM / devfreq: Move more initialization before registration
       [not found]   ` <CGME20190924101139epcas1p4c6799a5de9bdb4e90abb74de1e881388@epcms1p4>
@ 2019-09-25  1:58       ` MyungJoo Ham
  0 siblings, 0 replies; 82+ messages in thread
From: MyungJoo Ham @ 2019-09-25  1:58 UTC (permalink / raw)
  To: Leonard Crestez, Kyungmin Park, Matthias Kaehlcke
  Cc: Chanwoo Choi, Artur Swigon, Saravana Kannan, Krzysztof Kozlowski,
	Alexandre Bailon, Georgi Djakov, Abel Vesa, Jacky Bai,
	Viresh Kumar, Lukasz Luba, NXP Linux Team, linux-pm,
	linux-arm-kernel

>In general it is a better to initialize an object before making it
>accessible externally (through device_register).
>
>This makes it possible to avoid relying on locking a partially
>initialized object.
>
>Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>Reviewed-by: Matthias Kaehlcke <mka@chromium.org>

Do you object to the general idea of devm_* for device drivers?
or did you find a bug in the memory handling in the code?

The result of this commit still relies on locking anyway.


Cheers,
MyungJoo.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* RE: [PATCH v8 2/6] PM / devfreq: Move more initialization before registration
@ 2019-09-25  1:58       ` MyungJoo Ham
  0 siblings, 0 replies; 82+ messages in thread
From: MyungJoo Ham @ 2019-09-25  1:58 UTC (permalink / raw)
  To: Leonard Crestez, Kyungmin Park, Matthias Kaehlcke
  Cc: Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, Artur Swigon,
	Krzysztof Kozlowski, Lukasz Luba, Chanwoo Choi, Alexandre Bailon,
	NXP Linux Team, Georgi Djakov, linux-arm-kernel, Jacky Bai

>In general it is a better to initialize an object before making it
>accessible externally (through device_register).
>
>This makes it possible to avoid relying on locking a partially
>initialized object.
>
>Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>Reviewed-by: Matthias Kaehlcke <mka@chromium.org>

Do you object to the general idea of devm_* for device drivers?
or did you find a bug in the memory handling in the code?

The result of this commit still relies on locking anyway.


Cheers,
MyungJoo.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-24 10:11     ` Leonard Crestez
@ 2019-09-25  2:15       ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-25  2:15 UTC (permalink / raw)
  To: Leonard Crestez, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> Register notifiers with the PM QoS framework in order to respond to
> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
> 
> No notifiers are added by this patch but PM QoS constraints can be
> imposed externally (for example from other devices).
> 
> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> ---
>  drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>  include/linux/devfreq.h   |  5 +++
>  2 files changed, 80 insertions(+)
> 
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index eee403e70c84..784f3e40536a 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -22,15 +22,18 @@
>  #include <linux/platform_device.h>
>  #include <linux/list.h>
>  #include <linux/printk.h>
>  #include <linux/hrtimer.h>
>  #include <linux/of.h>
> +#include <linux/pm_qos.h>
>  #include "governor.h"
>  
>  #define CREATE_TRACE_POINTS
>  #include <trace/events/devfreq.h>
>  
> +#define HZ_PER_KHZ	1000
> +
>  static struct class *devfreq_class;
>  
>  /*
>   * devfreq core provides delayed work based load monitoring helper
>   * functions. Governors can use these or can implement their own
> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>  static void get_freq_range(struct devfreq *devfreq,
>  			   unsigned long *min_freq,
>  			   unsigned long *max_freq)
>  {
>  	unsigned long *freq_table = devfreq->profile->freq_table;
> +	unsigned long qos_min_freq, qos_max_freq;
>  
>  	lockdep_assert_held(&devfreq->lock);
>  
>  	/*
>  	 * Init min/max frequency from freq table.
> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>  	} else {
>  		*min_freq = freq_table[devfreq->profile->max_state - 1];
>  		*max_freq = freq_table[0];
>  	}
>  
> +	/* constraints from PM QoS */

As I commented on patch4,
'constraints' -> 'Constraint' because first verb have to be used
as the sigular verbs.

I prefer to use following comments: 

	/* Constraint minimum/maximum frequency from PM QoS constraints */

> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> +					     DEV_PM_QOS_MIN_FREQUENCY);
> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> +					     DEV_PM_QOS_MIN_FREQUENCY);
> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
> +
>  	/* constraints from sysfs */
>  	*min_freq = max(*min_freq, devfreq->min_freq);
>  	*max_freq = min(*max_freq, devfreq->max_freq);
>  
>  	/* constraints from OPP interface */
> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>  	mutex_unlock(&devfreq->lock);
>  
>  	return ret;
>  }
>  
> +/**
> + * qos_notifier_call() - Common handler for QoS constraints.
> + * @devfreq:    the devfreq instance.
> + */
> +static int qos_notifier_call(struct devfreq *devfreq)
> +{
> +	int err;
> +
> +	mutex_lock(&devfreq->lock);
> +	err = update_devfreq(devfreq);
> +	mutex_unlock(&devfreq->lock);
> +	if (err)
> +		dev_err(devfreq->dev.parent,
> +				"failed to update frequency for PM QoS constraints (%d)\n",

Is it not over 80 char?

> +				err);
> +
> +	return NOTIFY_OK;
> +}
> +
> +/**
> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
> + * @nb:		Should be devfreq->nb_min
> + */
> +static int qos_min_notifier_call(struct notifier_block *nb,
> +					 unsigned long val, void *ptr)
> +{
> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
> +}
> +
> +/**
> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
> + * @nb:		Should be devfreq->nb_max
> + */
> +static int qos_max_notifier_call(struct notifier_block *nb,
> +					 unsigned long val, void *ptr)
> +{
> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
> +}
> +
>  /**
>   * devfreq_dev_release() - Callback for struct device to release the device.
>   * @dev:	the devfreq device
>   *
>   * Remove devfreq from the list and release its resources.
> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>  
>  	mutex_lock(&devfreq_list_lock);
>  	list_del(&devfreq->node);
>  	mutex_unlock(&devfreq_list_lock);
>  
> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
> +			DEV_PM_QOS_MAX_FREQUENCY);
> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
> +			DEV_PM_QOS_MIN_FREQUENCY);
> +

Just print error with dev_err() without stopping the release step.

I prefer to handle the return value if kernel API provides
the error code.

>  	if (devfreq->profile->exit)
>  		devfreq->profile->exit(devfreq->dev.parent);
>  
>  	kfree(devfreq->time_in_state);
>  	kfree(devfreq->trans_table);
> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  	if (err) {
>  		put_device(&devfreq->dev);
>  		goto err_out;
>  	}
>  
> +	/*
> +	 * Register notifiers for updates to min/max_freq after device is
> +	 * initialized (and we can handle notifications) but before the
> +	 * governor is started (which should do an initial enforcement of
> +	 * constraints).
> +	 */

My previous comment is not enough why I prefer to remove it. Sorry.
Actually, until now, the devfreq_add_device() don't have the detailed
comments because the line code is not too long. But, at the present time,
devfreq_add_device() is too long. It means that the detailed comment
are necessary. 

So, I'll add the detailed comment for each step of devfreq_add_device()
on separate patch to keep the same style. I'll send the patch to you
for the review.

> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
> +				      DEV_PM_QOS_MIN_FREQUENCY);
> +	if (err)
> +		goto err_devfreq;
> +
> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
> +				      DEV_PM_QOS_MAX_FREQUENCY);
> +	if (err)
> +		goto err_devfreq;
> +
>  	mutex_lock(&devfreq_list_lock);
>  
>  	governor = try_then_request_governor(devfreq->governor_name);
>  	if (IS_ERR(governor)) {
>  		dev_err(dev, "%s: Unable to find governor for the device\n",
> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  
>  	return devfreq;
>  
>  err_init:
>  	mutex_unlock(&devfreq_list_lock);
> +err_devfreq:
>  	devfreq_remove_device(devfreq);
>  	return ERR_PTR(err);
>  
>  err_dev:
>  	/*
> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> index c3cbc15fdf08..dac0dffeabb4 100644
> --- a/include/linux/devfreq.h
> +++ b/include/linux/devfreq.h
> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>   * @total_trans:	Number of devfreq transitions
>   * @trans_table:	Statistics of devfreq transitions
>   * @time_in_state:	Statistics of devfreq states
>   * @last_stat_updated:	The last time stat updated
>   * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>   *
>   * This structure stores the devfreq information for a give device.
>   *
>   * Note that when a governor accesses entries in struct devfreq in its
>   * functions except for the context of callbacks defined in struct
> @@ -176,10 +178,13 @@ struct devfreq {
>  	unsigned int *trans_table;
>  	unsigned long *time_in_state;
>  	unsigned long last_stat_updated;
>  
>  	struct srcu_notifier_head transition_notifier_list;
> +
> +	struct notifier_block nb_min;
> +	struct notifier_block nb_max;
>  };
>  
>  struct devfreq_freqs {
>  	unsigned long old;
>  	unsigned long new;
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-25  2:15       ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-25  2:15 UTC (permalink / raw)
  To: Leonard Crestez, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> Register notifiers with the PM QoS framework in order to respond to
> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
> 
> No notifiers are added by this patch but PM QoS constraints can be
> imposed externally (for example from other devices).
> 
> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> ---
>  drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>  include/linux/devfreq.h   |  5 +++
>  2 files changed, 80 insertions(+)
> 
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index eee403e70c84..784f3e40536a 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -22,15 +22,18 @@
>  #include <linux/platform_device.h>
>  #include <linux/list.h>
>  #include <linux/printk.h>
>  #include <linux/hrtimer.h>
>  #include <linux/of.h>
> +#include <linux/pm_qos.h>
>  #include "governor.h"
>  
>  #define CREATE_TRACE_POINTS
>  #include <trace/events/devfreq.h>
>  
> +#define HZ_PER_KHZ	1000
> +
>  static struct class *devfreq_class;
>  
>  /*
>   * devfreq core provides delayed work based load monitoring helper
>   * functions. Governors can use these or can implement their own
> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>  static void get_freq_range(struct devfreq *devfreq,
>  			   unsigned long *min_freq,
>  			   unsigned long *max_freq)
>  {
>  	unsigned long *freq_table = devfreq->profile->freq_table;
> +	unsigned long qos_min_freq, qos_max_freq;
>  
>  	lockdep_assert_held(&devfreq->lock);
>  
>  	/*
>  	 * Init min/max frequency from freq table.
> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>  	} else {
>  		*min_freq = freq_table[devfreq->profile->max_state - 1];
>  		*max_freq = freq_table[0];
>  	}
>  
> +	/* constraints from PM QoS */

As I commented on patch4,
'constraints' -> 'Constraint' because first verb have to be used
as the sigular verbs.

I prefer to use following comments: 

	/* Constraint minimum/maximum frequency from PM QoS constraints */

> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> +					     DEV_PM_QOS_MIN_FREQUENCY);
> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> +					     DEV_PM_QOS_MIN_FREQUENCY);
> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
> +
>  	/* constraints from sysfs */
>  	*min_freq = max(*min_freq, devfreq->min_freq);
>  	*max_freq = min(*max_freq, devfreq->max_freq);
>  
>  	/* constraints from OPP interface */
> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>  	mutex_unlock(&devfreq->lock);
>  
>  	return ret;
>  }
>  
> +/**
> + * qos_notifier_call() - Common handler for QoS constraints.
> + * @devfreq:    the devfreq instance.
> + */
> +static int qos_notifier_call(struct devfreq *devfreq)
> +{
> +	int err;
> +
> +	mutex_lock(&devfreq->lock);
> +	err = update_devfreq(devfreq);
> +	mutex_unlock(&devfreq->lock);
> +	if (err)
> +		dev_err(devfreq->dev.parent,
> +				"failed to update frequency for PM QoS constraints (%d)\n",

Is it not over 80 char?

> +				err);
> +
> +	return NOTIFY_OK;
> +}
> +
> +/**
> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
> + * @nb:		Should be devfreq->nb_min
> + */
> +static int qos_min_notifier_call(struct notifier_block *nb,
> +					 unsigned long val, void *ptr)
> +{
> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
> +}
> +
> +/**
> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
> + * @nb:		Should be devfreq->nb_max
> + */
> +static int qos_max_notifier_call(struct notifier_block *nb,
> +					 unsigned long val, void *ptr)
> +{
> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
> +}
> +
>  /**
>   * devfreq_dev_release() - Callback for struct device to release the device.
>   * @dev:	the devfreq device
>   *
>   * Remove devfreq from the list and release its resources.
> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>  
>  	mutex_lock(&devfreq_list_lock);
>  	list_del(&devfreq->node);
>  	mutex_unlock(&devfreq_list_lock);
>  
> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
> +			DEV_PM_QOS_MAX_FREQUENCY);
> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
> +			DEV_PM_QOS_MIN_FREQUENCY);
> +

Just print error with dev_err() without stopping the release step.

I prefer to handle the return value if kernel API provides
the error code.

>  	if (devfreq->profile->exit)
>  		devfreq->profile->exit(devfreq->dev.parent);
>  
>  	kfree(devfreq->time_in_state);
>  	kfree(devfreq->trans_table);
> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  	if (err) {
>  		put_device(&devfreq->dev);
>  		goto err_out;
>  	}
>  
> +	/*
> +	 * Register notifiers for updates to min/max_freq after device is
> +	 * initialized (and we can handle notifications) but before the
> +	 * governor is started (which should do an initial enforcement of
> +	 * constraints).
> +	 */

My previous comment is not enough why I prefer to remove it. Sorry.
Actually, until now, the devfreq_add_device() don't have the detailed
comments because the line code is not too long. But, at the present time,
devfreq_add_device() is too long. It means that the detailed comment
are necessary. 

So, I'll add the detailed comment for each step of devfreq_add_device()
on separate patch to keep the same style. I'll send the patch to you
for the review.

> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
> +				      DEV_PM_QOS_MIN_FREQUENCY);
> +	if (err)
> +		goto err_devfreq;
> +
> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
> +				      DEV_PM_QOS_MAX_FREQUENCY);
> +	if (err)
> +		goto err_devfreq;
> +
>  	mutex_lock(&devfreq_list_lock);
>  
>  	governor = try_then_request_governor(devfreq->governor_name);
>  	if (IS_ERR(governor)) {
>  		dev_err(dev, "%s: Unable to find governor for the device\n",
> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  
>  	return devfreq;
>  
>  err_init:
>  	mutex_unlock(&devfreq_list_lock);
> +err_devfreq:
>  	devfreq_remove_device(devfreq);
>  	return ERR_PTR(err);
>  
>  err_dev:
>  	/*
> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> index c3cbc15fdf08..dac0dffeabb4 100644
> --- a/include/linux/devfreq.h
> +++ b/include/linux/devfreq.h
> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>   * @total_trans:	Number of devfreq transitions
>   * @trans_table:	Statistics of devfreq transitions
>   * @time_in_state:	Statistics of devfreq states
>   * @last_stat_updated:	The last time stat updated
>   * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>   *
>   * This structure stores the devfreq information for a give device.
>   *
>   * Note that when a governor accesses entries in struct devfreq in its
>   * functions except for the context of callbacks defined in struct
> @@ -176,10 +178,13 @@ struct devfreq {
>  	unsigned int *trans_table;
>  	unsigned long *time_in_state;
>  	unsigned long last_stat_updated;
>  
>  	struct srcu_notifier_head transition_notifier_list;
> +
> +	struct notifier_block nb_min;
> +	struct notifier_block nb_max;
>  };
>  
>  struct devfreq_freqs {
>  	unsigned long old;
>  	unsigned long new;
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-24 19:22         ` Leonard Crestez
@ 2019-09-25  2:17           ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-25  2:17 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 19. 9. 25. 오전 4:22, Leonard Crestez wrote:
> On 24.09.2019 22:11, Matthias Kaehlcke wrote:
>> On Tue, Sep 24, 2019 at 01:11:29PM +0300, Leonard Crestez wrote:
>>> Register notifiers with the PM QoS framework in order to respond to
>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>
>>> No notifiers are added by this patch but PM QoS constraints can be
>>> imposed externally (for example from other devices).
>>>
>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>> ---
>>>   drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>   include/linux/devfreq.h   |  5 +++
>>>   2 files changed, 80 insertions(+)
>>>
>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>> index eee403e70c84..784f3e40536a 100644
>>> --- a/drivers/devfreq/devfreq.c
>>> +++ b/drivers/devfreq/devfreq.c
>>> @@ -22,15 +22,18 @@
>>>   #include <linux/platform_device.h>
>>>   #include <linux/list.h>
>>>   #include <linux/printk.h>
>>>   #include <linux/hrtimer.h>
>>>   #include <linux/of.h>
>>> +#include <linux/pm_qos.h>
>>>   #include "governor.h"
>>>   
>>>   #define CREATE_TRACE_POINTS
>>>   #include <trace/events/devfreq.h>
>>>   
>>> +#define HZ_PER_KHZ	1000
>>> +
>>>   static struct class *devfreq_class;
>>>   
>>>   /*
>>>    * devfreq core provides delayed work based load monitoring helper
>>>    * functions. Governors can use these or can implement their own
>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>   static void get_freq_range(struct devfreq *devfreq,
>>>   			   unsigned long *min_freq,
>>>   			   unsigned long *max_freq)
>>>   {
>>>   	unsigned long *freq_table = devfreq->profile->freq_table;
>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>   
>>>   	lockdep_assert_held(&devfreq->lock);
>>>   
>>>   	/*
>>>   	 * Init min/max frequency from freq table.
>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>   	} else {
>>>   		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>   		*max_freq = freq_table[0];
>>>   	}
>>>   
>>> +	/* constraints from PM QoS */
>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>> +					     DEV_PM_QOS_MIN_FREQUENCY); >
>> This needs to be DEV_PM_QOS_MAX_FREQUENCY. I missed this in the earlier
>> reviews, but stumbled across it when testing.
>>
>> !Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> 
> I broke it in v8 while processing comments. Thanks for catching it.

Did you test this patchset with v8?
Maybe it is not working with this mistake.

> 
> --
> Regards,
> Leonard
> 
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-25  2:17           ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-25  2:17 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 19. 9. 25. 오전 4:22, Leonard Crestez wrote:
> On 24.09.2019 22:11, Matthias Kaehlcke wrote:
>> On Tue, Sep 24, 2019 at 01:11:29PM +0300, Leonard Crestez wrote:
>>> Register notifiers with the PM QoS framework in order to respond to
>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>
>>> No notifiers are added by this patch but PM QoS constraints can be
>>> imposed externally (for example from other devices).
>>>
>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>> ---
>>>   drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>   include/linux/devfreq.h   |  5 +++
>>>   2 files changed, 80 insertions(+)
>>>
>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>> index eee403e70c84..784f3e40536a 100644
>>> --- a/drivers/devfreq/devfreq.c
>>> +++ b/drivers/devfreq/devfreq.c
>>> @@ -22,15 +22,18 @@
>>>   #include <linux/platform_device.h>
>>>   #include <linux/list.h>
>>>   #include <linux/printk.h>
>>>   #include <linux/hrtimer.h>
>>>   #include <linux/of.h>
>>> +#include <linux/pm_qos.h>
>>>   #include "governor.h"
>>>   
>>>   #define CREATE_TRACE_POINTS
>>>   #include <trace/events/devfreq.h>
>>>   
>>> +#define HZ_PER_KHZ	1000
>>> +
>>>   static struct class *devfreq_class;
>>>   
>>>   /*
>>>    * devfreq core provides delayed work based load monitoring helper
>>>    * functions. Governors can use these or can implement their own
>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>   static void get_freq_range(struct devfreq *devfreq,
>>>   			   unsigned long *min_freq,
>>>   			   unsigned long *max_freq)
>>>   {
>>>   	unsigned long *freq_table = devfreq->profile->freq_table;
>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>   
>>>   	lockdep_assert_held(&devfreq->lock);
>>>   
>>>   	/*
>>>   	 * Init min/max frequency from freq table.
>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>   	} else {
>>>   		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>   		*max_freq = freq_table[0];
>>>   	}
>>>   
>>> +	/* constraints from PM QoS */
>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>> +					     DEV_PM_QOS_MIN_FREQUENCY); >
>> This needs to be DEV_PM_QOS_MAX_FREQUENCY. I missed this in the earlier
>> reviews, but stumbled across it when testing.
>>
>> !Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> 
> I broke it in v8 while processing comments. Thanks for catching it.

Did you test this patchset with v8?
Maybe it is not working with this mistake.

> 
> --
> Regards,
> Leonard
> 
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
  2019-09-24 10:11     ` Leonard Crestez
@ 2019-09-25  2:41       ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-25  2:41 UTC (permalink / raw)
  To: Leonard Crestez, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> Switch the handling of min_freq and max_freq from sysfs to use the
> dev_pm_qos_request interface.
> 
> Since PM QoS handles frequencies as kHz this change reduces the
> precision of min_freq and max_freq. This shouldn't introduce problems
> because frequencies which are not an integer number of kHz are likely
> not an integer number of Hz either.
> 
> Try to ensure compatibility by rounding min values down and rounding
> max values up.
> 
> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> ---
>  drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
>  include/linux/devfreq.h   |  9 ++++----
>  2 files changed, 33 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 784f3e40536a..8bb7efd821ab 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
>  	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>  					     DEV_PM_QOS_MIN_FREQUENCY);
>  	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>  	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>  
> -	/* constraints from sysfs */
> -	*min_freq = max(*min_freq, devfreq->min_freq);
> -	*max_freq = min(*max_freq, devfreq->max_freq);
> -
>  	/* constraints from OPP interface */
>  	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>  	/* scaling_max_freq can be zero on error */
>  	if (devfreq->scaling_max_freq)
>  		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
> @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
>  			DEV_PM_QOS_MIN_FREQUENCY);
>  
>  	if (devfreq->profile->exit)
>  		devfreq->profile->exit(devfreq->dev.parent);
>  
> +	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
> +	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);

Please check the return value if error happen, just print the err with dev_err()
without stopping the release steps.

>  	kfree(devfreq->time_in_state);
>  	kfree(devfreq->trans_table);
>  	mutex_destroy(&devfreq->lock);
>  	kfree(devfreq);
>  }
> @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
>  	if (!devfreq->scaling_min_freq) {
>  		err = -EINVAL;
>  		goto err_dev;
>  	}
> -	devfreq->min_freq = devfreq->scaling_min_freq;
>  
>  	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
>  	if (!devfreq->scaling_max_freq) {
>  		err = -EINVAL;
>  		goto err_dev;
>  	}
> -	devfreq->max_freq = devfreq->scaling_max_freq;
> +
> +	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
> +				     DEV_PM_QOS_MIN_FREQUENCY, 0);
> +	if (err < 0)
> +		goto err_dev;
> +	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
> +				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
> +	if (err < 0)
> +		goto err_dev;
>  
>  	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
>  	atomic_set(&devfreq->suspend_count, 0);
>  
>  	devfreq->trans_table = kzalloc(
> @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  err_dev:
>  	/*
>  	 * Cleanup path for errors that happen before registration.
>  	 * Otherwise we rely on devfreq_dev_release.
>  	 */
> +	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
> +		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);

Please check the return value if error happen, just print the err with dev_err()
without stopping the release steps.

	dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");

> +	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
> +		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
	
	dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");

>  	kfree(devfreq->time_in_state);
>  	kfree(devfreq->trans_table);
>  	kfree(devfreq);
>  err_out:
>  	return ERR_PTR(err);
> @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>  
>  	ret = sscanf(buf, "%lu", &value);
>  	if (ret != 1)
>  		return -EINVAL;
>  
> -	mutex_lock(&df->lock);
> -	df->min_freq = value;
> -	update_devfreq(df);
> -	mutex_unlock(&df->lock);
> +	/* round down to kHz for PM QoS */

I prefer more detailed description as following:

	/*                                                                                                      
	 * Round down to KHz to decide the proper minimum frequency                                          
	 * which is closed to user request.
 	 */


> +	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
> +					value / HZ_PER_KHZ);
> +	if (ret < 0)
> +		return ret;
>  
>  	return count;
>  }
>  
>  static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
> @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>  
>  	ret = sscanf(buf, "%lu", &value);
>  	if (ret != 1)
>  		return -EINVAL;
>  
> -	mutex_lock(&df->lock);
> -
> -	/* Interpret zero as "don't care" */
> -	if (!value)
> -		value = ULONG_MAX;
> +	/* round up to kHz for PM QoS and interpret zero as "don't care" */

I think that "don't care" comment style is not good.

I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
I prefer more detailed description as following:
	/*                                                                                                      
	 * Round up to KHz to decide the proper maximum frequency                                          
	 * which is closed to user request. If value is zero,                                                   
	 * the user does not care.                                                                              
 	 */


> +	if (value)
> +		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
> +	else
> +		value = S32_MAX;
>  
> -	df->max_freq = value;
> -	update_devfreq(df);
> -	mutex_unlock(&df->lock);
> +	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
> +	if (ret < 0)
> +		return ret;
>  
>  	return count;
>  }
>  static DEVICE_ATTR_RW(min_freq);
>  
> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> index dac0dffeabb4..7849fe4c666d 100644
> --- a/include/linux/devfreq.h
> +++ b/include/linux/devfreq.h
> @@ -11,10 +11,11 @@
>  #define __LINUX_DEVFREQ_H__
>  
>  #include <linux/device.h>
>  #include <linux/notifier.h>
>  #include <linux/pm_opp.h>
> +#include <linux/pm_qos.h>
>  
>  #define DEVFREQ_NAME_LEN 16
>  
>  /* DEVFREQ governor name */
>  #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
> @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
>   *		devfreq.nb to the corresponding register notifier call chain.
>   * @work:	delayed work for load monitoring.
>   * @previous_freq:	previously configured frequency value.
>   * @data:	Private data of the governor. The devfreq framework does not
>   *		touch this.
> - * @min_freq:	Limit minimum frequency requested by user (0: none)
> - * @max_freq:	Limit maximum frequency requested by user (0: none)
> + * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)

min -> minimum and then remove parenthesis as following:
	PM QoS minimum frequency request by user via sysfs

> + * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)

ditto. max -> maximum
	PM QoS maximum frequency request by user via sysfs

>   * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
>   * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
>   * @stop_polling:	 devfreq polling status of a device.
>   * @suspend_freq:	 frequency of a device set during suspend phase.
>   * @resume_freq:	 frequency of a device set in resume phase.
> @@ -161,12 +162,12 @@ struct devfreq {
>  	unsigned long previous_freq;
>  	struct devfreq_dev_status last_status;
>  
>  	void *data; /* private data for governors */
>  
> -	unsigned long min_freq;
> -	unsigned long max_freq;
> +	struct dev_pm_qos_request user_min_freq_req;
> +	struct dev_pm_qos_request user_max_freq_req;
>  	unsigned long scaling_min_freq;
>  	unsigned long scaling_max_freq;
>  	bool stop_polling;
>  
>  	unsigned long suspend_freq;
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
@ 2019-09-25  2:41       ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-25  2:41 UTC (permalink / raw)
  To: Leonard Crestez, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> Switch the handling of min_freq and max_freq from sysfs to use the
> dev_pm_qos_request interface.
> 
> Since PM QoS handles frequencies as kHz this change reduces the
> precision of min_freq and max_freq. This shouldn't introduce problems
> because frequencies which are not an integer number of kHz are likely
> not an integer number of Hz either.
> 
> Try to ensure compatibility by rounding min values down and rounding
> max values up.
> 
> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> ---
>  drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
>  include/linux/devfreq.h   |  9 ++++----
>  2 files changed, 33 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 784f3e40536a..8bb7efd821ab 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
>  	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>  					     DEV_PM_QOS_MIN_FREQUENCY);
>  	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>  	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>  
> -	/* constraints from sysfs */
> -	*min_freq = max(*min_freq, devfreq->min_freq);
> -	*max_freq = min(*max_freq, devfreq->max_freq);
> -
>  	/* constraints from OPP interface */
>  	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>  	/* scaling_max_freq can be zero on error */
>  	if (devfreq->scaling_max_freq)
>  		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
> @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
>  			DEV_PM_QOS_MIN_FREQUENCY);
>  
>  	if (devfreq->profile->exit)
>  		devfreq->profile->exit(devfreq->dev.parent);
>  
> +	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
> +	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);

Please check the return value if error happen, just print the err with dev_err()
without stopping the release steps.

>  	kfree(devfreq->time_in_state);
>  	kfree(devfreq->trans_table);
>  	mutex_destroy(&devfreq->lock);
>  	kfree(devfreq);
>  }
> @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
>  	if (!devfreq->scaling_min_freq) {
>  		err = -EINVAL;
>  		goto err_dev;
>  	}
> -	devfreq->min_freq = devfreq->scaling_min_freq;
>  
>  	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
>  	if (!devfreq->scaling_max_freq) {
>  		err = -EINVAL;
>  		goto err_dev;
>  	}
> -	devfreq->max_freq = devfreq->scaling_max_freq;
> +
> +	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
> +				     DEV_PM_QOS_MIN_FREQUENCY, 0);
> +	if (err < 0)
> +		goto err_dev;
> +	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
> +				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
> +	if (err < 0)
> +		goto err_dev;
>  
>  	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
>  	atomic_set(&devfreq->suspend_count, 0);
>  
>  	devfreq->trans_table = kzalloc(
> @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
>  err_dev:
>  	/*
>  	 * Cleanup path for errors that happen before registration.
>  	 * Otherwise we rely on devfreq_dev_release.
>  	 */
> +	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
> +		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);

Please check the return value if error happen, just print the err with dev_err()
without stopping the release steps.

	dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");

> +	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
> +		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
	
	dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");

>  	kfree(devfreq->time_in_state);
>  	kfree(devfreq->trans_table);
>  	kfree(devfreq);
>  err_out:
>  	return ERR_PTR(err);
> @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>  
>  	ret = sscanf(buf, "%lu", &value);
>  	if (ret != 1)
>  		return -EINVAL;
>  
> -	mutex_lock(&df->lock);
> -	df->min_freq = value;
> -	update_devfreq(df);
> -	mutex_unlock(&df->lock);
> +	/* round down to kHz for PM QoS */

I prefer more detailed description as following:

	/*                                                                                                      
	 * Round down to KHz to decide the proper minimum frequency                                          
	 * which is closed to user request.
 	 */


> +	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
> +					value / HZ_PER_KHZ);
> +	if (ret < 0)
> +		return ret;
>  
>  	return count;
>  }
>  
>  static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
> @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>  
>  	ret = sscanf(buf, "%lu", &value);
>  	if (ret != 1)
>  		return -EINVAL;
>  
> -	mutex_lock(&df->lock);
> -
> -	/* Interpret zero as "don't care" */
> -	if (!value)
> -		value = ULONG_MAX;
> +	/* round up to kHz for PM QoS and interpret zero as "don't care" */

I think that "don't care" comment style is not good.

I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
I prefer more detailed description as following:
	/*                                                                                                      
	 * Round up to KHz to decide the proper maximum frequency                                          
	 * which is closed to user request. If value is zero,                                                   
	 * the user does not care.                                                                              
 	 */


> +	if (value)
> +		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
> +	else
> +		value = S32_MAX;
>  
> -	df->max_freq = value;
> -	update_devfreq(df);
> -	mutex_unlock(&df->lock);
> +	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
> +	if (ret < 0)
> +		return ret;
>  
>  	return count;
>  }
>  static DEVICE_ATTR_RW(min_freq);
>  
> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> index dac0dffeabb4..7849fe4c666d 100644
> --- a/include/linux/devfreq.h
> +++ b/include/linux/devfreq.h
> @@ -11,10 +11,11 @@
>  #define __LINUX_DEVFREQ_H__
>  
>  #include <linux/device.h>
>  #include <linux/notifier.h>
>  #include <linux/pm_opp.h>
> +#include <linux/pm_qos.h>
>  
>  #define DEVFREQ_NAME_LEN 16
>  
>  /* DEVFREQ governor name */
>  #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
> @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
>   *		devfreq.nb to the corresponding register notifier call chain.
>   * @work:	delayed work for load monitoring.
>   * @previous_freq:	previously configured frequency value.
>   * @data:	Private data of the governor. The devfreq framework does not
>   *		touch this.
> - * @min_freq:	Limit minimum frequency requested by user (0: none)
> - * @max_freq:	Limit maximum frequency requested by user (0: none)
> + * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)

min -> minimum and then remove parenthesis as following:
	PM QoS minimum frequency request by user via sysfs

> + * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)

ditto. max -> maximum
	PM QoS maximum frequency request by user via sysfs

>   * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
>   * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
>   * @stop_polling:	 devfreq polling status of a device.
>   * @suspend_freq:	 frequency of a device set during suspend phase.
>   * @resume_freq:	 frequency of a device set in resume phase.
> @@ -161,12 +162,12 @@ struct devfreq {
>  	unsigned long previous_freq;
>  	struct devfreq_dev_status last_status;
>  
>  	void *data; /* private data for governors */
>  
> -	unsigned long min_freq;
> -	unsigned long max_freq;
> +	struct dev_pm_qos_request user_min_freq_req;
> +	struct dev_pm_qos_request user_max_freq_req;
>  	unsigned long scaling_min_freq;
>  	unsigned long scaling_max_freq;
>  	bool stop_polling;
>  
>  	unsigned long suspend_freq;
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-25  2:15       ` Chanwoo Choi
@ 2019-09-25 16:06         ` Matthias Kaehlcke
  -1 siblings, 0 replies; 82+ messages in thread
From: Matthias Kaehlcke @ 2019-09-25 16:06 UTC (permalink / raw)
  To: Chanwoo Choi
  Cc: Leonard Crestez, MyungJoo Ham, Kyungmin Park,
	Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

On Wed, Sep 25, 2019 at 11:15:36AM +0900, Chanwoo Choi wrote:
> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> > Register notifiers with the PM QoS framework in order to respond to
> > requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
> > 
> > No notifiers are added by this patch but PM QoS constraints can be
> > imposed externally (for example from other devices).
> > 
> > Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> > Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> > ---
> >  drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
> >  include/linux/devfreq.h   |  5 +++
> >  2 files changed, 80 insertions(+)
> > 
> > diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> > index eee403e70c84..784f3e40536a 100644
> > --- a/drivers/devfreq/devfreq.c
> > +++ b/drivers/devfreq/devfreq.c
> > @@ -22,15 +22,18 @@
> >  #include <linux/platform_device.h>
> >  #include <linux/list.h>
> >  #include <linux/printk.h>
> >  #include <linux/hrtimer.h>
> >  #include <linux/of.h>
> > +#include <linux/pm_qos.h>
> >  #include "governor.h"
> >  
> >  #define CREATE_TRACE_POINTS
> >  #include <trace/events/devfreq.h>
> >  
> > +#define HZ_PER_KHZ	1000
> > +
> >  static struct class *devfreq_class;
> >  
> >  /*
> >   * devfreq core provides delayed work based load monitoring helper
> >   * functions. Governors can use these or can implement their own
> > @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
> >  static void get_freq_range(struct devfreq *devfreq,
> >  			   unsigned long *min_freq,
> >  			   unsigned long *max_freq)
> >  {
> >  	unsigned long *freq_table = devfreq->profile->freq_table;
> > +	unsigned long qos_min_freq, qos_max_freq;
> >  
> >  	lockdep_assert_held(&devfreq->lock);
> >  
> >  	/*
> >  	 * Init min/max frequency from freq table.
> > @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
> >  	} else {
> >  		*min_freq = freq_table[devfreq->profile->max_state - 1];
> >  		*max_freq = freq_table[0];
> >  	}
> >  
> > +	/* constraints from PM QoS */
> 
> As I commented on patch4,
> 'constraints' -> 'Constraint' because first verb have to be used
> as the sigular verbs.

'constraints' is not a verb in this case, but the plural of the noun
constraint

> I prefer to use following comments: 
> 
> 	/* Constraint minimum/maximum frequency from PM QoS constraints */

I'm not convinced that this is really an improvement. First there is the
repeated use of 'Constraint ... constraints'. An improvement could be to use
'Limit' instead of 'Constraint'. Anyway from the code it is pretty obvious
that the min/max frequencies are limited. Are you suggesting to also say
further below "Limit minimum/maximum frequency from sysfs constraints"
and the same for the OPP ones?

If you really want a verb the comments could be something like "Apply
<interface> constraints" or "Apply constraints from <interface>".

IMO the current comments provide enough information, unnecessarily verbose
comments can rather get in the way of code readability.

> > +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> > +					     DEV_PM_QOS_MIN_FREQUENCY);
> > +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> > +					     DEV_PM_QOS_MIN_FREQUENCY);
> > +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
> > +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
> > +
> >  	/* constraints from sysfs */
> >  	*min_freq = max(*min_freq, devfreq->min_freq);
> >  	*max_freq = min(*max_freq, devfreq->max_freq);
> >  
> >  	/* constraints from OPP interface */
> > @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
> >  	mutex_unlock(&devfreq->lock);
> >  
> >  	return ret;
> >  }
> >  
> > +/**
> > + * qos_notifier_call() - Common handler for QoS constraints.
> > + * @devfreq:    the devfreq instance.
> > + */
> > +static int qos_notifier_call(struct devfreq *devfreq)
> > +{
> > +	int err;
> > +
> > +	mutex_lock(&devfreq->lock);
> > +	err = update_devfreq(devfreq);
> > +	mutex_unlock(&devfreq->lock);
> > +	if (err)
> > +		dev_err(devfreq->dev.parent,
> > +				"failed to update frequency for PM QoS constraints (%d)\n",
> 
> Is it not over 80 char?

It is and Leonard split it up initially, however I asked him to not
break it up because:

  2) Breaking long lines and strings

  However, *never* break user-visible strings such as printk messages,
  because that breaks the ability to grep for them.

  Documentation/process/coding-style.rst

Line length could be reduced a bit by adjusting indentation though.

> 
> > +				err);
> > +
> > +	return NOTIFY_OK;
> > +}
> > +
> > +/**
> > + * qos_min_notifier_call() - Callback for QoS min_freq changes.
> > + * @nb:		Should be devfreq->nb_min
> > + */
> > +static int qos_min_notifier_call(struct notifier_block *nb,
> > +					 unsigned long val, void *ptr)
> > +{
> > +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
> > +}
> > +
> > +/**
> > + * qos_max_notifier_call() - Callback for QoS max_freq changes.
> > + * @nb:		Should be devfreq->nb_max
> > + */
> > +static int qos_max_notifier_call(struct notifier_block *nb,
> > +					 unsigned long val, void *ptr)
> > +{
> > +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
> > +}
> > +
> >  /**
> >   * devfreq_dev_release() - Callback for struct device to release the device.
> >   * @dev:	the devfreq device
> >   *
> >   * Remove devfreq from the list and release its resources.
> > @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
> >  
> >  	mutex_lock(&devfreq_list_lock);
> >  	list_del(&devfreq->node);
> >  	mutex_unlock(&devfreq_list_lock);
> >  
> > +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
> > +			DEV_PM_QOS_MAX_FREQUENCY);
> > +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
> > +			DEV_PM_QOS_MIN_FREQUENCY);
> > +
> 
> Just print error with dev_err() without stopping the release step.
> 
> I prefer to handle the return value if kernel API provides
> the error code.
> 
> >  	if (devfreq->profile->exit)
> >  		devfreq->profile->exit(devfreq->dev.parent);
> >  
> >  	kfree(devfreq->time_in_state);
> >  	kfree(devfreq->trans_table);
> > @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
> >  	if (err) {
> >  		put_device(&devfreq->dev);
> >  		goto err_out;
> >  	}
> >  
> > +	/*
> > +	 * Register notifiers for updates to min/max_freq after device is
> > +	 * initialized (and we can handle notifications) but before the
> > +	 * governor is started (which should do an initial enforcement of
> > +	 * constraints).
> > +	 */
> 
> My previous comment is not enough why I prefer to remove it. Sorry.
> Actually, until now, the devfreq_add_device() don't have the detailed
> comments because the line code is not too long. But, at the present time,
> devfreq_add_device() is too long. It means that the detailed comment
> are necessary. 
> 
> So, I'll add the detailed comment for each step of devfreq_add_device()
> on separate patch to keep the same style. I'll send the patch to you
> for the review.
> 
> > +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
> > +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
> > +				      DEV_PM_QOS_MIN_FREQUENCY);
> > +	if (err)
> > +		goto err_devfreq;
> > +
> > +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
> > +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
> > +				      DEV_PM_QOS_MAX_FREQUENCY);
> > +	if (err)
> > +		goto err_devfreq;
> > +
> >  	mutex_lock(&devfreq_list_lock);
> >  
> >  	governor = try_then_request_governor(devfreq->governor_name);
> >  	if (IS_ERR(governor)) {
> >  		dev_err(dev, "%s: Unable to find governor for the device\n",
> > @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
> >  
> >  	return devfreq;
> >  
> >  err_init:
> >  	mutex_unlock(&devfreq_list_lock);
> > +err_devfreq:
> >  	devfreq_remove_device(devfreq);
> >  	return ERR_PTR(err);
> >  
> >  err_dev:
> >  	/*
> > diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> > index c3cbc15fdf08..dac0dffeabb4 100644
> > --- a/include/linux/devfreq.h
> > +++ b/include/linux/devfreq.h
> > @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
> >   * @total_trans:	Number of devfreq transitions
> >   * @trans_table:	Statistics of devfreq transitions
> >   * @time_in_state:	Statistics of devfreq states
> >   * @last_stat_updated:	The last time stat updated
> >   * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
> > + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
> > + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
> >   *
> >   * This structure stores the devfreq information for a give device.
> >   *
> >   * Note that when a governor accesses entries in struct devfreq in its
> >   * functions except for the context of callbacks defined in struct
> > @@ -176,10 +178,13 @@ struct devfreq {
> >  	unsigned int *trans_table;
> >  	unsigned long *time_in_state;
> >  	unsigned long last_stat_updated;
> >  
> >  	struct srcu_notifier_head transition_notifier_list;
> > +
> > +	struct notifier_block nb_min;
> > +	struct notifier_block nb_max;
> >  };
> >  
> >  struct devfreq_freqs {
> >  	unsigned long old;
> >  	unsigned long new;
> > 
> 
> 
> -- 
> Best Regards,
> Chanwoo Choi
> Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-25 16:06         ` Matthias Kaehlcke
  0 siblings, 0 replies; 82+ messages in thread
From: Matthias Kaehlcke @ 2019-09-25 16:06 UTC (permalink / raw)
  To: Chanwoo Choi
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park,
	MyungJoo Ham, Alexandre Bailon, Leonard Crestez, Georgi Djakov,
	linux-arm-kernel, Jacky Bai

On Wed, Sep 25, 2019 at 11:15:36AM +0900, Chanwoo Choi wrote:
> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> > Register notifiers with the PM QoS framework in order to respond to
> > requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
> > 
> > No notifiers are added by this patch but PM QoS constraints can be
> > imposed externally (for example from other devices).
> > 
> > Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> > Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> > ---
> >  drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
> >  include/linux/devfreq.h   |  5 +++
> >  2 files changed, 80 insertions(+)
> > 
> > diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> > index eee403e70c84..784f3e40536a 100644
> > --- a/drivers/devfreq/devfreq.c
> > +++ b/drivers/devfreq/devfreq.c
> > @@ -22,15 +22,18 @@
> >  #include <linux/platform_device.h>
> >  #include <linux/list.h>
> >  #include <linux/printk.h>
> >  #include <linux/hrtimer.h>
> >  #include <linux/of.h>
> > +#include <linux/pm_qos.h>
> >  #include "governor.h"
> >  
> >  #define CREATE_TRACE_POINTS
> >  #include <trace/events/devfreq.h>
> >  
> > +#define HZ_PER_KHZ	1000
> > +
> >  static struct class *devfreq_class;
> >  
> >  /*
> >   * devfreq core provides delayed work based load monitoring helper
> >   * functions. Governors can use these or can implement their own
> > @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
> >  static void get_freq_range(struct devfreq *devfreq,
> >  			   unsigned long *min_freq,
> >  			   unsigned long *max_freq)
> >  {
> >  	unsigned long *freq_table = devfreq->profile->freq_table;
> > +	unsigned long qos_min_freq, qos_max_freq;
> >  
> >  	lockdep_assert_held(&devfreq->lock);
> >  
> >  	/*
> >  	 * Init min/max frequency from freq table.
> > @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
> >  	} else {
> >  		*min_freq = freq_table[devfreq->profile->max_state - 1];
> >  		*max_freq = freq_table[0];
> >  	}
> >  
> > +	/* constraints from PM QoS */
> 
> As I commented on patch4,
> 'constraints' -> 'Constraint' because first verb have to be used
> as the sigular verbs.

'constraints' is not a verb in this case, but the plural of the noun
constraint

> I prefer to use following comments: 
> 
> 	/* Constraint minimum/maximum frequency from PM QoS constraints */

I'm not convinced that this is really an improvement. First there is the
repeated use of 'Constraint ... constraints'. An improvement could be to use
'Limit' instead of 'Constraint'. Anyway from the code it is pretty obvious
that the min/max frequencies are limited. Are you suggesting to also say
further below "Limit minimum/maximum frequency from sysfs constraints"
and the same for the OPP ones?

If you really want a verb the comments could be something like "Apply
<interface> constraints" or "Apply constraints from <interface>".

IMO the current comments provide enough information, unnecessarily verbose
comments can rather get in the way of code readability.

> > +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> > +					     DEV_PM_QOS_MIN_FREQUENCY);
> > +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> > +					     DEV_PM_QOS_MIN_FREQUENCY);
> > +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
> > +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
> > +
> >  	/* constraints from sysfs */
> >  	*min_freq = max(*min_freq, devfreq->min_freq);
> >  	*max_freq = min(*max_freq, devfreq->max_freq);
> >  
> >  	/* constraints from OPP interface */
> > @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
> >  	mutex_unlock(&devfreq->lock);
> >  
> >  	return ret;
> >  }
> >  
> > +/**
> > + * qos_notifier_call() - Common handler for QoS constraints.
> > + * @devfreq:    the devfreq instance.
> > + */
> > +static int qos_notifier_call(struct devfreq *devfreq)
> > +{
> > +	int err;
> > +
> > +	mutex_lock(&devfreq->lock);
> > +	err = update_devfreq(devfreq);
> > +	mutex_unlock(&devfreq->lock);
> > +	if (err)
> > +		dev_err(devfreq->dev.parent,
> > +				"failed to update frequency for PM QoS constraints (%d)\n",
> 
> Is it not over 80 char?

It is and Leonard split it up initially, however I asked him to not
break it up because:

  2) Breaking long lines and strings

  However, *never* break user-visible strings such as printk messages,
  because that breaks the ability to grep for them.

  Documentation/process/coding-style.rst

Line length could be reduced a bit by adjusting indentation though.

> 
> > +				err);
> > +
> > +	return NOTIFY_OK;
> > +}
> > +
> > +/**
> > + * qos_min_notifier_call() - Callback for QoS min_freq changes.
> > + * @nb:		Should be devfreq->nb_min
> > + */
> > +static int qos_min_notifier_call(struct notifier_block *nb,
> > +					 unsigned long val, void *ptr)
> > +{
> > +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
> > +}
> > +
> > +/**
> > + * qos_max_notifier_call() - Callback for QoS max_freq changes.
> > + * @nb:		Should be devfreq->nb_max
> > + */
> > +static int qos_max_notifier_call(struct notifier_block *nb,
> > +					 unsigned long val, void *ptr)
> > +{
> > +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
> > +}
> > +
> >  /**
> >   * devfreq_dev_release() - Callback for struct device to release the device.
> >   * @dev:	the devfreq device
> >   *
> >   * Remove devfreq from the list and release its resources.
> > @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
> >  
> >  	mutex_lock(&devfreq_list_lock);
> >  	list_del(&devfreq->node);
> >  	mutex_unlock(&devfreq_list_lock);
> >  
> > +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
> > +			DEV_PM_QOS_MAX_FREQUENCY);
> > +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
> > +			DEV_PM_QOS_MIN_FREQUENCY);
> > +
> 
> Just print error with dev_err() without stopping the release step.
> 
> I prefer to handle the return value if kernel API provides
> the error code.
> 
> >  	if (devfreq->profile->exit)
> >  		devfreq->profile->exit(devfreq->dev.parent);
> >  
> >  	kfree(devfreq->time_in_state);
> >  	kfree(devfreq->trans_table);
> > @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
> >  	if (err) {
> >  		put_device(&devfreq->dev);
> >  		goto err_out;
> >  	}
> >  
> > +	/*
> > +	 * Register notifiers for updates to min/max_freq after device is
> > +	 * initialized (and we can handle notifications) but before the
> > +	 * governor is started (which should do an initial enforcement of
> > +	 * constraints).
> > +	 */
> 
> My previous comment is not enough why I prefer to remove it. Sorry.
> Actually, until now, the devfreq_add_device() don't have the detailed
> comments because the line code is not too long. But, at the present time,
> devfreq_add_device() is too long. It means that the detailed comment
> are necessary. 
> 
> So, I'll add the detailed comment for each step of devfreq_add_device()
> on separate patch to keep the same style. I'll send the patch to you
> for the review.
> 
> > +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
> > +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
> > +				      DEV_PM_QOS_MIN_FREQUENCY);
> > +	if (err)
> > +		goto err_devfreq;
> > +
> > +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
> > +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
> > +				      DEV_PM_QOS_MAX_FREQUENCY);
> > +	if (err)
> > +		goto err_devfreq;
> > +
> >  	mutex_lock(&devfreq_list_lock);
> >  
> >  	governor = try_then_request_governor(devfreq->governor_name);
> >  	if (IS_ERR(governor)) {
> >  		dev_err(dev, "%s: Unable to find governor for the device\n",
> > @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
> >  
> >  	return devfreq;
> >  
> >  err_init:
> >  	mutex_unlock(&devfreq_list_lock);
> > +err_devfreq:
> >  	devfreq_remove_device(devfreq);
> >  	return ERR_PTR(err);
> >  
> >  err_dev:
> >  	/*
> > diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> > index c3cbc15fdf08..dac0dffeabb4 100644
> > --- a/include/linux/devfreq.h
> > +++ b/include/linux/devfreq.h
> > @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
> >   * @total_trans:	Number of devfreq transitions
> >   * @trans_table:	Statistics of devfreq transitions
> >   * @time_in_state:	Statistics of devfreq states
> >   * @last_stat_updated:	The last time stat updated
> >   * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
> > + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
> > + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
> >   *
> >   * This structure stores the devfreq information for a give device.
> >   *
> >   * Note that when a governor accesses entries in struct devfreq in its
> >   * functions except for the context of callbacks defined in struct
> > @@ -176,10 +178,13 @@ struct devfreq {
> >  	unsigned int *trans_table;
> >  	unsigned long *time_in_state;
> >  	unsigned long last_stat_updated;
> >  
> >  	struct srcu_notifier_head transition_notifier_list;
> > +
> > +	struct notifier_block nb_min;
> > +	struct notifier_block nb_max;
> >  };
> >  
> >  struct devfreq_freqs {
> >  	unsigned long old;
> >  	unsigned long new;
> > 
> 
> 
> -- 
> Best Regards,
> Chanwoo Choi
> Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
  2019-09-25  2:41       ` Chanwoo Choi
@ 2019-09-25 16:45         ` Matthias Kaehlcke
  -1 siblings, 0 replies; 82+ messages in thread
From: Matthias Kaehlcke @ 2019-09-25 16:45 UTC (permalink / raw)
  To: Chanwoo Choi
  Cc: Leonard Crestez, MyungJoo Ham, Kyungmin Park,
	Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

On Wed, Sep 25, 2019 at 11:41:07AM +0900, Chanwoo Choi wrote:
> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> > Switch the handling of min_freq and max_freq from sysfs to use the
> > dev_pm_qos_request interface.
> > 
> > Since PM QoS handles frequencies as kHz this change reduces the
> > precision of min_freq and max_freq. This shouldn't introduce problems
> > because frequencies which are not an integer number of kHz are likely
> > not an integer number of Hz either.
> > 
> > Try to ensure compatibility by rounding min values down and rounding
> > max values up.
> > 
> > Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> > Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> > ---
> >  drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
> >  include/linux/devfreq.h   |  9 ++++----
> >  2 files changed, 33 insertions(+), 22 deletions(-)
> > 
> > diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> > index 784f3e40536a..8bb7efd821ab 100644
> > --- a/drivers/devfreq/devfreq.c
> > +++ b/drivers/devfreq/devfreq.c
> > @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
> >  	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> >  					     DEV_PM_QOS_MIN_FREQUENCY);
> >  	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
> >  	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
> >  
> > -	/* constraints from sysfs */
> > -	*min_freq = max(*min_freq, devfreq->min_freq);
> > -	*max_freq = min(*max_freq, devfreq->max_freq);
> > -
> >  	/* constraints from OPP interface */
> >  	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
> >  	/* scaling_max_freq can be zero on error */
> >  	if (devfreq->scaling_max_freq)
> >  		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
> > @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
> >  			DEV_PM_QOS_MIN_FREQUENCY);
> >  
> >  	if (devfreq->profile->exit)
> >  		devfreq->profile->exit(devfreq->dev.parent);
> >  
> > +	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
> > +	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
> 
> Please check the return value if error happen, just print the err with dev_err()
> without stopping the release steps.

I wonder if dev_warn() would be more appropriate, since the current operation
is not aborted.

> >  	kfree(devfreq->time_in_state);
> >  	kfree(devfreq->trans_table);
> >  	mutex_destroy(&devfreq->lock);
> >  	kfree(devfreq);
> >  }
> > @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
> >  	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
> >  	if (!devfreq->scaling_min_freq) {
> >  		err = -EINVAL;
> >  		goto err_dev;
> >  	}
> > -	devfreq->min_freq = devfreq->scaling_min_freq;
> >  
> >  	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
> >  	if (!devfreq->scaling_max_freq) {
> >  		err = -EINVAL;
> >  		goto err_dev;
> >  	}
> > -	devfreq->max_freq = devfreq->scaling_max_freq;
> > +
> > +	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
> > +				     DEV_PM_QOS_MIN_FREQUENCY, 0);
> > +	if (err < 0)
> > +		goto err_dev;
> > +	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
> > +				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
> > +	if (err < 0)
> > +		goto err_dev;
> >  
> >  	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
> >  	atomic_set(&devfreq->suspend_count, 0);
> >  
> >  	devfreq->trans_table = kzalloc(
> > @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
> >  err_dev:
> >  	/*
> >  	 * Cleanup path for errors that happen before registration.
> >  	 * Otherwise we rely on devfreq_dev_release.
> >  	 */
> > +	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
> > +		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
> 
> Please check the return value if error happen, just print the err with dev_err()
> without stopping the release steps.
> 
> 	dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");

dev_warn() for the same reason as above?

I think the message would be better with a slight change:

"failed to remove DEV_PM_QOS_MAX_FREQUENCY request\n"

> 
> > +	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
> > +		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
> 	
> 	dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");

ditto

> >  	kfree(devfreq->time_in_state);
> >  	kfree(devfreq->trans_table);
> >  	kfree(devfreq);
> >  err_out:
> >  	return ERR_PTR(err);
> > @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
> >  
> >  	ret = sscanf(buf, "%lu", &value);
> >  	if (ret != 1)
> >  		return -EINVAL;
> >  
> > -	mutex_lock(&df->lock);
> > -	df->min_freq = value;
> > -	update_devfreq(df);
> > -	mutex_unlock(&df->lock);
> > +	/* round down to kHz for PM QoS */
> 
> I prefer more detailed description as following:
> 
> 	/*
> 	 * Round down to KHz to decide the proper minimum frequency

it should be kHz, with a lower-case 'k', as in the original comment.

> 	 * which is closed to user request.
>  	 */

The comment you suggest doesn't provide any information about why the
conversion to kHz is done, in this sense the original comment that
mentions PM QoS provides more value.

With whatever we end up, I suggest to use 'convert' instead of
'round down'.

> > +	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
> > +					value / HZ_PER_KHZ);
> > +	if (ret < 0)
> > +		return ret;
> >  
> >  	return count;
> >  }
> >  
> >  static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
> > @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
> >  
> >  	ret = sscanf(buf, "%lu", &value);
> >  	if (ret != 1)
> >  		return -EINVAL;
> >  
> > -	mutex_lock(&df->lock);
> > -
> > -	/* Interpret zero as "don't care" */
> > -	if (!value)
> > -		value = ULONG_MAX;
> > +	/* round up to kHz for PM QoS and interpret zero as "don't care" */
> 
> I think that "don't care" comment style is not good.
> 
> I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
> I prefer more detailed description as following:
> 	/*
> 	 * Round up to KHz to decide the proper maximum frequency

kHz

> 	 * which is closed to user request. If value is zero,
> 	 * the user does not care.

"the user does not care" is still very casual you didn't like initially.
How about "A value of zero is interpreted as 'no limit'."?

As for the min freq, I think PM QoS should be mentioned to make clear why
the conversion to kHz is needed.

>  	 */
> 
> 
> > +	if (value)
> > +		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
> > +	else
> > +		value = S32_MAX;
> >  
> > -	df->max_freq = value;
> > -	update_devfreq(df);
> > -	mutex_unlock(&df->lock);
> > +	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
> > +	if (ret < 0)
> > +		return ret;
> >  
> >  	return count;
> >  }
> >  static DEVICE_ATTR_RW(min_freq);
> >  
> > diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> > index dac0dffeabb4..7849fe4c666d 100644
> > --- a/include/linux/devfreq.h
> > +++ b/include/linux/devfreq.h
> > @@ -11,10 +11,11 @@
> >  #define __LINUX_DEVFREQ_H__
> >  
> >  #include <linux/device.h>
> >  #include <linux/notifier.h>
> >  #include <linux/pm_opp.h>
> > +#include <linux/pm_qos.h>
> >  
> >  #define DEVFREQ_NAME_LEN 16
> >  
> >  /* DEVFREQ governor name */
> >  #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
> > @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
> >   *		devfreq.nb to the corresponding register notifier call chain.
> >   * @work:	delayed work for load monitoring.
> >   * @previous_freq:	previously configured frequency value.
> >   * @data:	Private data of the governor. The devfreq framework does not
> >   *		touch this.
> > - * @min_freq:	Limit minimum frequency requested by user (0: none)
> > - * @max_freq:	Limit maximum frequency requested by user (0: none)
> > + * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)
> 
> min -> minimum and then remove parenthesis as following:
> 	PM QoS minimum frequency request by user via sysfs
> 
> > + * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)
> 
> ditto. max -> maximum
> 	PM QoS maximum frequency request by user via sysfs
> 
> >   * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
> >   * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
> >   * @stop_polling:	 devfreq polling status of a device.
> >   * @suspend_freq:	 frequency of a device set during suspend phase.
> >   * @resume_freq:	 frequency of a device set in resume phase.
> > @@ -161,12 +162,12 @@ struct devfreq {
> >  	unsigned long previous_freq;
> >  	struct devfreq_dev_status last_status;
> >  
> >  	void *data; /* private data for governors */
> >  
> > -	unsigned long min_freq;
> > -	unsigned long max_freq;
> > +	struct dev_pm_qos_request user_min_freq_req;
> > +	struct dev_pm_qos_request user_max_freq_req;
> >  	unsigned long scaling_min_freq;
> >  	unsigned long scaling_max_freq;
> >  	bool stop_polling;
> >  
> >  	unsigned long suspend_freq;
> > 
> 
> 
> -- 
> Best Regards,
> Chanwoo Choi
> Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
@ 2019-09-25 16:45         ` Matthias Kaehlcke
  0 siblings, 0 replies; 82+ messages in thread
From: Matthias Kaehlcke @ 2019-09-25 16:45 UTC (permalink / raw)
  To: Chanwoo Choi
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park,
	MyungJoo Ham, Alexandre Bailon, Leonard Crestez, Georgi Djakov,
	linux-arm-kernel, Jacky Bai

On Wed, Sep 25, 2019 at 11:41:07AM +0900, Chanwoo Choi wrote:
> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> > Switch the handling of min_freq and max_freq from sysfs to use the
> > dev_pm_qos_request interface.
> > 
> > Since PM QoS handles frequencies as kHz this change reduces the
> > precision of min_freq and max_freq. This shouldn't introduce problems
> > because frequencies which are not an integer number of kHz are likely
> > not an integer number of Hz either.
> > 
> > Try to ensure compatibility by rounding min values down and rounding
> > max values up.
> > 
> > Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> > Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> > ---
> >  drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
> >  include/linux/devfreq.h   |  9 ++++----
> >  2 files changed, 33 insertions(+), 22 deletions(-)
> > 
> > diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> > index 784f3e40536a..8bb7efd821ab 100644
> > --- a/drivers/devfreq/devfreq.c
> > +++ b/drivers/devfreq/devfreq.c
> > @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
> >  	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> >  					     DEV_PM_QOS_MIN_FREQUENCY);
> >  	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
> >  	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
> >  
> > -	/* constraints from sysfs */
> > -	*min_freq = max(*min_freq, devfreq->min_freq);
> > -	*max_freq = min(*max_freq, devfreq->max_freq);
> > -
> >  	/* constraints from OPP interface */
> >  	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
> >  	/* scaling_max_freq can be zero on error */
> >  	if (devfreq->scaling_max_freq)
> >  		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
> > @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
> >  			DEV_PM_QOS_MIN_FREQUENCY);
> >  
> >  	if (devfreq->profile->exit)
> >  		devfreq->profile->exit(devfreq->dev.parent);
> >  
> > +	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
> > +	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
> 
> Please check the return value if error happen, just print the err with dev_err()
> without stopping the release steps.

I wonder if dev_warn() would be more appropriate, since the current operation
is not aborted.

> >  	kfree(devfreq->time_in_state);
> >  	kfree(devfreq->trans_table);
> >  	mutex_destroy(&devfreq->lock);
> >  	kfree(devfreq);
> >  }
> > @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
> >  	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
> >  	if (!devfreq->scaling_min_freq) {
> >  		err = -EINVAL;
> >  		goto err_dev;
> >  	}
> > -	devfreq->min_freq = devfreq->scaling_min_freq;
> >  
> >  	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
> >  	if (!devfreq->scaling_max_freq) {
> >  		err = -EINVAL;
> >  		goto err_dev;
> >  	}
> > -	devfreq->max_freq = devfreq->scaling_max_freq;
> > +
> > +	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
> > +				     DEV_PM_QOS_MIN_FREQUENCY, 0);
> > +	if (err < 0)
> > +		goto err_dev;
> > +	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
> > +				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
> > +	if (err < 0)
> > +		goto err_dev;
> >  
> >  	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
> >  	atomic_set(&devfreq->suspend_count, 0);
> >  
> >  	devfreq->trans_table = kzalloc(
> > @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
> >  err_dev:
> >  	/*
> >  	 * Cleanup path for errors that happen before registration.
> >  	 * Otherwise we rely on devfreq_dev_release.
> >  	 */
> > +	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
> > +		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
> 
> Please check the return value if error happen, just print the err with dev_err()
> without stopping the release steps.
> 
> 	dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");

dev_warn() for the same reason as above?

I think the message would be better with a slight change:

"failed to remove DEV_PM_QOS_MAX_FREQUENCY request\n"

> 
> > +	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
> > +		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
> 	
> 	dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");

ditto

> >  	kfree(devfreq->time_in_state);
> >  	kfree(devfreq->trans_table);
> >  	kfree(devfreq);
> >  err_out:
> >  	return ERR_PTR(err);
> > @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
> >  
> >  	ret = sscanf(buf, "%lu", &value);
> >  	if (ret != 1)
> >  		return -EINVAL;
> >  
> > -	mutex_lock(&df->lock);
> > -	df->min_freq = value;
> > -	update_devfreq(df);
> > -	mutex_unlock(&df->lock);
> > +	/* round down to kHz for PM QoS */
> 
> I prefer more detailed description as following:
> 
> 	/*
> 	 * Round down to KHz to decide the proper minimum frequency

it should be kHz, with a lower-case 'k', as in the original comment.

> 	 * which is closed to user request.
>  	 */

The comment you suggest doesn't provide any information about why the
conversion to kHz is done, in this sense the original comment that
mentions PM QoS provides more value.

With whatever we end up, I suggest to use 'convert' instead of
'round down'.

> > +	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
> > +					value / HZ_PER_KHZ);
> > +	if (ret < 0)
> > +		return ret;
> >  
> >  	return count;
> >  }
> >  
> >  static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
> > @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
> >  
> >  	ret = sscanf(buf, "%lu", &value);
> >  	if (ret != 1)
> >  		return -EINVAL;
> >  
> > -	mutex_lock(&df->lock);
> > -
> > -	/* Interpret zero as "don't care" */
> > -	if (!value)
> > -		value = ULONG_MAX;
> > +	/* round up to kHz for PM QoS and interpret zero as "don't care" */
> 
> I think that "don't care" comment style is not good.
> 
> I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
> I prefer more detailed description as following:
> 	/*
> 	 * Round up to KHz to decide the proper maximum frequency

kHz

> 	 * which is closed to user request. If value is zero,
> 	 * the user does not care.

"the user does not care" is still very casual you didn't like initially.
How about "A value of zero is interpreted as 'no limit'."?

As for the min freq, I think PM QoS should be mentioned to make clear why
the conversion to kHz is needed.

>  	 */
> 
> 
> > +	if (value)
> > +		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
> > +	else
> > +		value = S32_MAX;
> >  
> > -	df->max_freq = value;
> > -	update_devfreq(df);
> > -	mutex_unlock(&df->lock);
> > +	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
> > +	if (ret < 0)
> > +		return ret;
> >  
> >  	return count;
> >  }
> >  static DEVICE_ATTR_RW(min_freq);
> >  
> > diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> > index dac0dffeabb4..7849fe4c666d 100644
> > --- a/include/linux/devfreq.h
> > +++ b/include/linux/devfreq.h
> > @@ -11,10 +11,11 @@
> >  #define __LINUX_DEVFREQ_H__
> >  
> >  #include <linux/device.h>
> >  #include <linux/notifier.h>
> >  #include <linux/pm_opp.h>
> > +#include <linux/pm_qos.h>
> >  
> >  #define DEVFREQ_NAME_LEN 16
> >  
> >  /* DEVFREQ governor name */
> >  #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
> > @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
> >   *		devfreq.nb to the corresponding register notifier call chain.
> >   * @work:	delayed work for load monitoring.
> >   * @previous_freq:	previously configured frequency value.
> >   * @data:	Private data of the governor. The devfreq framework does not
> >   *		touch this.
> > - * @min_freq:	Limit minimum frequency requested by user (0: none)
> > - * @max_freq:	Limit maximum frequency requested by user (0: none)
> > + * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)
> 
> min -> minimum and then remove parenthesis as following:
> 	PM QoS minimum frequency request by user via sysfs
> 
> > + * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)
> 
> ditto. max -> maximum
> 	PM QoS maximum frequency request by user via sysfs
> 
> >   * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
> >   * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
> >   * @stop_polling:	 devfreq polling status of a device.
> >   * @suspend_freq:	 frequency of a device set during suspend phase.
> >   * @resume_freq:	 frequency of a device set in resume phase.
> > @@ -161,12 +162,12 @@ struct devfreq {
> >  	unsigned long previous_freq;
> >  	struct devfreq_dev_status last_status;
> >  
> >  	void *data; /* private data for governors */
> >  
> > -	unsigned long min_freq;
> > -	unsigned long max_freq;
> > +	struct dev_pm_qos_request user_min_freq_req;
> > +	struct dev_pm_qos_request user_max_freq_req;
> >  	unsigned long scaling_min_freq;
> >  	unsigned long scaling_max_freq;
> >  	bool stop_polling;
> >  
> >  	unsigned long suspend_freq;
> > 
> 
> 
> -- 
> Best Regards,
> Chanwoo Choi
> Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 2/6] PM / devfreq: Move more initialization before registration
  2019-09-25  1:58       ` MyungJoo Ham
@ 2019-09-25 19:33         ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-25 19:33 UTC (permalink / raw)
  To: myungjoo.ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Chanwoo Choi, Artur Swigon, Saravana Kannan, Krzysztof Kozlowski,
	Alexandre Bailon, Georgi Djakov, Abel Vesa, Jacky Bai,
	Viresh Kumar, Lukasz Luba, dl-linux-imx, linux-pm,
	linux-arm-kernel

On 25.09.2019 04:59, MyungJoo Ham wrote:
>> In general it is a better to initialize an object before making it
>> accessible externally (through device_register).
>>
>> This makes it possible to avoid relying on locking a partially
>> initialized object.
>>
>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> 
> Do you object to the general idea of devm_* for device drivers?
> or did you find a bug in the memory handling in the code?
> 
> The result of this commit still relies on locking anyway.

This is a dependency of the following patch which removes the locking. I 
will add this to the commit message because everybody asks.

This patch removes devm because devm itself is only available after 
device_initialize. Moving the allocation ahead of device_register (which 
calls device_initialize) requires switching to manual memory management. 
Since there are only two pointers it seemed reasonable.

Alternatively device_register could be split into explicit 
"device_initialize" and "device_add" steps and devm could be used 
between those steps.

Before:
  - device_register
  - devm-based-alloc

After:
  + device_initialize
  + devm-based-alloc
  + device_add

Does this make sense?

--
Regards,
Leonard

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 2/6] PM / devfreq: Move more initialization before registration
@ 2019-09-25 19:33         ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-25 19:33 UTC (permalink / raw)
  To: myungjoo.ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, Artur Swigon,
	Krzysztof Kozlowski, Lukasz Luba, Chanwoo Choi, Alexandre Bailon,
	dl-linux-imx, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 25.09.2019 04:59, MyungJoo Ham wrote:
>> In general it is a better to initialize an object before making it
>> accessible externally (through device_register).
>>
>> This makes it possible to avoid relying on locking a partially
>> initialized object.
>>
>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> 
> Do you object to the general idea of devm_* for device drivers?
> or did you find a bug in the memory handling in the code?
> 
> The result of this commit still relies on locking anyway.

This is a dependency of the following patch which removes the locking. I 
will add this to the commit message because everybody asks.

This patch removes devm because devm itself is only available after 
device_initialize. Moving the allocation ahead of device_register (which 
calls device_initialize) requires switching to manual memory management. 
Since there are only two pointers it seemed reasonable.

Alternatively device_register could be split into explicit 
"device_initialize" and "device_add" steps and devm could be used 
between those steps.

Before:
  - device_register
  - devm-based-alloc

After:
  + device_initialize
  + devm-based-alloc
  + device_add

Does this make sense?

--
Regards,
Leonard

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 0/6] PM / devfreq: Add dev_pm_qos support
  2019-09-25  1:44     ` Chanwoo Choi
@ 2019-09-25 19:37       ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-25 19:37 UTC (permalink / raw)
  To: Chanwoo Choi, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 25.09.2019 04:40, Chanwoo Choi wrote:
> Hi Leonard,
> 
> Basically, I think that these series are very important.
> 
> But, you better to send the next version patch
> after finishing the review/discussion on previous version.
> 
> I reviewed the v7 and then you replied your comment.
> It is OK. But, you just send v8 without waiting my comment
> from your reply. It is not efficient discussion method.
> 
> If we finish the review of some point in the v7,
> it doesn't need to discuss the same comment on v8.
> 
> Please wait the reply for review. I think that
> it can save the our time for the review and contribution.

Sorry.

I already incorporated a large number of the changes in v7 so I thought 
I'd post the new version already.

> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>> Add dev_pm_qos notifiers to devfreq core in order to support frequency
>> limits via dev_pm_qos_add_request.
>>
>> Unlike the rest of devfreq the dev_pm_qos frequency is measured in Khz,
>> this is consistent with current dev_pm_qos usage for cpufreq and
>> allows frequencies above 2Ghz (pm_qos expresses limits as s32).
>>
>> Like with cpufreq the handling of min_freq/max_freq is moved to the
>> dev_pm_qos mechanism. Constraints from userspace are no longer clamped on
>> store, instead all values can be written and we only check against OPPs in a
>> new devfreq_get_freq_range function. This is consistent with the design of
>> dev_pm_qos.
>>
>> Notifiers from pm_qos are executed under a single global dev_pm_qos_mtx and
>> need to take devfreq->lock. Notifier registration takes the same dev_pm_qos_mtx
>> so in order to prevent lockdep warnings it must be done outside devfreq->lock.
>> Current devfreq_add_device does all initialization under devfreq->lock and that
>> needs to be relaxed.
>>
>> ---
>> Changes since v7:
>> * Only #define HZ_PER_KHZ in patch where it's used.
>> * Drop devfreq_ prefix for some internal functions.
>> * Improve qos update error message.
>> * Remove some unnecessary comments.
>> * Collect reviews
>> Link to v7: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fcover%2F11157649%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=mbxGHSFiLylBMcuoA4ABoyClJq0ELiZtr9QytMnPT7w%3D&amp;reserved=0
>>
>> Changes since v6:
>> * Don't return errno from devfreq_qos_notifier_call, return NOTIFY_DONE
>> and print the error.
>> * More spelling and punctuation nits
>> Link to v6: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fcover%2F11157201%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=ry1hAJ8Gb5zmefVDRMOup5E2agQ8lrha4MxU66kN27U%3D&amp;reserved=0
>>
>> Changes since v5:
>> * Drop patches which are not strictly related to PM QoS.
>> * Add a comment explaining why devfreq_add_device needs two cleanup paths.
>> * Remove {} for single line.
>> * Rename {min,max}_freq_req to user_{min,max}_freq_req
>> * Collect reviews
>> Link to v5: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fcover%2F11149497%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=ShneYomxXC1gUt5hU4agsZH%2FLfsHvxO%2FiaCNDGKsv94%3D&amp;reserved=0
>>
>> Sorry for forgetting to properly label v5. I know this is inside the
>> merge window but review would still be appreciated.
>>
>> Changes since v4:
>> * Move more devfreq_add_device init ahead of device_register.
>> * Make devfreq_dev_release cleanup devices not yet in devfreq_list. This is
>> simpler than previous attempt to add to devfreq_list sonner.
>> * Take devfreq->lock in trans_stat_show
>> * Register dev_pm_opp notifier on devfreq parent dev (which has OPPs)
>> Link to v4: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fcover%2F11114657%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=n3f%2Fd86jzWTG005SPrikbUOg%2FaGpf7LMZRoVrwybqSk%3D&amp;reserved=0
>>
>> Changes since v4:
>> * Move more devfreq_add_device init ahead of device_register.
>> * Make devfreq_dev_release cleanup devices not yet in devfreq_list. This is
>> simpler than previous attempt to add to devfreq_list sonner.
>> * Take devfreq->lock in trans_stat_show
>> * Register dev_pm_opp notifier on devfreq parent dev (which has OPPs)
>> Like to v4: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fcover%2F11114657%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=n3f%2Fd86jzWTG005SPrikbUOg%2FaGpf7LMZRoVrwybqSk%3D&amp;reserved=0
>>
>> Changes since v3:
>> * Cleanup locking and error-handling in devfreq_add_device
>> * Register notifiers after device registration but before governor start
>> * Keep the initialization of min_req/max_req ahead of device_register
>> because it's used for sysfs handling
>> * Use HZ_PER_KHZ instead of 1000
>> * Add kernel-doc comments
>> * Move OPP notifier to core
>> Link to v3: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fcover%2F11104061%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=XXzabOjV26KBso7j7BC%2BGTdIiKxiFUNmf3P5q1vXgbs%3D&amp;reserved=0
>>
>> Changes since v2:
>> * Handle sysfs via dev_pm_qos (in separate patch)
>> * Add locking to {min,max}_freq_show
>> * Fix checkpatch issues (long lines etc)
>> Link to v2: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fpatch%2F11084279%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=3CB%2FD82NoBKd%2FAREWaI%2FTl9uIPLXxz6e%2Fhzd3msRGcw%3D&amp;reserved=0
>>
>> Changes since v1:
>> * Add doxygen comments for min_nb/max_nb
>> * Remove notifiers on error/cleanup paths. Keep gotos simple by relying on
>> dev_pm_qos_remove_notifier ignoring notifiers which were not added.
>> Link to v1: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fpatch%2F11078475%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=tqOV6t0KUvFtUWxHrzAwVozZ4sKrylmuvdtiFSW3FV4%3D&amp;reserved=0
>>
>> Leonard Crestez (6):
>>    PM / devfreq: Don't fail devfreq_dev_release if not in list
>>    PM / devfreq: Move more initialization before registration
>>    PM / devfreq: Don't take lock in devfreq_add_device
>>    PM / devfreq: Introduce get_freq_range helper
>>    PM / devfreq: Add PM QoS support
>>    PM / devfreq: Use PM QoS for sysfs min/max_freq
>>
>>   drivers/devfreq/devfreq.c | 268 +++++++++++++++++++++++++-------------
>>   include/linux/devfreq.h   |  14 +-
>>   2 files changed, 191 insertions(+), 91 deletions(-)
>>
> 


^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 0/6] PM / devfreq: Add dev_pm_qos support
@ 2019-09-25 19:37       ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-25 19:37 UTC (permalink / raw)
  To: Chanwoo Choi, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Alexandre Bailon,
	Georgi Djakov, linux-arm-kernel, Jacky Bai

On 25.09.2019 04:40, Chanwoo Choi wrote:
> Hi Leonard,
> 
> Basically, I think that these series are very important.
> 
> But, you better to send the next version patch
> after finishing the review/discussion on previous version.
> 
> I reviewed the v7 and then you replied your comment.
> It is OK. But, you just send v8 without waiting my comment
> from your reply. It is not efficient discussion method.
> 
> If we finish the review of some point in the v7,
> it doesn't need to discuss the same comment on v8.
> 
> Please wait the reply for review. I think that
> it can save the our time for the review and contribution.

Sorry.

I already incorporated a large number of the changes in v7 so I thought 
I'd post the new version already.

> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>> Add dev_pm_qos notifiers to devfreq core in order to support frequency
>> limits via dev_pm_qos_add_request.
>>
>> Unlike the rest of devfreq the dev_pm_qos frequency is measured in Khz,
>> this is consistent with current dev_pm_qos usage for cpufreq and
>> allows frequencies above 2Ghz (pm_qos expresses limits as s32).
>>
>> Like with cpufreq the handling of min_freq/max_freq is moved to the
>> dev_pm_qos mechanism. Constraints from userspace are no longer clamped on
>> store, instead all values can be written and we only check against OPPs in a
>> new devfreq_get_freq_range function. This is consistent with the design of
>> dev_pm_qos.
>>
>> Notifiers from pm_qos are executed under a single global dev_pm_qos_mtx and
>> need to take devfreq->lock. Notifier registration takes the same dev_pm_qos_mtx
>> so in order to prevent lockdep warnings it must be done outside devfreq->lock.
>> Current devfreq_add_device does all initialization under devfreq->lock and that
>> needs to be relaxed.
>>
>> ---
>> Changes since v7:
>> * Only #define HZ_PER_KHZ in patch where it's used.
>> * Drop devfreq_ prefix for some internal functions.
>> * Improve qos update error message.
>> * Remove some unnecessary comments.
>> * Collect reviews
>> Link to v7: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fcover%2F11157649%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=mbxGHSFiLylBMcuoA4ABoyClJq0ELiZtr9QytMnPT7w%3D&amp;reserved=0
>>
>> Changes since v6:
>> * Don't return errno from devfreq_qos_notifier_call, return NOTIFY_DONE
>> and print the error.
>> * More spelling and punctuation nits
>> Link to v6: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fcover%2F11157201%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=ry1hAJ8Gb5zmefVDRMOup5E2agQ8lrha4MxU66kN27U%3D&amp;reserved=0
>>
>> Changes since v5:
>> * Drop patches which are not strictly related to PM QoS.
>> * Add a comment explaining why devfreq_add_device needs two cleanup paths.
>> * Remove {} for single line.
>> * Rename {min,max}_freq_req to user_{min,max}_freq_req
>> * Collect reviews
>> Link to v5: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fcover%2F11149497%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=ShneYomxXC1gUt5hU4agsZH%2FLfsHvxO%2FiaCNDGKsv94%3D&amp;reserved=0
>>
>> Sorry for forgetting to properly label v5. I know this is inside the
>> merge window but review would still be appreciated.
>>
>> Changes since v4:
>> * Move more devfreq_add_device init ahead of device_register.
>> * Make devfreq_dev_release cleanup devices not yet in devfreq_list. This is
>> simpler than previous attempt to add to devfreq_list sonner.
>> * Take devfreq->lock in trans_stat_show
>> * Register dev_pm_opp notifier on devfreq parent dev (which has OPPs)
>> Link to v4: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fcover%2F11114657%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=n3f%2Fd86jzWTG005SPrikbUOg%2FaGpf7LMZRoVrwybqSk%3D&amp;reserved=0
>>
>> Changes since v4:
>> * Move more devfreq_add_device init ahead of device_register.
>> * Make devfreq_dev_release cleanup devices not yet in devfreq_list. This is
>> simpler than previous attempt to add to devfreq_list sonner.
>> * Take devfreq->lock in trans_stat_show
>> * Register dev_pm_opp notifier on devfreq parent dev (which has OPPs)
>> Like to v4: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fcover%2F11114657%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=n3f%2Fd86jzWTG005SPrikbUOg%2FaGpf7LMZRoVrwybqSk%3D&amp;reserved=0
>>
>> Changes since v3:
>> * Cleanup locking and error-handling in devfreq_add_device
>> * Register notifiers after device registration but before governor start
>> * Keep the initialization of min_req/max_req ahead of device_register
>> because it's used for sysfs handling
>> * Use HZ_PER_KHZ instead of 1000
>> * Add kernel-doc comments
>> * Move OPP notifier to core
>> Link to v3: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fcover%2F11104061%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=XXzabOjV26KBso7j7BC%2BGTdIiKxiFUNmf3P5q1vXgbs%3D&amp;reserved=0
>>
>> Changes since v2:
>> * Handle sysfs via dev_pm_qos (in separate patch)
>> * Add locking to {min,max}_freq_show
>> * Fix checkpatch issues (long lines etc)
>> Link to v2: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fpatch%2F11084279%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=3CB%2FD82NoBKd%2FAREWaI%2FTl9uIPLXxz6e%2Fhzd3msRGcw%3D&amp;reserved=0
>>
>> Changes since v1:
>> * Add doxygen comments for min_nb/max_nb
>> * Remove notifiers on error/cleanup paths. Keep gotos simple by relying on
>> dev_pm_qos_remove_notifier ignoring notifiers which were not added.
>> Link to v1: https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatchwork.kernel.org%2Fpatch%2F11078475%2F&amp;data=02%7C01%7Cleonard.crestez%40nxp.com%7Cb4e87dc885c64c7fe83d08d741594dcb%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637049724139242058&amp;sdata=tqOV6t0KUvFtUWxHrzAwVozZ4sKrylmuvdtiFSW3FV4%3D&amp;reserved=0
>>
>> Leonard Crestez (6):
>>    PM / devfreq: Don't fail devfreq_dev_release if not in list
>>    PM / devfreq: Move more initialization before registration
>>    PM / devfreq: Don't take lock in devfreq_add_device
>>    PM / devfreq: Introduce get_freq_range helper
>>    PM / devfreq: Add PM QoS support
>>    PM / devfreq: Use PM QoS for sysfs min/max_freq
>>
>>   drivers/devfreq/devfreq.c | 268 +++++++++++++++++++++++++-------------
>>   include/linux/devfreq.h   |  14 +-
>>   2 files changed, 191 insertions(+), 91 deletions(-)
>>
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-25  2:17           ` Chanwoo Choi
@ 2019-09-25 19:40             ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-25 19:40 UTC (permalink / raw)
  To: Chanwoo Choi, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 25.09.2019 05:13, Chanwoo Choi wrote:
> On 19. 9. 25. 오전 4:22, Leonard Crestez wrote:
>> On 24.09.2019 22:11, Matthias Kaehlcke wrote:
>>> On Tue, Sep 24, 2019 at 01:11:29PM +0300, Leonard Crestez wrote:
>>>> Register notifiers with the PM QoS framework in order to respond to
>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>
>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>> imposed externally (for example from other devices).
>>>>
>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>> ---
>>>>    drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>    include/linux/devfreq.h   |  5 +++
>>>>    2 files changed, 80 insertions(+)
>>>>
>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>> index eee403e70c84..784f3e40536a 100644
>>>> --- a/drivers/devfreq/devfreq.c
>>>> +++ b/drivers/devfreq/devfreq.c
>>>> @@ -22,15 +22,18 @@
>>>>    #include <linux/platform_device.h>
>>>>    #include <linux/list.h>
>>>>    #include <linux/printk.h>
>>>>    #include <linux/hrtimer.h>
>>>>    #include <linux/of.h>
>>>> +#include <linux/pm_qos.h>
>>>>    #include "governor.h"
>>>>    
>>>>    #define CREATE_TRACE_POINTS
>>>>    #include <trace/events/devfreq.h>
>>>>    
>>>> +#define HZ_PER_KHZ	1000
>>>> +
>>>>    static struct class *devfreq_class;
>>>>    
>>>>    /*
>>>>     * devfreq core provides delayed work based load monitoring helper
>>>>     * functions. Governors can use these or can implement their own
>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>    static void get_freq_range(struct devfreq *devfreq,
>>>>    			   unsigned long *min_freq,
>>>>    			   unsigned long *max_freq)
>>>>    {
>>>>    	unsigned long *freq_table = devfreq->profile->freq_table;
>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>    
>>>>    	lockdep_assert_held(&devfreq->lock);
>>>>    
>>>>    	/*
>>>>    	 * Init min/max frequency from freq table.
>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>    	} else {
>>>>    		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>    		*max_freq = freq_table[0];
>>>>    	}
>>>>    
>>>> +	/* constraints from PM QoS */
>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>> +					     DEV_PM_QOS_MIN_FREQUENCY); >
>>> This needs to be DEV_PM_QOS_MAX_FREQUENCY. I missed this in the earlier
>>> reviews, but stumbled across it when testing.
>>>
>>> !Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>
>> I broke it in v8 while processing comments. Thanks for catching it.
> 
> Did you test this patchset with v8?
> Maybe it is not working with this mistake.

I ran some scripts which test that min_freq requests work as expected 
(using imx interconnect+devfreq). They don't touch max_freq.

--
Regards,
Leonard

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-25 19:40             ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-25 19:40 UTC (permalink / raw)
  To: Chanwoo Choi, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 25.09.2019 05:13, Chanwoo Choi wrote:
> On 19. 9. 25. 오전 4:22, Leonard Crestez wrote:
>> On 24.09.2019 22:11, Matthias Kaehlcke wrote:
>>> On Tue, Sep 24, 2019 at 01:11:29PM +0300, Leonard Crestez wrote:
>>>> Register notifiers with the PM QoS framework in order to respond to
>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>
>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>> imposed externally (for example from other devices).
>>>>
>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>> ---
>>>>    drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>    include/linux/devfreq.h   |  5 +++
>>>>    2 files changed, 80 insertions(+)
>>>>
>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>> index eee403e70c84..784f3e40536a 100644
>>>> --- a/drivers/devfreq/devfreq.c
>>>> +++ b/drivers/devfreq/devfreq.c
>>>> @@ -22,15 +22,18 @@
>>>>    #include <linux/platform_device.h>
>>>>    #include <linux/list.h>
>>>>    #include <linux/printk.h>
>>>>    #include <linux/hrtimer.h>
>>>>    #include <linux/of.h>
>>>> +#include <linux/pm_qos.h>
>>>>    #include "governor.h"
>>>>    
>>>>    #define CREATE_TRACE_POINTS
>>>>    #include <trace/events/devfreq.h>
>>>>    
>>>> +#define HZ_PER_KHZ	1000
>>>> +
>>>>    static struct class *devfreq_class;
>>>>    
>>>>    /*
>>>>     * devfreq core provides delayed work based load monitoring helper
>>>>     * functions. Governors can use these or can implement their own
>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>    static void get_freq_range(struct devfreq *devfreq,
>>>>    			   unsigned long *min_freq,
>>>>    			   unsigned long *max_freq)
>>>>    {
>>>>    	unsigned long *freq_table = devfreq->profile->freq_table;
>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>    
>>>>    	lockdep_assert_held(&devfreq->lock);
>>>>    
>>>>    	/*
>>>>    	 * Init min/max frequency from freq table.
>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>    	} else {
>>>>    		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>    		*max_freq = freq_table[0];
>>>>    	}
>>>>    
>>>> +	/* constraints from PM QoS */
>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>> +					     DEV_PM_QOS_MIN_FREQUENCY); >
>>> This needs to be DEV_PM_QOS_MAX_FREQUENCY. I missed this in the earlier
>>> reviews, but stumbled across it when testing.
>>>
>>> !Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>
>> I broke it in v8 while processing comments. Thanks for catching it.
> 
> Did you test this patchset with v8?
> Maybe it is not working with this mistake.

I ran some scripts which test that min_freq requests work as expected 
(using imx interconnect+devfreq). They don't touch max_freq.

--
Regards,
Leonard
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 4/6] PM / devfreq: Introduce get_freq_range helper
  2019-09-25  1:37       ` Chanwoo Choi
@ 2019-09-25 20:55         ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-25 20:55 UTC (permalink / raw)
  To: Chanwoo Choi, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke,
	Viresh Kumar
  Cc: Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Lukasz Luba, dl-linux-imx,
	linux-pm, linux-arm-kernel

On 25.09.2019 04:32, Chanwoo Choi wrote:
> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>> Moving handling of min/max freq to a single function and call it from
>> update_devfreq and for printing min/max freq values in sysfs.
>>
>> This changes the behavior of out-of-range min_freq/max_freq: clamping
>> is now done at evaluation time. This means that if an out-of-range
>> constraint is imposed by sysfs and it later becomes valid then it will
>> be enforced.
>>
>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>> ---
>>   drivers/devfreq/devfreq.c | 112 ++++++++++++++++++++++----------------
>>   1 file changed, 64 insertions(+), 48 deletions(-)
>>
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index 4a878baa809e..eee403e70c84 100644
>> --- a/drivers/devfreq/devfreq.c
>> +++ b/drivers/devfreq/devfreq.c
>> @@ -96,10 +96,54 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>   		dev_pm_opp_put(opp);
>>   
>>   	return max_freq;
>>   }
>>   
>> +/**
>> + * get_freq_range() - Get the current freq range
>> + * @devfreq:	the devfreq instance
>> + * @min_freq:	the min frequency
>> + * @max_freq:	the max frequency
>> + *
>> + * This takes into consideration all constraints.
>> + */
>> +static void get_freq_range(struct devfreq *devfreq,
>> +			   unsigned long *min_freq,
>> +			   unsigned long *max_freq)
>> +{
>> +	unsigned long *freq_table = devfreq->profile->freq_table;
>> +
>> +	lockdep_assert_held(&devfreq->lock);
>> +
>> +	/*
>> +	 * Init min/max frequency from freq table.
> 
> Init -> Initialize
> min/max -> minimum/maximum
> 
>> +	 * Drivers can initialize this in either ascending or descending order
> 
> Drivers -> devfreq drivers
> 
>> +	 * and devfreq core supports both.
>> +	 */
> 
> 
> In result, I prefer to change the comments as following:
> 	/*
> 	 * Initialize the minimum/maximum frequency from freq_table.
>   	 * The devfreq drivers can initialize freq_table in either
> 	 * ascending or descending order and devfreq core supports both.
> 	 */

OK

>> +	if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
>> +		*min_freq = freq_table[0];
>> +		*max_freq = freq_table[devfreq->profile->max_state - 1];
>> +	} else {
>> +		*min_freq = freq_table[devfreq->profile->max_state - 1];
>> +		*max_freq = freq_table[0];
>> +	}
>> +
>> +	/* constraints from sysfs */
> 
> 'constraints' -> Constraint because first verb have to be used
> as the sigular verbs. Also, I think that have to enhance the comments
> I prefer to use following comments:
> 
> 	 /* Constraint minimum/maximum frequency from user input via sysfs */
> 
> 
> 
>> +	*min_freq = max(*min_freq, devfreq->min_freq);
>> +	*max_freq = min(*max_freq, devfreq->max_freq);
>> +
>> +	/* constraints from OPP interface */
> 
> ditto. I prefer to use following comments:
> 
> 	/* Constraint minimum/maximum frequency from OPP interface */
> 
> 
>> +	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>> +	/* scaling_max_freq can be zero on error */
> 
> Please remove it.
> 
>> +	if (devfreq->scaling_max_freq)
> 
> As I knew, devfreq->scaling_max_freq is never zero.
> So, it is always true. This if statement is needed.

It can happen if find_available_max_freq encounters an error when called 
from devfreq_notifier_call.

Maybe that should be separately fixed to set scaling_max_freq to a 
neutral value such as "ULONG_MAX" instead?

BTW: the devfreq_notifier_call function returns -EINVAL on error but it 
should return one of the NOTIFY_OK/DONE/STOP values instead. The OPP 
framework ignores notifier results but (-EINVAL & NOTIFY_STOP) evaluates 
as true so other notifiers will be skipped unintentionally.

>> +		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
>> +
>> +	/* max_freq takes precedence over min_freq */
> 
> As I said, almost people know that min_freq have be under than max_freq.
> Please remove it. And until finishing the discussion on mailing list,
> please don't send the next version. If you just replied from my comment
> and then wait my next comment, we can save the time without replying
> the repetitive and same comment for same point.

This series makes it possible to set a min_freq higher than max_freq 
(for example via PM QoS from various devices).

It is not obvious that min_freq takes precedence over max_freq but the 
code is self-evident so I will remove the comment.

>> +	if (*min_freq > *max_freq)
>> +		*min_freq = *max_freq;
>> +}
>> +
>>   /**
>>    * devfreq_get_freq_level() - Lookup freq_table for the frequency
>>    * @devfreq:	the devfreq instance
>>    * @freq:	the target frequency
>>    */
>> @@ -349,20 +393,11 @@ int update_devfreq(struct devfreq *devfreq)
>>   
>>   	/* Reevaluate the proper frequency */
>>   	err = devfreq->governor->get_target_freq(devfreq, &freq);
>>   	if (err)
>>   		return err;
>> -
>> -	/*
>> -	 * Adjust the frequency with user freq, QoS and available freq.
>> -	 *
>> -	 * List from the highest priority
>> -	 * max_freq
>> -	 * min_freq
>> -	 */
>> -	max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
>> -	min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
>> +	get_freq_range(devfreq, &min_freq, &max_freq);
>>   
>>   	if (freq < min_freq) {
>>   		freq = min_freq;
>>   		flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
>>   	}
>> @@ -1298,40 +1333,28 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>   	ret = sscanf(buf, "%lu", &value);
>>   	if (ret != 1)
>>   		return -EINVAL;
>>   
>>   	mutex_lock(&df->lock);
>> -
>> -	if (value) {
>> -		if (value > df->max_freq) {
>> -			ret = -EINVAL;
>> -			goto unlock;
>> -		}
>> -	} else {
>> -		unsigned long *freq_table = df->profile->freq_table;
>> -
>> -		/* Get minimum frequency according to sorting order */
>> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
>> -			value = freq_table[0];
>> -		else
>> -			value = freq_table[df->profile->max_state - 1];
>> -	}
>> -
>>   	df->min_freq = value;
>>   	update_devfreq(df);
>> -	ret = count;
>> -unlock:
>>   	mutex_unlock(&df->lock);
>> -	return ret;
>> +
>> +	return count;
>>   }
>>   
>>   static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>>   			     char *buf)
>>   {
>>   	struct devfreq *df = to_devfreq(dev);
>> +	unsigned long min_freq, max_freq;
>> +
>> +	mutex_lock(&df->lock);
>> +	get_freq_range(df, &min_freq, &max_freq);
>> +	mutex_unlock(&df->lock);
>>   
>> -	return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
>> +	return sprintf(buf, "%lu\n", min_freq);
>>   }
>>   
>>   static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>   			      const char *buf, size_t count)
>>   {
>> @@ -1343,40 +1366,33 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>   	if (ret != 1)
>>   		return -EINVAL;
>>   
>>   	mutex_lock(&df->lock);
>>   
>> -	if (value) {
>> -		if (value < df->min_freq) {
>> -			ret = -EINVAL;
>> -			goto unlock;
>> -		}
>> -	} else {
>> -		unsigned long *freq_table = df->profile->freq_table;
>> -
>> -		/* Get maximum frequency according to sorting order */
>> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
>> -			value = freq_table[df->profile->max_state - 1];
>> -		else
>> -			value = freq_table[0];
>> -	}
>> +	/* Interpret zero as "don't care" */
> 
> Please remove it. Also, the detailed comment for user have to add
> the documentation file.

OK

> 
>> +	if (!value)
>> +		value = ULONG_MAX;
>>   
>>   	df->max_freq = value;
>>   	update_devfreq(df);
>> -	ret = count;
>> -unlock:
>>   	mutex_unlock(&df->lock);
>> -	return ret;
>> +
>> +	return count;
>>   }
>>   static DEVICE_ATTR_RW(min_freq);
>>   
>>   static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
>>   			     char *buf)
>>   {
>>   	struct devfreq *df = to_devfreq(dev);
>> +	unsigned long min_freq, max_freq;
>> +
>> +	mutex_lock(&df->lock);
>> +	get_freq_range(df, &min_freq, &max_freq);
>> +	mutex_unlock(&df->lock);
>>   
>> -	return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
>> +	return sprintf(buf, "%lu\n", max_freq);
>>   }
>>   static DEVICE_ATTR_RW(max_freq);
>>   
>>   static ssize_t available_frequencies_show(struct device *d,
>>   					  struct device_attribute *attr,

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 4/6] PM / devfreq: Introduce get_freq_range helper
@ 2019-09-25 20:55         ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-25 20:55 UTC (permalink / raw)
  To: Chanwoo Choi, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke,
	Viresh Kumar
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Alexandre Bailon,
	Georgi Djakov, linux-arm-kernel, Jacky Bai

On 25.09.2019 04:32, Chanwoo Choi wrote:
> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>> Moving handling of min/max freq to a single function and call it from
>> update_devfreq and for printing min/max freq values in sysfs.
>>
>> This changes the behavior of out-of-range min_freq/max_freq: clamping
>> is now done at evaluation time. This means that if an out-of-range
>> constraint is imposed by sysfs and it later becomes valid then it will
>> be enforced.
>>
>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>> ---
>>   drivers/devfreq/devfreq.c | 112 ++++++++++++++++++++++----------------
>>   1 file changed, 64 insertions(+), 48 deletions(-)
>>
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index 4a878baa809e..eee403e70c84 100644
>> --- a/drivers/devfreq/devfreq.c
>> +++ b/drivers/devfreq/devfreq.c
>> @@ -96,10 +96,54 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>   		dev_pm_opp_put(opp);
>>   
>>   	return max_freq;
>>   }
>>   
>> +/**
>> + * get_freq_range() - Get the current freq range
>> + * @devfreq:	the devfreq instance
>> + * @min_freq:	the min frequency
>> + * @max_freq:	the max frequency
>> + *
>> + * This takes into consideration all constraints.
>> + */
>> +static void get_freq_range(struct devfreq *devfreq,
>> +			   unsigned long *min_freq,
>> +			   unsigned long *max_freq)
>> +{
>> +	unsigned long *freq_table = devfreq->profile->freq_table;
>> +
>> +	lockdep_assert_held(&devfreq->lock);
>> +
>> +	/*
>> +	 * Init min/max frequency from freq table.
> 
> Init -> Initialize
> min/max -> minimum/maximum
> 
>> +	 * Drivers can initialize this in either ascending or descending order
> 
> Drivers -> devfreq drivers
> 
>> +	 * and devfreq core supports both.
>> +	 */
> 
> 
> In result, I prefer to change the comments as following:
> 	/*
> 	 * Initialize the minimum/maximum frequency from freq_table.
>   	 * The devfreq drivers can initialize freq_table in either
> 	 * ascending or descending order and devfreq core supports both.
> 	 */

OK

>> +	if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
>> +		*min_freq = freq_table[0];
>> +		*max_freq = freq_table[devfreq->profile->max_state - 1];
>> +	} else {
>> +		*min_freq = freq_table[devfreq->profile->max_state - 1];
>> +		*max_freq = freq_table[0];
>> +	}
>> +
>> +	/* constraints from sysfs */
> 
> 'constraints' -> Constraint because first verb have to be used
> as the sigular verbs. Also, I think that have to enhance the comments
> I prefer to use following comments:
> 
> 	 /* Constraint minimum/maximum frequency from user input via sysfs */
> 
> 
> 
>> +	*min_freq = max(*min_freq, devfreq->min_freq);
>> +	*max_freq = min(*max_freq, devfreq->max_freq);
>> +
>> +	/* constraints from OPP interface */
> 
> ditto. I prefer to use following comments:
> 
> 	/* Constraint minimum/maximum frequency from OPP interface */
> 
> 
>> +	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>> +	/* scaling_max_freq can be zero on error */
> 
> Please remove it.
> 
>> +	if (devfreq->scaling_max_freq)
> 
> As I knew, devfreq->scaling_max_freq is never zero.
> So, it is always true. This if statement is needed.

It can happen if find_available_max_freq encounters an error when called 
from devfreq_notifier_call.

Maybe that should be separately fixed to set scaling_max_freq to a 
neutral value such as "ULONG_MAX" instead?

BTW: the devfreq_notifier_call function returns -EINVAL on error but it 
should return one of the NOTIFY_OK/DONE/STOP values instead. The OPP 
framework ignores notifier results but (-EINVAL & NOTIFY_STOP) evaluates 
as true so other notifiers will be skipped unintentionally.

>> +		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
>> +
>> +	/* max_freq takes precedence over min_freq */
> 
> As I said, almost people know that min_freq have be under than max_freq.
> Please remove it. And until finishing the discussion on mailing list,
> please don't send the next version. If you just replied from my comment
> and then wait my next comment, we can save the time without replying
> the repetitive and same comment for same point.

This series makes it possible to set a min_freq higher than max_freq 
(for example via PM QoS from various devices).

It is not obvious that min_freq takes precedence over max_freq but the 
code is self-evident so I will remove the comment.

>> +	if (*min_freq > *max_freq)
>> +		*min_freq = *max_freq;
>> +}
>> +
>>   /**
>>    * devfreq_get_freq_level() - Lookup freq_table for the frequency
>>    * @devfreq:	the devfreq instance
>>    * @freq:	the target frequency
>>    */
>> @@ -349,20 +393,11 @@ int update_devfreq(struct devfreq *devfreq)
>>   
>>   	/* Reevaluate the proper frequency */
>>   	err = devfreq->governor->get_target_freq(devfreq, &freq);
>>   	if (err)
>>   		return err;
>> -
>> -	/*
>> -	 * Adjust the frequency with user freq, QoS and available freq.
>> -	 *
>> -	 * List from the highest priority
>> -	 * max_freq
>> -	 * min_freq
>> -	 */
>> -	max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
>> -	min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
>> +	get_freq_range(devfreq, &min_freq, &max_freq);
>>   
>>   	if (freq < min_freq) {
>>   		freq = min_freq;
>>   		flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
>>   	}
>> @@ -1298,40 +1333,28 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>   	ret = sscanf(buf, "%lu", &value);
>>   	if (ret != 1)
>>   		return -EINVAL;
>>   
>>   	mutex_lock(&df->lock);
>> -
>> -	if (value) {
>> -		if (value > df->max_freq) {
>> -			ret = -EINVAL;
>> -			goto unlock;
>> -		}
>> -	} else {
>> -		unsigned long *freq_table = df->profile->freq_table;
>> -
>> -		/* Get minimum frequency according to sorting order */
>> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
>> -			value = freq_table[0];
>> -		else
>> -			value = freq_table[df->profile->max_state - 1];
>> -	}
>> -
>>   	df->min_freq = value;
>>   	update_devfreq(df);
>> -	ret = count;
>> -unlock:
>>   	mutex_unlock(&df->lock);
>> -	return ret;
>> +
>> +	return count;
>>   }
>>   
>>   static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>>   			     char *buf)
>>   {
>>   	struct devfreq *df = to_devfreq(dev);
>> +	unsigned long min_freq, max_freq;
>> +
>> +	mutex_lock(&df->lock);
>> +	get_freq_range(df, &min_freq, &max_freq);
>> +	mutex_unlock(&df->lock);
>>   
>> -	return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
>> +	return sprintf(buf, "%lu\n", min_freq);
>>   }
>>   
>>   static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>   			      const char *buf, size_t count)
>>   {
>> @@ -1343,40 +1366,33 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>   	if (ret != 1)
>>   		return -EINVAL;
>>   
>>   	mutex_lock(&df->lock);
>>   
>> -	if (value) {
>> -		if (value < df->min_freq) {
>> -			ret = -EINVAL;
>> -			goto unlock;
>> -		}
>> -	} else {
>> -		unsigned long *freq_table = df->profile->freq_table;
>> -
>> -		/* Get maximum frequency according to sorting order */
>> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
>> -			value = freq_table[df->profile->max_state - 1];
>> -		else
>> -			value = freq_table[0];
>> -	}
>> +	/* Interpret zero as "don't care" */
> 
> Please remove it. Also, the detailed comment for user have to add
> the documentation file.

OK

> 
>> +	if (!value)
>> +		value = ULONG_MAX;
>>   
>>   	df->max_freq = value;
>>   	update_devfreq(df);
>> -	ret = count;
>> -unlock:
>>   	mutex_unlock(&df->lock);
>> -	return ret;
>> +
>> +	return count;
>>   }
>>   static DEVICE_ATTR_RW(min_freq);
>>   
>>   static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
>>   			     char *buf)
>>   {
>>   	struct devfreq *df = to_devfreq(dev);
>> +	unsigned long min_freq, max_freq;
>> +
>> +	mutex_lock(&df->lock);
>> +	get_freq_range(df, &min_freq, &max_freq);
>> +	mutex_unlock(&df->lock);
>>   
>> -	return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
>> +	return sprintf(buf, "%lu\n", max_freq);
>>   }
>>   static DEVICE_ATTR_RW(max_freq);
>>   
>>   static ssize_t available_frequencies_show(struct device *d,
>>   					  struct device_attribute *attr,
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-25  2:15       ` Chanwoo Choi
@ 2019-09-25 21:18         ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-25 21:18 UTC (permalink / raw)
  To: Chanwoo Choi, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 25.09.2019 05:11, Chanwoo Choi wrote:
> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>> Register notifiers with the PM QoS framework in order to respond to
>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>
>> No notifiers are added by this patch but PM QoS constraints can be
>> imposed externally (for example from other devices).
>>
>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>> ---
>>   drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>   include/linux/devfreq.h   |  5 +++
>>   2 files changed, 80 insertions(+)
>>
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index eee403e70c84..784f3e40536a 100644
>> --- a/drivers/devfreq/devfreq.c
>> +++ b/drivers/devfreq/devfreq.c
>> @@ -22,15 +22,18 @@
>>   #include <linux/platform_device.h>
>>   #include <linux/list.h>
>>   #include <linux/printk.h>
>>   #include <linux/hrtimer.h>
>>   #include <linux/of.h>
>> +#include <linux/pm_qos.h>
>>   #include "governor.h"
>>   
>>   #define CREATE_TRACE_POINTS
>>   #include <trace/events/devfreq.h>
>>   
>> +#define HZ_PER_KHZ	1000
>> +
>>   static struct class *devfreq_class;
>>   
>>   /*
>>    * devfreq core provides delayed work based load monitoring helper
>>    * functions. Governors can use these or can implement their own
>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>   static void get_freq_range(struct devfreq *devfreq,
>>   			   unsigned long *min_freq,
>>   			   unsigned long *max_freq)
>>   {
>>   	unsigned long *freq_table = devfreq->profile->freq_table;
>> +	unsigned long qos_min_freq, qos_max_freq;
>>   
>>   	lockdep_assert_held(&devfreq->lock);
>>   
>>   	/*
>>   	 * Init min/max frequency from freq table.
>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>   	} else {
>>   		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>   		*max_freq = freq_table[0];
>>   	}
>>   
>> +	/* constraints from PM QoS */
> 
> As I commented on patch4,
> 'constraints' -> 'Constraint' because first verb have to be used
> as the sigular verbs.

Already discussed for another patch; I will modify to "Apply constraints 
from PM QoS" instead.

> I prefer to use following comments:
> 
> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
> 
>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>> +
>>   	/* constraints from sysfs */
>>   	*min_freq = max(*min_freq, devfreq->min_freq);
>>   	*max_freq = min(*max_freq, devfreq->max_freq);
>>   
>>   	/* constraints from OPP interface */
>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>   	mutex_unlock(&devfreq->lock);
>>   
>>   	return ret;
>>   }
>>   
>> +/**
>> + * qos_notifier_call() - Common handler for QoS constraints.
>> + * @devfreq:    the devfreq instance.
>> + */
>> +static int qos_notifier_call(struct devfreq *devfreq)
>> +{
>> +	int err;
>> +
>> +	mutex_lock(&devfreq->lock);
>> +	err = update_devfreq(devfreq);
>> +	mutex_unlock(&devfreq->lock);
>> +	if (err)
>> +		dev_err(devfreq->dev.parent,
>> +				"failed to update frequency for PM QoS constraints (%d)\n",
> 
> Is it not over 80 char?

Yes but coding style explicitly forbids breaking strings.

>> +				err);
>> +
>> +	return NOTIFY_OK;
>> +}
>> +
>> +/**
>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>> + * @nb:		Should be devfreq->nb_min
>> + */
>> +static int qos_min_notifier_call(struct notifier_block *nb,
>> +					 unsigned long val, void *ptr)
>> +{
>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>> +}
>> +
>> +/**
>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>> + * @nb:		Should be devfreq->nb_max
>> + */
>> +static int qos_max_notifier_call(struct notifier_block *nb,
>> +					 unsigned long val, void *ptr)
>> +{
>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>> +}
>> +
>>   /**
>>    * devfreq_dev_release() - Callback for struct device to release the device.
>>    * @dev:	the devfreq device
>>    *
>>    * Remove devfreq from the list and release its resources.
>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>   
>>   	mutex_lock(&devfreq_list_lock);
>>   	list_del(&devfreq->node);
>>   	mutex_unlock(&devfreq_list_lock);
>>   
>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>> +			DEV_PM_QOS_MAX_FREQUENCY);
>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>> +			DEV_PM_QOS_MIN_FREQUENCY);
>> +
> 
> Just print error with dev_err() without stopping the release step.
> 
> I prefer to handle the return value if kernel API provides
> the error code.
> 
>>   	if (devfreq->profile->exit)
>>   		devfreq->profile->exit(devfreq->dev.parent);
>>   
>>   	kfree(devfreq->time_in_state);
>>   	kfree(devfreq->trans_table);
>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>   	if (err) {
>>   		put_device(&devfreq->dev);
>>   		goto err_out;
>>   	}
>>   
>> +	/*
>> +	 * Register notifiers for updates to min/max_freq after device is
>> +	 * initialized (and we can handle notifications) but before the
>> +	 * governor is started (which should do an initial enforcement of
>> +	 * constraints).
>> +	 */
> 
> My previous comment is not enough why I prefer to remove it. Sorry.
> Actually, until now, the devfreq_add_device() don't have the detailed
> comments because the line code is not too long. But, at the present time,
> devfreq_add_device() is too long. It means that the detailed comment
> are necessary.
> 
> So, I'll add the detailed comment for each step of devfreq_add_device()
> on separate patch to keep the same style. I'll send the patch to you
> for the review.

This is very likely to result in merge conflicts, maybe wait for my 
series to go in first?

>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>> +	if (err)
>> +		goto err_devfreq;
>> +
>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>> +	if (err)
>> +		goto err_devfreq;
>> +
>>   	mutex_lock(&devfreq_list_lock);
>>   
>>   	governor = try_then_request_governor(devfreq->governor_name);
>>   	if (IS_ERR(governor)) {
>>   		dev_err(dev, "%s: Unable to find governor for the device\n",
>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>   
>>   	return devfreq;
>>   
>>   err_init:
>>   	mutex_unlock(&devfreq_list_lock);
>> +err_devfreq:
>>   	devfreq_remove_device(devfreq);
>>   	return ERR_PTR(err);
>>   
>>   err_dev:
>>   	/*
>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>> index c3cbc15fdf08..dac0dffeabb4 100644
>> --- a/include/linux/devfreq.h
>> +++ b/include/linux/devfreq.h
>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>    * @total_trans:	Number of devfreq transitions
>>    * @trans_table:	Statistics of devfreq transitions
>>    * @time_in_state:	Statistics of devfreq states
>>    * @last_stat_updated:	The last time stat updated
>>    * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>    *
>>    * This structure stores the devfreq information for a give device.
>>    *
>>    * Note that when a governor accesses entries in struct devfreq in its
>>    * functions except for the context of callbacks defined in struct
>> @@ -176,10 +178,13 @@ struct devfreq {
>>   	unsigned int *trans_table;
>>   	unsigned long *time_in_state;
>>   	unsigned long last_stat_updated;
>>   
>>   	struct srcu_notifier_head transition_notifier_list;
>> +
>> +	struct notifier_block nb_min;
>> +	struct notifier_block nb_max;
>>   };
>>   
>>   struct devfreq_freqs {
>>   	unsigned long old;
>>   	unsigned long new;
>>
> 
> 


^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-25 21:18         ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-25 21:18 UTC (permalink / raw)
  To: Chanwoo Choi, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 25.09.2019 05:11, Chanwoo Choi wrote:
> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>> Register notifiers with the PM QoS framework in order to respond to
>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>
>> No notifiers are added by this patch but PM QoS constraints can be
>> imposed externally (for example from other devices).
>>
>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>> ---
>>   drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>   include/linux/devfreq.h   |  5 +++
>>   2 files changed, 80 insertions(+)
>>
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index eee403e70c84..784f3e40536a 100644
>> --- a/drivers/devfreq/devfreq.c
>> +++ b/drivers/devfreq/devfreq.c
>> @@ -22,15 +22,18 @@
>>   #include <linux/platform_device.h>
>>   #include <linux/list.h>
>>   #include <linux/printk.h>
>>   #include <linux/hrtimer.h>
>>   #include <linux/of.h>
>> +#include <linux/pm_qos.h>
>>   #include "governor.h"
>>   
>>   #define CREATE_TRACE_POINTS
>>   #include <trace/events/devfreq.h>
>>   
>> +#define HZ_PER_KHZ	1000
>> +
>>   static struct class *devfreq_class;
>>   
>>   /*
>>    * devfreq core provides delayed work based load monitoring helper
>>    * functions. Governors can use these or can implement their own
>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>   static void get_freq_range(struct devfreq *devfreq,
>>   			   unsigned long *min_freq,
>>   			   unsigned long *max_freq)
>>   {
>>   	unsigned long *freq_table = devfreq->profile->freq_table;
>> +	unsigned long qos_min_freq, qos_max_freq;
>>   
>>   	lockdep_assert_held(&devfreq->lock);
>>   
>>   	/*
>>   	 * Init min/max frequency from freq table.
>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>   	} else {
>>   		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>   		*max_freq = freq_table[0];
>>   	}
>>   
>> +	/* constraints from PM QoS */
> 
> As I commented on patch4,
> 'constraints' -> 'Constraint' because first verb have to be used
> as the sigular verbs.

Already discussed for another patch; I will modify to "Apply constraints 
from PM QoS" instead.

> I prefer to use following comments:
> 
> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
> 
>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>> +
>>   	/* constraints from sysfs */
>>   	*min_freq = max(*min_freq, devfreq->min_freq);
>>   	*max_freq = min(*max_freq, devfreq->max_freq);
>>   
>>   	/* constraints from OPP interface */
>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>   	mutex_unlock(&devfreq->lock);
>>   
>>   	return ret;
>>   }
>>   
>> +/**
>> + * qos_notifier_call() - Common handler for QoS constraints.
>> + * @devfreq:    the devfreq instance.
>> + */
>> +static int qos_notifier_call(struct devfreq *devfreq)
>> +{
>> +	int err;
>> +
>> +	mutex_lock(&devfreq->lock);
>> +	err = update_devfreq(devfreq);
>> +	mutex_unlock(&devfreq->lock);
>> +	if (err)
>> +		dev_err(devfreq->dev.parent,
>> +				"failed to update frequency for PM QoS constraints (%d)\n",
> 
> Is it not over 80 char?

Yes but coding style explicitly forbids breaking strings.

>> +				err);
>> +
>> +	return NOTIFY_OK;
>> +}
>> +
>> +/**
>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>> + * @nb:		Should be devfreq->nb_min
>> + */
>> +static int qos_min_notifier_call(struct notifier_block *nb,
>> +					 unsigned long val, void *ptr)
>> +{
>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>> +}
>> +
>> +/**
>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>> + * @nb:		Should be devfreq->nb_max
>> + */
>> +static int qos_max_notifier_call(struct notifier_block *nb,
>> +					 unsigned long val, void *ptr)
>> +{
>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>> +}
>> +
>>   /**
>>    * devfreq_dev_release() - Callback for struct device to release the device.
>>    * @dev:	the devfreq device
>>    *
>>    * Remove devfreq from the list and release its resources.
>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>   
>>   	mutex_lock(&devfreq_list_lock);
>>   	list_del(&devfreq->node);
>>   	mutex_unlock(&devfreq_list_lock);
>>   
>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>> +			DEV_PM_QOS_MAX_FREQUENCY);
>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>> +			DEV_PM_QOS_MIN_FREQUENCY);
>> +
> 
> Just print error with dev_err() without stopping the release step.
> 
> I prefer to handle the return value if kernel API provides
> the error code.
> 
>>   	if (devfreq->profile->exit)
>>   		devfreq->profile->exit(devfreq->dev.parent);
>>   
>>   	kfree(devfreq->time_in_state);
>>   	kfree(devfreq->trans_table);
>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>   	if (err) {
>>   		put_device(&devfreq->dev);
>>   		goto err_out;
>>   	}
>>   
>> +	/*
>> +	 * Register notifiers for updates to min/max_freq after device is
>> +	 * initialized (and we can handle notifications) but before the
>> +	 * governor is started (which should do an initial enforcement of
>> +	 * constraints).
>> +	 */
> 
> My previous comment is not enough why I prefer to remove it. Sorry.
> Actually, until now, the devfreq_add_device() don't have the detailed
> comments because the line code is not too long. But, at the present time,
> devfreq_add_device() is too long. It means that the detailed comment
> are necessary.
> 
> So, I'll add the detailed comment for each step of devfreq_add_device()
> on separate patch to keep the same style. I'll send the patch to you
> for the review.

This is very likely to result in merge conflicts, maybe wait for my 
series to go in first?

>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>> +	if (err)
>> +		goto err_devfreq;
>> +
>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>> +	if (err)
>> +		goto err_devfreq;
>> +
>>   	mutex_lock(&devfreq_list_lock);
>>   
>>   	governor = try_then_request_governor(devfreq->governor_name);
>>   	if (IS_ERR(governor)) {
>>   		dev_err(dev, "%s: Unable to find governor for the device\n",
>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>   
>>   	return devfreq;
>>   
>>   err_init:
>>   	mutex_unlock(&devfreq_list_lock);
>> +err_devfreq:
>>   	devfreq_remove_device(devfreq);
>>   	return ERR_PTR(err);
>>   
>>   err_dev:
>>   	/*
>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>> index c3cbc15fdf08..dac0dffeabb4 100644
>> --- a/include/linux/devfreq.h
>> +++ b/include/linux/devfreq.h
>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>    * @total_trans:	Number of devfreq transitions
>>    * @trans_table:	Statistics of devfreq transitions
>>    * @time_in_state:	Statistics of devfreq states
>>    * @last_stat_updated:	The last time stat updated
>>    * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>    *
>>    * This structure stores the devfreq information for a give device.
>>    *
>>    * Note that when a governor accesses entries in struct devfreq in its
>>    * functions except for the context of callbacks defined in struct
>> @@ -176,10 +178,13 @@ struct devfreq {
>>   	unsigned int *trans_table;
>>   	unsigned long *time_in_state;
>>   	unsigned long last_stat_updated;
>>   
>>   	struct srcu_notifier_head transition_notifier_list;
>> +
>> +	struct notifier_block nb_min;
>> +	struct notifier_block nb_max;
>>   };
>>   
>>   struct devfreq_freqs {
>>   	unsigned long old;
>>   	unsigned long new;
>>
> 
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
  2019-09-25  2:41       ` Chanwoo Choi
@ 2019-09-25 22:11         ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-25 22:11 UTC (permalink / raw)
  To: Chanwoo Choi, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 25.09.2019 05:36, Chanwoo Choi wrote:
> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>> Switch the handling of min_freq and max_freq from sysfs to use the
>> dev_pm_qos_request interface.
>>
>> Since PM QoS handles frequencies as kHz this change reduces the
>> precision of min_freq and max_freq. This shouldn't introduce problems
>> because frequencies which are not an integer number of kHz are likely
>> not an integer number of Hz either.
>>
>> Try to ensure compatibility by rounding min values down and rounding
>> max values up.
>>
>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>> ---
>>   drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
>>   include/linux/devfreq.h   |  9 ++++----
>>   2 files changed, 33 insertions(+), 22 deletions(-)
>>
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index 784f3e40536a..8bb7efd821ab 100644
>> --- a/drivers/devfreq/devfreq.c
>> +++ b/drivers/devfreq/devfreq.c
>> @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
>>   	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>   					     DEV_PM_QOS_MIN_FREQUENCY);
>>   	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>   	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>   
>> -	/* constraints from sysfs */
>> -	*min_freq = max(*min_freq, devfreq->min_freq);
>> -	*max_freq = min(*max_freq, devfreq->max_freq);
>> -
>>   	/* constraints from OPP interface */
>>   	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>>   	/* scaling_max_freq can be zero on error */
>>   	if (devfreq->scaling_max_freq)
>>   		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
>> @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
>>   			DEV_PM_QOS_MIN_FREQUENCY);
>>   
>>   	if (devfreq->profile->exit)
>>   		devfreq->profile->exit(devfreq->dev.parent);
>>   
>> +	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>> +	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
> 
> Please check the return value if error happen, just print the err with dev_err()
> without stopping the release steps.

OK, will print errors

>>   	kfree(devfreq->time_in_state);
>>   	kfree(devfreq->trans_table);
>>   	mutex_destroy(&devfreq->lock);
>>   	kfree(devfreq);
>>   }
>> @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>   	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
>>   	if (!devfreq->scaling_min_freq) {
>>   		err = -EINVAL;
>>   		goto err_dev;
>>   	}
>> -	devfreq->min_freq = devfreq->scaling_min_freq;
>>   
>>   	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
>>   	if (!devfreq->scaling_max_freq) {
>>   		err = -EINVAL;
>>   		goto err_dev;
>>   	}
>> -	devfreq->max_freq = devfreq->scaling_max_freq;
>> +
>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
>> +				     DEV_PM_QOS_MIN_FREQUENCY, 0);
>> +	if (err < 0)
>> +		goto err_dev;
>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
>> +				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
>> +	if (err < 0)
>> +		goto err_dev;
>>   
>>   	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
>>   	atomic_set(&devfreq->suspend_count, 0);
>>   
>>   	devfreq->trans_table = kzalloc(
>> @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>   err_dev:
>>   	/*
>>   	 * Cleanup path for errors that happen before registration.
>>   	 * Otherwise we rely on devfreq_dev_release.
>>   	 */
>> +	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
>> +		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
> 
> Please check the return value if error happen, just print the err with dev_err()
> without stopping the release steps.

OK, will print errors

> 
> 	dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");
> 
>> +	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
>> +		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
> 	
> 	dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");
> 
>>   	kfree(devfreq->time_in_state);
>>   	kfree(devfreq->trans_table);
>>   	kfree(devfreq);
>>   err_out:
>>   	return ERR_PTR(err);
>> @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>   
>>   	ret = sscanf(buf, "%lu", &value);
>>   	if (ret != 1)
>>   		return -EINVAL;
>>   
>> -	mutex_lock(&df->lock);
>> -	df->min_freq = value;
>> -	update_devfreq(df);
>> -	mutex_unlock(&df->lock);
>> +	/* round down to kHz for PM QoS */
> 
> I prefer more detailed description as following:
> 
> 	/*
> 	 * Round down to KHz to decide the proper minimum frequency
> 	 * which is closed to user request.
>   	 */
> 
> 
>> +	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
>> +					value / HZ_PER_KHZ);
>> +	if (ret < 0)
>> +		return ret;
>>   
>>   	return count;
>>   }
>>   
>>   static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>> @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>   
>>   	ret = sscanf(buf, "%lu", &value);
>>   	if (ret != 1)
>>   		return -EINVAL;
>>   
>> -	mutex_lock(&df->lock);
>> -
>> -	/* Interpret zero as "don't care" */
>> -	if (!value)
>> -		value = ULONG_MAX;
>> +	/* round up to kHz for PM QoS and interpret zero as "don't care" */
> 
> I think that "don't care" comment style is not good.
> 
> I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
> I prefer more detailed description as following:
> 	/*
> 	 * Round up to KHz to decide the proper maximum frequency
> 	 * which is closed to user request. If value is zero,
> 	 * the user does not care.
>   	 */

OK, will update this comment

>> +	if (value)
>> +		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
>> +	else
>> +		value = S32_MAX;
>>   
>> -	df->max_freq = value;
>> -	update_devfreq(df);
>> -	mutex_unlock(&df->lock);
>> +	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
>> +	if (ret < 0)
>> +		return ret;
>>   
>>   	return count;
>>   }
>>   static DEVICE_ATTR_RW(min_freq);
>>   
>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>> index dac0dffeabb4..7849fe4c666d 100644
>> --- a/include/linux/devfreq.h
>> +++ b/include/linux/devfreq.h
>> @@ -11,10 +11,11 @@
>>   #define __LINUX_DEVFREQ_H__
>>   
>>   #include <linux/device.h>
>>   #include <linux/notifier.h>
>>   #include <linux/pm_opp.h>
>> +#include <linux/pm_qos.h>
>>   
>>   #define DEVFREQ_NAME_LEN 16
>>   
>>   /* DEVFREQ governor name */
>>   #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
>> @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
>>    *		devfreq.nb to the corresponding register notifier call chain.
>>    * @work:	delayed work for load monitoring.
>>    * @previous_freq:	previously configured frequency value.
>>    * @data:	Private data of the governor. The devfreq framework does not
>>    *		touch this.
>> - * @min_freq:	Limit minimum frequency requested by user (0: none)
>> - * @max_freq:	Limit maximum frequency requested by user (0: none)
>> + * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)
> 
> min -> minimum and then remove parenthesis as following:
> 	PM QoS minimum frequency request by user via sysfs
> 
>> + * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)
> 
> ditto. max -> maximum
> 	PM QoS maximum frequency request by user via sysfs

OK

>>    * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
>>    * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
>>    * @stop_polling:	 devfreq polling status of a device.
>>    * @suspend_freq:	 frequency of a device set during suspend phase.
>>    * @resume_freq:	 frequency of a device set in resume phase.
>> @@ -161,12 +162,12 @@ struct devfreq {
>>   	unsigned long previous_freq;
>>   	struct devfreq_dev_status last_status;
>>   
>>   	void *data; /* private data for governors */
>>   
>> -	unsigned long min_freq;
>> -	unsigned long max_freq;
>> +	struct dev_pm_qos_request user_min_freq_req;
>> +	struct dev_pm_qos_request user_max_freq_req;
>>   	unsigned long scaling_min_freq;
>>   	unsigned long scaling_max_freq;
>>   	bool stop_polling;
>>   
>>   	unsigned long suspend_freq;
>>
> 
> 


^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
@ 2019-09-25 22:11         ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-25 22:11 UTC (permalink / raw)
  To: Chanwoo Choi, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 25.09.2019 05:36, Chanwoo Choi wrote:
> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>> Switch the handling of min_freq and max_freq from sysfs to use the
>> dev_pm_qos_request interface.
>>
>> Since PM QoS handles frequencies as kHz this change reduces the
>> precision of min_freq and max_freq. This shouldn't introduce problems
>> because frequencies which are not an integer number of kHz are likely
>> not an integer number of Hz either.
>>
>> Try to ensure compatibility by rounding min values down and rounding
>> max values up.
>>
>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>> ---
>>   drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
>>   include/linux/devfreq.h   |  9 ++++----
>>   2 files changed, 33 insertions(+), 22 deletions(-)
>>
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index 784f3e40536a..8bb7efd821ab 100644
>> --- a/drivers/devfreq/devfreq.c
>> +++ b/drivers/devfreq/devfreq.c
>> @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
>>   	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>   					     DEV_PM_QOS_MIN_FREQUENCY);
>>   	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>   	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>   
>> -	/* constraints from sysfs */
>> -	*min_freq = max(*min_freq, devfreq->min_freq);
>> -	*max_freq = min(*max_freq, devfreq->max_freq);
>> -
>>   	/* constraints from OPP interface */
>>   	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>>   	/* scaling_max_freq can be zero on error */
>>   	if (devfreq->scaling_max_freq)
>>   		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
>> @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
>>   			DEV_PM_QOS_MIN_FREQUENCY);
>>   
>>   	if (devfreq->profile->exit)
>>   		devfreq->profile->exit(devfreq->dev.parent);
>>   
>> +	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>> +	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
> 
> Please check the return value if error happen, just print the err with dev_err()
> without stopping the release steps.

OK, will print errors

>>   	kfree(devfreq->time_in_state);
>>   	kfree(devfreq->trans_table);
>>   	mutex_destroy(&devfreq->lock);
>>   	kfree(devfreq);
>>   }
>> @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>   	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
>>   	if (!devfreq->scaling_min_freq) {
>>   		err = -EINVAL;
>>   		goto err_dev;
>>   	}
>> -	devfreq->min_freq = devfreq->scaling_min_freq;
>>   
>>   	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
>>   	if (!devfreq->scaling_max_freq) {
>>   		err = -EINVAL;
>>   		goto err_dev;
>>   	}
>> -	devfreq->max_freq = devfreq->scaling_max_freq;
>> +
>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
>> +				     DEV_PM_QOS_MIN_FREQUENCY, 0);
>> +	if (err < 0)
>> +		goto err_dev;
>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
>> +				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
>> +	if (err < 0)
>> +		goto err_dev;
>>   
>>   	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
>>   	atomic_set(&devfreq->suspend_count, 0);
>>   
>>   	devfreq->trans_table = kzalloc(
>> @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>   err_dev:
>>   	/*
>>   	 * Cleanup path for errors that happen before registration.
>>   	 * Otherwise we rely on devfreq_dev_release.
>>   	 */
>> +	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
>> +		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
> 
> Please check the return value if error happen, just print the err with dev_err()
> without stopping the release steps.

OK, will print errors

> 
> 	dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");
> 
>> +	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
>> +		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
> 	
> 	dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");
> 
>>   	kfree(devfreq->time_in_state);
>>   	kfree(devfreq->trans_table);
>>   	kfree(devfreq);
>>   err_out:
>>   	return ERR_PTR(err);
>> @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>   
>>   	ret = sscanf(buf, "%lu", &value);
>>   	if (ret != 1)
>>   		return -EINVAL;
>>   
>> -	mutex_lock(&df->lock);
>> -	df->min_freq = value;
>> -	update_devfreq(df);
>> -	mutex_unlock(&df->lock);
>> +	/* round down to kHz for PM QoS */
> 
> I prefer more detailed description as following:
> 
> 	/*
> 	 * Round down to KHz to decide the proper minimum frequency
> 	 * which is closed to user request.
>   	 */
> 
> 
>> +	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
>> +					value / HZ_PER_KHZ);
>> +	if (ret < 0)
>> +		return ret;
>>   
>>   	return count;
>>   }
>>   
>>   static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>> @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>   
>>   	ret = sscanf(buf, "%lu", &value);
>>   	if (ret != 1)
>>   		return -EINVAL;
>>   
>> -	mutex_lock(&df->lock);
>> -
>> -	/* Interpret zero as "don't care" */
>> -	if (!value)
>> -		value = ULONG_MAX;
>> +	/* round up to kHz for PM QoS and interpret zero as "don't care" */
> 
> I think that "don't care" comment style is not good.
> 
> I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
> I prefer more detailed description as following:
> 	/*
> 	 * Round up to KHz to decide the proper maximum frequency
> 	 * which is closed to user request. If value is zero,
> 	 * the user does not care.
>   	 */

OK, will update this comment

>> +	if (value)
>> +		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
>> +	else
>> +		value = S32_MAX;
>>   
>> -	df->max_freq = value;
>> -	update_devfreq(df);
>> -	mutex_unlock(&df->lock);
>> +	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
>> +	if (ret < 0)
>> +		return ret;
>>   
>>   	return count;
>>   }
>>   static DEVICE_ATTR_RW(min_freq);
>>   
>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>> index dac0dffeabb4..7849fe4c666d 100644
>> --- a/include/linux/devfreq.h
>> +++ b/include/linux/devfreq.h
>> @@ -11,10 +11,11 @@
>>   #define __LINUX_DEVFREQ_H__
>>   
>>   #include <linux/device.h>
>>   #include <linux/notifier.h>
>>   #include <linux/pm_opp.h>
>> +#include <linux/pm_qos.h>
>>   
>>   #define DEVFREQ_NAME_LEN 16
>>   
>>   /* DEVFREQ governor name */
>>   #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
>> @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
>>    *		devfreq.nb to the corresponding register notifier call chain.
>>    * @work:	delayed work for load monitoring.
>>    * @previous_freq:	previously configured frequency value.
>>    * @data:	Private data of the governor. The devfreq framework does not
>>    *		touch this.
>> - * @min_freq:	Limit minimum frequency requested by user (0: none)
>> - * @max_freq:	Limit maximum frequency requested by user (0: none)
>> + * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)
> 
> min -> minimum and then remove parenthesis as following:
> 	PM QoS minimum frequency request by user via sysfs
> 
>> + * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)
> 
> ditto. max -> maximum
> 	PM QoS maximum frequency request by user via sysfs

OK

>>    * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
>>    * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
>>    * @stop_polling:	 devfreq polling status of a device.
>>    * @suspend_freq:	 frequency of a device set during suspend phase.
>>    * @resume_freq:	 frequency of a device set in resume phase.
>> @@ -161,12 +162,12 @@ struct devfreq {
>>   	unsigned long previous_freq;
>>   	struct devfreq_dev_status last_status;
>>   
>>   	void *data; /* private data for governors */
>>   
>> -	unsigned long min_freq;
>> -	unsigned long max_freq;
>> +	struct dev_pm_qos_request user_min_freq_req;
>> +	struct dev_pm_qos_request user_max_freq_req;
>>   	unsigned long scaling_min_freq;
>>   	unsigned long scaling_max_freq;
>>   	bool stop_polling;
>>   
>>   	unsigned long suspend_freq;
>>
> 
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 4/6] PM / devfreq: Introduce get_freq_range helper
  2019-09-25 20:55         ` Leonard Crestez
@ 2019-09-26  1:06           ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-26  1:06 UTC (permalink / raw)
  To: Leonard Crestez, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke,
	Viresh Kumar
  Cc: Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Lukasz Luba, dl-linux-imx,
	linux-pm, linux-arm-kernel

Hi,

On 19. 9. 26. 오전 5:55, Leonard Crestez wrote:
> On 25.09.2019 04:32, Chanwoo Choi wrote:
>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>> Moving handling of min/max freq to a single function and call it from
>>> update_devfreq and for printing min/max freq values in sysfs.
>>>
>>> This changes the behavior of out-of-range min_freq/max_freq: clamping
>>> is now done at evaluation time. This means that if an out-of-range
>>> constraint is imposed by sysfs and it later becomes valid then it will
>>> be enforced.
>>>
>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>> ---
>>>   drivers/devfreq/devfreq.c | 112 ++++++++++++++++++++++----------------
>>>   1 file changed, 64 insertions(+), 48 deletions(-)
>>>
>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>> index 4a878baa809e..eee403e70c84 100644
>>> --- a/drivers/devfreq/devfreq.c
>>> +++ b/drivers/devfreq/devfreq.c
>>> @@ -96,10 +96,54 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>   		dev_pm_opp_put(opp);
>>>   
>>>   	return max_freq;
>>>   }
>>>   
>>> +/**
>>> + * get_freq_range() - Get the current freq range
>>> + * @devfreq:	the devfreq instance
>>> + * @min_freq:	the min frequency
>>> + * @max_freq:	the max frequency
>>> + *
>>> + * This takes into consideration all constraints.
>>> + */
>>> +static void get_freq_range(struct devfreq *devfreq,
>>> +			   unsigned long *min_freq,
>>> +			   unsigned long *max_freq)
>>> +{
>>> +	unsigned long *freq_table = devfreq->profile->freq_table;
>>> +
>>> +	lockdep_assert_held(&devfreq->lock);
>>> +
>>> +	/*
>>> +	 * Init min/max frequency from freq table.
>>
>> Init -> Initialize
>> min/max -> minimum/maximum
>>
>>> +	 * Drivers can initialize this in either ascending or descending order
>>
>> Drivers -> devfreq drivers
>>
>>> +	 * and devfreq core supports both.
>>> +	 */
>>
>>
>> In result, I prefer to change the comments as following:
>> 	/*
>> 	 * Initialize the minimum/maximum frequency from freq_table.
>>   	 * The devfreq drivers can initialize freq_table in either
>> 	 * ascending or descending order and devfreq core supports both.
>> 	 */
> 
> OK
> 
>>> +	if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
>>> +		*min_freq = freq_table[0];
>>> +		*max_freq = freq_table[devfreq->profile->max_state - 1];
>>> +	} else {
>>> +		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>> +		*max_freq = freq_table[0];
>>> +	}
>>> +
>>> +	/* constraints from sysfs */
>>
>> 'constraints' -> Constraint because first verb have to be used
>> as the sigular verbs. Also, I think that have to enhance the comments
>> I prefer to use following comments:
>>
>> 	 /* Constraint minimum/maximum frequency from user input via sysfs */
>>
>>
>>
>>> +	*min_freq = max(*min_freq, devfreq->min_freq);
>>> +	*max_freq = min(*max_freq, devfreq->max_freq);
>>> +
>>> +	/* constraints from OPP interface */
>>
>> ditto. I prefer to use following comments:
>>
>> 	/* Constraint minimum/maximum frequency from OPP interface */
>>
>>
>>> +	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>>> +	/* scaling_max_freq can be zero on error */
>>
>> Please remove it.
>>
>>> +	if (devfreq->scaling_max_freq)
>>
>> As I knew, devfreq->scaling_max_freq is never zero.
>> So, it is always true. This if statement is needed.
> 
> It can happen if find_available_max_freq encounters an error when called 
> from devfreq_notifier_call.

If you are wondering this case, I think that have to fix
the possible issue on there instead of this point.

> 
> Maybe that should be separately fixed to set scaling_max_freq to a 
> neutral value such as "ULONG_MAX" instead?

OK.

> 
> BTW: the devfreq_notifier_call function returns -EINVAL on error but it 
> should return one of the NOTIFY_OK/DONE/STOP values instead. The OPP 
> framework ignores notifier results but (-EINVAL & NOTIFY_STOP) evaluates 
> as true so other notifiers will be skipped unintentionally.

I agree. It is needed to fix the return value type.

> 
>>> +		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
>>> +
>>> +	/* max_freq takes precedence over min_freq */
>>
>> As I said, almost people know that min_freq have be under than max_freq.
>> Please remove it. And until finishing the discussion on mailing list,
>> please don't send the next version. If you just replied from my comment
>> and then wait my next comment, we can save the time without replying
>> the repetitive and same comment for same point.
> 
> This series makes it possible to set a min_freq higher than max_freq 
> (for example via PM QoS from various devices).
> 
> It is not obvious that min_freq takes precedence over max_freq but the 
> code is self-evident so I will remove the comment.
> 
>>> +	if (*min_freq > *max_freq)
>>> +		*min_freq = *max_freq;
>>> +}
>>> +
>>>   /**
>>>    * devfreq_get_freq_level() - Lookup freq_table for the frequency
>>>    * @devfreq:	the devfreq instance
>>>    * @freq:	the target frequency
>>>    */
>>> @@ -349,20 +393,11 @@ int update_devfreq(struct devfreq *devfreq)
>>>   
>>>   	/* Reevaluate the proper frequency */
>>>   	err = devfreq->governor->get_target_freq(devfreq, &freq);
>>>   	if (err)
>>>   		return err;
>>> -
>>> -	/*
>>> -	 * Adjust the frequency with user freq, QoS and available freq.
>>> -	 *
>>> -	 * List from the highest priority
>>> -	 * max_freq
>>> -	 * min_freq
>>> -	 */
>>> -	max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
>>> -	min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
>>> +	get_freq_range(devfreq, &min_freq, &max_freq);
>>>   
>>>   	if (freq < min_freq) {
>>>   		freq = min_freq;
>>>   		flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
>>>   	}
>>> @@ -1298,40 +1333,28 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>>   	ret = sscanf(buf, "%lu", &value);
>>>   	if (ret != 1)
>>>   		return -EINVAL;
>>>   
>>>   	mutex_lock(&df->lock);
>>> -
>>> -	if (value) {
>>> -		if (value > df->max_freq) {
>>> -			ret = -EINVAL;
>>> -			goto unlock;
>>> -		}
>>> -	} else {
>>> -		unsigned long *freq_table = df->profile->freq_table;
>>> -
>>> -		/* Get minimum frequency according to sorting order */
>>> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
>>> -			value = freq_table[0];
>>> -		else
>>> -			value = freq_table[df->profile->max_state - 1];
>>> -	}
>>> -
>>>   	df->min_freq = value;
>>>   	update_devfreq(df);
>>> -	ret = count;
>>> -unlock:
>>>   	mutex_unlock(&df->lock);
>>> -	return ret;
>>> +
>>> +	return count;
>>>   }
>>>   
>>>   static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>>>   			     char *buf)
>>>   {
>>>   	struct devfreq *df = to_devfreq(dev);
>>> +	unsigned long min_freq, max_freq;
>>> +
>>> +	mutex_lock(&df->lock);
>>> +	get_freq_range(df, &min_freq, &max_freq);
>>> +	mutex_unlock(&df->lock);
>>>   
>>> -	return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
>>> +	return sprintf(buf, "%lu\n", min_freq);
>>>   }
>>>   
>>>   static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>   			      const char *buf, size_t count)
>>>   {
>>> @@ -1343,40 +1366,33 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>   	if (ret != 1)
>>>   		return -EINVAL;
>>>   
>>>   	mutex_lock(&df->lock);
>>>   
>>> -	if (value) {
>>> -		if (value < df->min_freq) {
>>> -			ret = -EINVAL;
>>> -			goto unlock;
>>> -		}
>>> -	} else {
>>> -		unsigned long *freq_table = df->profile->freq_table;
>>> -
>>> -		/* Get maximum frequency according to sorting order */
>>> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
>>> -			value = freq_table[df->profile->max_state - 1];
>>> -		else
>>> -			value = freq_table[0];
>>> -	}
>>> +	/* Interpret zero as "don't care" */
>>
>> Please remove it. Also, the detailed comment for user have to add
>> the documentation file.
> 
> OK
> 
>>
>>> +	if (!value)
>>> +		value = ULONG_MAX;
>>>   
>>>   	df->max_freq = value;
>>>   	update_devfreq(df);
>>> -	ret = count;
>>> -unlock:
>>>   	mutex_unlock(&df->lock);
>>> -	return ret;
>>> +
>>> +	return count;
>>>   }
>>>   static DEVICE_ATTR_RW(min_freq);
>>>   
>>>   static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
>>>   			     char *buf)
>>>   {
>>>   	struct devfreq *df = to_devfreq(dev);
>>> +	unsigned long min_freq, max_freq;
>>> +
>>> +	mutex_lock(&df->lock);
>>> +	get_freq_range(df, &min_freq, &max_freq);
>>> +	mutex_unlock(&df->lock);
>>>   
>>> -	return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
>>> +	return sprintf(buf, "%lu\n", max_freq);
>>>   }
>>>   static DEVICE_ATTR_RW(max_freq);
>>>   
>>>   static ssize_t available_frequencies_show(struct device *d,
>>>   					  struct device_attribute *attr,


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 4/6] PM / devfreq: Introduce get_freq_range helper
@ 2019-09-26  1:06           ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-26  1:06 UTC (permalink / raw)
  To: Leonard Crestez, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke,
	Viresh Kumar
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Alexandre Bailon,
	Georgi Djakov, linux-arm-kernel, Jacky Bai

Hi,

On 19. 9. 26. 오전 5:55, Leonard Crestez wrote:
> On 25.09.2019 04:32, Chanwoo Choi wrote:
>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>> Moving handling of min/max freq to a single function and call it from
>>> update_devfreq and for printing min/max freq values in sysfs.
>>>
>>> This changes the behavior of out-of-range min_freq/max_freq: clamping
>>> is now done at evaluation time. This means that if an out-of-range
>>> constraint is imposed by sysfs and it later becomes valid then it will
>>> be enforced.
>>>
>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>> ---
>>>   drivers/devfreq/devfreq.c | 112 ++++++++++++++++++++++----------------
>>>   1 file changed, 64 insertions(+), 48 deletions(-)
>>>
>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>> index 4a878baa809e..eee403e70c84 100644
>>> --- a/drivers/devfreq/devfreq.c
>>> +++ b/drivers/devfreq/devfreq.c
>>> @@ -96,10 +96,54 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>   		dev_pm_opp_put(opp);
>>>   
>>>   	return max_freq;
>>>   }
>>>   
>>> +/**
>>> + * get_freq_range() - Get the current freq range
>>> + * @devfreq:	the devfreq instance
>>> + * @min_freq:	the min frequency
>>> + * @max_freq:	the max frequency
>>> + *
>>> + * This takes into consideration all constraints.
>>> + */
>>> +static void get_freq_range(struct devfreq *devfreq,
>>> +			   unsigned long *min_freq,
>>> +			   unsigned long *max_freq)
>>> +{
>>> +	unsigned long *freq_table = devfreq->profile->freq_table;
>>> +
>>> +	lockdep_assert_held(&devfreq->lock);
>>> +
>>> +	/*
>>> +	 * Init min/max frequency from freq table.
>>
>> Init -> Initialize
>> min/max -> minimum/maximum
>>
>>> +	 * Drivers can initialize this in either ascending or descending order
>>
>> Drivers -> devfreq drivers
>>
>>> +	 * and devfreq core supports both.
>>> +	 */
>>
>>
>> In result, I prefer to change the comments as following:
>> 	/*
>> 	 * Initialize the minimum/maximum frequency from freq_table.
>>   	 * The devfreq drivers can initialize freq_table in either
>> 	 * ascending or descending order and devfreq core supports both.
>> 	 */
> 
> OK
> 
>>> +	if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
>>> +		*min_freq = freq_table[0];
>>> +		*max_freq = freq_table[devfreq->profile->max_state - 1];
>>> +	} else {
>>> +		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>> +		*max_freq = freq_table[0];
>>> +	}
>>> +
>>> +	/* constraints from sysfs */
>>
>> 'constraints' -> Constraint because first verb have to be used
>> as the sigular verbs. Also, I think that have to enhance the comments
>> I prefer to use following comments:
>>
>> 	 /* Constraint minimum/maximum frequency from user input via sysfs */
>>
>>
>>
>>> +	*min_freq = max(*min_freq, devfreq->min_freq);
>>> +	*max_freq = min(*max_freq, devfreq->max_freq);
>>> +
>>> +	/* constraints from OPP interface */
>>
>> ditto. I prefer to use following comments:
>>
>> 	/* Constraint minimum/maximum frequency from OPP interface */
>>
>>
>>> +	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>>> +	/* scaling_max_freq can be zero on error */
>>
>> Please remove it.
>>
>>> +	if (devfreq->scaling_max_freq)
>>
>> As I knew, devfreq->scaling_max_freq is never zero.
>> So, it is always true. This if statement is needed.
> 
> It can happen if find_available_max_freq encounters an error when called 
> from devfreq_notifier_call.

If you are wondering this case, I think that have to fix
the possible issue on there instead of this point.

> 
> Maybe that should be separately fixed to set scaling_max_freq to a 
> neutral value such as "ULONG_MAX" instead?

OK.

> 
> BTW: the devfreq_notifier_call function returns -EINVAL on error but it 
> should return one of the NOTIFY_OK/DONE/STOP values instead. The OPP 
> framework ignores notifier results but (-EINVAL & NOTIFY_STOP) evaluates 
> as true so other notifiers will be skipped unintentionally.

I agree. It is needed to fix the return value type.

> 
>>> +		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
>>> +
>>> +	/* max_freq takes precedence over min_freq */
>>
>> As I said, almost people know that min_freq have be under than max_freq.
>> Please remove it. And until finishing the discussion on mailing list,
>> please don't send the next version. If you just replied from my comment
>> and then wait my next comment, we can save the time without replying
>> the repetitive and same comment for same point.
> 
> This series makes it possible to set a min_freq higher than max_freq 
> (for example via PM QoS from various devices).
> 
> It is not obvious that min_freq takes precedence over max_freq but the 
> code is self-evident so I will remove the comment.
> 
>>> +	if (*min_freq > *max_freq)
>>> +		*min_freq = *max_freq;
>>> +}
>>> +
>>>   /**
>>>    * devfreq_get_freq_level() - Lookup freq_table for the frequency
>>>    * @devfreq:	the devfreq instance
>>>    * @freq:	the target frequency
>>>    */
>>> @@ -349,20 +393,11 @@ int update_devfreq(struct devfreq *devfreq)
>>>   
>>>   	/* Reevaluate the proper frequency */
>>>   	err = devfreq->governor->get_target_freq(devfreq, &freq);
>>>   	if (err)
>>>   		return err;
>>> -
>>> -	/*
>>> -	 * Adjust the frequency with user freq, QoS and available freq.
>>> -	 *
>>> -	 * List from the highest priority
>>> -	 * max_freq
>>> -	 * min_freq
>>> -	 */
>>> -	max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
>>> -	min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
>>> +	get_freq_range(devfreq, &min_freq, &max_freq);
>>>   
>>>   	if (freq < min_freq) {
>>>   		freq = min_freq;
>>>   		flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
>>>   	}
>>> @@ -1298,40 +1333,28 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>>   	ret = sscanf(buf, "%lu", &value);
>>>   	if (ret != 1)
>>>   		return -EINVAL;
>>>   
>>>   	mutex_lock(&df->lock);
>>> -
>>> -	if (value) {
>>> -		if (value > df->max_freq) {
>>> -			ret = -EINVAL;
>>> -			goto unlock;
>>> -		}
>>> -	} else {
>>> -		unsigned long *freq_table = df->profile->freq_table;
>>> -
>>> -		/* Get minimum frequency according to sorting order */
>>> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
>>> -			value = freq_table[0];
>>> -		else
>>> -			value = freq_table[df->profile->max_state - 1];
>>> -	}
>>> -
>>>   	df->min_freq = value;
>>>   	update_devfreq(df);
>>> -	ret = count;
>>> -unlock:
>>>   	mutex_unlock(&df->lock);
>>> -	return ret;
>>> +
>>> +	return count;
>>>   }
>>>   
>>>   static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>>>   			     char *buf)
>>>   {
>>>   	struct devfreq *df = to_devfreq(dev);
>>> +	unsigned long min_freq, max_freq;
>>> +
>>> +	mutex_lock(&df->lock);
>>> +	get_freq_range(df, &min_freq, &max_freq);
>>> +	mutex_unlock(&df->lock);
>>>   
>>> -	return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
>>> +	return sprintf(buf, "%lu\n", min_freq);
>>>   }
>>>   
>>>   static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>   			      const char *buf, size_t count)
>>>   {
>>> @@ -1343,40 +1366,33 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>   	if (ret != 1)
>>>   		return -EINVAL;
>>>   
>>>   	mutex_lock(&df->lock);
>>>   
>>> -	if (value) {
>>> -		if (value < df->min_freq) {
>>> -			ret = -EINVAL;
>>> -			goto unlock;
>>> -		}
>>> -	} else {
>>> -		unsigned long *freq_table = df->profile->freq_table;
>>> -
>>> -		/* Get maximum frequency according to sorting order */
>>> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
>>> -			value = freq_table[df->profile->max_state - 1];
>>> -		else
>>> -			value = freq_table[0];
>>> -	}
>>> +	/* Interpret zero as "don't care" */
>>
>> Please remove it. Also, the detailed comment for user have to add
>> the documentation file.
> 
> OK
> 
>>
>>> +	if (!value)
>>> +		value = ULONG_MAX;
>>>   
>>>   	df->max_freq = value;
>>>   	update_devfreq(df);
>>> -	ret = count;
>>> -unlock:
>>>   	mutex_unlock(&df->lock);
>>> -	return ret;
>>> +
>>> +	return count;
>>>   }
>>>   static DEVICE_ATTR_RW(min_freq);
>>>   
>>>   static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
>>>   			     char *buf)
>>>   {
>>>   	struct devfreq *df = to_devfreq(dev);
>>> +	unsigned long min_freq, max_freq;
>>> +
>>> +	mutex_lock(&df->lock);
>>> +	get_freq_range(df, &min_freq, &max_freq);
>>> +	mutex_unlock(&df->lock);
>>>   
>>> -	return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
>>> +	return sprintf(buf, "%lu\n", max_freq);
>>>   }
>>>   static DEVICE_ATTR_RW(max_freq);
>>>   
>>>   static ssize_t available_frequencies_show(struct device *d,
>>>   					  struct device_attribute *attr,


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-25 19:40             ` Leonard Crestez
@ 2019-09-26  1:08               ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-26  1:08 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

Hi,

On 19. 9. 26. 오전 4:40, Leonard Crestez wrote:
> On 25.09.2019 05:13, Chanwoo Choi wrote:
>> On 19. 9. 25. 오전 4:22, Leonard Crestez wrote:
>>> On 24.09.2019 22:11, Matthias Kaehlcke wrote:
>>>> On Tue, Sep 24, 2019 at 01:11:29PM +0300, Leonard Crestez wrote:
>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>
>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>> imposed externally (for example from other devices).
>>>>>
>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>> ---
>>>>>    drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>>    include/linux/devfreq.h   |  5 +++
>>>>>    2 files changed, 80 insertions(+)
>>>>>
>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>> index eee403e70c84..784f3e40536a 100644
>>>>> --- a/drivers/devfreq/devfreq.c
>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>> @@ -22,15 +22,18 @@
>>>>>    #include <linux/platform_device.h>
>>>>>    #include <linux/list.h>
>>>>>    #include <linux/printk.h>
>>>>>    #include <linux/hrtimer.h>
>>>>>    #include <linux/of.h>
>>>>> +#include <linux/pm_qos.h>
>>>>>    #include "governor.h"
>>>>>    
>>>>>    #define CREATE_TRACE_POINTS
>>>>>    #include <trace/events/devfreq.h>
>>>>>    
>>>>> +#define HZ_PER_KHZ	1000
>>>>> +
>>>>>    static struct class *devfreq_class;
>>>>>    
>>>>>    /*
>>>>>     * devfreq core provides delayed work based load monitoring helper
>>>>>     * functions. Governors can use these or can implement their own
>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>>    static void get_freq_range(struct devfreq *devfreq,
>>>>>    			   unsigned long *min_freq,
>>>>>    			   unsigned long *max_freq)
>>>>>    {
>>>>>    	unsigned long *freq_table = devfreq->profile->freq_table;
>>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>>    
>>>>>    	lockdep_assert_held(&devfreq->lock);
>>>>>    
>>>>>    	/*
>>>>>    	 * Init min/max frequency from freq table.
>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>    	} else {
>>>>>    		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>>    		*max_freq = freq_table[0];
>>>>>    	}
>>>>>    
>>>>> +	/* constraints from PM QoS */
>>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY); >
>>>> This needs to be DEV_PM_QOS_MAX_FREQUENCY. I missed this in the earlier
>>>> reviews, but stumbled across it when testing.
>>>>
>>>> !Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>
>>> I broke it in v8 while processing comments. Thanks for catching it.
>>
>> Did you test this patchset with v8?
>> Maybe it is not working with this mistake.
> 
> I ran some scripts which test that min_freq requests work as expected 
> (using imx interconnect+devfreq). They don't touch max_freq.

We always have to test the code before contributing the patch.
Please test all cases for these patches.

> 
> --
> Regards,
> Leonard
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-26  1:08               ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-26  1:08 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

Hi,

On 19. 9. 26. 오전 4:40, Leonard Crestez wrote:
> On 25.09.2019 05:13, Chanwoo Choi wrote:
>> On 19. 9. 25. 오전 4:22, Leonard Crestez wrote:
>>> On 24.09.2019 22:11, Matthias Kaehlcke wrote:
>>>> On Tue, Sep 24, 2019 at 01:11:29PM +0300, Leonard Crestez wrote:
>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>
>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>> imposed externally (for example from other devices).
>>>>>
>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>> ---
>>>>>    drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>>    include/linux/devfreq.h   |  5 +++
>>>>>    2 files changed, 80 insertions(+)
>>>>>
>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>> index eee403e70c84..784f3e40536a 100644
>>>>> --- a/drivers/devfreq/devfreq.c
>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>> @@ -22,15 +22,18 @@
>>>>>    #include <linux/platform_device.h>
>>>>>    #include <linux/list.h>
>>>>>    #include <linux/printk.h>
>>>>>    #include <linux/hrtimer.h>
>>>>>    #include <linux/of.h>
>>>>> +#include <linux/pm_qos.h>
>>>>>    #include "governor.h"
>>>>>    
>>>>>    #define CREATE_TRACE_POINTS
>>>>>    #include <trace/events/devfreq.h>
>>>>>    
>>>>> +#define HZ_PER_KHZ	1000
>>>>> +
>>>>>    static struct class *devfreq_class;
>>>>>    
>>>>>    /*
>>>>>     * devfreq core provides delayed work based load monitoring helper
>>>>>     * functions. Governors can use these or can implement their own
>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>>    static void get_freq_range(struct devfreq *devfreq,
>>>>>    			   unsigned long *min_freq,
>>>>>    			   unsigned long *max_freq)
>>>>>    {
>>>>>    	unsigned long *freq_table = devfreq->profile->freq_table;
>>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>>    
>>>>>    	lockdep_assert_held(&devfreq->lock);
>>>>>    
>>>>>    	/*
>>>>>    	 * Init min/max frequency from freq table.
>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>    	} else {
>>>>>    		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>>    		*max_freq = freq_table[0];
>>>>>    	}
>>>>>    
>>>>> +	/* constraints from PM QoS */
>>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY); >
>>>> This needs to be DEV_PM_QOS_MAX_FREQUENCY. I missed this in the earlier
>>>> reviews, but stumbled across it when testing.
>>>>
>>>> !Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>
>>> I broke it in v8 while processing comments. Thanks for catching it.
>>
>> Did you test this patchset with v8?
>> Maybe it is not working with this mistake.
> 
> I ran some scripts which test that min_freq requests work as expected 
> (using imx interconnect+devfreq). They don't touch max_freq.

We always have to test the code before contributing the patch.
Please test all cases for these patches.

> 
> --
> Regards,
> Leonard
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-25 21:18         ` Leonard Crestez
@ 2019-09-26  1:12           ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-26  1:12 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
> On 25.09.2019 05:11, Chanwoo Choi wrote:
>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>> Register notifiers with the PM QoS framework in order to respond to
>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>
>>> No notifiers are added by this patch but PM QoS constraints can be
>>> imposed externally (for example from other devices).
>>>
>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>> ---
>>>   drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>   include/linux/devfreq.h   |  5 +++
>>>   2 files changed, 80 insertions(+)
>>>
>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>> index eee403e70c84..784f3e40536a 100644
>>> --- a/drivers/devfreq/devfreq.c
>>> +++ b/drivers/devfreq/devfreq.c
>>> @@ -22,15 +22,18 @@
>>>   #include <linux/platform_device.h>
>>>   #include <linux/list.h>
>>>   #include <linux/printk.h>
>>>   #include <linux/hrtimer.h>
>>>   #include <linux/of.h>
>>> +#include <linux/pm_qos.h>
>>>   #include "governor.h"
>>>   
>>>   #define CREATE_TRACE_POINTS
>>>   #include <trace/events/devfreq.h>
>>>   
>>> +#define HZ_PER_KHZ	1000
>>> +
>>>   static struct class *devfreq_class;
>>>   
>>>   /*
>>>    * devfreq core provides delayed work based load monitoring helper
>>>    * functions. Governors can use these or can implement their own
>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>   static void get_freq_range(struct devfreq *devfreq,
>>>   			   unsigned long *min_freq,
>>>   			   unsigned long *max_freq)
>>>   {
>>>   	unsigned long *freq_table = devfreq->profile->freq_table;
>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>   
>>>   	lockdep_assert_held(&devfreq->lock);
>>>   
>>>   	/*
>>>   	 * Init min/max frequency from freq table.
>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>   	} else {
>>>   		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>   		*max_freq = freq_table[0];
>>>   	}
>>>   
>>> +	/* constraints from PM QoS */
>>
>> As I commented on patch4,
>> 'constraints' -> 'Constraint' because first verb have to be used
>> as the sigular verbs.
> 
> Already discussed for another patch; I will modify to "Apply constraints 
> from PM QoS" instead.

I agree the new comment with 'Apply constraints ... '.

> 
>> I prefer to use following comments:
>>
>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>
>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>> +
>>>   	/* constraints from sysfs */
>>>   	*min_freq = max(*min_freq, devfreq->min_freq);
>>>   	*max_freq = min(*max_freq, devfreq->max_freq);
>>>   
>>>   	/* constraints from OPP interface */
>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>   	mutex_unlock(&devfreq->lock);
>>>   
>>>   	return ret;
>>>   }
>>>   
>>> +/**
>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>> + * @devfreq:    the devfreq instance.
>>> + */
>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>> +{
>>> +	int err;
>>> +
>>> +	mutex_lock(&devfreq->lock);
>>> +	err = update_devfreq(devfreq);
>>> +	mutex_unlock(&devfreq->lock);
>>> +	if (err)
>>> +		dev_err(devfreq->dev.parent,
>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>
>> Is it not over 80 char?
> 
> Yes but coding style explicitly forbids breaking strings.
> 
>>> +				err);
>>> +
>>> +	return NOTIFY_OK;
>>> +}
>>> +
>>> +/**
>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>> + * @nb:		Should be devfreq->nb_min
>>> + */
>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>> +					 unsigned long val, void *ptr)
>>> +{
>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>> +}
>>> +
>>> +/**
>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>> + * @nb:		Should be devfreq->nb_max
>>> + */
>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>> +					 unsigned long val, void *ptr)
>>> +{
>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>> +}
>>> +
>>>   /**
>>>    * devfreq_dev_release() - Callback for struct device to release the device.
>>>    * @dev:	the devfreq device
>>>    *
>>>    * Remove devfreq from the list and release its resources.
>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>   
>>>   	mutex_lock(&devfreq_list_lock);
>>>   	list_del(&devfreq->node);
>>>   	mutex_unlock(&devfreq_list_lock);
>>>   
>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>> +
>>
>> Just print error with dev_err() without stopping the release step.
>>
>> I prefer to handle the return value if kernel API provides
>> the error code.

How about?

>>
>>>   	if (devfreq->profile->exit)
>>>   		devfreq->profile->exit(devfreq->dev.parent);
>>>   
>>>   	kfree(devfreq->time_in_state);
>>>   	kfree(devfreq->trans_table);
>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>   	if (err) {
>>>   		put_device(&devfreq->dev);
>>>   		goto err_out;
>>>   	}
>>>   
>>> +	/*
>>> +	 * Register notifiers for updates to min/max_freq after device is
>>> +	 * initialized (and we can handle notifications) but before the
>>> +	 * governor is started (which should do an initial enforcement of
>>> +	 * constraints).
>>> +	 */
>>
>> My previous comment is not enough why I prefer to remove it. Sorry.
>> Actually, until now, the devfreq_add_device() don't have the detailed
>> comments because the line code is not too long. But, at the present time,
>> devfreq_add_device() is too long. It means that the detailed comment
>> are necessary.
>>
>> So, I'll add the detailed comment for each step of devfreq_add_device()
>> on separate patch to keep the same style. I'll send the patch to you
>> for the review.
> 
> This is very likely to result in merge conflicts, maybe wait for my 
> series to go in first?

I'll send the separate patch after finished the review of these patches.
So, if you agree, please remove this comment on this patch.

You can review the detailed comments on separate patch when I send.

> 
>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>> +	if (err)
>>> +		goto err_devfreq;
>>> +
>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>> +	if (err)
>>> +		goto err_devfreq;
>>> +
>>>   	mutex_lock(&devfreq_list_lock);
>>>   
>>>   	governor = try_then_request_governor(devfreq->governor_name);
>>>   	if (IS_ERR(governor)) {
>>>   		dev_err(dev, "%s: Unable to find governor for the device\n",
>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>   
>>>   	return devfreq;
>>>   
>>>   err_init:
>>>   	mutex_unlock(&devfreq_list_lock);
>>> +err_devfreq:
>>>   	devfreq_remove_device(devfreq);
>>>   	return ERR_PTR(err);
>>>   
>>>   err_dev:
>>>   	/*
>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>> --- a/include/linux/devfreq.h
>>> +++ b/include/linux/devfreq.h
>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>    * @total_trans:	Number of devfreq transitions
>>>    * @trans_table:	Statistics of devfreq transitions
>>>    * @time_in_state:	Statistics of devfreq states
>>>    * @last_stat_updated:	The last time stat updated
>>>    * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>    *
>>>    * This structure stores the devfreq information for a give device.
>>>    *
>>>    * Note that when a governor accesses entries in struct devfreq in its
>>>    * functions except for the context of callbacks defined in struct
>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>   	unsigned int *trans_table;
>>>   	unsigned long *time_in_state;
>>>   	unsigned long last_stat_updated;
>>>   
>>>   	struct srcu_notifier_head transition_notifier_list;
>>> +
>>> +	struct notifier_block nb_min;
>>> +	struct notifier_block nb_max;
>>>   };
>>>   
>>>   struct devfreq_freqs {
>>>   	unsigned long old;
>>>   	unsigned long new;
>>>
>>
>>
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-26  1:12           ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-26  1:12 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
> On 25.09.2019 05:11, Chanwoo Choi wrote:
>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>> Register notifiers with the PM QoS framework in order to respond to
>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>
>>> No notifiers are added by this patch but PM QoS constraints can be
>>> imposed externally (for example from other devices).
>>>
>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>> ---
>>>   drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>   include/linux/devfreq.h   |  5 +++
>>>   2 files changed, 80 insertions(+)
>>>
>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>> index eee403e70c84..784f3e40536a 100644
>>> --- a/drivers/devfreq/devfreq.c
>>> +++ b/drivers/devfreq/devfreq.c
>>> @@ -22,15 +22,18 @@
>>>   #include <linux/platform_device.h>
>>>   #include <linux/list.h>
>>>   #include <linux/printk.h>
>>>   #include <linux/hrtimer.h>
>>>   #include <linux/of.h>
>>> +#include <linux/pm_qos.h>
>>>   #include "governor.h"
>>>   
>>>   #define CREATE_TRACE_POINTS
>>>   #include <trace/events/devfreq.h>
>>>   
>>> +#define HZ_PER_KHZ	1000
>>> +
>>>   static struct class *devfreq_class;
>>>   
>>>   /*
>>>    * devfreq core provides delayed work based load monitoring helper
>>>    * functions. Governors can use these or can implement their own
>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>   static void get_freq_range(struct devfreq *devfreq,
>>>   			   unsigned long *min_freq,
>>>   			   unsigned long *max_freq)
>>>   {
>>>   	unsigned long *freq_table = devfreq->profile->freq_table;
>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>   
>>>   	lockdep_assert_held(&devfreq->lock);
>>>   
>>>   	/*
>>>   	 * Init min/max frequency from freq table.
>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>   	} else {
>>>   		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>   		*max_freq = freq_table[0];
>>>   	}
>>>   
>>> +	/* constraints from PM QoS */
>>
>> As I commented on patch4,
>> 'constraints' -> 'Constraint' because first verb have to be used
>> as the sigular verbs.
> 
> Already discussed for another patch; I will modify to "Apply constraints 
> from PM QoS" instead.

I agree the new comment with 'Apply constraints ... '.

> 
>> I prefer to use following comments:
>>
>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>
>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>> +
>>>   	/* constraints from sysfs */
>>>   	*min_freq = max(*min_freq, devfreq->min_freq);
>>>   	*max_freq = min(*max_freq, devfreq->max_freq);
>>>   
>>>   	/* constraints from OPP interface */
>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>   	mutex_unlock(&devfreq->lock);
>>>   
>>>   	return ret;
>>>   }
>>>   
>>> +/**
>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>> + * @devfreq:    the devfreq instance.
>>> + */
>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>> +{
>>> +	int err;
>>> +
>>> +	mutex_lock(&devfreq->lock);
>>> +	err = update_devfreq(devfreq);
>>> +	mutex_unlock(&devfreq->lock);
>>> +	if (err)
>>> +		dev_err(devfreq->dev.parent,
>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>
>> Is it not over 80 char?
> 
> Yes but coding style explicitly forbids breaking strings.
> 
>>> +				err);
>>> +
>>> +	return NOTIFY_OK;
>>> +}
>>> +
>>> +/**
>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>> + * @nb:		Should be devfreq->nb_min
>>> + */
>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>> +					 unsigned long val, void *ptr)
>>> +{
>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>> +}
>>> +
>>> +/**
>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>> + * @nb:		Should be devfreq->nb_max
>>> + */
>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>> +					 unsigned long val, void *ptr)
>>> +{
>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>> +}
>>> +
>>>   /**
>>>    * devfreq_dev_release() - Callback for struct device to release the device.
>>>    * @dev:	the devfreq device
>>>    *
>>>    * Remove devfreq from the list and release its resources.
>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>   
>>>   	mutex_lock(&devfreq_list_lock);
>>>   	list_del(&devfreq->node);
>>>   	mutex_unlock(&devfreq_list_lock);
>>>   
>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>> +
>>
>> Just print error with dev_err() without stopping the release step.
>>
>> I prefer to handle the return value if kernel API provides
>> the error code.

How about?

>>
>>>   	if (devfreq->profile->exit)
>>>   		devfreq->profile->exit(devfreq->dev.parent);
>>>   
>>>   	kfree(devfreq->time_in_state);
>>>   	kfree(devfreq->trans_table);
>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>   	if (err) {
>>>   		put_device(&devfreq->dev);
>>>   		goto err_out;
>>>   	}
>>>   
>>> +	/*
>>> +	 * Register notifiers for updates to min/max_freq after device is
>>> +	 * initialized (and we can handle notifications) but before the
>>> +	 * governor is started (which should do an initial enforcement of
>>> +	 * constraints).
>>> +	 */
>>
>> My previous comment is not enough why I prefer to remove it. Sorry.
>> Actually, until now, the devfreq_add_device() don't have the detailed
>> comments because the line code is not too long. But, at the present time,
>> devfreq_add_device() is too long. It means that the detailed comment
>> are necessary.
>>
>> So, I'll add the detailed comment for each step of devfreq_add_device()
>> on separate patch to keep the same style. I'll send the patch to you
>> for the review.
> 
> This is very likely to result in merge conflicts, maybe wait for my 
> series to go in first?

I'll send the separate patch after finished the review of these patches.
So, if you agree, please remove this comment on this patch.

You can review the detailed comments on separate patch when I send.

> 
>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>> +	if (err)
>>> +		goto err_devfreq;
>>> +
>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>> +	if (err)
>>> +		goto err_devfreq;
>>> +
>>>   	mutex_lock(&devfreq_list_lock);
>>>   
>>>   	governor = try_then_request_governor(devfreq->governor_name);
>>>   	if (IS_ERR(governor)) {
>>>   		dev_err(dev, "%s: Unable to find governor for the device\n",
>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>   
>>>   	return devfreq;
>>>   
>>>   err_init:
>>>   	mutex_unlock(&devfreq_list_lock);
>>> +err_devfreq:
>>>   	devfreq_remove_device(devfreq);
>>>   	return ERR_PTR(err);
>>>   
>>>   err_dev:
>>>   	/*
>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>> --- a/include/linux/devfreq.h
>>> +++ b/include/linux/devfreq.h
>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>    * @total_trans:	Number of devfreq transitions
>>>    * @trans_table:	Statistics of devfreq transitions
>>>    * @time_in_state:	Statistics of devfreq states
>>>    * @last_stat_updated:	The last time stat updated
>>>    * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>    *
>>>    * This structure stores the devfreq information for a give device.
>>>    *
>>>    * Note that when a governor accesses entries in struct devfreq in its
>>>    * functions except for the context of callbacks defined in struct
>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>   	unsigned int *trans_table;
>>>   	unsigned long *time_in_state;
>>>   	unsigned long last_stat_updated;
>>>   
>>>   	struct srcu_notifier_head transition_notifier_list;
>>> +
>>> +	struct notifier_block nb_min;
>>> +	struct notifier_block nb_max;
>>>   };
>>>   
>>>   struct devfreq_freqs {
>>>   	unsigned long old;
>>>   	unsigned long new;
>>>
>>
>>
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-25 21:18         ` Leonard Crestez
@ 2019-09-26  1:19           ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-26  1:19 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
> On 25.09.2019 05:11, Chanwoo Choi wrote:
>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>> Register notifiers with the PM QoS framework in order to respond to
>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>
>>> No notifiers are added by this patch but PM QoS constraints can be
>>> imposed externally (for example from other devices).
>>>
>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>> ---
>>>   drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>   include/linux/devfreq.h   |  5 +++
>>>   2 files changed, 80 insertions(+)
>>>
>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>> index eee403e70c84..784f3e40536a 100644
>>> --- a/drivers/devfreq/devfreq.c
>>> +++ b/drivers/devfreq/devfreq.c
>>> @@ -22,15 +22,18 @@
>>>   #include <linux/platform_device.h>
>>>   #include <linux/list.h>
>>>   #include <linux/printk.h>
>>>   #include <linux/hrtimer.h>
>>>   #include <linux/of.h>
>>> +#include <linux/pm_qos.h>
>>>   #include "governor.h"
>>>   
>>>   #define CREATE_TRACE_POINTS
>>>   #include <trace/events/devfreq.h>
>>>   
>>> +#define HZ_PER_KHZ	1000
>>> +
>>>   static struct class *devfreq_class;
>>>   
>>>   /*
>>>    * devfreq core provides delayed work based load monitoring helper
>>>    * functions. Governors can use these or can implement their own
>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>   static void get_freq_range(struct devfreq *devfreq,
>>>   			   unsigned long *min_freq,
>>>   			   unsigned long *max_freq)
>>>   {
>>>   	unsigned long *freq_table = devfreq->profile->freq_table;
>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>   
>>>   	lockdep_assert_held(&devfreq->lock);
>>>   
>>>   	/*
>>>   	 * Init min/max frequency from freq table.
>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>   	} else {
>>>   		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>   		*max_freq = freq_table[0];
>>>   	}
>>>   
>>> +	/* constraints from PM QoS */
>>
>> As I commented on patch4,
>> 'constraints' -> 'Constraint' because first verb have to be used
>> as the sigular verbs.
> 
> Already discussed for another patch; I will modify to "Apply constraints 
> from PM QoS" instead.
> 
>> I prefer to use following comments:
>>
>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>
>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>> +
>>>   	/* constraints from sysfs */
>>>   	*min_freq = max(*min_freq, devfreq->min_freq);
>>>   	*max_freq = min(*max_freq, devfreq->max_freq);
>>>   
>>>   	/* constraints from OPP interface */
>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>   	mutex_unlock(&devfreq->lock);
>>>   
>>>   	return ret;
>>>   }
>>>   
>>> +/**
>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>> + * @devfreq:    the devfreq instance.
>>> + */
>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>> +{
>>> +	int err;
>>> +
>>> +	mutex_lock(&devfreq->lock);
>>> +	err = update_devfreq(devfreq);
>>> +	mutex_unlock(&devfreq->lock);
>>> +	if (err)
>>> +		dev_err(devfreq->dev.parent,
>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>
>> Is it not over 80 char?
> 
> Yes but coding style explicitly forbids breaking strings.

I want to make it within 80 char. How about following comment?

		dev_err(devfreq->dev.parent,
			"failed to update frequency from PM QoS (%d)\n",

>>> +				err);
>>> +
>>> +	return NOTIFY_OK;
>>> +}
>>> +
>>> +/**
>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>> + * @nb:		Should be devfreq->nb_min
>>> + */
>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>> +					 unsigned long val, void *ptr)
>>> +{
>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>> +}
>>> +
>>> +/**
>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>> + * @nb:		Should be devfreq->nb_max
>>> + */
>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>> +					 unsigned long val, void *ptr)
>>> +{
>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>> +}
>>> +
>>>   /**
>>>    * devfreq_dev_release() - Callback for struct device to release the device.
>>>    * @dev:	the devfreq device
>>>    *
>>>    * Remove devfreq from the list and release its resources.
>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>   
>>>   	mutex_lock(&devfreq_list_lock);
>>>   	list_del(&devfreq->node);
>>>   	mutex_unlock(&devfreq_list_lock);
>>>   
>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>> +
>>
>> Just print error with dev_err() without stopping the release step.
>>
>> I prefer to handle the return value if kernel API provides
>> the error code.
>>
>>>   	if (devfreq->profile->exit)
>>>   		devfreq->profile->exit(devfreq->dev.parent);
>>>   
>>>   	kfree(devfreq->time_in_state);
>>>   	kfree(devfreq->trans_table);
>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>   	if (err) {
>>>   		put_device(&devfreq->dev);
>>>   		goto err_out;
>>>   	}
>>>   
>>> +	/*
>>> +	 * Register notifiers for updates to min/max_freq after device is
>>> +	 * initialized (and we can handle notifications) but before the
>>> +	 * governor is started (which should do an initial enforcement of
>>> +	 * constraints).
>>> +	 */
>>
>> My previous comment is not enough why I prefer to remove it. Sorry.
>> Actually, until now, the devfreq_add_device() don't have the detailed
>> comments because the line code is not too long. But, at the present time,
>> devfreq_add_device() is too long. It means that the detailed comment
>> are necessary.
>>
>> So, I'll add the detailed comment for each step of devfreq_add_device()
>> on separate patch to keep the same style. I'll send the patch to you
>> for the review.
> 
> This is very likely to result in merge conflicts, maybe wait for my 
> series to go in first?
> 
>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>> +	if (err)
>>> +		goto err_devfreq;
>>> +
>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>> +	if (err)
>>> +		goto err_devfreq;
>>> +
>>>   	mutex_lock(&devfreq_list_lock);
>>>   
>>>   	governor = try_then_request_governor(devfreq->governor_name);
>>>   	if (IS_ERR(governor)) {
>>>   		dev_err(dev, "%s: Unable to find governor for the device\n",
>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>   
>>>   	return devfreq;
>>>   
>>>   err_init:
>>>   	mutex_unlock(&devfreq_list_lock);
>>> +err_devfreq:
>>>   	devfreq_remove_device(devfreq);
>>>   	return ERR_PTR(err);
>>>   
>>>   err_dev:
>>>   	/*
>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>> --- a/include/linux/devfreq.h
>>> +++ b/include/linux/devfreq.h
>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>    * @total_trans:	Number of devfreq transitions
>>>    * @trans_table:	Statistics of devfreq transitions
>>>    * @time_in_state:	Statistics of devfreq states
>>>    * @last_stat_updated:	The last time stat updated
>>>    * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>    *
>>>    * This structure stores the devfreq information for a give device.
>>>    *
>>>    * Note that when a governor accesses entries in struct devfreq in its
>>>    * functions except for the context of callbacks defined in struct
>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>   	unsigned int *trans_table;
>>>   	unsigned long *time_in_state;
>>>   	unsigned long last_stat_updated;
>>>   
>>>   	struct srcu_notifier_head transition_notifier_list;
>>> +
>>> +	struct notifier_block nb_min;
>>> +	struct notifier_block nb_max;
>>>   };
>>>   
>>>   struct devfreq_freqs {
>>>   	unsigned long old;
>>>   	unsigned long new;
>>>
>>
>>
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-26  1:19           ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-26  1:19 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
> On 25.09.2019 05:11, Chanwoo Choi wrote:
>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>> Register notifiers with the PM QoS framework in order to respond to
>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>
>>> No notifiers are added by this patch but PM QoS constraints can be
>>> imposed externally (for example from other devices).
>>>
>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>> ---
>>>   drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>   include/linux/devfreq.h   |  5 +++
>>>   2 files changed, 80 insertions(+)
>>>
>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>> index eee403e70c84..784f3e40536a 100644
>>> --- a/drivers/devfreq/devfreq.c
>>> +++ b/drivers/devfreq/devfreq.c
>>> @@ -22,15 +22,18 @@
>>>   #include <linux/platform_device.h>
>>>   #include <linux/list.h>
>>>   #include <linux/printk.h>
>>>   #include <linux/hrtimer.h>
>>>   #include <linux/of.h>
>>> +#include <linux/pm_qos.h>
>>>   #include "governor.h"
>>>   
>>>   #define CREATE_TRACE_POINTS
>>>   #include <trace/events/devfreq.h>
>>>   
>>> +#define HZ_PER_KHZ	1000
>>> +
>>>   static struct class *devfreq_class;
>>>   
>>>   /*
>>>    * devfreq core provides delayed work based load monitoring helper
>>>    * functions. Governors can use these or can implement their own
>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>   static void get_freq_range(struct devfreq *devfreq,
>>>   			   unsigned long *min_freq,
>>>   			   unsigned long *max_freq)
>>>   {
>>>   	unsigned long *freq_table = devfreq->profile->freq_table;
>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>   
>>>   	lockdep_assert_held(&devfreq->lock);
>>>   
>>>   	/*
>>>   	 * Init min/max frequency from freq table.
>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>   	} else {
>>>   		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>   		*max_freq = freq_table[0];
>>>   	}
>>>   
>>> +	/* constraints from PM QoS */
>>
>> As I commented on patch4,
>> 'constraints' -> 'Constraint' because first verb have to be used
>> as the sigular verbs.
> 
> Already discussed for another patch; I will modify to "Apply constraints 
> from PM QoS" instead.
> 
>> I prefer to use following comments:
>>
>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>
>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>> +
>>>   	/* constraints from sysfs */
>>>   	*min_freq = max(*min_freq, devfreq->min_freq);
>>>   	*max_freq = min(*max_freq, devfreq->max_freq);
>>>   
>>>   	/* constraints from OPP interface */
>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>   	mutex_unlock(&devfreq->lock);
>>>   
>>>   	return ret;
>>>   }
>>>   
>>> +/**
>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>> + * @devfreq:    the devfreq instance.
>>> + */
>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>> +{
>>> +	int err;
>>> +
>>> +	mutex_lock(&devfreq->lock);
>>> +	err = update_devfreq(devfreq);
>>> +	mutex_unlock(&devfreq->lock);
>>> +	if (err)
>>> +		dev_err(devfreq->dev.parent,
>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>
>> Is it not over 80 char?
> 
> Yes but coding style explicitly forbids breaking strings.

I want to make it within 80 char. How about following comment?

		dev_err(devfreq->dev.parent,
			"failed to update frequency from PM QoS (%d)\n",

>>> +				err);
>>> +
>>> +	return NOTIFY_OK;
>>> +}
>>> +
>>> +/**
>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>> + * @nb:		Should be devfreq->nb_min
>>> + */
>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>> +					 unsigned long val, void *ptr)
>>> +{
>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>> +}
>>> +
>>> +/**
>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>> + * @nb:		Should be devfreq->nb_max
>>> + */
>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>> +					 unsigned long val, void *ptr)
>>> +{
>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>> +}
>>> +
>>>   /**
>>>    * devfreq_dev_release() - Callback for struct device to release the device.
>>>    * @dev:	the devfreq device
>>>    *
>>>    * Remove devfreq from the list and release its resources.
>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>   
>>>   	mutex_lock(&devfreq_list_lock);
>>>   	list_del(&devfreq->node);
>>>   	mutex_unlock(&devfreq_list_lock);
>>>   
>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>> +
>>
>> Just print error with dev_err() without stopping the release step.
>>
>> I prefer to handle the return value if kernel API provides
>> the error code.
>>
>>>   	if (devfreq->profile->exit)
>>>   		devfreq->profile->exit(devfreq->dev.parent);
>>>   
>>>   	kfree(devfreq->time_in_state);
>>>   	kfree(devfreq->trans_table);
>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>   	if (err) {
>>>   		put_device(&devfreq->dev);
>>>   		goto err_out;
>>>   	}
>>>   
>>> +	/*
>>> +	 * Register notifiers for updates to min/max_freq after device is
>>> +	 * initialized (and we can handle notifications) but before the
>>> +	 * governor is started (which should do an initial enforcement of
>>> +	 * constraints).
>>> +	 */
>>
>> My previous comment is not enough why I prefer to remove it. Sorry.
>> Actually, until now, the devfreq_add_device() don't have the detailed
>> comments because the line code is not too long. But, at the present time,
>> devfreq_add_device() is too long. It means that the detailed comment
>> are necessary.
>>
>> So, I'll add the detailed comment for each step of devfreq_add_device()
>> on separate patch to keep the same style. I'll send the patch to you
>> for the review.
> 
> This is very likely to result in merge conflicts, maybe wait for my 
> series to go in first?
> 
>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>> +	if (err)
>>> +		goto err_devfreq;
>>> +
>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>> +	if (err)
>>> +		goto err_devfreq;
>>> +
>>>   	mutex_lock(&devfreq_list_lock);
>>>   
>>>   	governor = try_then_request_governor(devfreq->governor_name);
>>>   	if (IS_ERR(governor)) {
>>>   		dev_err(dev, "%s: Unable to find governor for the device\n",
>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>   
>>>   	return devfreq;
>>>   
>>>   err_init:
>>>   	mutex_unlock(&devfreq_list_lock);
>>> +err_devfreq:
>>>   	devfreq_remove_device(devfreq);
>>>   	return ERR_PTR(err);
>>>   
>>>   err_dev:
>>>   	/*
>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>> --- a/include/linux/devfreq.h
>>> +++ b/include/linux/devfreq.h
>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>    * @total_trans:	Number of devfreq transitions
>>>    * @trans_table:	Statistics of devfreq transitions
>>>    * @time_in_state:	Statistics of devfreq states
>>>    * @last_stat_updated:	The last time stat updated
>>>    * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>    *
>>>    * This structure stores the devfreq information for a give device.
>>>    *
>>>    * Note that when a governor accesses entries in struct devfreq in its
>>>    * functions except for the context of callbacks defined in struct
>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>   	unsigned int *trans_table;
>>>   	unsigned long *time_in_state;
>>>   	unsigned long last_stat_updated;
>>>   
>>>   	struct srcu_notifier_head transition_notifier_list;
>>> +
>>> +	struct notifier_block nb_min;
>>> +	struct notifier_block nb_max;
>>>   };
>>>   
>>>   struct devfreq_freqs {
>>>   	unsigned long old;
>>>   	unsigned long new;
>>>
>>
>>
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
  2019-09-25 16:45         ` Matthias Kaehlcke
@ 2019-09-26  1:25           ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-26  1:25 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: Leonard Crestez, MyungJoo Ham, Kyungmin Park,
	Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

On 19. 9. 26. 오전 1:45, Matthias Kaehlcke wrote:
> On Wed, Sep 25, 2019 at 11:41:07AM +0900, Chanwoo Choi wrote:
>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>> Switch the handling of min_freq and max_freq from sysfs to use the
>>> dev_pm_qos_request interface.
>>>
>>> Since PM QoS handles frequencies as kHz this change reduces the
>>> precision of min_freq and max_freq. This shouldn't introduce problems
>>> because frequencies which are not an integer number of kHz are likely
>>> not an integer number of Hz either.
>>>
>>> Try to ensure compatibility by rounding min values down and rounding
>>> max values up.
>>>
>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>> ---
>>>  drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
>>>  include/linux/devfreq.h   |  9 ++++----
>>>  2 files changed, 33 insertions(+), 22 deletions(-)
>>>
>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>> index 784f3e40536a..8bb7efd821ab 100644
>>> --- a/drivers/devfreq/devfreq.c
>>> +++ b/drivers/devfreq/devfreq.c
>>> @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
>>>  	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>  					     DEV_PM_QOS_MIN_FREQUENCY);
>>>  	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>  	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>  
>>> -	/* constraints from sysfs */
>>> -	*min_freq = max(*min_freq, devfreq->min_freq);
>>> -	*max_freq = min(*max_freq, devfreq->max_freq);
>>> -
>>>  	/* constraints from OPP interface */
>>>  	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>>>  	/* scaling_max_freq can be zero on error */
>>>  	if (devfreq->scaling_max_freq)
>>>  		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
>>> @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
>>>  			DEV_PM_QOS_MIN_FREQUENCY);
>>>  
>>>  	if (devfreq->profile->exit)
>>>  		devfreq->profile->exit(devfreq->dev.parent);
>>>  
>>> +	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>>> +	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
>>
>> Please check the return value if error happen, just print the err with dev_err()
>> without stopping the release steps.
> 
> I wonder if dev_warn() would be more appropriate, since the current operation
> is not aborted.
> 
>>>  	kfree(devfreq->time_in_state);
>>>  	kfree(devfreq->trans_table);
>>>  	mutex_destroy(&devfreq->lock);
>>>  	kfree(devfreq);
>>>  }
>>> @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>  	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
>>>  	if (!devfreq->scaling_min_freq) {
>>>  		err = -EINVAL;
>>>  		goto err_dev;
>>>  	}
>>> -	devfreq->min_freq = devfreq->scaling_min_freq;
>>>  
>>>  	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
>>>  	if (!devfreq->scaling_max_freq) {
>>>  		err = -EINVAL;
>>>  		goto err_dev;
>>>  	}
>>> -	devfreq->max_freq = devfreq->scaling_max_freq;
>>> +
>>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
>>> +				     DEV_PM_QOS_MIN_FREQUENCY, 0);
>>> +	if (err < 0)
>>> +		goto err_dev;
>>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
>>> +				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
>>> +	if (err < 0)
>>> +		goto err_dev;
>>>  
>>>  	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
>>>  	atomic_set(&devfreq->suspend_count, 0);
>>>  
>>>  	devfreq->trans_table = kzalloc(
>>> @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>  err_dev:
>>>  	/*
>>>  	 * Cleanup path for errors that happen before registration.
>>>  	 * Otherwise we rely on devfreq_dev_release.
>>>  	 */
>>> +	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
>>> +		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>>
>> Please check the return value if error happen, just print the err with dev_err()
>> without stopping the release steps.
>>
>> 	dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");
> 
> dev_warn() for the same reason as above?

Actually, I think that is not critical error but need to print the error
So, I think that dev_err() is enough. If this thing is critical,
better to use dev_warn.

> 
> I think the message would be better with a slight change:
> 
> "failed to remove DEV_PM_QOS_MAX_FREQUENCY request\n"

OK.

> 
>>
>>> +	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
>>> +		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
>> 	
>> 	dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");
> 
> ditto
> 
>>>  	kfree(devfreq->time_in_state);
>>>  	kfree(devfreq->trans_table);
>>>  	kfree(devfreq);
>>>  err_out:
>>>  	return ERR_PTR(err);
>>> @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>>  
>>>  	ret = sscanf(buf, "%lu", &value);
>>>  	if (ret != 1)
>>>  		return -EINVAL;
>>>  
>>> -	mutex_lock(&df->lock);
>>> -	df->min_freq = value;
>>> -	update_devfreq(df);
>>> -	mutex_unlock(&df->lock);
>>> +	/* round down to kHz for PM QoS */
>>
>> I prefer more detailed description as following:
>>
>> 	/*
>> 	 * Round down to KHz to decide the proper minimum frequency
> 
> it should be kHz, with a lower-case 'k', as in the original comment.

Good.

> 
>> 	 * which is closed to user request.
>>  	 */
> 
> The comment you suggest doesn't provide any information about why the
> conversion to kHz is done, in this sense the original comment that
> mentions PM QoS provides more value.
> 
> With whatever we end up, I suggest to use 'convert' instead of
> 'round down'.

I agree to use 'convert' instead of 'round down'
if some expression indicates the correct meaning.

> 
>>> +	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
>>> +					value / HZ_PER_KHZ);
>>> +	if (ret < 0)
>>> +		return ret;
>>>  
>>>  	return count;
>>>  }
>>>  
>>>  static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>>> @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>  
>>>  	ret = sscanf(buf, "%lu", &value);
>>>  	if (ret != 1)
>>>  		return -EINVAL;
>>>  
>>> -	mutex_lock(&df->lock);
>>> -
>>> -	/* Interpret zero as "don't care" */
>>> -	if (!value)
>>> -		value = ULONG_MAX;
>>> +	/* round up to kHz for PM QoS and interpret zero as "don't care" */
>>
>> I think that "don't care" comment style is not good.
>>
>> I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
>> I prefer more detailed description as following:
>> 	/*
>> 	 * Round up to KHz to decide the proper maximum frequency
> 
> kHz
> 
>> 	 * which is closed to user request. If value is zero,
>> 	 * the user does not care.
> 
> "the user does not care" is still very casual you didn't like initially.
> How about "A value of zero is interpreted as 'no limit'."?
> 
> As for the min freq, I think PM QoS should be mentioned to make clear why
> the conversion to kHz is needed.

Agree. I expect that Leonard will mention that.

> 
>>  	 */
>>
>>
>>> +	if (value)
>>> +		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
>>> +	else
>>> +		value = S32_MAX;
>>>  
>>> -	df->max_freq = value;
>>> -	update_devfreq(df);
>>> -	mutex_unlock(&df->lock);
>>> +	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
>>> +	if (ret < 0)
>>> +		return ret;
>>>  
>>>  	return count;
>>>  }
>>>  static DEVICE_ATTR_RW(min_freq);
>>>  
>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>> index dac0dffeabb4..7849fe4c666d 100644
>>> --- a/include/linux/devfreq.h
>>> +++ b/include/linux/devfreq.h
>>> @@ -11,10 +11,11 @@
>>>  #define __LINUX_DEVFREQ_H__
>>>  
>>>  #include <linux/device.h>
>>>  #include <linux/notifier.h>
>>>  #include <linux/pm_opp.h>
>>> +#include <linux/pm_qos.h>
>>>  
>>>  #define DEVFREQ_NAME_LEN 16
>>>  
>>>  /* DEVFREQ governor name */
>>>  #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
>>> @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
>>>   *		devfreq.nb to the corresponding register notifier call chain.
>>>   * @work:	delayed work for load monitoring.
>>>   * @previous_freq:	previously configured frequency value.
>>>   * @data:	Private data of the governor. The devfreq framework does not
>>>   *		touch this.
>>> - * @min_freq:	Limit minimum frequency requested by user (0: none)
>>> - * @max_freq:	Limit maximum frequency requested by user (0: none)
>>> + * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)
>>
>> min -> minimum and then remove parenthesis as following:
>> 	PM QoS minimum frequency request by user via sysfs
>>
>>> + * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)
>>
>> ditto. max -> maximum
>> 	PM QoS maximum frequency request by user via sysfs
>>
>>>   * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
>>>   * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
>>>   * @stop_polling:	 devfreq polling status of a device.
>>>   * @suspend_freq:	 frequency of a device set during suspend phase.
>>>   * @resume_freq:	 frequency of a device set in resume phase.
>>> @@ -161,12 +162,12 @@ struct devfreq {
>>>  	unsigned long previous_freq;
>>>  	struct devfreq_dev_status last_status;
>>>  
>>>  	void *data; /* private data for governors */
>>>  
>>> -	unsigned long min_freq;
>>> -	unsigned long max_freq;
>>> +	struct dev_pm_qos_request user_min_freq_req;
>>> +	struct dev_pm_qos_request user_max_freq_req;
>>>  	unsigned long scaling_min_freq;
>>>  	unsigned long scaling_max_freq;
>>>  	bool stop_polling;
>>>  
>>>  	unsigned long suspend_freq;
>>>
>>
>>
>> -- 
>> Best Regards,
>> Chanwoo Choi
>> Samsung Electronics
> 
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
@ 2019-09-26  1:25           ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-26  1:25 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park,
	MyungJoo Ham, Alexandre Bailon, Leonard Crestez, Georgi Djakov,
	linux-arm-kernel, Jacky Bai

On 19. 9. 26. 오전 1:45, Matthias Kaehlcke wrote:
> On Wed, Sep 25, 2019 at 11:41:07AM +0900, Chanwoo Choi wrote:
>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>> Switch the handling of min_freq and max_freq from sysfs to use the
>>> dev_pm_qos_request interface.
>>>
>>> Since PM QoS handles frequencies as kHz this change reduces the
>>> precision of min_freq and max_freq. This shouldn't introduce problems
>>> because frequencies which are not an integer number of kHz are likely
>>> not an integer number of Hz either.
>>>
>>> Try to ensure compatibility by rounding min values down and rounding
>>> max values up.
>>>
>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>> ---
>>>  drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
>>>  include/linux/devfreq.h   |  9 ++++----
>>>  2 files changed, 33 insertions(+), 22 deletions(-)
>>>
>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>> index 784f3e40536a..8bb7efd821ab 100644
>>> --- a/drivers/devfreq/devfreq.c
>>> +++ b/drivers/devfreq/devfreq.c
>>> @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
>>>  	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>  					     DEV_PM_QOS_MIN_FREQUENCY);
>>>  	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>  	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>  
>>> -	/* constraints from sysfs */
>>> -	*min_freq = max(*min_freq, devfreq->min_freq);
>>> -	*max_freq = min(*max_freq, devfreq->max_freq);
>>> -
>>>  	/* constraints from OPP interface */
>>>  	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>>>  	/* scaling_max_freq can be zero on error */
>>>  	if (devfreq->scaling_max_freq)
>>>  		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
>>> @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
>>>  			DEV_PM_QOS_MIN_FREQUENCY);
>>>  
>>>  	if (devfreq->profile->exit)
>>>  		devfreq->profile->exit(devfreq->dev.parent);
>>>  
>>> +	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>>> +	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
>>
>> Please check the return value if error happen, just print the err with dev_err()
>> without stopping the release steps.
> 
> I wonder if dev_warn() would be more appropriate, since the current operation
> is not aborted.
> 
>>>  	kfree(devfreq->time_in_state);
>>>  	kfree(devfreq->trans_table);
>>>  	mutex_destroy(&devfreq->lock);
>>>  	kfree(devfreq);
>>>  }
>>> @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>  	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
>>>  	if (!devfreq->scaling_min_freq) {
>>>  		err = -EINVAL;
>>>  		goto err_dev;
>>>  	}
>>> -	devfreq->min_freq = devfreq->scaling_min_freq;
>>>  
>>>  	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
>>>  	if (!devfreq->scaling_max_freq) {
>>>  		err = -EINVAL;
>>>  		goto err_dev;
>>>  	}
>>> -	devfreq->max_freq = devfreq->scaling_max_freq;
>>> +
>>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
>>> +				     DEV_PM_QOS_MIN_FREQUENCY, 0);
>>> +	if (err < 0)
>>> +		goto err_dev;
>>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
>>> +				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
>>> +	if (err < 0)
>>> +		goto err_dev;
>>>  
>>>  	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
>>>  	atomic_set(&devfreq->suspend_count, 0);
>>>  
>>>  	devfreq->trans_table = kzalloc(
>>> @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>  err_dev:
>>>  	/*
>>>  	 * Cleanup path for errors that happen before registration.
>>>  	 * Otherwise we rely on devfreq_dev_release.
>>>  	 */
>>> +	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
>>> +		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>>
>> Please check the return value if error happen, just print the err with dev_err()
>> without stopping the release steps.
>>
>> 	dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");
> 
> dev_warn() for the same reason as above?

Actually, I think that is not critical error but need to print the error
So, I think that dev_err() is enough. If this thing is critical,
better to use dev_warn.

> 
> I think the message would be better with a slight change:
> 
> "failed to remove DEV_PM_QOS_MAX_FREQUENCY request\n"

OK.

> 
>>
>>> +	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
>>> +		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
>> 	
>> 	dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");
> 
> ditto
> 
>>>  	kfree(devfreq->time_in_state);
>>>  	kfree(devfreq->trans_table);
>>>  	kfree(devfreq);
>>>  err_out:
>>>  	return ERR_PTR(err);
>>> @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>>  
>>>  	ret = sscanf(buf, "%lu", &value);
>>>  	if (ret != 1)
>>>  		return -EINVAL;
>>>  
>>> -	mutex_lock(&df->lock);
>>> -	df->min_freq = value;
>>> -	update_devfreq(df);
>>> -	mutex_unlock(&df->lock);
>>> +	/* round down to kHz for PM QoS */
>>
>> I prefer more detailed description as following:
>>
>> 	/*
>> 	 * Round down to KHz to decide the proper minimum frequency
> 
> it should be kHz, with a lower-case 'k', as in the original comment.

Good.

> 
>> 	 * which is closed to user request.
>>  	 */
> 
> The comment you suggest doesn't provide any information about why the
> conversion to kHz is done, in this sense the original comment that
> mentions PM QoS provides more value.
> 
> With whatever we end up, I suggest to use 'convert' instead of
> 'round down'.

I agree to use 'convert' instead of 'round down'
if some expression indicates the correct meaning.

> 
>>> +	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
>>> +					value / HZ_PER_KHZ);
>>> +	if (ret < 0)
>>> +		return ret;
>>>  
>>>  	return count;
>>>  }
>>>  
>>>  static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>>> @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>  
>>>  	ret = sscanf(buf, "%lu", &value);
>>>  	if (ret != 1)
>>>  		return -EINVAL;
>>>  
>>> -	mutex_lock(&df->lock);
>>> -
>>> -	/* Interpret zero as "don't care" */
>>> -	if (!value)
>>> -		value = ULONG_MAX;
>>> +	/* round up to kHz for PM QoS and interpret zero as "don't care" */
>>
>> I think that "don't care" comment style is not good.
>>
>> I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
>> I prefer more detailed description as following:
>> 	/*
>> 	 * Round up to KHz to decide the proper maximum frequency
> 
> kHz
> 
>> 	 * which is closed to user request. If value is zero,
>> 	 * the user does not care.
> 
> "the user does not care" is still very casual you didn't like initially.
> How about "A value of zero is interpreted as 'no limit'."?
> 
> As for the min freq, I think PM QoS should be mentioned to make clear why
> the conversion to kHz is needed.

Agree. I expect that Leonard will mention that.

> 
>>  	 */
>>
>>
>>> +	if (value)
>>> +		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
>>> +	else
>>> +		value = S32_MAX;
>>>  
>>> -	df->max_freq = value;
>>> -	update_devfreq(df);
>>> -	mutex_unlock(&df->lock);
>>> +	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
>>> +	if (ret < 0)
>>> +		return ret;
>>>  
>>>  	return count;
>>>  }
>>>  static DEVICE_ATTR_RW(min_freq);
>>>  
>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>> index dac0dffeabb4..7849fe4c666d 100644
>>> --- a/include/linux/devfreq.h
>>> +++ b/include/linux/devfreq.h
>>> @@ -11,10 +11,11 @@
>>>  #define __LINUX_DEVFREQ_H__
>>>  
>>>  #include <linux/device.h>
>>>  #include <linux/notifier.h>
>>>  #include <linux/pm_opp.h>
>>> +#include <linux/pm_qos.h>
>>>  
>>>  #define DEVFREQ_NAME_LEN 16
>>>  
>>>  /* DEVFREQ governor name */
>>>  #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
>>> @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
>>>   *		devfreq.nb to the corresponding register notifier call chain.
>>>   * @work:	delayed work for load monitoring.
>>>   * @previous_freq:	previously configured frequency value.
>>>   * @data:	Private data of the governor. The devfreq framework does not
>>>   *		touch this.
>>> - * @min_freq:	Limit minimum frequency requested by user (0: none)
>>> - * @max_freq:	Limit maximum frequency requested by user (0: none)
>>> + * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)
>>
>> min -> minimum and then remove parenthesis as following:
>> 	PM QoS minimum frequency request by user via sysfs
>>
>>> + * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)
>>
>> ditto. max -> maximum
>> 	PM QoS maximum frequency request by user via sysfs
>>
>>>   * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
>>>   * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
>>>   * @stop_polling:	 devfreq polling status of a device.
>>>   * @suspend_freq:	 frequency of a device set during suspend phase.
>>>   * @resume_freq:	 frequency of a device set in resume phase.
>>> @@ -161,12 +162,12 @@ struct devfreq {
>>>  	unsigned long previous_freq;
>>>  	struct devfreq_dev_status last_status;
>>>  
>>>  	void *data; /* private data for governors */
>>>  
>>> -	unsigned long min_freq;
>>> -	unsigned long max_freq;
>>> +	struct dev_pm_qos_request user_min_freq_req;
>>> +	struct dev_pm_qos_request user_max_freq_req;
>>>  	unsigned long scaling_min_freq;
>>>  	unsigned long scaling_max_freq;
>>>  	bool stop_polling;
>>>  
>>>  	unsigned long suspend_freq;
>>>
>>
>>
>> -- 
>> Best Regards,
>> Chanwoo Choi
>> Samsung Electronics
> 
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
  2019-09-25 22:11         ` Leonard Crestez
@ 2019-09-26  1:26           ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-26  1:26 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 19. 9. 26. 오전 7:11, Leonard Crestez wrote:
> On 25.09.2019 05:36, Chanwoo Choi wrote:
>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>> Switch the handling of min_freq and max_freq from sysfs to use the
>>> dev_pm_qos_request interface.
>>>
>>> Since PM QoS handles frequencies as kHz this change reduces the
>>> precision of min_freq and max_freq. This shouldn't introduce problems
>>> because frequencies which are not an integer number of kHz are likely
>>> not an integer number of Hz either.
>>>
>>> Try to ensure compatibility by rounding min values down and rounding
>>> max values up.
>>>
>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>> ---
>>>   drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
>>>   include/linux/devfreq.h   |  9 ++++----
>>>   2 files changed, 33 insertions(+), 22 deletions(-)
>>>
>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>> index 784f3e40536a..8bb7efd821ab 100644
>>> --- a/drivers/devfreq/devfreq.c
>>> +++ b/drivers/devfreq/devfreq.c
>>> @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
>>>   	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>   					     DEV_PM_QOS_MIN_FREQUENCY);
>>>   	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>   	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>   
>>> -	/* constraints from sysfs */
>>> -	*min_freq = max(*min_freq, devfreq->min_freq);
>>> -	*max_freq = min(*max_freq, devfreq->max_freq);
>>> -
>>>   	/* constraints from OPP interface */
>>>   	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>>>   	/* scaling_max_freq can be zero on error */
>>>   	if (devfreq->scaling_max_freq)
>>>   		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
>>> @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
>>>   			DEV_PM_QOS_MIN_FREQUENCY);
>>>   
>>>   	if (devfreq->profile->exit)
>>>   		devfreq->profile->exit(devfreq->dev.parent);
>>>   
>>> +	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>>> +	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
>>
>> Please check the return value if error happen, just print the err with dev_err()
>> without stopping the release steps.
> 
> OK, will print errors
> 
>>>   	kfree(devfreq->time_in_state);
>>>   	kfree(devfreq->trans_table);
>>>   	mutex_destroy(&devfreq->lock);
>>>   	kfree(devfreq);
>>>   }
>>> @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>   	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
>>>   	if (!devfreq->scaling_min_freq) {
>>>   		err = -EINVAL;
>>>   		goto err_dev;
>>>   	}
>>> -	devfreq->min_freq = devfreq->scaling_min_freq;
>>>   
>>>   	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
>>>   	if (!devfreq->scaling_max_freq) {
>>>   		err = -EINVAL;
>>>   		goto err_dev;
>>>   	}
>>> -	devfreq->max_freq = devfreq->scaling_max_freq;
>>> +
>>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
>>> +				     DEV_PM_QOS_MIN_FREQUENCY, 0);
>>> +	if (err < 0)
>>> +		goto err_dev;
>>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
>>> +				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
>>> +	if (err < 0)
>>> +		goto err_dev;
>>>   
>>>   	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
>>>   	atomic_set(&devfreq->suspend_count, 0);
>>>   
>>>   	devfreq->trans_table = kzalloc(
>>> @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>   err_dev:
>>>   	/*
>>>   	 * Cleanup path for errors that happen before registration.
>>>   	 * Otherwise we rely on devfreq_dev_release.
>>>   	 */
>>> +	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
>>> +		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>>
>> Please check the return value if error happen, just print the err with dev_err()
>> without stopping the release steps.
> 
> OK, will print errors
> 
>>
>> 	dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");
>>
>>> +	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
>>> +		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
>> 	
>> 	dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");
>>
>>>   	kfree(devfreq->time_in_state);
>>>   	kfree(devfreq->trans_table);
>>>   	kfree(devfreq);
>>>   err_out:
>>>   	return ERR_PTR(err);
>>> @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>>   
>>>   	ret = sscanf(buf, "%lu", &value);
>>>   	if (ret != 1)
>>>   		return -EINVAL;
>>>   
>>> -	mutex_lock(&df->lock);
>>> -	df->min_freq = value;
>>> -	update_devfreq(df);
>>> -	mutex_unlock(&df->lock);
>>> +	/* round down to kHz for PM QoS */
>>
>> I prefer more detailed description as following:
>>
>> 	/*
>> 	 * Round down to KHz to decide the proper minimum frequency
>> 	 * which is closed to user request.
>>   	 */

How about this comment? and with Matthias comment on other reply thread.

>>
>>
>>> +	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
>>> +					value / HZ_PER_KHZ);
>>> +	if (ret < 0)
>>> +		return ret;
>>>   
>>>   	return count;
>>>   }
>>>   
>>>   static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>>> @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>   
>>>   	ret = sscanf(buf, "%lu", &value);
>>>   	if (ret != 1)
>>>   		return -EINVAL;
>>>   
>>> -	mutex_lock(&df->lock);
>>> -
>>> -	/* Interpret zero as "don't care" */
>>> -	if (!value)
>>> -		value = ULONG_MAX;
>>> +	/* round up to kHz for PM QoS and interpret zero as "don't care" */
>>
>> I think that "don't care" comment style is not good.
>>
>> I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
>> I prefer more detailed description as following:
>> 	/*
>> 	 * Round up to KHz to decide the proper maximum frequency
>> 	 * which is closed to user request. If value is zero,
>> 	 * the user does not care.
>>   	 */
> 
> OK, will update this comment
> 
>>> +	if (value)
>>> +		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
>>> +	else
>>> +		value = S32_MAX;
>>>   
>>> -	df->max_freq = value;
>>> -	update_devfreq(df);
>>> -	mutex_unlock(&df->lock);
>>> +	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
>>> +	if (ret < 0)
>>> +		return ret;
>>>   
>>>   	return count;
>>>   }
>>>   static DEVICE_ATTR_RW(min_freq);
>>>   
>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>> index dac0dffeabb4..7849fe4c666d 100644
>>> --- a/include/linux/devfreq.h
>>> +++ b/include/linux/devfreq.h
>>> @@ -11,10 +11,11 @@
>>>   #define __LINUX_DEVFREQ_H__
>>>   
>>>   #include <linux/device.h>
>>>   #include <linux/notifier.h>
>>>   #include <linux/pm_opp.h>
>>> +#include <linux/pm_qos.h>
>>>   
>>>   #define DEVFREQ_NAME_LEN 16
>>>   
>>>   /* DEVFREQ governor name */
>>>   #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
>>> @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
>>>    *		devfreq.nb to the corresponding register notifier call chain.
>>>    * @work:	delayed work for load monitoring.
>>>    * @previous_freq:	previously configured frequency value.
>>>    * @data:	Private data of the governor. The devfreq framework does not
>>>    *		touch this.
>>> - * @min_freq:	Limit minimum frequency requested by user (0: none)
>>> - * @max_freq:	Limit maximum frequency requested by user (0: none)
>>> + * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)
>>
>> min -> minimum and then remove parenthesis as following:
>> 	PM QoS minimum frequency request by user via sysfs
>>
>>> + * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)
>>
>> ditto. max -> maximum
>> 	PM QoS maximum frequency request by user via sysfs
> 
> OK

Thanks.

> 
>>>    * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
>>>    * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
>>>    * @stop_polling:	 devfreq polling status of a device.
>>>    * @suspend_freq:	 frequency of a device set during suspend phase.
>>>    * @resume_freq:	 frequency of a device set in resume phase.
>>> @@ -161,12 +162,12 @@ struct devfreq {
>>>   	unsigned long previous_freq;
>>>   	struct devfreq_dev_status last_status;
>>>   
>>>   	void *data; /* private data for governors */
>>>   
>>> -	unsigned long min_freq;
>>> -	unsigned long max_freq;
>>> +	struct dev_pm_qos_request user_min_freq_req;
>>> +	struct dev_pm_qos_request user_max_freq_req;
>>>   	unsigned long scaling_min_freq;
>>>   	unsigned long scaling_max_freq;
>>>   	bool stop_polling;
>>>   
>>>   	unsigned long suspend_freq;
>>>
>>
>>
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
@ 2019-09-26  1:26           ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-26  1:26 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 19. 9. 26. 오전 7:11, Leonard Crestez wrote:
> On 25.09.2019 05:36, Chanwoo Choi wrote:
>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>> Switch the handling of min_freq and max_freq from sysfs to use the
>>> dev_pm_qos_request interface.
>>>
>>> Since PM QoS handles frequencies as kHz this change reduces the
>>> precision of min_freq and max_freq. This shouldn't introduce problems
>>> because frequencies which are not an integer number of kHz are likely
>>> not an integer number of Hz either.
>>>
>>> Try to ensure compatibility by rounding min values down and rounding
>>> max values up.
>>>
>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>> ---
>>>   drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
>>>   include/linux/devfreq.h   |  9 ++++----
>>>   2 files changed, 33 insertions(+), 22 deletions(-)
>>>
>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>> index 784f3e40536a..8bb7efd821ab 100644
>>> --- a/drivers/devfreq/devfreq.c
>>> +++ b/drivers/devfreq/devfreq.c
>>> @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
>>>   	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>   					     DEV_PM_QOS_MIN_FREQUENCY);
>>>   	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>   	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>   
>>> -	/* constraints from sysfs */
>>> -	*min_freq = max(*min_freq, devfreq->min_freq);
>>> -	*max_freq = min(*max_freq, devfreq->max_freq);
>>> -
>>>   	/* constraints from OPP interface */
>>>   	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>>>   	/* scaling_max_freq can be zero on error */
>>>   	if (devfreq->scaling_max_freq)
>>>   		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
>>> @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
>>>   			DEV_PM_QOS_MIN_FREQUENCY);
>>>   
>>>   	if (devfreq->profile->exit)
>>>   		devfreq->profile->exit(devfreq->dev.parent);
>>>   
>>> +	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>>> +	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
>>
>> Please check the return value if error happen, just print the err with dev_err()
>> without stopping the release steps.
> 
> OK, will print errors
> 
>>>   	kfree(devfreq->time_in_state);
>>>   	kfree(devfreq->trans_table);
>>>   	mutex_destroy(&devfreq->lock);
>>>   	kfree(devfreq);
>>>   }
>>> @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>   	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
>>>   	if (!devfreq->scaling_min_freq) {
>>>   		err = -EINVAL;
>>>   		goto err_dev;
>>>   	}
>>> -	devfreq->min_freq = devfreq->scaling_min_freq;
>>>   
>>>   	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
>>>   	if (!devfreq->scaling_max_freq) {
>>>   		err = -EINVAL;
>>>   		goto err_dev;
>>>   	}
>>> -	devfreq->max_freq = devfreq->scaling_max_freq;
>>> +
>>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
>>> +				     DEV_PM_QOS_MIN_FREQUENCY, 0);
>>> +	if (err < 0)
>>> +		goto err_dev;
>>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
>>> +				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
>>> +	if (err < 0)
>>> +		goto err_dev;
>>>   
>>>   	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
>>>   	atomic_set(&devfreq->suspend_count, 0);
>>>   
>>>   	devfreq->trans_table = kzalloc(
>>> @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>   err_dev:
>>>   	/*
>>>   	 * Cleanup path for errors that happen before registration.
>>>   	 * Otherwise we rely on devfreq_dev_release.
>>>   	 */
>>> +	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
>>> +		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>>
>> Please check the return value if error happen, just print the err with dev_err()
>> without stopping the release steps.
> 
> OK, will print errors
> 
>>
>> 	dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");
>>
>>> +	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
>>> +		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
>> 	
>> 	dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");
>>
>>>   	kfree(devfreq->time_in_state);
>>>   	kfree(devfreq->trans_table);
>>>   	kfree(devfreq);
>>>   err_out:
>>>   	return ERR_PTR(err);
>>> @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>>   
>>>   	ret = sscanf(buf, "%lu", &value);
>>>   	if (ret != 1)
>>>   		return -EINVAL;
>>>   
>>> -	mutex_lock(&df->lock);
>>> -	df->min_freq = value;
>>> -	update_devfreq(df);
>>> -	mutex_unlock(&df->lock);
>>> +	/* round down to kHz for PM QoS */
>>
>> I prefer more detailed description as following:
>>
>> 	/*
>> 	 * Round down to KHz to decide the proper minimum frequency
>> 	 * which is closed to user request.
>>   	 */

How about this comment? and with Matthias comment on other reply thread.

>>
>>
>>> +	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
>>> +					value / HZ_PER_KHZ);
>>> +	if (ret < 0)
>>> +		return ret;
>>>   
>>>   	return count;
>>>   }
>>>   
>>>   static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>>> @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>   
>>>   	ret = sscanf(buf, "%lu", &value);
>>>   	if (ret != 1)
>>>   		return -EINVAL;
>>>   
>>> -	mutex_lock(&df->lock);
>>> -
>>> -	/* Interpret zero as "don't care" */
>>> -	if (!value)
>>> -		value = ULONG_MAX;
>>> +	/* round up to kHz for PM QoS and interpret zero as "don't care" */
>>
>> I think that "don't care" comment style is not good.
>>
>> I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
>> I prefer more detailed description as following:
>> 	/*
>> 	 * Round up to KHz to decide the proper maximum frequency
>> 	 * which is closed to user request. If value is zero,
>> 	 * the user does not care.
>>   	 */
> 
> OK, will update this comment
> 
>>> +	if (value)
>>> +		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
>>> +	else
>>> +		value = S32_MAX;
>>>   
>>> -	df->max_freq = value;
>>> -	update_devfreq(df);
>>> -	mutex_unlock(&df->lock);
>>> +	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
>>> +	if (ret < 0)
>>> +		return ret;
>>>   
>>>   	return count;
>>>   }
>>>   static DEVICE_ATTR_RW(min_freq);
>>>   
>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>> index dac0dffeabb4..7849fe4c666d 100644
>>> --- a/include/linux/devfreq.h
>>> +++ b/include/linux/devfreq.h
>>> @@ -11,10 +11,11 @@
>>>   #define __LINUX_DEVFREQ_H__
>>>   
>>>   #include <linux/device.h>
>>>   #include <linux/notifier.h>
>>>   #include <linux/pm_opp.h>
>>> +#include <linux/pm_qos.h>
>>>   
>>>   #define DEVFREQ_NAME_LEN 16
>>>   
>>>   /* DEVFREQ governor name */
>>>   #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
>>> @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
>>>    *		devfreq.nb to the corresponding register notifier call chain.
>>>    * @work:	delayed work for load monitoring.
>>>    * @previous_freq:	previously configured frequency value.
>>>    * @data:	Private data of the governor. The devfreq framework does not
>>>    *		touch this.
>>> - * @min_freq:	Limit minimum frequency requested by user (0: none)
>>> - * @max_freq:	Limit maximum frequency requested by user (0: none)
>>> + * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)
>>
>> min -> minimum and then remove parenthesis as following:
>> 	PM QoS minimum frequency request by user via sysfs
>>
>>> + * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)
>>
>> ditto. max -> maximum
>> 	PM QoS maximum frequency request by user via sysfs
> 
> OK

Thanks.

> 
>>>    * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
>>>    * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
>>>    * @stop_polling:	 devfreq polling status of a device.
>>>    * @suspend_freq:	 frequency of a device set during suspend phase.
>>>    * @resume_freq:	 frequency of a device set in resume phase.
>>> @@ -161,12 +162,12 @@ struct devfreq {
>>>   	unsigned long previous_freq;
>>>   	struct devfreq_dev_status last_status;
>>>   
>>>   	void *data; /* private data for governors */
>>>   
>>> -	unsigned long min_freq;
>>> -	unsigned long max_freq;
>>> +	struct dev_pm_qos_request user_min_freq_req;
>>> +	struct dev_pm_qos_request user_max_freq_req;
>>>   	unsigned long scaling_min_freq;
>>>   	unsigned long scaling_max_freq;
>>>   	bool stop_polling;
>>>   
>>>   	unsigned long suspend_freq;
>>>
>>
>>
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-26  1:12           ` Chanwoo Choi
@ 2019-09-26 13:43             ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-26 13:43 UTC (permalink / raw)
  To: Chanwoo Choi, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 2019-09-26 4:07 AM, Chanwoo Choi wrote:
> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>> Register notifiers with the PM QoS framework in order to respond to
>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>
>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>> imposed externally (for example from other devices).
>>>>
>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>> ---
>>>>    drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>    include/linux/devfreq.h   |  5 +++
>>>>    2 files changed, 80 insertions(+)
>>>>
>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>> index eee403e70c84..784f3e40536a 100644
>>>> --- a/drivers/devfreq/devfreq.c
>>>> +++ b/drivers/devfreq/devfreq.c
>>>> @@ -22,15 +22,18 @@
>>>>    #include <linux/platform_device.h>
>>>>    #include <linux/list.h>
>>>>    #include <linux/printk.h>
>>>>    #include <linux/hrtimer.h>
>>>>    #include <linux/of.h>
>>>> +#include <linux/pm_qos.h>
>>>>    #include "governor.h"
>>>>    
>>>>    #define CREATE_TRACE_POINTS
>>>>    #include <trace/events/devfreq.h>
>>>>    
>>>> +#define HZ_PER_KHZ	1000
>>>> +
>>>>    static struct class *devfreq_class;
>>>>    
>>>>    /*
>>>>     * devfreq core provides delayed work based load monitoring helper
>>>>     * functions. Governors can use these or can implement their own
>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>    static void get_freq_range(struct devfreq *devfreq,
>>>>    			   unsigned long *min_freq,
>>>>    			   unsigned long *max_freq)
>>>>    {
>>>>    	unsigned long *freq_table = devfreq->profile->freq_table;
>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>    
>>>>    	lockdep_assert_held(&devfreq->lock);
>>>>    
>>>>    	/*
>>>>    	 * Init min/max frequency from freq table.
>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>    	} else {
>>>>    		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>    		*max_freq = freq_table[0];
>>>>    	}
>>>>    
>>>> +	/* constraints from PM QoS */
>>>
>>> As I commented on patch4,
>>> 'constraints' -> 'Constraint' because first verb have to be used
>>> as the sigular verbs.
>>
>> Already discussed for another patch; I will modify to "Apply constraints
>> from PM QoS" instead.
> 
> I agree the new comment with 'Apply constraints ... '.
> 
>>
>>> I prefer to use following comments:
>>>
>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>
>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>> +
>>>>    	/* constraints from sysfs */
>>>>    	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>    	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>    
>>>>    	/* constraints from OPP interface */
>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>    	mutex_unlock(&devfreq->lock);
>>>>    
>>>>    	return ret;
>>>>    }
>>>>    
>>>> +/**
>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>> + * @devfreq:    the devfreq instance.
>>>> + */
>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>> +{
>>>> +	int err;
>>>> +
>>>> +	mutex_lock(&devfreq->lock);
>>>> +	err = update_devfreq(devfreq);
>>>> +	mutex_unlock(&devfreq->lock);
>>>> +	if (err)
>>>> +		dev_err(devfreq->dev.parent,
>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>
>>> Is it not over 80 char?
>>
>> Yes but coding style explicitly forbids breaking strings.
>>
>>>> +				err);
>>>> +
>>>> +	return NOTIFY_OK;
>>>> +}
>>>> +
>>>> +/**
>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>> + * @nb:		Should be devfreq->nb_min
>>>> + */
>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>> +					 unsigned long val, void *ptr)
>>>> +{
>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>> +}
>>>> +
>>>> +/**
>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>> + * @nb:		Should be devfreq->nb_max
>>>> + */
>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>> +					 unsigned long val, void *ptr)
>>>> +{
>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>> +}
>>>> +
>>>>    /**
>>>>     * devfreq_dev_release() - Callback for struct device to release the device.
>>>>     * @dev:	the devfreq device
>>>>     *
>>>>     * Remove devfreq from the list and release its resources.
>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>    
>>>>    	mutex_lock(&devfreq_list_lock);
>>>>    	list_del(&devfreq->node);
>>>>    	mutex_unlock(&devfreq_list_lock);
>>>>    
>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>> +
>>>
>>> Just print error with dev_err() without stopping the release step.
>>>
>>> I prefer to handle the return value if kernel API provides
>>> the error code.
> 
> How about?

Modified to dev_warn. This also applies to PATCH 6 so I replied there.

>>>>    	if (devfreq->profile->exit)
>>>>    		devfreq->profile->exit(devfreq->dev.parent);
>>>>    
>>>>    	kfree(devfreq->time_in_state);
>>>>    	kfree(devfreq->trans_table);
>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>    	if (err) {
>>>>    		put_device(&devfreq->dev);
>>>>    		goto err_out;
>>>>    	}
>>>>    
>>>> +	/*
>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>> +	 * initialized (and we can handle notifications) but before the
>>>> +	 * governor is started (which should do an initial enforcement of
>>>> +	 * constraints).
>>>> +	 */
>>>
>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>> comments because the line code is not too long. But, at the present time,
>>> devfreq_add_device() is too long. It means that the detailed comment
>>> are necessary.
>>>
>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>> on separate patch to keep the same style. I'll send the patch to you
>>> for the review.
>>
>> This is very likely to result in merge conflicts, maybe wait for my
>> series to go in first?
> 
> I'll send the separate patch after finished the review of these patches.
> So, if you agree, please remove this comment on this patch.
> 
> You can review the detailed comments on separate patch when I send.
This patch already contains comments and they explain the code being 
added. Doesn't it make more sense for comments and code to go in together?

I think the comment is a resonable explanation as to why notifiers are 
registered at that specific step in the initialization sequence.

>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>> +	if (err)
>>>> +		goto err_devfreq;
>>>> +
>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>> +	if (err)
>>>> +		goto err_devfreq;
>>>> +
>>>>    	mutex_lock(&devfreq_list_lock);
>>>>    
>>>>    	governor = try_then_request_governor(devfreq->governor_name);
>>>>    	if (IS_ERR(governor)) {
>>>>    		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>    
>>>>    	return devfreq;
>>>>    
>>>>    err_init:
>>>>    	mutex_unlock(&devfreq_list_lock);
>>>> +err_devfreq:
>>>>    	devfreq_remove_device(devfreq);
>>>>    	return ERR_PTR(err);
>>>>    
>>>>    err_dev:
>>>>    	/*
>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>> --- a/include/linux/devfreq.h
>>>> +++ b/include/linux/devfreq.h
>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>     * @total_trans:	Number of devfreq transitions
>>>>     * @trans_table:	Statistics of devfreq transitions
>>>>     * @time_in_state:	Statistics of devfreq states
>>>>     * @last_stat_updated:	The last time stat updated
>>>>     * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>     *
>>>>     * This structure stores the devfreq information for a give device.
>>>>     *
>>>>     * Note that when a governor accesses entries in struct devfreq in its
>>>>     * functions except for the context of callbacks defined in struct
>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>    	unsigned int *trans_table;
>>>>    	unsigned long *time_in_state;
>>>>    	unsigned long last_stat_updated;
>>>>    
>>>>    	struct srcu_notifier_head transition_notifier_list;
>>>> +
>>>> +	struct notifier_block nb_min;
>>>> +	struct notifier_block nb_max;
>>>>    };
>>>>    
>>>>    struct devfreq_freqs {
>>>>    	unsigned long old;
>>>>    	unsigned long new;

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-26 13:43             ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-26 13:43 UTC (permalink / raw)
  To: Chanwoo Choi, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 2019-09-26 4:07 AM, Chanwoo Choi wrote:
> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>> Register notifiers with the PM QoS framework in order to respond to
>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>
>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>> imposed externally (for example from other devices).
>>>>
>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>> ---
>>>>    drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>    include/linux/devfreq.h   |  5 +++
>>>>    2 files changed, 80 insertions(+)
>>>>
>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>> index eee403e70c84..784f3e40536a 100644
>>>> --- a/drivers/devfreq/devfreq.c
>>>> +++ b/drivers/devfreq/devfreq.c
>>>> @@ -22,15 +22,18 @@
>>>>    #include <linux/platform_device.h>
>>>>    #include <linux/list.h>
>>>>    #include <linux/printk.h>
>>>>    #include <linux/hrtimer.h>
>>>>    #include <linux/of.h>
>>>> +#include <linux/pm_qos.h>
>>>>    #include "governor.h"
>>>>    
>>>>    #define CREATE_TRACE_POINTS
>>>>    #include <trace/events/devfreq.h>
>>>>    
>>>> +#define HZ_PER_KHZ	1000
>>>> +
>>>>    static struct class *devfreq_class;
>>>>    
>>>>    /*
>>>>     * devfreq core provides delayed work based load monitoring helper
>>>>     * functions. Governors can use these or can implement their own
>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>    static void get_freq_range(struct devfreq *devfreq,
>>>>    			   unsigned long *min_freq,
>>>>    			   unsigned long *max_freq)
>>>>    {
>>>>    	unsigned long *freq_table = devfreq->profile->freq_table;
>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>    
>>>>    	lockdep_assert_held(&devfreq->lock);
>>>>    
>>>>    	/*
>>>>    	 * Init min/max frequency from freq table.
>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>    	} else {
>>>>    		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>    		*max_freq = freq_table[0];
>>>>    	}
>>>>    
>>>> +	/* constraints from PM QoS */
>>>
>>> As I commented on patch4,
>>> 'constraints' -> 'Constraint' because first verb have to be used
>>> as the sigular verbs.
>>
>> Already discussed for another patch; I will modify to "Apply constraints
>> from PM QoS" instead.
> 
> I agree the new comment with 'Apply constraints ... '.
> 
>>
>>> I prefer to use following comments:
>>>
>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>
>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>> +
>>>>    	/* constraints from sysfs */
>>>>    	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>    	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>    
>>>>    	/* constraints from OPP interface */
>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>    	mutex_unlock(&devfreq->lock);
>>>>    
>>>>    	return ret;
>>>>    }
>>>>    
>>>> +/**
>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>> + * @devfreq:    the devfreq instance.
>>>> + */
>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>> +{
>>>> +	int err;
>>>> +
>>>> +	mutex_lock(&devfreq->lock);
>>>> +	err = update_devfreq(devfreq);
>>>> +	mutex_unlock(&devfreq->lock);
>>>> +	if (err)
>>>> +		dev_err(devfreq->dev.parent,
>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>
>>> Is it not over 80 char?
>>
>> Yes but coding style explicitly forbids breaking strings.
>>
>>>> +				err);
>>>> +
>>>> +	return NOTIFY_OK;
>>>> +}
>>>> +
>>>> +/**
>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>> + * @nb:		Should be devfreq->nb_min
>>>> + */
>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>> +					 unsigned long val, void *ptr)
>>>> +{
>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>> +}
>>>> +
>>>> +/**
>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>> + * @nb:		Should be devfreq->nb_max
>>>> + */
>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>> +					 unsigned long val, void *ptr)
>>>> +{
>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>> +}
>>>> +
>>>>    /**
>>>>     * devfreq_dev_release() - Callback for struct device to release the device.
>>>>     * @dev:	the devfreq device
>>>>     *
>>>>     * Remove devfreq from the list and release its resources.
>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>    
>>>>    	mutex_lock(&devfreq_list_lock);
>>>>    	list_del(&devfreq->node);
>>>>    	mutex_unlock(&devfreq_list_lock);
>>>>    
>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>> +
>>>
>>> Just print error with dev_err() without stopping the release step.
>>>
>>> I prefer to handle the return value if kernel API provides
>>> the error code.
> 
> How about?

Modified to dev_warn. This also applies to PATCH 6 so I replied there.

>>>>    	if (devfreq->profile->exit)
>>>>    		devfreq->profile->exit(devfreq->dev.parent);
>>>>    
>>>>    	kfree(devfreq->time_in_state);
>>>>    	kfree(devfreq->trans_table);
>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>    	if (err) {
>>>>    		put_device(&devfreq->dev);
>>>>    		goto err_out;
>>>>    	}
>>>>    
>>>> +	/*
>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>> +	 * initialized (and we can handle notifications) but before the
>>>> +	 * governor is started (which should do an initial enforcement of
>>>> +	 * constraints).
>>>> +	 */
>>>
>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>> comments because the line code is not too long. But, at the present time,
>>> devfreq_add_device() is too long. It means that the detailed comment
>>> are necessary.
>>>
>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>> on separate patch to keep the same style. I'll send the patch to you
>>> for the review.
>>
>> This is very likely to result in merge conflicts, maybe wait for my
>> series to go in first?
> 
> I'll send the separate patch after finished the review of these patches.
> So, if you agree, please remove this comment on this patch.
> 
> You can review the detailed comments on separate patch when I send.
This patch already contains comments and they explain the code being 
added. Doesn't it make more sense for comments and code to go in together?

I think the comment is a resonable explanation as to why notifiers are 
registered at that specific step in the initialization sequence.

>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>> +	if (err)
>>>> +		goto err_devfreq;
>>>> +
>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>> +	if (err)
>>>> +		goto err_devfreq;
>>>> +
>>>>    	mutex_lock(&devfreq_list_lock);
>>>>    
>>>>    	governor = try_then_request_governor(devfreq->governor_name);
>>>>    	if (IS_ERR(governor)) {
>>>>    		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>    
>>>>    	return devfreq;
>>>>    
>>>>    err_init:
>>>>    	mutex_unlock(&devfreq_list_lock);
>>>> +err_devfreq:
>>>>    	devfreq_remove_device(devfreq);
>>>>    	return ERR_PTR(err);
>>>>    
>>>>    err_dev:
>>>>    	/*
>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>> --- a/include/linux/devfreq.h
>>>> +++ b/include/linux/devfreq.h
>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>     * @total_trans:	Number of devfreq transitions
>>>>     * @trans_table:	Statistics of devfreq transitions
>>>>     * @time_in_state:	Statistics of devfreq states
>>>>     * @last_stat_updated:	The last time stat updated
>>>>     * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>     *
>>>>     * This structure stores the devfreq information for a give device.
>>>>     *
>>>>     * Note that when a governor accesses entries in struct devfreq in its
>>>>     * functions except for the context of callbacks defined in struct
>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>    	unsigned int *trans_table;
>>>>    	unsigned long *time_in_state;
>>>>    	unsigned long last_stat_updated;
>>>>    
>>>>    	struct srcu_notifier_head transition_notifier_list;
>>>> +
>>>> +	struct notifier_block nb_min;
>>>> +	struct notifier_block nb_max;
>>>>    };
>>>>    
>>>>    struct devfreq_freqs {
>>>>    	unsigned long old;
>>>>    	unsigned long new;
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 4/6] PM / devfreq: Introduce get_freq_range helper
  2019-09-26  1:06           ` Chanwoo Choi
@ 2019-09-26 14:03             ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-26 14:03 UTC (permalink / raw)
  To: Chanwoo Choi, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke,
	Viresh Kumar
  Cc: Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Lukasz Luba, dl-linux-imx,
	linux-pm, linux-arm-kernel

On 2019-09-26 4:02 AM, Chanwoo Choi wrote:
> Hi,
> 
> On 19. 9. 26. 오전 5:55, Leonard Crestez wrote:
>> On 25.09.2019 04:32, Chanwoo Choi wrote:
>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>> Moving handling of min/max freq to a single function and call it from
>>>> update_devfreq and for printing min/max freq values in sysfs.
>>>>
>>>> This changes the behavior of out-of-range min_freq/max_freq: clamping
>>>> is now done at evaluation time. This means that if an out-of-range
>>>> constraint is imposed by sysfs and it later becomes valid then it will
>>>> be enforced.
>>>>
>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>> ---
>>>>    drivers/devfreq/devfreq.c | 112 ++++++++++++++++++++++----------------
>>>>    1 file changed, 64 insertions(+), 48 deletions(-)
>>>>
>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>> index 4a878baa809e..eee403e70c84 100644
>>>> --- a/drivers/devfreq/devfreq.c
>>>> +++ b/drivers/devfreq/devfreq.c
>>>> @@ -96,10 +96,54 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>    		dev_pm_opp_put(opp);
>>>>    
>>>>    	return max_freq;
>>>>    }
>>>>    
>>>> +/**
>>>> + * get_freq_range() - Get the current freq range
>>>> + * @devfreq:	the devfreq instance
>>>> + * @min_freq:	the min frequency
>>>> + * @max_freq:	the max frequency
>>>> + *
>>>> + * This takes into consideration all constraints.
>>>> + */
>>>> +static void get_freq_range(struct devfreq *devfreq,
>>>> +			   unsigned long *min_freq,
>>>> +			   unsigned long *max_freq)
>>>> +{
>>>> +	unsigned long *freq_table = devfreq->profile->freq_table;
>>>> +
>>>> +	lockdep_assert_held(&devfreq->lock);
>>>> +
>>>> +	/*
>>>> +	 * Init min/max frequency from freq table.
>>>
>>> Init -> Initialize
>>> min/max -> minimum/maximum
>>>
>>>> +	 * Drivers can initialize this in either ascending or descending order
>>>
>>> Drivers -> devfreq drivers
>>>
>>>> +	 * and devfreq core supports both.
>>>> +	 */
>>>
>>>
>>> In result, I prefer to change the comments as following:
>>> 	/*
>>> 	 * Initialize the minimum/maximum frequency from freq_table.
>>>    	 * The devfreq drivers can initialize freq_table in either
>>> 	 * ascending or descending order and devfreq core supports both.
>>> 	 */
>>
>> OK
>>
>>>> +	if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
>>>> +		*min_freq = freq_table[0];
>>>> +		*max_freq = freq_table[devfreq->profile->max_state - 1];
>>>> +	} else {
>>>> +		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>> +		*max_freq = freq_table[0];
>>>> +	}
>>>> +
>>>> +	/* constraints from sysfs */
>>>
>>> 'constraints' -> Constraint because first verb have to be used
>>> as the sigular verbs. Also, I think that have to enhance the comments
>>> I prefer to use following comments:
>>>
>>> 	 /* Constraint minimum/maximum frequency from user input via sysfs */
>>>
>>>
>>>
>>>> +	*min_freq = max(*min_freq, devfreq->min_freq);
>>>> +	*max_freq = min(*max_freq, devfreq->max_freq);
>>>> +
>>>> +	/* constraints from OPP interface */
>>>
>>> ditto. I prefer to use following comments:
>>>
>>> 	/* Constraint minimum/maximum frequency from OPP interface */
>>>
>>>
>>>> +	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>>>> +	/* scaling_max_freq can be zero on error */
>>>
>>> Please remove it.
>>>
>>>> +	if (devfreq->scaling_max_freq)
>>>
>>> As I knew, devfreq->scaling_max_freq is never zero.
>>> So, it is always true. This if statement is needed.
>>
>> It can happen if find_available_max_freq encounters an error when called
>> from devfreq_notifier_call.
> 
> If you are wondering this case, I think that have to fix
> the possible issue on there instead of this point.
> 
>>
>> Maybe that should be separately fixed to set scaling_max_freq to a
>> neutral value such as "ULONG_MAX" instead?
> 
> OK.
> 
>>
>> BTW: the devfreq_notifier_call function returns -EINVAL on error but it
>> should return one of the NOTIFY_OK/DONE/STOP values instead. The OPP
>> framework ignores notifier results but (-EINVAL & NOTIFY_STOP) evaluates
>> as true so other notifiers will be skipped unintentionally.
> 
> I agree. It is needed to fix the return value type.

Will include as separate patches in v9.

>>>> +		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
>>>> +
>>>> +	/* max_freq takes precedence over min_freq */
>>>
>>> As I said, almost people know that min_freq have be under than max_freq.
>>> Please remove it. And until finishing the discussion on mailing list,
>>> please don't send the next version. If you just replied from my comment
>>> and then wait my next comment, we can save the time without replying
>>> the repetitive and same comment for same point.
>>
>> This series makes it possible to set a min_freq higher than max_freq
>> (for example via PM QoS from various devices).
>>
>> It is not obvious that min_freq takes precedence over max_freq but the
>> code is self-evident so I will remove the comment.
>>
>>>> +	if (*min_freq > *max_freq)
>>>> +		*min_freq = *max_freq;
>>>> +}
>>>> +
>>>>    /**
>>>>     * devfreq_get_freq_level() - Lookup freq_table for the frequency
>>>>     * @devfreq:	the devfreq instance
>>>>     * @freq:	the target frequency
>>>>     */
>>>> @@ -349,20 +393,11 @@ int update_devfreq(struct devfreq *devfreq)
>>>>    
>>>>    	/* Reevaluate the proper frequency */
>>>>    	err = devfreq->governor->get_target_freq(devfreq, &freq);
>>>>    	if (err)
>>>>    		return err;
>>>> -
>>>> -	/*
>>>> -	 * Adjust the frequency with user freq, QoS and available freq.
>>>> -	 *
>>>> -	 * List from the highest priority
>>>> -	 * max_freq
>>>> -	 * min_freq
>>>> -	 */
>>>> -	max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
>>>> -	min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
>>>> +	get_freq_range(devfreq, &min_freq, &max_freq);
>>>>    
>>>>    	if (freq < min_freq) {
>>>>    		freq = min_freq;
>>>>    		flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
>>>>    	}
>>>> @@ -1298,40 +1333,28 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>>>    	ret = sscanf(buf, "%lu", &value);
>>>>    	if (ret != 1)
>>>>    		return -EINVAL;
>>>>    
>>>>    	mutex_lock(&df->lock);
>>>> -
>>>> -	if (value) {
>>>> -		if (value > df->max_freq) {
>>>> -			ret = -EINVAL;
>>>> -			goto unlock;
>>>> -		}
>>>> -	} else {
>>>> -		unsigned long *freq_table = df->profile->freq_table;
>>>> -
>>>> -		/* Get minimum frequency according to sorting order */
>>>> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
>>>> -			value = freq_table[0];
>>>> -		else
>>>> -			value = freq_table[df->profile->max_state - 1];
>>>> -	}
>>>> -
>>>>    	df->min_freq = value;
>>>>    	update_devfreq(df);
>>>> -	ret = count;
>>>> -unlock:
>>>>    	mutex_unlock(&df->lock);
>>>> -	return ret;
>>>> +
>>>> +	return count;
>>>>    }
>>>>    
>>>>    static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>>>>    			     char *buf)
>>>>    {
>>>>    	struct devfreq *df = to_devfreq(dev);
>>>> +	unsigned long min_freq, max_freq;
>>>> +
>>>> +	mutex_lock(&df->lock);
>>>> +	get_freq_range(df, &min_freq, &max_freq);
>>>> +	mutex_unlock(&df->lock);
>>>>    
>>>> -	return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
>>>> +	return sprintf(buf, "%lu\n", min_freq);
>>>>    }
>>>>    
>>>>    static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>>    			      const char *buf, size_t count)
>>>>    {
>>>> @@ -1343,40 +1366,33 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>>    	if (ret != 1)
>>>>    		return -EINVAL;
>>>>    
>>>>    	mutex_lock(&df->lock);
>>>>    
>>>> -	if (value) {
>>>> -		if (value < df->min_freq) {
>>>> -			ret = -EINVAL;
>>>> -			goto unlock;
>>>> -		}
>>>> -	} else {
>>>> -		unsigned long *freq_table = df->profile->freq_table;
>>>> -
>>>> -		/* Get maximum frequency according to sorting order */
>>>> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
>>>> -			value = freq_table[df->profile->max_state - 1];
>>>> -		else
>>>> -			value = freq_table[0];
>>>> -	}
>>>> +	/* Interpret zero as "don't care" */
>>>
>>> Please remove it. Also, the detailed comment for user have to add
>>> the documentation file.
>>
>> OK
>>
>>>
>>>> +	if (!value)
>>>> +		value = ULONG_MAX;
>>>>    
>>>>    	df->max_freq = value;
>>>>    	update_devfreq(df);
>>>> -	ret = count;
>>>> -unlock:
>>>>    	mutex_unlock(&df->lock);
>>>> -	return ret;
>>>> +
>>>> +	return count;
>>>>    }
>>>>    static DEVICE_ATTR_RW(min_freq);
>>>>    
>>>>    static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
>>>>    			     char *buf)
>>>>    {
>>>>    	struct devfreq *df = to_devfreq(dev);
>>>> +	unsigned long min_freq, max_freq;
>>>> +
>>>> +	mutex_lock(&df->lock);
>>>> +	get_freq_range(df, &min_freq, &max_freq);
>>>> +	mutex_unlock(&df->lock);
>>>>    
>>>> -	return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
>>>> +	return sprintf(buf, "%lu\n", max_freq);
>>>>    }
>>>>    static DEVICE_ATTR_RW(max_freq);
>>>>    
>>>>    static ssize_t available_frequencies_show(struct device *d,
>>>>    					  struct device_attribute *attr,
> 
> 


^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 4/6] PM / devfreq: Introduce get_freq_range helper
@ 2019-09-26 14:03             ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-26 14:03 UTC (permalink / raw)
  To: Chanwoo Choi, MyungJoo Ham, Kyungmin Park, Matthias Kaehlcke,
	Viresh Kumar
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Alexandre Bailon,
	Georgi Djakov, linux-arm-kernel, Jacky Bai

On 2019-09-26 4:02 AM, Chanwoo Choi wrote:
> Hi,
> 
> On 19. 9. 26. 오전 5:55, Leonard Crestez wrote:
>> On 25.09.2019 04:32, Chanwoo Choi wrote:
>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>> Moving handling of min/max freq to a single function and call it from
>>>> update_devfreq and for printing min/max freq values in sysfs.
>>>>
>>>> This changes the behavior of out-of-range min_freq/max_freq: clamping
>>>> is now done at evaluation time. This means that if an out-of-range
>>>> constraint is imposed by sysfs and it later becomes valid then it will
>>>> be enforced.
>>>>
>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>> ---
>>>>    drivers/devfreq/devfreq.c | 112 ++++++++++++++++++++++----------------
>>>>    1 file changed, 64 insertions(+), 48 deletions(-)
>>>>
>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>> index 4a878baa809e..eee403e70c84 100644
>>>> --- a/drivers/devfreq/devfreq.c
>>>> +++ b/drivers/devfreq/devfreq.c
>>>> @@ -96,10 +96,54 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>    		dev_pm_opp_put(opp);
>>>>    
>>>>    	return max_freq;
>>>>    }
>>>>    
>>>> +/**
>>>> + * get_freq_range() - Get the current freq range
>>>> + * @devfreq:	the devfreq instance
>>>> + * @min_freq:	the min frequency
>>>> + * @max_freq:	the max frequency
>>>> + *
>>>> + * This takes into consideration all constraints.
>>>> + */
>>>> +static void get_freq_range(struct devfreq *devfreq,
>>>> +			   unsigned long *min_freq,
>>>> +			   unsigned long *max_freq)
>>>> +{
>>>> +	unsigned long *freq_table = devfreq->profile->freq_table;
>>>> +
>>>> +	lockdep_assert_held(&devfreq->lock);
>>>> +
>>>> +	/*
>>>> +	 * Init min/max frequency from freq table.
>>>
>>> Init -> Initialize
>>> min/max -> minimum/maximum
>>>
>>>> +	 * Drivers can initialize this in either ascending or descending order
>>>
>>> Drivers -> devfreq drivers
>>>
>>>> +	 * and devfreq core supports both.
>>>> +	 */
>>>
>>>
>>> In result, I prefer to change the comments as following:
>>> 	/*
>>> 	 * Initialize the minimum/maximum frequency from freq_table.
>>>    	 * The devfreq drivers can initialize freq_table in either
>>> 	 * ascending or descending order and devfreq core supports both.
>>> 	 */
>>
>> OK
>>
>>>> +	if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
>>>> +		*min_freq = freq_table[0];
>>>> +		*max_freq = freq_table[devfreq->profile->max_state - 1];
>>>> +	} else {
>>>> +		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>> +		*max_freq = freq_table[0];
>>>> +	}
>>>> +
>>>> +	/* constraints from sysfs */
>>>
>>> 'constraints' -> Constraint because first verb have to be used
>>> as the sigular verbs. Also, I think that have to enhance the comments
>>> I prefer to use following comments:
>>>
>>> 	 /* Constraint minimum/maximum frequency from user input via sysfs */
>>>
>>>
>>>
>>>> +	*min_freq = max(*min_freq, devfreq->min_freq);
>>>> +	*max_freq = min(*max_freq, devfreq->max_freq);
>>>> +
>>>> +	/* constraints from OPP interface */
>>>
>>> ditto. I prefer to use following comments:
>>>
>>> 	/* Constraint minimum/maximum frequency from OPP interface */
>>>
>>>
>>>> +	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>>>> +	/* scaling_max_freq can be zero on error */
>>>
>>> Please remove it.
>>>
>>>> +	if (devfreq->scaling_max_freq)
>>>
>>> As I knew, devfreq->scaling_max_freq is never zero.
>>> So, it is always true. This if statement is needed.
>>
>> It can happen if find_available_max_freq encounters an error when called
>> from devfreq_notifier_call.
> 
> If you are wondering this case, I think that have to fix
> the possible issue on there instead of this point.
> 
>>
>> Maybe that should be separately fixed to set scaling_max_freq to a
>> neutral value such as "ULONG_MAX" instead?
> 
> OK.
> 
>>
>> BTW: the devfreq_notifier_call function returns -EINVAL on error but it
>> should return one of the NOTIFY_OK/DONE/STOP values instead. The OPP
>> framework ignores notifier results but (-EINVAL & NOTIFY_STOP) evaluates
>> as true so other notifiers will be skipped unintentionally.
> 
> I agree. It is needed to fix the return value type.

Will include as separate patches in v9.

>>>> +		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
>>>> +
>>>> +	/* max_freq takes precedence over min_freq */
>>>
>>> As I said, almost people know that min_freq have be under than max_freq.
>>> Please remove it. And until finishing the discussion on mailing list,
>>> please don't send the next version. If you just replied from my comment
>>> and then wait my next comment, we can save the time without replying
>>> the repetitive and same comment for same point.
>>
>> This series makes it possible to set a min_freq higher than max_freq
>> (for example via PM QoS from various devices).
>>
>> It is not obvious that min_freq takes precedence over max_freq but the
>> code is self-evident so I will remove the comment.
>>
>>>> +	if (*min_freq > *max_freq)
>>>> +		*min_freq = *max_freq;
>>>> +}
>>>> +
>>>>    /**
>>>>     * devfreq_get_freq_level() - Lookup freq_table for the frequency
>>>>     * @devfreq:	the devfreq instance
>>>>     * @freq:	the target frequency
>>>>     */
>>>> @@ -349,20 +393,11 @@ int update_devfreq(struct devfreq *devfreq)
>>>>    
>>>>    	/* Reevaluate the proper frequency */
>>>>    	err = devfreq->governor->get_target_freq(devfreq, &freq);
>>>>    	if (err)
>>>>    		return err;
>>>> -
>>>> -	/*
>>>> -	 * Adjust the frequency with user freq, QoS and available freq.
>>>> -	 *
>>>> -	 * List from the highest priority
>>>> -	 * max_freq
>>>> -	 * min_freq
>>>> -	 */
>>>> -	max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
>>>> -	min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
>>>> +	get_freq_range(devfreq, &min_freq, &max_freq);
>>>>    
>>>>    	if (freq < min_freq) {
>>>>    		freq = min_freq;
>>>>    		flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
>>>>    	}
>>>> @@ -1298,40 +1333,28 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>>>    	ret = sscanf(buf, "%lu", &value);
>>>>    	if (ret != 1)
>>>>    		return -EINVAL;
>>>>    
>>>>    	mutex_lock(&df->lock);
>>>> -
>>>> -	if (value) {
>>>> -		if (value > df->max_freq) {
>>>> -			ret = -EINVAL;
>>>> -			goto unlock;
>>>> -		}
>>>> -	} else {
>>>> -		unsigned long *freq_table = df->profile->freq_table;
>>>> -
>>>> -		/* Get minimum frequency according to sorting order */
>>>> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
>>>> -			value = freq_table[0];
>>>> -		else
>>>> -			value = freq_table[df->profile->max_state - 1];
>>>> -	}
>>>> -
>>>>    	df->min_freq = value;
>>>>    	update_devfreq(df);
>>>> -	ret = count;
>>>> -unlock:
>>>>    	mutex_unlock(&df->lock);
>>>> -	return ret;
>>>> +
>>>> +	return count;
>>>>    }
>>>>    
>>>>    static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>>>>    			     char *buf)
>>>>    {
>>>>    	struct devfreq *df = to_devfreq(dev);
>>>> +	unsigned long min_freq, max_freq;
>>>> +
>>>> +	mutex_lock(&df->lock);
>>>> +	get_freq_range(df, &min_freq, &max_freq);
>>>> +	mutex_unlock(&df->lock);
>>>>    
>>>> -	return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
>>>> +	return sprintf(buf, "%lu\n", min_freq);
>>>>    }
>>>>    
>>>>    static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>>    			      const char *buf, size_t count)
>>>>    {
>>>> @@ -1343,40 +1366,33 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>>    	if (ret != 1)
>>>>    		return -EINVAL;
>>>>    
>>>>    	mutex_lock(&df->lock);
>>>>    
>>>> -	if (value) {
>>>> -		if (value < df->min_freq) {
>>>> -			ret = -EINVAL;
>>>> -			goto unlock;
>>>> -		}
>>>> -	} else {
>>>> -		unsigned long *freq_table = df->profile->freq_table;
>>>> -
>>>> -		/* Get maximum frequency according to sorting order */
>>>> -		if (freq_table[0] < freq_table[df->profile->max_state - 1])
>>>> -			value = freq_table[df->profile->max_state - 1];
>>>> -		else
>>>> -			value = freq_table[0];
>>>> -	}
>>>> +	/* Interpret zero as "don't care" */
>>>
>>> Please remove it. Also, the detailed comment for user have to add
>>> the documentation file.
>>
>> OK
>>
>>>
>>>> +	if (!value)
>>>> +		value = ULONG_MAX;
>>>>    
>>>>    	df->max_freq = value;
>>>>    	update_devfreq(df);
>>>> -	ret = count;
>>>> -unlock:
>>>>    	mutex_unlock(&df->lock);
>>>> -	return ret;
>>>> +
>>>> +	return count;
>>>>    }
>>>>    static DEVICE_ATTR_RW(min_freq);
>>>>    
>>>>    static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
>>>>    			     char *buf)
>>>>    {
>>>>    	struct devfreq *df = to_devfreq(dev);
>>>> +	unsigned long min_freq, max_freq;
>>>> +
>>>> +	mutex_lock(&df->lock);
>>>> +	get_freq_range(df, &min_freq, &max_freq);
>>>> +	mutex_unlock(&df->lock);
>>>>    
>>>> -	return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
>>>> +	return sprintf(buf, "%lu\n", max_freq);
>>>>    }
>>>>    static DEVICE_ATTR_RW(max_freq);
>>>>    
>>>>    static ssize_t available_frequencies_show(struct device *d,
>>>>    					  struct device_attribute *attr,
> 
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
  2019-09-26  1:25           ` Chanwoo Choi
@ 2019-09-26 16:04             ` Matthias Kaehlcke
  -1 siblings, 0 replies; 82+ messages in thread
From: Matthias Kaehlcke @ 2019-09-26 16:04 UTC (permalink / raw)
  To: Chanwoo Choi
  Cc: Leonard Crestez, MyungJoo Ham, Kyungmin Park,
	Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

On Thu, Sep 26, 2019 at 10:25:41AM +0900, Chanwoo Choi wrote:
> On 19. 9. 26. 오전 1:45, Matthias Kaehlcke wrote:
> > On Wed, Sep 25, 2019 at 11:41:07AM +0900, Chanwoo Choi wrote:
> >> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> >>> Switch the handling of min_freq and max_freq from sysfs to use the
> >>> dev_pm_qos_request interface.
> >>>
> >>> Since PM QoS handles frequencies as kHz this change reduces the
> >>> precision of min_freq and max_freq. This shouldn't introduce problems
> >>> because frequencies which are not an integer number of kHz are likely
> >>> not an integer number of Hz either.
> >>>
> >>> Try to ensure compatibility by rounding min values down and rounding
> >>> max values up.
> >>>
> >>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> >>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> >>> ---
> >>>  drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
> >>>  include/linux/devfreq.h   |  9 ++++----
> >>>  2 files changed, 33 insertions(+), 22 deletions(-)
> >>>
> >>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> >>> index 784f3e40536a..8bb7efd821ab 100644
> >>> --- a/drivers/devfreq/devfreq.c
> >>> +++ b/drivers/devfreq/devfreq.c
> >>> @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
> >>>  	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> >>>  					     DEV_PM_QOS_MIN_FREQUENCY);
> >>>  	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
> >>>  	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
> >>>  
> >>> -	/* constraints from sysfs */
> >>> -	*min_freq = max(*min_freq, devfreq->min_freq);
> >>> -	*max_freq = min(*max_freq, devfreq->max_freq);
> >>> -
> >>>  	/* constraints from OPP interface */
> >>>  	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
> >>>  	/* scaling_max_freq can be zero on error */
> >>>  	if (devfreq->scaling_max_freq)
> >>>  		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
> >>> @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
> >>>  			DEV_PM_QOS_MIN_FREQUENCY);
> >>>  
> >>>  	if (devfreq->profile->exit)
> >>>  		devfreq->profile->exit(devfreq->dev.parent);
> >>>  
> >>> +	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
> >>> +	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
> >>
> >> Please check the return value if error happen, just print the err with dev_err()
> >> without stopping the release steps.
> > 
> > I wonder if dev_warn() would be more appropriate, since the current operation
> > is not aborted.
> > 
> >>>  	kfree(devfreq->time_in_state);
> >>>  	kfree(devfreq->trans_table);
> >>>  	mutex_destroy(&devfreq->lock);
> >>>  	kfree(devfreq);
> >>>  }
> >>> @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
> >>>  	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
> >>>  	if (!devfreq->scaling_min_freq) {
> >>>  		err = -EINVAL;
> >>>  		goto err_dev;
> >>>  	}
> >>> -	devfreq->min_freq = devfreq->scaling_min_freq;
> >>>  
> >>>  	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
> >>>  	if (!devfreq->scaling_max_freq) {
> >>>  		err = -EINVAL;
> >>>  		goto err_dev;
> >>>  	}
> >>> -	devfreq->max_freq = devfreq->scaling_max_freq;
> >>> +
> >>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
> >>> +				     DEV_PM_QOS_MIN_FREQUENCY, 0);
> >>> +	if (err < 0)
> >>> +		goto err_dev;
> >>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
> >>> +				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
> >>> +	if (err < 0)
> >>> +		goto err_dev;
> >>>  
> >>>  	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
> >>>  	atomic_set(&devfreq->suspend_count, 0);
> >>>  
> >>>  	devfreq->trans_table = kzalloc(
> >>> @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
> >>>  err_dev:
> >>>  	/*
> >>>  	 * Cleanup path for errors that happen before registration.
> >>>  	 * Otherwise we rely on devfreq_dev_release.
> >>>  	 */
> >>> +	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
> >>> +		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
> >>
> >> Please check the return value if error happen, just print the err with dev_err()
> >> without stopping the release steps.
> >>
> >> 	dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");
> > 
> > dev_warn() for the same reason as above?
> 
> Actually, I think that is not critical error but need to print the error
> So, I think that dev_err() is enough. If this thing is critical,
> better to use dev_warn.

We agree that this is not critical, but not when to use dev_err()
and dev_warn(). You seem to imply that dev_warn() is more severe
than dev_err(), however it's the other way around:

#define KERN_ERR        KERN_SOH "3"    /* error conditions */
#define KERN_WARNING    KERN_SOH "4"    /* warning conditions */
#define KERN_NOTICE     KERN_SOH "5"    /* normal but significant condition */

I think in this case you can go either way, it's certainly an error,
but the driver continues with the normal execution path.

> > 
> > I think the message would be better with a slight change:
> > 
> > "failed to remove DEV_PM_QOS_MAX_FREQUENCY request\n"
> 
> OK.
> 
> > 
> >>
> >>> +	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
> >>> +		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
> >> 	
> >> 	dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");
> > 
> > ditto
> > 
> >>>  	kfree(devfreq->time_in_state);
> >>>  	kfree(devfreq->trans_table);
> >>>  	kfree(devfreq);
> >>>  err_out:
> >>>  	return ERR_PTR(err);
> >>> @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
> >>>  
> >>>  	ret = sscanf(buf, "%lu", &value);
> >>>  	if (ret != 1)
> >>>  		return -EINVAL;
> >>>  
> >>> -	mutex_lock(&df->lock);
> >>> -	df->min_freq = value;
> >>> -	update_devfreq(df);
> >>> -	mutex_unlock(&df->lock);
> >>> +	/* round down to kHz for PM QoS */
> >>
> >> I prefer more detailed description as following:
> >>
> >> 	/*
> >> 	 * Round down to KHz to decide the proper minimum frequency
> > 
> > it should be kHz, with a lower-case 'k', as in the original comment.
> 
> Good.
> 
> > 
> >> 	 * which is closed to user request.
> >>  	 */
> > 
> > The comment you suggest doesn't provide any information about why the
> > conversion to kHz is done, in this sense the original comment that
> > mentions PM QoS provides more value.
> > 
> > With whatever we end up, I suggest to use 'convert' instead of
> > 'round down'.
> 
> I agree to use 'convert' instead of 'round down'
> if some expression indicates the correct meaning.
> 
> > 
> >>> +	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
> >>> +					value / HZ_PER_KHZ);
> >>> +	if (ret < 0)
> >>> +		return ret;
> >>>  
> >>>  	return count;
> >>>  }
> >>>  
> >>>  static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
> >>> @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
> >>>  
> >>>  	ret = sscanf(buf, "%lu", &value);
> >>>  	if (ret != 1)
> >>>  		return -EINVAL;
> >>>  
> >>> -	mutex_lock(&df->lock);
> >>> -
> >>> -	/* Interpret zero as "don't care" */
> >>> -	if (!value)
> >>> -		value = ULONG_MAX;
> >>> +	/* round up to kHz for PM QoS and interpret zero as "don't care" */
> >>
> >> I think that "don't care" comment style is not good.
> >>
> >> I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
> >> I prefer more detailed description as following:
> >> 	/*
> >> 	 * Round up to KHz to decide the proper maximum frequency
> > 
> > kHz
> > 
> >> 	 * which is closed to user request. If value is zero,
> >> 	 * the user does not care.
> > 
> > "the user does not care" is still very casual you didn't like initially.
> > How about "A value of zero is interpreted as 'no limit'."?
> > 
> > As for the min freq, I think PM QoS should be mentioned to make clear why
> > the conversion to kHz is needed.
> 
> Agree. I expect that Leonard will mention that.
> 
> > 
> >>  	 */
> >>
> >>
> >>> +	if (value)
> >>> +		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
> >>> +	else
> >>> +		value = S32_MAX;
> >>>  
> >>> -	df->max_freq = value;
> >>> -	update_devfreq(df);
> >>> -	mutex_unlock(&df->lock);
> >>> +	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
> >>> +	if (ret < 0)
> >>> +		return ret;
> >>>  
> >>>  	return count;
> >>>  }
> >>>  static DEVICE_ATTR_RW(min_freq);
> >>>  
> >>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> >>> index dac0dffeabb4..7849fe4c666d 100644
> >>> --- a/include/linux/devfreq.h
> >>> +++ b/include/linux/devfreq.h
> >>> @@ -11,10 +11,11 @@
> >>>  #define __LINUX_DEVFREQ_H__
> >>>  
> >>>  #include <linux/device.h>
> >>>  #include <linux/notifier.h>
> >>>  #include <linux/pm_opp.h>
> >>> +#include <linux/pm_qos.h>
> >>>  
> >>>  #define DEVFREQ_NAME_LEN 16
> >>>  
> >>>  /* DEVFREQ governor name */
> >>>  #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
> >>> @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
> >>>   *		devfreq.nb to the corresponding register notifier call chain.
> >>>   * @work:	delayed work for load monitoring.
> >>>   * @previous_freq:	previously configured frequency value.
> >>>   * @data:	Private data of the governor. The devfreq framework does not
> >>>   *		touch this.
> >>> - * @min_freq:	Limit minimum frequency requested by user (0: none)
> >>> - * @max_freq:	Limit maximum frequency requested by user (0: none)
> >>> + * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)
> >>
> >> min -> minimum and then remove parenthesis as following:
> >> 	PM QoS minimum frequency request by user via sysfs
> >>
> >>> + * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)
> >>
> >> ditto. max -> maximum
> >> 	PM QoS maximum frequency request by user via sysfs
> >>
> >>>   * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
> >>>   * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
> >>>   * @stop_polling:	 devfreq polling status of a device.
> >>>   * @suspend_freq:	 frequency of a device set during suspend phase.
> >>>   * @resume_freq:	 frequency of a device set in resume phase.
> >>> @@ -161,12 +162,12 @@ struct devfreq {
> >>>  	unsigned long previous_freq;
> >>>  	struct devfreq_dev_status last_status;
> >>>  
> >>>  	void *data; /* private data for governors */
> >>>  
> >>> -	unsigned long min_freq;
> >>> -	unsigned long max_freq;
> >>> +	struct dev_pm_qos_request user_min_freq_req;
> >>> +	struct dev_pm_qos_request user_max_freq_req;
> >>>  	unsigned long scaling_min_freq;
> >>>  	unsigned long scaling_max_freq;
> >>>  	bool stop_polling;
> >>>  
> >>>  	unsigned long suspend_freq;
> >>>
> >>
> >>
> >> -- 
> >> Best Regards,
> >> Chanwoo Choi
> >> Samsung Electronics
> > 
> > 
> 
> 
> -- 
> Best Regards,
> Chanwoo Choi
> Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
@ 2019-09-26 16:04             ` Matthias Kaehlcke
  0 siblings, 0 replies; 82+ messages in thread
From: Matthias Kaehlcke @ 2019-09-26 16:04 UTC (permalink / raw)
  To: Chanwoo Choi
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park,
	MyungJoo Ham, Alexandre Bailon, Leonard Crestez, Georgi Djakov,
	linux-arm-kernel, Jacky Bai

On Thu, Sep 26, 2019 at 10:25:41AM +0900, Chanwoo Choi wrote:
> On 19. 9. 26. 오전 1:45, Matthias Kaehlcke wrote:
> > On Wed, Sep 25, 2019 at 11:41:07AM +0900, Chanwoo Choi wrote:
> >> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
> >>> Switch the handling of min_freq and max_freq from sysfs to use the
> >>> dev_pm_qos_request interface.
> >>>
> >>> Since PM QoS handles frequencies as kHz this change reduces the
> >>> precision of min_freq and max_freq. This shouldn't introduce problems
> >>> because frequencies which are not an integer number of kHz are likely
> >>> not an integer number of Hz either.
> >>>
> >>> Try to ensure compatibility by rounding min values down and rounding
> >>> max values up.
> >>>
> >>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
> >>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
> >>> ---
> >>>  drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
> >>>  include/linux/devfreq.h   |  9 ++++----
> >>>  2 files changed, 33 insertions(+), 22 deletions(-)
> >>>
> >>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> >>> index 784f3e40536a..8bb7efd821ab 100644
> >>> --- a/drivers/devfreq/devfreq.c
> >>> +++ b/drivers/devfreq/devfreq.c
> >>> @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
> >>>  	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
> >>>  					     DEV_PM_QOS_MIN_FREQUENCY);
> >>>  	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
> >>>  	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
> >>>  
> >>> -	/* constraints from sysfs */
> >>> -	*min_freq = max(*min_freq, devfreq->min_freq);
> >>> -	*max_freq = min(*max_freq, devfreq->max_freq);
> >>> -
> >>>  	/* constraints from OPP interface */
> >>>  	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
> >>>  	/* scaling_max_freq can be zero on error */
> >>>  	if (devfreq->scaling_max_freq)
> >>>  		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
> >>> @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
> >>>  			DEV_PM_QOS_MIN_FREQUENCY);
> >>>  
> >>>  	if (devfreq->profile->exit)
> >>>  		devfreq->profile->exit(devfreq->dev.parent);
> >>>  
> >>> +	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
> >>> +	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
> >>
> >> Please check the return value if error happen, just print the err with dev_err()
> >> without stopping the release steps.
> > 
> > I wonder if dev_warn() would be more appropriate, since the current operation
> > is not aborted.
> > 
> >>>  	kfree(devfreq->time_in_state);
> >>>  	kfree(devfreq->trans_table);
> >>>  	mutex_destroy(&devfreq->lock);
> >>>  	kfree(devfreq);
> >>>  }
> >>> @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
> >>>  	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
> >>>  	if (!devfreq->scaling_min_freq) {
> >>>  		err = -EINVAL;
> >>>  		goto err_dev;
> >>>  	}
> >>> -	devfreq->min_freq = devfreq->scaling_min_freq;
> >>>  
> >>>  	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
> >>>  	if (!devfreq->scaling_max_freq) {
> >>>  		err = -EINVAL;
> >>>  		goto err_dev;
> >>>  	}
> >>> -	devfreq->max_freq = devfreq->scaling_max_freq;
> >>> +
> >>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
> >>> +				     DEV_PM_QOS_MIN_FREQUENCY, 0);
> >>> +	if (err < 0)
> >>> +		goto err_dev;
> >>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
> >>> +				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
> >>> +	if (err < 0)
> >>> +		goto err_dev;
> >>>  
> >>>  	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
> >>>  	atomic_set(&devfreq->suspend_count, 0);
> >>>  
> >>>  	devfreq->trans_table = kzalloc(
> >>> @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
> >>>  err_dev:
> >>>  	/*
> >>>  	 * Cleanup path for errors that happen before registration.
> >>>  	 * Otherwise we rely on devfreq_dev_release.
> >>>  	 */
> >>> +	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
> >>> +		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
> >>
> >> Please check the return value if error happen, just print the err with dev_err()
> >> without stopping the release steps.
> >>
> >> 	dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");
> > 
> > dev_warn() for the same reason as above?
> 
> Actually, I think that is not critical error but need to print the error
> So, I think that dev_err() is enough. If this thing is critical,
> better to use dev_warn.

We agree that this is not critical, but not when to use dev_err()
and dev_warn(). You seem to imply that dev_warn() is more severe
than dev_err(), however it's the other way around:

#define KERN_ERR        KERN_SOH "3"    /* error conditions */
#define KERN_WARNING    KERN_SOH "4"    /* warning conditions */
#define KERN_NOTICE     KERN_SOH "5"    /* normal but significant condition */

I think in this case you can go either way, it's certainly an error,
but the driver continues with the normal execution path.

> > 
> > I think the message would be better with a slight change:
> > 
> > "failed to remove DEV_PM_QOS_MAX_FREQUENCY request\n"
> 
> OK.
> 
> > 
> >>
> >>> +	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
> >>> +		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
> >> 	
> >> 	dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");
> > 
> > ditto
> > 
> >>>  	kfree(devfreq->time_in_state);
> >>>  	kfree(devfreq->trans_table);
> >>>  	kfree(devfreq);
> >>>  err_out:
> >>>  	return ERR_PTR(err);
> >>> @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
> >>>  
> >>>  	ret = sscanf(buf, "%lu", &value);
> >>>  	if (ret != 1)
> >>>  		return -EINVAL;
> >>>  
> >>> -	mutex_lock(&df->lock);
> >>> -	df->min_freq = value;
> >>> -	update_devfreq(df);
> >>> -	mutex_unlock(&df->lock);
> >>> +	/* round down to kHz for PM QoS */
> >>
> >> I prefer more detailed description as following:
> >>
> >> 	/*
> >> 	 * Round down to KHz to decide the proper minimum frequency
> > 
> > it should be kHz, with a lower-case 'k', as in the original comment.
> 
> Good.
> 
> > 
> >> 	 * which is closed to user request.
> >>  	 */
> > 
> > The comment you suggest doesn't provide any information about why the
> > conversion to kHz is done, in this sense the original comment that
> > mentions PM QoS provides more value.
> > 
> > With whatever we end up, I suggest to use 'convert' instead of
> > 'round down'.
> 
> I agree to use 'convert' instead of 'round down'
> if some expression indicates the correct meaning.
> 
> > 
> >>> +	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
> >>> +					value / HZ_PER_KHZ);
> >>> +	if (ret < 0)
> >>> +		return ret;
> >>>  
> >>>  	return count;
> >>>  }
> >>>  
> >>>  static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
> >>> @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
> >>>  
> >>>  	ret = sscanf(buf, "%lu", &value);
> >>>  	if (ret != 1)
> >>>  		return -EINVAL;
> >>>  
> >>> -	mutex_lock(&df->lock);
> >>> -
> >>> -	/* Interpret zero as "don't care" */
> >>> -	if (!value)
> >>> -		value = ULONG_MAX;
> >>> +	/* round up to kHz for PM QoS and interpret zero as "don't care" */
> >>
> >> I think that "don't care" comment style is not good.
> >>
> >> I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
> >> I prefer more detailed description as following:
> >> 	/*
> >> 	 * Round up to KHz to decide the proper maximum frequency
> > 
> > kHz
> > 
> >> 	 * which is closed to user request. If value is zero,
> >> 	 * the user does not care.
> > 
> > "the user does not care" is still very casual you didn't like initially.
> > How about "A value of zero is interpreted as 'no limit'."?
> > 
> > As for the min freq, I think PM QoS should be mentioned to make clear why
> > the conversion to kHz is needed.
> 
> Agree. I expect that Leonard will mention that.
> 
> > 
> >>  	 */
> >>
> >>
> >>> +	if (value)
> >>> +		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
> >>> +	else
> >>> +		value = S32_MAX;
> >>>  
> >>> -	df->max_freq = value;
> >>> -	update_devfreq(df);
> >>> -	mutex_unlock(&df->lock);
> >>> +	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
> >>> +	if (ret < 0)
> >>> +		return ret;
> >>>  
> >>>  	return count;
> >>>  }
> >>>  static DEVICE_ATTR_RW(min_freq);
> >>>  
> >>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> >>> index dac0dffeabb4..7849fe4c666d 100644
> >>> --- a/include/linux/devfreq.h
> >>> +++ b/include/linux/devfreq.h
> >>> @@ -11,10 +11,11 @@
> >>>  #define __LINUX_DEVFREQ_H__
> >>>  
> >>>  #include <linux/device.h>
> >>>  #include <linux/notifier.h>
> >>>  #include <linux/pm_opp.h>
> >>> +#include <linux/pm_qos.h>
> >>>  
> >>>  #define DEVFREQ_NAME_LEN 16
> >>>  
> >>>  /* DEVFREQ governor name */
> >>>  #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
> >>> @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
> >>>   *		devfreq.nb to the corresponding register notifier call chain.
> >>>   * @work:	delayed work for load monitoring.
> >>>   * @previous_freq:	previously configured frequency value.
> >>>   * @data:	Private data of the governor. The devfreq framework does not
> >>>   *		touch this.
> >>> - * @min_freq:	Limit minimum frequency requested by user (0: none)
> >>> - * @max_freq:	Limit maximum frequency requested by user (0: none)
> >>> + * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)
> >>
> >> min -> minimum and then remove parenthesis as following:
> >> 	PM QoS minimum frequency request by user via sysfs
> >>
> >>> + * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)
> >>
> >> ditto. max -> maximum
> >> 	PM QoS maximum frequency request by user via sysfs
> >>
> >>>   * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
> >>>   * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
> >>>   * @stop_polling:	 devfreq polling status of a device.
> >>>   * @suspend_freq:	 frequency of a device set during suspend phase.
> >>>   * @resume_freq:	 frequency of a device set in resume phase.
> >>> @@ -161,12 +162,12 @@ struct devfreq {
> >>>  	unsigned long previous_freq;
> >>>  	struct devfreq_dev_status last_status;
> >>>  
> >>>  	void *data; /* private data for governors */
> >>>  
> >>> -	unsigned long min_freq;
> >>> -	unsigned long max_freq;
> >>> +	struct dev_pm_qos_request user_min_freq_req;
> >>> +	struct dev_pm_qos_request user_max_freq_req;
> >>>  	unsigned long scaling_min_freq;
> >>>  	unsigned long scaling_max_freq;
> >>>  	bool stop_polling;
> >>>  
> >>>  	unsigned long suspend_freq;
> >>>
> >>
> >>
> >> -- 
> >> Best Regards,
> >> Chanwoo Choi
> >> Samsung Electronics
> > 
> > 
> 
> 
> -- 
> Best Regards,
> Chanwoo Choi
> Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-26 13:43             ` Leonard Crestez
@ 2019-09-27  1:49               ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-27  1:49 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 19. 9. 26. 오후 10:43, Leonard Crestez wrote:
> On 2019-09-26 4:07 AM, Chanwoo Choi wrote:
>> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>
>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>> imposed externally (for example from other devices).
>>>>>
>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>> ---
>>>>>    drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>>    include/linux/devfreq.h   |  5 +++
>>>>>    2 files changed, 80 insertions(+)
>>>>>
>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>> index eee403e70c84..784f3e40536a 100644
>>>>> --- a/drivers/devfreq/devfreq.c
>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>> @@ -22,15 +22,18 @@
>>>>>    #include <linux/platform_device.h>
>>>>>    #include <linux/list.h>
>>>>>    #include <linux/printk.h>
>>>>>    #include <linux/hrtimer.h>
>>>>>    #include <linux/of.h>
>>>>> +#include <linux/pm_qos.h>
>>>>>    #include "governor.h"
>>>>>    
>>>>>    #define CREATE_TRACE_POINTS
>>>>>    #include <trace/events/devfreq.h>
>>>>>    
>>>>> +#define HZ_PER_KHZ	1000
>>>>> +
>>>>>    static struct class *devfreq_class;
>>>>>    
>>>>>    /*
>>>>>     * devfreq core provides delayed work based load monitoring helper
>>>>>     * functions. Governors can use these or can implement their own
>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>>    static void get_freq_range(struct devfreq *devfreq,
>>>>>    			   unsigned long *min_freq,
>>>>>    			   unsigned long *max_freq)
>>>>>    {
>>>>>    	unsigned long *freq_table = devfreq->profile->freq_table;
>>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>>    
>>>>>    	lockdep_assert_held(&devfreq->lock);
>>>>>    
>>>>>    	/*
>>>>>    	 * Init min/max frequency from freq table.
>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>    	} else {
>>>>>    		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>>    		*max_freq = freq_table[0];
>>>>>    	}
>>>>>    
>>>>> +	/* constraints from PM QoS */
>>>>
>>>> As I commented on patch4,
>>>> 'constraints' -> 'Constraint' because first verb have to be used
>>>> as the sigular verbs.
>>>
>>> Already discussed for another patch; I will modify to "Apply constraints
>>> from PM QoS" instead.
>>
>> I agree the new comment with 'Apply constraints ... '.
>>
>>>
>>>> I prefer to use following comments:
>>>>
>>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>>
>>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>> +
>>>>>    	/* constraints from sysfs */
>>>>>    	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>>    	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>>    
>>>>>    	/* constraints from OPP interface */
>>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>>    	mutex_unlock(&devfreq->lock);
>>>>>    
>>>>>    	return ret;
>>>>>    }
>>>>>    
>>>>> +/**
>>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>>> + * @devfreq:    the devfreq instance.
>>>>> + */
>>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>>> +{
>>>>> +	int err;
>>>>> +
>>>>> +	mutex_lock(&devfreq->lock);
>>>>> +	err = update_devfreq(devfreq);
>>>>> +	mutex_unlock(&devfreq->lock);
>>>>> +	if (err)
>>>>> +		dev_err(devfreq->dev.parent,
>>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>>
>>>> Is it not over 80 char?
>>>
>>> Yes but coding style explicitly forbids breaking strings.
>>>
>>>>> +				err);
>>>>> +
>>>>> +	return NOTIFY_OK;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>>> + * @nb:		Should be devfreq->nb_min
>>>>> + */
>>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>>> +					 unsigned long val, void *ptr)
>>>>> +{
>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>>> + * @nb:		Should be devfreq->nb_max
>>>>> + */
>>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>>> +					 unsigned long val, void *ptr)
>>>>> +{
>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>>> +}
>>>>> +
>>>>>    /**
>>>>>     * devfreq_dev_release() - Callback for struct device to release the device.
>>>>>     * @dev:	the devfreq device
>>>>>     *
>>>>>     * Remove devfreq from the list and release its resources.
>>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>>    
>>>>>    	mutex_lock(&devfreq_list_lock);
>>>>>    	list_del(&devfreq->node);
>>>>>    	mutex_unlock(&devfreq_list_lock);
>>>>>    
>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +
>>>>
>>>> Just print error with dev_err() without stopping the release step.
>>>>
>>>> I prefer to handle the return value if kernel API provides
>>>> the error code.
>>
>> How about?
> 
> Modified to dev_warn. This also applies to PATCH 6 so I replied there.
> 
>>>>>    	if (devfreq->profile->exit)
>>>>>    		devfreq->profile->exit(devfreq->dev.parent);
>>>>>    
>>>>>    	kfree(devfreq->time_in_state);
>>>>>    	kfree(devfreq->trans_table);
>>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>    	if (err) {
>>>>>    		put_device(&devfreq->dev);
>>>>>    		goto err_out;
>>>>>    	}
>>>>>    
>>>>> +	/*
>>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>>> +	 * initialized (and we can handle notifications) but before the
>>>>> +	 * governor is started (which should do an initial enforcement of
>>>>> +	 * constraints).
>>>>> +	 */
>>>>
>>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>>> comments because the line code is not too long. But, at the present time,
>>>> devfreq_add_device() is too long. It means that the detailed comment
>>>> are necessary.
>>>>
>>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>>> on separate patch to keep the same style. I'll send the patch to you
>>>> for the review.
>>>
>>> This is very likely to result in merge conflicts, maybe wait for my
>>> series to go in first?
>>
>> I'll send the separate patch after finished the review of these patches.
>> So, if you agree, please remove this comment on this patch.
>>
>> You can review the detailed comments on separate patch when I send.
> This patch already contains comments and they explain the code being 
> added. Doesn't it make more sense for comments and code to go in together?
> 
> I think the comment is a resonable explanation as to why notifiers are 
> registered at that specific step in the initialization sequence.

If you add this comment on this patch, OK. just I have some comments.

	/*
	 * Register notifiers for updates to min/max_freq after device is
	 * initialized (and we can handle notifications) but before the

I think that 'device is initialized' is not needed.
It is always true, it don't need to add the additional comments.
because dev_pm_qos_add_notifier() must need the 'devfreq->dev'.
The this code prove the call sequence between them.

About 'us', don't use 'we'. The subject is 'devfreq' or other device instead of us.

	 * governor is started (which should do an initial enforcement of
	 * constraints).
 	 */

Actually, it doesn't matter the initialization step between governor
and PM_QOS registration.

If start governor and then register PM_QOS,
the governor can decide the new frequency. And then PM_QOS request
the new constraints for min/max frequency. On request time of PM_QOS,
devfreq can detect this time and then apply the constraints from PM_QOS.

The user of devfreq's PM_QOS must need the phandle or device instance
of devfreq deivce. It means that user of devfreq's PM_QOS can request
the any constraints of PM_QOS_MIN/MAX through PM_QOS interface.

So, it doesn't need to add the following comments
because following comment is not always mandatory.
" governor is started (which should do an initial enforcement of constraints)."

Also, you don't need to use parentheses on comments.

Actually, I think that following comments are enough.

	/* Register PM QoS notifiers for updating to min/max freq */


> 
>>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +	if (err)
>>>>> +		goto err_devfreq;
>>>>> +
>>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>>> +	if (err)
>>>>> +		goto err_devfreq;
>>>>> +
>>>>>    	mutex_lock(&devfreq_list_lock);
>>>>>    
>>>>>    	governor = try_then_request_governor(devfreq->governor_name);
>>>>>    	if (IS_ERR(governor)) {
>>>>>    		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>    
>>>>>    	return devfreq;
>>>>>    
>>>>>    err_init:
>>>>>    	mutex_unlock(&devfreq_list_lock);
>>>>> +err_devfreq:
>>>>>    	devfreq_remove_device(devfreq);
>>>>>    	return ERR_PTR(err);
>>>>>    
>>>>>    err_dev:
>>>>>    	/*
>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>>> --- a/include/linux/devfreq.h
>>>>> +++ b/include/linux/devfreq.h
>>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>>     * @total_trans:	Number of devfreq transitions
>>>>>     * @trans_table:	Statistics of devfreq transitions
>>>>>     * @time_in_state:	Statistics of devfreq states
>>>>>     * @last_stat_updated:	The last time stat updated
>>>>>     * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>>     *
>>>>>     * This structure stores the devfreq information for a give device.
>>>>>     *
>>>>>     * Note that when a governor accesses entries in struct devfreq in its
>>>>>     * functions except for the context of callbacks defined in struct
>>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>>    	unsigned int *trans_table;
>>>>>    	unsigned long *time_in_state;
>>>>>    	unsigned long last_stat_updated;
>>>>>    
>>>>>    	struct srcu_notifier_head transition_notifier_list;
>>>>> +
>>>>> +	struct notifier_block nb_min;
>>>>> +	struct notifier_block nb_max;
>>>>>    };
>>>>>    
>>>>>    struct devfreq_freqs {
>>>>>    	unsigned long old;
>>>>>    	unsigned long new;


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-27  1:49               ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-27  1:49 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 19. 9. 26. 오후 10:43, Leonard Crestez wrote:
> On 2019-09-26 4:07 AM, Chanwoo Choi wrote:
>> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>
>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>> imposed externally (for example from other devices).
>>>>>
>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>> ---
>>>>>    drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>>    include/linux/devfreq.h   |  5 +++
>>>>>    2 files changed, 80 insertions(+)
>>>>>
>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>> index eee403e70c84..784f3e40536a 100644
>>>>> --- a/drivers/devfreq/devfreq.c
>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>> @@ -22,15 +22,18 @@
>>>>>    #include <linux/platform_device.h>
>>>>>    #include <linux/list.h>
>>>>>    #include <linux/printk.h>
>>>>>    #include <linux/hrtimer.h>
>>>>>    #include <linux/of.h>
>>>>> +#include <linux/pm_qos.h>
>>>>>    #include "governor.h"
>>>>>    
>>>>>    #define CREATE_TRACE_POINTS
>>>>>    #include <trace/events/devfreq.h>
>>>>>    
>>>>> +#define HZ_PER_KHZ	1000
>>>>> +
>>>>>    static struct class *devfreq_class;
>>>>>    
>>>>>    /*
>>>>>     * devfreq core provides delayed work based load monitoring helper
>>>>>     * functions. Governors can use these or can implement their own
>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>>    static void get_freq_range(struct devfreq *devfreq,
>>>>>    			   unsigned long *min_freq,
>>>>>    			   unsigned long *max_freq)
>>>>>    {
>>>>>    	unsigned long *freq_table = devfreq->profile->freq_table;
>>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>>    
>>>>>    	lockdep_assert_held(&devfreq->lock);
>>>>>    
>>>>>    	/*
>>>>>    	 * Init min/max frequency from freq table.
>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>    	} else {
>>>>>    		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>>    		*max_freq = freq_table[0];
>>>>>    	}
>>>>>    
>>>>> +	/* constraints from PM QoS */
>>>>
>>>> As I commented on patch4,
>>>> 'constraints' -> 'Constraint' because first verb have to be used
>>>> as the sigular verbs.
>>>
>>> Already discussed for another patch; I will modify to "Apply constraints
>>> from PM QoS" instead.
>>
>> I agree the new comment with 'Apply constraints ... '.
>>
>>>
>>>> I prefer to use following comments:
>>>>
>>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>>
>>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>> +
>>>>>    	/* constraints from sysfs */
>>>>>    	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>>    	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>>    
>>>>>    	/* constraints from OPP interface */
>>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>>    	mutex_unlock(&devfreq->lock);
>>>>>    
>>>>>    	return ret;
>>>>>    }
>>>>>    
>>>>> +/**
>>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>>> + * @devfreq:    the devfreq instance.
>>>>> + */
>>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>>> +{
>>>>> +	int err;
>>>>> +
>>>>> +	mutex_lock(&devfreq->lock);
>>>>> +	err = update_devfreq(devfreq);
>>>>> +	mutex_unlock(&devfreq->lock);
>>>>> +	if (err)
>>>>> +		dev_err(devfreq->dev.parent,
>>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>>
>>>> Is it not over 80 char?
>>>
>>> Yes but coding style explicitly forbids breaking strings.
>>>
>>>>> +				err);
>>>>> +
>>>>> +	return NOTIFY_OK;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>>> + * @nb:		Should be devfreq->nb_min
>>>>> + */
>>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>>> +					 unsigned long val, void *ptr)
>>>>> +{
>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>>> + * @nb:		Should be devfreq->nb_max
>>>>> + */
>>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>>> +					 unsigned long val, void *ptr)
>>>>> +{
>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>>> +}
>>>>> +
>>>>>    /**
>>>>>     * devfreq_dev_release() - Callback for struct device to release the device.
>>>>>     * @dev:	the devfreq device
>>>>>     *
>>>>>     * Remove devfreq from the list and release its resources.
>>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>>    
>>>>>    	mutex_lock(&devfreq_list_lock);
>>>>>    	list_del(&devfreq->node);
>>>>>    	mutex_unlock(&devfreq_list_lock);
>>>>>    
>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +
>>>>
>>>> Just print error with dev_err() without stopping the release step.
>>>>
>>>> I prefer to handle the return value if kernel API provides
>>>> the error code.
>>
>> How about?
> 
> Modified to dev_warn. This also applies to PATCH 6 so I replied there.
> 
>>>>>    	if (devfreq->profile->exit)
>>>>>    		devfreq->profile->exit(devfreq->dev.parent);
>>>>>    
>>>>>    	kfree(devfreq->time_in_state);
>>>>>    	kfree(devfreq->trans_table);
>>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>    	if (err) {
>>>>>    		put_device(&devfreq->dev);
>>>>>    		goto err_out;
>>>>>    	}
>>>>>    
>>>>> +	/*
>>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>>> +	 * initialized (and we can handle notifications) but before the
>>>>> +	 * governor is started (which should do an initial enforcement of
>>>>> +	 * constraints).
>>>>> +	 */
>>>>
>>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>>> comments because the line code is not too long. But, at the present time,
>>>> devfreq_add_device() is too long. It means that the detailed comment
>>>> are necessary.
>>>>
>>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>>> on separate patch to keep the same style. I'll send the patch to you
>>>> for the review.
>>>
>>> This is very likely to result in merge conflicts, maybe wait for my
>>> series to go in first?
>>
>> I'll send the separate patch after finished the review of these patches.
>> So, if you agree, please remove this comment on this patch.
>>
>> You can review the detailed comments on separate patch when I send.
> This patch already contains comments and they explain the code being 
> added. Doesn't it make more sense for comments and code to go in together?
> 
> I think the comment is a resonable explanation as to why notifiers are 
> registered at that specific step in the initialization sequence.

If you add this comment on this patch, OK. just I have some comments.

	/*
	 * Register notifiers for updates to min/max_freq after device is
	 * initialized (and we can handle notifications) but before the

I think that 'device is initialized' is not needed.
It is always true, it don't need to add the additional comments.
because dev_pm_qos_add_notifier() must need the 'devfreq->dev'.
The this code prove the call sequence between them.

About 'us', don't use 'we'. The subject is 'devfreq' or other device instead of us.

	 * governor is started (which should do an initial enforcement of
	 * constraints).
 	 */

Actually, it doesn't matter the initialization step between governor
and PM_QOS registration.

If start governor and then register PM_QOS,
the governor can decide the new frequency. And then PM_QOS request
the new constraints for min/max frequency. On request time of PM_QOS,
devfreq can detect this time and then apply the constraints from PM_QOS.

The user of devfreq's PM_QOS must need the phandle or device instance
of devfreq deivce. It means that user of devfreq's PM_QOS can request
the any constraints of PM_QOS_MIN/MAX through PM_QOS interface.

So, it doesn't need to add the following comments
because following comment is not always mandatory.
" governor is started (which should do an initial enforcement of constraints)."

Also, you don't need to use parentheses on comments.

Actually, I think that following comments are enough.

	/* Register PM QoS notifiers for updating to min/max freq */


> 
>>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +	if (err)
>>>>> +		goto err_devfreq;
>>>>> +
>>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>>> +	if (err)
>>>>> +		goto err_devfreq;
>>>>> +
>>>>>    	mutex_lock(&devfreq_list_lock);
>>>>>    
>>>>>    	governor = try_then_request_governor(devfreq->governor_name);
>>>>>    	if (IS_ERR(governor)) {
>>>>>    		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>    
>>>>>    	return devfreq;
>>>>>    
>>>>>    err_init:
>>>>>    	mutex_unlock(&devfreq_list_lock);
>>>>> +err_devfreq:
>>>>>    	devfreq_remove_device(devfreq);
>>>>>    	return ERR_PTR(err);
>>>>>    
>>>>>    err_dev:
>>>>>    	/*
>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>>> --- a/include/linux/devfreq.h
>>>>> +++ b/include/linux/devfreq.h
>>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>>     * @total_trans:	Number of devfreq transitions
>>>>>     * @trans_table:	Statistics of devfreq transitions
>>>>>     * @time_in_state:	Statistics of devfreq states
>>>>>     * @last_stat_updated:	The last time stat updated
>>>>>     * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>>     *
>>>>>     * This structure stores the devfreq information for a give device.
>>>>>     *
>>>>>     * Note that when a governor accesses entries in struct devfreq in its
>>>>>     * functions except for the context of callbacks defined in struct
>>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>>    	unsigned int *trans_table;
>>>>>    	unsigned long *time_in_state;
>>>>>    	unsigned long last_stat_updated;
>>>>>    
>>>>>    	struct srcu_notifier_head transition_notifier_list;
>>>>> +
>>>>> +	struct notifier_block nb_min;
>>>>> +	struct notifier_block nb_max;
>>>>>    };
>>>>>    
>>>>>    struct devfreq_freqs {
>>>>>    	unsigned long old;
>>>>>    	unsigned long new;


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
  2019-09-26 16:04             ` Matthias Kaehlcke
@ 2019-09-27  1:58               ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-27  1:58 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: Leonard Crestez, MyungJoo Ham, Kyungmin Park,
	Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	NXP Linux Team, linux-pm, linux-arm-kernel

On 19. 9. 27. 오전 1:04, Matthias Kaehlcke wrote:
> On Thu, Sep 26, 2019 at 10:25:41AM +0900, Chanwoo Choi wrote:
>> On 19. 9. 26. 오전 1:45, Matthias Kaehlcke wrote:
>>> On Wed, Sep 25, 2019 at 11:41:07AM +0900, Chanwoo Choi wrote:
>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>> Switch the handling of min_freq and max_freq from sysfs to use the
>>>>> dev_pm_qos_request interface.
>>>>>
>>>>> Since PM QoS handles frequencies as kHz this change reduces the
>>>>> precision of min_freq and max_freq. This shouldn't introduce problems
>>>>> because frequencies which are not an integer number of kHz are likely
>>>>> not an integer number of Hz either.
>>>>>
>>>>> Try to ensure compatibility by rounding min values down and rounding
>>>>> max values up.
>>>>>
>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>> ---
>>>>>  drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
>>>>>  include/linux/devfreq.h   |  9 ++++----
>>>>>  2 files changed, 33 insertions(+), 22 deletions(-)
>>>>>
>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>> index 784f3e40536a..8bb7efd821ab 100644
>>>>> --- a/drivers/devfreq/devfreq.c
>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>> @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>  	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>  					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>  	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>>  	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>>  
>>>>> -	/* constraints from sysfs */
>>>>> -	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>> -	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>> -
>>>>>  	/* constraints from OPP interface */
>>>>>  	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>>>>>  	/* scaling_max_freq can be zero on error */
>>>>>  	if (devfreq->scaling_max_freq)
>>>>>  		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
>>>>> @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
>>>>>  			DEV_PM_QOS_MIN_FREQUENCY);
>>>>>  
>>>>>  	if (devfreq->profile->exit)
>>>>>  		devfreq->profile->exit(devfreq->dev.parent);
>>>>>  
>>>>> +	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>>>>> +	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
>>>>
>>>> Please check the return value if error happen, just print the err with dev_err()
>>>> without stopping the release steps.
>>>
>>> I wonder if dev_warn() would be more appropriate, since the current operation
>>> is not aborted.
>>>
>>>>>  	kfree(devfreq->time_in_state);
>>>>>  	kfree(devfreq->trans_table);
>>>>>  	mutex_destroy(&devfreq->lock);
>>>>>  	kfree(devfreq);
>>>>>  }
>>>>> @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>  	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
>>>>>  	if (!devfreq->scaling_min_freq) {
>>>>>  		err = -EINVAL;
>>>>>  		goto err_dev;
>>>>>  	}
>>>>> -	devfreq->min_freq = devfreq->scaling_min_freq;
>>>>>  
>>>>>  	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
>>>>>  	if (!devfreq->scaling_max_freq) {
>>>>>  		err = -EINVAL;
>>>>>  		goto err_dev;
>>>>>  	}
>>>>> -	devfreq->max_freq = devfreq->scaling_max_freq;
>>>>> +
>>>>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
>>>>> +				     DEV_PM_QOS_MIN_FREQUENCY, 0);
>>>>> +	if (err < 0)
>>>>> +		goto err_dev;
>>>>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
>>>>> +				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
>>>>> +	if (err < 0)
>>>>> +		goto err_dev;
>>>>>  
>>>>>  	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
>>>>>  	atomic_set(&devfreq->suspend_count, 0);
>>>>>  
>>>>>  	devfreq->trans_table = kzalloc(
>>>>> @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>  err_dev:
>>>>>  	/*
>>>>>  	 * Cleanup path for errors that happen before registration.
>>>>>  	 * Otherwise we rely on devfreq_dev_release.
>>>>>  	 */
>>>>> +	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
>>>>> +		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>>>>
>>>> Please check the return value if error happen, just print the err with dev_err()
>>>> without stopping the release steps.
>>>>
>>>> 	dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");
>>>
>>> dev_warn() for the same reason as above?
>>
>> Actually, I think that is not critical error but need to print the error
>> So, I think that dev_err() is enough. If this thing is critical,
>> better to use dev_warn.
> 
> We agree that this is not critical, but not when to use dev_err()
> and dev_warn(). You seem to imply that dev_warn() is more severe
> than dev_err(), however it's the other way around:
> 
> #define KERN_ERR        KERN_SOH "3"    /* error conditions */
> #define KERN_WARNING    KERN_SOH "4"    /* warning conditions */
> #define KERN_NOTICE     KERN_SOH "5"    /* normal but significant condition */
> 
> I think in this case you can go either way, it's certainly an error,
> but the driver continues with the normal execution path.

I agree to use dev_warn. Thanks for detailed explanation.

> 
>>>
>>> I think the message would be better with a slight change:
>>>
>>> "failed to remove DEV_PM_QOS_MAX_FREQUENCY request\n"
>>
>> OK.
>>
>>>
>>>>
>>>>> +	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
>>>>> +		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
>>>> 	
>>>> 	dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");
>>>
>>> ditto
>>>
>>>>>  	kfree(devfreq->time_in_state);
>>>>>  	kfree(devfreq->trans_table);
>>>>>  	kfree(devfreq);
>>>>>  err_out:
>>>>>  	return ERR_PTR(err);
>>>>> @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>>>>  
>>>>>  	ret = sscanf(buf, "%lu", &value);
>>>>>  	if (ret != 1)
>>>>>  		return -EINVAL;
>>>>>  
>>>>> -	mutex_lock(&df->lock);
>>>>> -	df->min_freq = value;
>>>>> -	update_devfreq(df);
>>>>> -	mutex_unlock(&df->lock);
>>>>> +	/* round down to kHz for PM QoS */
>>>>
>>>> I prefer more detailed description as following:
>>>>
>>>> 	/*
>>>> 	 * Round down to KHz to decide the proper minimum frequency
>>>
>>> it should be kHz, with a lower-case 'k', as in the original comment.
>>
>> Good.
>>
>>>
>>>> 	 * which is closed to user request.
>>>>  	 */
>>>
>>> The comment you suggest doesn't provide any information about why the
>>> conversion to kHz is done, in this sense the original comment that
>>> mentions PM QoS provides more value.
>>>
>>> With whatever we end up, I suggest to use 'convert' instead of
>>> 'round down'.
>>
>> I agree to use 'convert' instead of 'round down'
>> if some expression indicates the correct meaning.
>>
>>>
>>>>> +	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
>>>>> +					value / HZ_PER_KHZ);
>>>>> +	if (ret < 0)
>>>>> +		return ret;
>>>>>  
>>>>>  	return count;
>>>>>  }
>>>>>  
>>>>>  static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>>>>> @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>>>  
>>>>>  	ret = sscanf(buf, "%lu", &value);
>>>>>  	if (ret != 1)
>>>>>  		return -EINVAL;
>>>>>  
>>>>> -	mutex_lock(&df->lock);
>>>>> -
>>>>> -	/* Interpret zero as "don't care" */
>>>>> -	if (!value)
>>>>> -		value = ULONG_MAX;
>>>>> +	/* round up to kHz for PM QoS and interpret zero as "don't care" */
>>>>
>>>> I think that "don't care" comment style is not good.
>>>>
>>>> I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
>>>> I prefer more detailed description as following:
>>>> 	/*
>>>> 	 * Round up to KHz to decide the proper maximum frequency
>>>
>>> kHz
>>>
>>>> 	 * which is closed to user request. If value is zero,
>>>> 	 * the user does not care.
>>>
>>> "the user does not care" is still very casual you didn't like initially.
>>> How about "A value of zero is interpreted as 'no limit'."?
>>>
>>> As for the min freq, I think PM QoS should be mentioned to make clear why
>>> the conversion to kHz is needed.
>>
>> Agree. I expect that Leonard will mention that.
>>
>>>
>>>>  	 */
>>>>
>>>>
>>>>> +	if (value)
>>>>> +		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
>>>>> +	else
>>>>> +		value = S32_MAX;
>>>>>  
>>>>> -	df->max_freq = value;
>>>>> -	update_devfreq(df);
>>>>> -	mutex_unlock(&df->lock);
>>>>> +	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
>>>>> +	if (ret < 0)
>>>>> +		return ret;
>>>>>  
>>>>>  	return count;
>>>>>  }
>>>>>  static DEVICE_ATTR_RW(min_freq);
>>>>>  
>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>> index dac0dffeabb4..7849fe4c666d 100644
>>>>> --- a/include/linux/devfreq.h
>>>>> +++ b/include/linux/devfreq.h
>>>>> @@ -11,10 +11,11 @@
>>>>>  #define __LINUX_DEVFREQ_H__
>>>>>  
>>>>>  #include <linux/device.h>
>>>>>  #include <linux/notifier.h>
>>>>>  #include <linux/pm_opp.h>
>>>>> +#include <linux/pm_qos.h>
>>>>>  
>>>>>  #define DEVFREQ_NAME_LEN 16
>>>>>  
>>>>>  /* DEVFREQ governor name */
>>>>>  #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
>>>>> @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
>>>>>   *		devfreq.nb to the corresponding register notifier call chain.
>>>>>   * @work:	delayed work for load monitoring.
>>>>>   * @previous_freq:	previously configured frequency value.
>>>>>   * @data:	Private data of the governor. The devfreq framework does not
>>>>>   *		touch this.
>>>>> - * @min_freq:	Limit minimum frequency requested by user (0: none)
>>>>> - * @max_freq:	Limit maximum frequency requested by user (0: none)
>>>>> + * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)
>>>>
>>>> min -> minimum and then remove parenthesis as following:
>>>> 	PM QoS minimum frequency request by user via sysfs
>>>>
>>>>> + * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)
>>>>
>>>> ditto. max -> maximum
>>>> 	PM QoS maximum frequency request by user via sysfs
>>>>
>>>>>   * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
>>>>>   * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
>>>>>   * @stop_polling:	 devfreq polling status of a device.
>>>>>   * @suspend_freq:	 frequency of a device set during suspend phase.
>>>>>   * @resume_freq:	 frequency of a device set in resume phase.
>>>>> @@ -161,12 +162,12 @@ struct devfreq {
>>>>>  	unsigned long previous_freq;
>>>>>  	struct devfreq_dev_status last_status;
>>>>>  
>>>>>  	void *data; /* private data for governors */
>>>>>  
>>>>> -	unsigned long min_freq;
>>>>> -	unsigned long max_freq;
>>>>> +	struct dev_pm_qos_request user_min_freq_req;
>>>>> +	struct dev_pm_qos_request user_max_freq_req;
>>>>>  	unsigned long scaling_min_freq;
>>>>>  	unsigned long scaling_max_freq;
>>>>>  	bool stop_polling;
>>>>>  
>>>>>  	unsigned long suspend_freq;
>>>>>
>>>>
>>>>
>>>> -- 
>>>> Best Regards,
>>>> Chanwoo Choi
>>>> Samsung Electronics
>>>
>>>
>>
>>
>> -- 
>> Best Regards,
>> Chanwoo Choi
>> Samsung Electronics
> 
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
@ 2019-09-27  1:58               ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-27  1:58 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar,
	NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park,
	MyungJoo Ham, Alexandre Bailon, Leonard Crestez, Georgi Djakov,
	linux-arm-kernel, Jacky Bai

On 19. 9. 27. 오전 1:04, Matthias Kaehlcke wrote:
> On Thu, Sep 26, 2019 at 10:25:41AM +0900, Chanwoo Choi wrote:
>> On 19. 9. 26. 오전 1:45, Matthias Kaehlcke wrote:
>>> On Wed, Sep 25, 2019 at 11:41:07AM +0900, Chanwoo Choi wrote:
>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>> Switch the handling of min_freq and max_freq from sysfs to use the
>>>>> dev_pm_qos_request interface.
>>>>>
>>>>> Since PM QoS handles frequencies as kHz this change reduces the
>>>>> precision of min_freq and max_freq. This shouldn't introduce problems
>>>>> because frequencies which are not an integer number of kHz are likely
>>>>> not an integer number of Hz either.
>>>>>
>>>>> Try to ensure compatibility by rounding min values down and rounding
>>>>> max values up.
>>>>>
>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>> ---
>>>>>  drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
>>>>>  include/linux/devfreq.h   |  9 ++++----
>>>>>  2 files changed, 33 insertions(+), 22 deletions(-)
>>>>>
>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>> index 784f3e40536a..8bb7efd821ab 100644
>>>>> --- a/drivers/devfreq/devfreq.c
>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>> @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>  	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>  					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>  	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>>  	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>>  
>>>>> -	/* constraints from sysfs */
>>>>> -	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>> -	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>> -
>>>>>  	/* constraints from OPP interface */
>>>>>  	*min_freq = max(*min_freq, devfreq->scaling_min_freq);
>>>>>  	/* scaling_max_freq can be zero on error */
>>>>>  	if (devfreq->scaling_max_freq)
>>>>>  		*max_freq = min(*max_freq, devfreq->scaling_max_freq);
>>>>> @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
>>>>>  			DEV_PM_QOS_MIN_FREQUENCY);
>>>>>  
>>>>>  	if (devfreq->profile->exit)
>>>>>  		devfreq->profile->exit(devfreq->dev.parent);
>>>>>  
>>>>> +	dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>>>>> +	dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
>>>>
>>>> Please check the return value if error happen, just print the err with dev_err()
>>>> without stopping the release steps.
>>>
>>> I wonder if dev_warn() would be more appropriate, since the current operation
>>> is not aborted.
>>>
>>>>>  	kfree(devfreq->time_in_state);
>>>>>  	kfree(devfreq->trans_table);
>>>>>  	mutex_destroy(&devfreq->lock);
>>>>>  	kfree(devfreq);
>>>>>  }
>>>>> @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>  	devfreq->scaling_min_freq = find_available_min_freq(devfreq);
>>>>>  	if (!devfreq->scaling_min_freq) {
>>>>>  		err = -EINVAL;
>>>>>  		goto err_dev;
>>>>>  	}
>>>>> -	devfreq->min_freq = devfreq->scaling_min_freq;
>>>>>  
>>>>>  	devfreq->scaling_max_freq = find_available_max_freq(devfreq);
>>>>>  	if (!devfreq->scaling_max_freq) {
>>>>>  		err = -EINVAL;
>>>>>  		goto err_dev;
>>>>>  	}
>>>>> -	devfreq->max_freq = devfreq->scaling_max_freq;
>>>>> +
>>>>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
>>>>> +				     DEV_PM_QOS_MIN_FREQUENCY, 0);
>>>>> +	if (err < 0)
>>>>> +		goto err_dev;
>>>>> +	err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
>>>>> +				     DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
>>>>> +	if (err < 0)
>>>>> +		goto err_dev;
>>>>>  
>>>>>  	devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
>>>>>  	atomic_set(&devfreq->suspend_count, 0);
>>>>>  
>>>>>  	devfreq->trans_table = kzalloc(
>>>>> @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>  err_dev:
>>>>>  	/*
>>>>>  	 * Cleanup path for errors that happen before registration.
>>>>>  	 * Otherwise we rely on devfreq_dev_release.
>>>>>  	 */
>>>>> +	if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
>>>>> +		dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>>>>
>>>> Please check the return value if error happen, just print the err with dev_err()
>>>> without stopping the release steps.
>>>>
>>>> 	dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");
>>>
>>> dev_warn() for the same reason as above?
>>
>> Actually, I think that is not critical error but need to print the error
>> So, I think that dev_err() is enough. If this thing is critical,
>> better to use dev_warn.
> 
> We agree that this is not critical, but not when to use dev_err()
> and dev_warn(). You seem to imply that dev_warn() is more severe
> than dev_err(), however it's the other way around:
> 
> #define KERN_ERR        KERN_SOH "3"    /* error conditions */
> #define KERN_WARNING    KERN_SOH "4"    /* warning conditions */
> #define KERN_NOTICE     KERN_SOH "5"    /* normal but significant condition */
> 
> I think in this case you can go either way, it's certainly an error,
> but the driver continues with the normal execution path.

I agree to use dev_warn. Thanks for detailed explanation.

> 
>>>
>>> I think the message would be better with a slight change:
>>>
>>> "failed to remove DEV_PM_QOS_MAX_FREQUENCY request\n"
>>
>> OK.
>>
>>>
>>>>
>>>>> +	if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
>>>>> +		dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
>>>> 	
>>>> 	dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");
>>>
>>> ditto
>>>
>>>>>  	kfree(devfreq->time_in_state);
>>>>>  	kfree(devfreq->trans_table);
>>>>>  	kfree(devfreq);
>>>>>  err_out:
>>>>>  	return ERR_PTR(err);
>>>>> @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>>>>  
>>>>>  	ret = sscanf(buf, "%lu", &value);
>>>>>  	if (ret != 1)
>>>>>  		return -EINVAL;
>>>>>  
>>>>> -	mutex_lock(&df->lock);
>>>>> -	df->min_freq = value;
>>>>> -	update_devfreq(df);
>>>>> -	mutex_unlock(&df->lock);
>>>>> +	/* round down to kHz for PM QoS */
>>>>
>>>> I prefer more detailed description as following:
>>>>
>>>> 	/*
>>>> 	 * Round down to KHz to decide the proper minimum frequency
>>>
>>> it should be kHz, with a lower-case 'k', as in the original comment.
>>
>> Good.
>>
>>>
>>>> 	 * which is closed to user request.
>>>>  	 */
>>>
>>> The comment you suggest doesn't provide any information about why the
>>> conversion to kHz is done, in this sense the original comment that
>>> mentions PM QoS provides more value.
>>>
>>> With whatever we end up, I suggest to use 'convert' instead of
>>> 'round down'.
>>
>> I agree to use 'convert' instead of 'round down'
>> if some expression indicates the correct meaning.
>>
>>>
>>>>> +	ret = dev_pm_qos_update_request(&df->user_min_freq_req,
>>>>> +					value / HZ_PER_KHZ);
>>>>> +	if (ret < 0)
>>>>> +		return ret;
>>>>>  
>>>>>  	return count;
>>>>>  }
>>>>>  
>>>>>  static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>>>>> @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>>>  
>>>>>  	ret = sscanf(buf, "%lu", &value);
>>>>>  	if (ret != 1)
>>>>>  		return -EINVAL;
>>>>>  
>>>>> -	mutex_lock(&df->lock);
>>>>> -
>>>>> -	/* Interpret zero as "don't care" */
>>>>> -	if (!value)
>>>>> -		value = ULONG_MAX;
>>>>> +	/* round up to kHz for PM QoS and interpret zero as "don't care" */
>>>>
>>>> I think that "don't care" comment style is not good.
>>>>
>>>> I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
>>>> I prefer more detailed description as following:
>>>> 	/*
>>>> 	 * Round up to KHz to decide the proper maximum frequency
>>>
>>> kHz
>>>
>>>> 	 * which is closed to user request. If value is zero,
>>>> 	 * the user does not care.
>>>
>>> "the user does not care" is still very casual you didn't like initially.
>>> How about "A value of zero is interpreted as 'no limit'."?
>>>
>>> As for the min freq, I think PM QoS should be mentioned to make clear why
>>> the conversion to kHz is needed.
>>
>> Agree. I expect that Leonard will mention that.
>>
>>>
>>>>  	 */
>>>>
>>>>
>>>>> +	if (value)
>>>>> +		value = DIV_ROUND_UP(value, HZ_PER_KHZ);
>>>>> +	else
>>>>> +		value = S32_MAX;
>>>>>  
>>>>> -	df->max_freq = value;
>>>>> -	update_devfreq(df);
>>>>> -	mutex_unlock(&df->lock);
>>>>> +	ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
>>>>> +	if (ret < 0)
>>>>> +		return ret;
>>>>>  
>>>>>  	return count;
>>>>>  }
>>>>>  static DEVICE_ATTR_RW(min_freq);
>>>>>  
>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>> index dac0dffeabb4..7849fe4c666d 100644
>>>>> --- a/include/linux/devfreq.h
>>>>> +++ b/include/linux/devfreq.h
>>>>> @@ -11,10 +11,11 @@
>>>>>  #define __LINUX_DEVFREQ_H__
>>>>>  
>>>>>  #include <linux/device.h>
>>>>>  #include <linux/notifier.h>
>>>>>  #include <linux/pm_opp.h>
>>>>> +#include <linux/pm_qos.h>
>>>>>  
>>>>>  #define DEVFREQ_NAME_LEN 16
>>>>>  
>>>>>  /* DEVFREQ governor name */
>>>>>  #define DEVFREQ_GOV_SIMPLE_ONDEMAND	"simple_ondemand"
>>>>> @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
>>>>>   *		devfreq.nb to the corresponding register notifier call chain.
>>>>>   * @work:	delayed work for load monitoring.
>>>>>   * @previous_freq:	previously configured frequency value.
>>>>>   * @data:	Private data of the governor. The devfreq framework does not
>>>>>   *		touch this.
>>>>> - * @min_freq:	Limit minimum frequency requested by user (0: none)
>>>>> - * @max_freq:	Limit maximum frequency requested by user (0: none)
>>>>> + * @user_min_freq_req:	PM QoS min frequency request from user (via sysfs)
>>>>
>>>> min -> minimum and then remove parenthesis as following:
>>>> 	PM QoS minimum frequency request by user via sysfs
>>>>
>>>>> + * @user_max_freq_req:	PM QoS max frequency request from user (via sysfs)
>>>>
>>>> ditto. max -> maximum
>>>> 	PM QoS maximum frequency request by user via sysfs
>>>>
>>>>>   * @scaling_min_freq:	Limit minimum frequency requested by OPP interface
>>>>>   * @scaling_max_freq:	Limit maximum frequency requested by OPP interface
>>>>>   * @stop_polling:	 devfreq polling status of a device.
>>>>>   * @suspend_freq:	 frequency of a device set during suspend phase.
>>>>>   * @resume_freq:	 frequency of a device set in resume phase.
>>>>> @@ -161,12 +162,12 @@ struct devfreq {
>>>>>  	unsigned long previous_freq;
>>>>>  	struct devfreq_dev_status last_status;
>>>>>  
>>>>>  	void *data; /* private data for governors */
>>>>>  
>>>>> -	unsigned long min_freq;
>>>>> -	unsigned long max_freq;
>>>>> +	struct dev_pm_qos_request user_min_freq_req;
>>>>> +	struct dev_pm_qos_request user_max_freq_req;
>>>>>  	unsigned long scaling_min_freq;
>>>>>  	unsigned long scaling_max_freq;
>>>>>  	bool stop_polling;
>>>>>  
>>>>>  	unsigned long suspend_freq;
>>>>>
>>>>
>>>>
>>>> -- 
>>>> Best Regards,
>>>> Chanwoo Choi
>>>> Samsung Electronics
>>>
>>>
>>
>>
>> -- 
>> Best Regards,
>> Chanwoo Choi
>> Samsung Electronics
> 
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-26  1:19           ` Chanwoo Choi
@ 2019-09-30 12:43             ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-30 12:43 UTC (permalink / raw)
  To: Chanwoo Choi, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 2019-09-26 4:14 AM, Chanwoo Choi wrote:
> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>> Register notifiers with the PM QoS framework in order to respond to
>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>
>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>> imposed externally (for example from other devices).
>>>>
>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>> ---
>>>>    drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>    include/linux/devfreq.h   |  5 +++
>>>>    2 files changed, 80 insertions(+)
>>>>
>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>> index eee403e70c84..784f3e40536a 100644
>>>> --- a/drivers/devfreq/devfreq.c
>>>> +++ b/drivers/devfreq/devfreq.c
>>>> @@ -22,15 +22,18 @@
>>>>    #include <linux/platform_device.h>
>>>>    #include <linux/list.h>
>>>>    #include <linux/printk.h>
>>>>    #include <linux/hrtimer.h>
>>>>    #include <linux/of.h>
>>>> +#include <linux/pm_qos.h>
>>>>    #include "governor.h"
>>>>    
>>>>    #define CREATE_TRACE_POINTS
>>>>    #include <trace/events/devfreq.h>
>>>>    
>>>> +#define HZ_PER_KHZ	1000
>>>> +
>>>>    static struct class *devfreq_class;
>>>>    
>>>>    /*
>>>>     * devfreq core provides delayed work based load monitoring helper
>>>>     * functions. Governors can use these or can implement their own
>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>    static void get_freq_range(struct devfreq *devfreq,
>>>>    			   unsigned long *min_freq,
>>>>    			   unsigned long *max_freq)
>>>>    {
>>>>    	unsigned long *freq_table = devfreq->profile->freq_table;
>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>    
>>>>    	lockdep_assert_held(&devfreq->lock);
>>>>    
>>>>    	/*
>>>>    	 * Init min/max frequency from freq table.
>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>    	} else {
>>>>    		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>    		*max_freq = freq_table[0];
>>>>    	}
>>>>    
>>>> +	/* constraints from PM QoS */
>>>
>>> As I commented on patch4,
>>> 'constraints' -> 'Constraint' because first verb have to be used
>>> as the sigular verbs.
>>
>> Already discussed for another patch; I will modify to "Apply constraints
>> from PM QoS" instead.
>>
>>> I prefer to use following comments:
>>>
>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>
>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>> +
>>>>    	/* constraints from sysfs */
>>>>    	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>    	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>    
>>>>    	/* constraints from OPP interface */
>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>    	mutex_unlock(&devfreq->lock);
>>>>    
>>>>    	return ret;
>>>>    }
>>>>    
>>>> +/**
>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>> + * @devfreq:    the devfreq instance.
>>>> + */
>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>> +{
>>>> +	int err;
>>>> +
>>>> +	mutex_lock(&devfreq->lock);
>>>> +	err = update_devfreq(devfreq);
>>>> +	mutex_unlock(&devfreq->lock);
>>>> +	if (err)
>>>> +		dev_err(devfreq->dev.parent,
>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>
>>> Is it not over 80 char?
>>
>> Yes but coding style explicitly forbids breaking strings.
> 
> I want to make it within 80 char. How about following comment?
> 
> 		dev_err(devfreq->dev.parent,
> 			"failed to update frequency from PM QoS (%d)\n",

Yes, shrinking the comment and aligning with open parenthesis can keep 
it under 80 chars. Maybe it could be shrunk further to

     "failed update for PM QoS"

>>>> +				err);
>>>> +
>>>> +	return NOTIFY_OK;
>>>> +}
>>>> +
>>>> +/**
>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>> + * @nb:		Should be devfreq->nb_min
>>>> + */
>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>> +					 unsigned long val, void *ptr)
>>>> +{
>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>> +}
>>>> +
>>>> +/**
>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>> + * @nb:		Should be devfreq->nb_max
>>>> + */
>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>> +					 unsigned long val, void *ptr)
>>>> +{
>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>> +}
>>>> +
>>>>    /**
>>>>     * devfreq_dev_release() - Callback for struct device to release the device.
>>>>     * @dev:	the devfreq device
>>>>     *
>>>>     * Remove devfreq from the list and release its resources.
>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>    
>>>>    	mutex_lock(&devfreq_list_lock);
>>>>    	list_del(&devfreq->node);
>>>>    	mutex_unlock(&devfreq_list_lock);
>>>>    
>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>> +
>>>
>>> Just print error with dev_err() without stopping the release step.
>>>
>>> I prefer to handle the return value if kernel API provides
>>> the error code.
>>>
>>>>    	if (devfreq->profile->exit)
>>>>    		devfreq->profile->exit(devfreq->dev.parent);
>>>>    
>>>>    	kfree(devfreq->time_in_state);
>>>>    	kfree(devfreq->trans_table);
>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>    	if (err) {
>>>>    		put_device(&devfreq->dev);
>>>>    		goto err_out;
>>>>    	}
>>>>    
>>>> +	/*
>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>> +	 * initialized (and we can handle notifications) but before the
>>>> +	 * governor is started (which should do an initial enforcement of
>>>> +	 * constraints).
>>>> +	 */
>>>
>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>> comments because the line code is not too long. But, at the present time,
>>> devfreq_add_device() is too long. It means that the detailed comment
>>> are necessary.
>>>
>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>> on separate patch to keep the same style. I'll send the patch to you
>>> for the review.
>>
>> This is very likely to result in merge conflicts, maybe wait for my
>> series to go in first?
>>
>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>> +	if (err)
>>>> +		goto err_devfreq;
>>>> +
>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>> +	if (err)
>>>> +		goto err_devfreq;
>>>> +
>>>>    	mutex_lock(&devfreq_list_lock);
>>>>    
>>>>    	governor = try_then_request_governor(devfreq->governor_name);
>>>>    	if (IS_ERR(governor)) {
>>>>    		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>    
>>>>    	return devfreq;
>>>>    
>>>>    err_init:
>>>>    	mutex_unlock(&devfreq_list_lock);
>>>> +err_devfreq:
>>>>    	devfreq_remove_device(devfreq);
>>>>    	return ERR_PTR(err);
>>>>    
>>>>    err_dev:
>>>>    	/*
>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>> --- a/include/linux/devfreq.h
>>>> +++ b/include/linux/devfreq.h
>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>     * @total_trans:	Number of devfreq transitions
>>>>     * @trans_table:	Statistics of devfreq transitions
>>>>     * @time_in_state:	Statistics of devfreq states
>>>>     * @last_stat_updated:	The last time stat updated
>>>>     * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>     *
>>>>     * This structure stores the devfreq information for a give device.
>>>>     *
>>>>     * Note that when a governor accesses entries in struct devfreq in its
>>>>     * functions except for the context of callbacks defined in struct
>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>    	unsigned int *trans_table;
>>>>    	unsigned long *time_in_state;
>>>>    	unsigned long last_stat_updated;
>>>>    
>>>>    	struct srcu_notifier_head transition_notifier_list;
>>>> +
>>>> +	struct notifier_block nb_min;
>>>> +	struct notifier_block nb_max;
>>>>    };
>>>>    
>>>>    struct devfreq_freqs {
>>>>    	unsigned long old;
>>>>    	unsigned long new;
>>>>
>>>
>>>
>>
> 
> 


^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-30 12:43             ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-30 12:43 UTC (permalink / raw)
  To: Chanwoo Choi, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 2019-09-26 4:14 AM, Chanwoo Choi wrote:
> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>> Register notifiers with the PM QoS framework in order to respond to
>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>
>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>> imposed externally (for example from other devices).
>>>>
>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>> ---
>>>>    drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>    include/linux/devfreq.h   |  5 +++
>>>>    2 files changed, 80 insertions(+)
>>>>
>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>> index eee403e70c84..784f3e40536a 100644
>>>> --- a/drivers/devfreq/devfreq.c
>>>> +++ b/drivers/devfreq/devfreq.c
>>>> @@ -22,15 +22,18 @@
>>>>    #include <linux/platform_device.h>
>>>>    #include <linux/list.h>
>>>>    #include <linux/printk.h>
>>>>    #include <linux/hrtimer.h>
>>>>    #include <linux/of.h>
>>>> +#include <linux/pm_qos.h>
>>>>    #include "governor.h"
>>>>    
>>>>    #define CREATE_TRACE_POINTS
>>>>    #include <trace/events/devfreq.h>
>>>>    
>>>> +#define HZ_PER_KHZ	1000
>>>> +
>>>>    static struct class *devfreq_class;
>>>>    
>>>>    /*
>>>>     * devfreq core provides delayed work based load monitoring helper
>>>>     * functions. Governors can use these or can implement their own
>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>    static void get_freq_range(struct devfreq *devfreq,
>>>>    			   unsigned long *min_freq,
>>>>    			   unsigned long *max_freq)
>>>>    {
>>>>    	unsigned long *freq_table = devfreq->profile->freq_table;
>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>    
>>>>    	lockdep_assert_held(&devfreq->lock);
>>>>    
>>>>    	/*
>>>>    	 * Init min/max frequency from freq table.
>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>    	} else {
>>>>    		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>    		*max_freq = freq_table[0];
>>>>    	}
>>>>    
>>>> +	/* constraints from PM QoS */
>>>
>>> As I commented on patch4,
>>> 'constraints' -> 'Constraint' because first verb have to be used
>>> as the sigular verbs.
>>
>> Already discussed for another patch; I will modify to "Apply constraints
>> from PM QoS" instead.
>>
>>> I prefer to use following comments:
>>>
>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>
>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>> +
>>>>    	/* constraints from sysfs */
>>>>    	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>    	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>    
>>>>    	/* constraints from OPP interface */
>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>    	mutex_unlock(&devfreq->lock);
>>>>    
>>>>    	return ret;
>>>>    }
>>>>    
>>>> +/**
>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>> + * @devfreq:    the devfreq instance.
>>>> + */
>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>> +{
>>>> +	int err;
>>>> +
>>>> +	mutex_lock(&devfreq->lock);
>>>> +	err = update_devfreq(devfreq);
>>>> +	mutex_unlock(&devfreq->lock);
>>>> +	if (err)
>>>> +		dev_err(devfreq->dev.parent,
>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>
>>> Is it not over 80 char?
>>
>> Yes but coding style explicitly forbids breaking strings.
> 
> I want to make it within 80 char. How about following comment?
> 
> 		dev_err(devfreq->dev.parent,
> 			"failed to update frequency from PM QoS (%d)\n",

Yes, shrinking the comment and aligning with open parenthesis can keep 
it under 80 chars. Maybe it could be shrunk further to

     "failed update for PM QoS"

>>>> +				err);
>>>> +
>>>> +	return NOTIFY_OK;
>>>> +}
>>>> +
>>>> +/**
>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>> + * @nb:		Should be devfreq->nb_min
>>>> + */
>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>> +					 unsigned long val, void *ptr)
>>>> +{
>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>> +}
>>>> +
>>>> +/**
>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>> + * @nb:		Should be devfreq->nb_max
>>>> + */
>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>> +					 unsigned long val, void *ptr)
>>>> +{
>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>> +}
>>>> +
>>>>    /**
>>>>     * devfreq_dev_release() - Callback for struct device to release the device.
>>>>     * @dev:	the devfreq device
>>>>     *
>>>>     * Remove devfreq from the list and release its resources.
>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>    
>>>>    	mutex_lock(&devfreq_list_lock);
>>>>    	list_del(&devfreq->node);
>>>>    	mutex_unlock(&devfreq_list_lock);
>>>>    
>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>> +
>>>
>>> Just print error with dev_err() without stopping the release step.
>>>
>>> I prefer to handle the return value if kernel API provides
>>> the error code.
>>>
>>>>    	if (devfreq->profile->exit)
>>>>    		devfreq->profile->exit(devfreq->dev.parent);
>>>>    
>>>>    	kfree(devfreq->time_in_state);
>>>>    	kfree(devfreq->trans_table);
>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>    	if (err) {
>>>>    		put_device(&devfreq->dev);
>>>>    		goto err_out;
>>>>    	}
>>>>    
>>>> +	/*
>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>> +	 * initialized (and we can handle notifications) but before the
>>>> +	 * governor is started (which should do an initial enforcement of
>>>> +	 * constraints).
>>>> +	 */
>>>
>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>> comments because the line code is not too long. But, at the present time,
>>> devfreq_add_device() is too long. It means that the detailed comment
>>> are necessary.
>>>
>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>> on separate patch to keep the same style. I'll send the patch to you
>>> for the review.
>>
>> This is very likely to result in merge conflicts, maybe wait for my
>> series to go in first?
>>
>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>> +	if (err)
>>>> +		goto err_devfreq;
>>>> +
>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>> +	if (err)
>>>> +		goto err_devfreq;
>>>> +
>>>>    	mutex_lock(&devfreq_list_lock);
>>>>    
>>>>    	governor = try_then_request_governor(devfreq->governor_name);
>>>>    	if (IS_ERR(governor)) {
>>>>    		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>    
>>>>    	return devfreq;
>>>>    
>>>>    err_init:
>>>>    	mutex_unlock(&devfreq_list_lock);
>>>> +err_devfreq:
>>>>    	devfreq_remove_device(devfreq);
>>>>    	return ERR_PTR(err);
>>>>    
>>>>    err_dev:
>>>>    	/*
>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>> --- a/include/linux/devfreq.h
>>>> +++ b/include/linux/devfreq.h
>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>     * @total_trans:	Number of devfreq transitions
>>>>     * @trans_table:	Statistics of devfreq transitions
>>>>     * @time_in_state:	Statistics of devfreq states
>>>>     * @last_stat_updated:	The last time stat updated
>>>>     * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>     *
>>>>     * This structure stores the devfreq information for a give device.
>>>>     *
>>>>     * Note that when a governor accesses entries in struct devfreq in its
>>>>     * functions except for the context of callbacks defined in struct
>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>    	unsigned int *trans_table;
>>>>    	unsigned long *time_in_state;
>>>>    	unsigned long last_stat_updated;
>>>>    
>>>>    	struct srcu_notifier_head transition_notifier_list;
>>>> +
>>>> +	struct notifier_block nb_min;
>>>> +	struct notifier_block nb_max;
>>>>    };
>>>>    
>>>>    struct devfreq_freqs {
>>>>    	unsigned long old;
>>>>    	unsigned long new;
>>>>
>>>
>>>
>>
> 
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-27  1:49               ` Chanwoo Choi
@ 2019-09-30 13:16                 ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-30 13:16 UTC (permalink / raw)
  To: Chanwoo Choi, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 2019-09-27 4:45 AM, Chanwoo Choi wrote:
> On 19. 9. 26. 오후 10:43, Leonard Crestez wrote:
>> On 2019-09-26 4:07 AM, Chanwoo Choi wrote:
>>> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>>>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>>
>>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>>> imposed externally (for example from other devices).
>>>>>>
>>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>>> ---
>>>>>>     drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>>>     include/linux/devfreq.h   |  5 +++
>>>>>>     2 files changed, 80 insertions(+)
>>>>>>
>>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>>> index eee403e70c84..784f3e40536a 100644
>>>>>> --- a/drivers/devfreq/devfreq.c
>>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>>> @@ -22,15 +22,18 @@
>>>>>>     #include <linux/platform_device.h>
>>>>>>     #include <linux/list.h>
>>>>>>     #include <linux/printk.h>
>>>>>>     #include <linux/hrtimer.h>
>>>>>>     #include <linux/of.h>
>>>>>> +#include <linux/pm_qos.h>
>>>>>>     #include "governor.h"
>>>>>>     
>>>>>>     #define CREATE_TRACE_POINTS
>>>>>>     #include <trace/events/devfreq.h>
>>>>>>     
>>>>>> +#define HZ_PER_KHZ	1000
>>>>>> +
>>>>>>     static struct class *devfreq_class;
>>>>>>     
>>>>>>     /*
>>>>>>      * devfreq core provides delayed work based load monitoring helper
>>>>>>      * functions. Governors can use these or can implement their own
>>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>>>     static void get_freq_range(struct devfreq *devfreq,
>>>>>>     			   unsigned long *min_freq,
>>>>>>     			   unsigned long *max_freq)
>>>>>>     {
>>>>>>     	unsigned long *freq_table = devfreq->profile->freq_table;
>>>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>>>     
>>>>>>     	lockdep_assert_held(&devfreq->lock);
>>>>>>     
>>>>>>     	/*
>>>>>>     	 * Init min/max frequency from freq table.
>>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>>     	} else {
>>>>>>     		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>>>     		*max_freq = freq_table[0];
>>>>>>     	}
>>>>>>     
>>>>>> +	/* constraints from PM QoS */
>>>>>
>>>>> As I commented on patch4,
>>>>> 'constraints' -> 'Constraint' because first verb have to be used
>>>>> as the sigular verbs.
>>>>
>>>> Already discussed for another patch; I will modify to "Apply constraints
>>>> from PM QoS" instead.
>>>
>>> I agree the new comment with 'Apply constraints ... '.
>>>
>>>>
>>>>> I prefer to use following comments:
>>>>>
>>>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>>>
>>>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>>> +
>>>>>>     	/* constraints from sysfs */
>>>>>>     	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>>>     	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>>>     
>>>>>>     	/* constraints from OPP interface */
>>>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>>>     	mutex_unlock(&devfreq->lock);
>>>>>>     
>>>>>>     	return ret;
>>>>>>     }
>>>>>>     
>>>>>> +/**
>>>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>>>> + * @devfreq:    the devfreq instance.
>>>>>> + */
>>>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>>>> +{
>>>>>> +	int err;
>>>>>> +
>>>>>> +	mutex_lock(&devfreq->lock);
>>>>>> +	err = update_devfreq(devfreq);
>>>>>> +	mutex_unlock(&devfreq->lock);
>>>>>> +	if (err)
>>>>>> +		dev_err(devfreq->dev.parent,
>>>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>>>
>>>>> Is it not over 80 char?
>>>>
>>>> Yes but coding style explicitly forbids breaking strings.
>>>>
>>>>>> +				err);
>>>>>> +
>>>>>> +	return NOTIFY_OK;
>>>>>> +}
>>>>>> +
>>>>>> +/**
>>>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>>>> + * @nb:		Should be devfreq->nb_min
>>>>>> + */
>>>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>>>> +					 unsigned long val, void *ptr)
>>>>>> +{
>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>>>> +}
>>>>>> +
>>>>>> +/**
>>>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>>>> + * @nb:		Should be devfreq->nb_max
>>>>>> + */
>>>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>>>> +					 unsigned long val, void *ptr)
>>>>>> +{
>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>>>> +}
>>>>>> +
>>>>>>     /**
>>>>>>      * devfreq_dev_release() - Callback for struct device to release the device.
>>>>>>      * @dev:	the devfreq device
>>>>>>      *
>>>>>>      * Remove devfreq from the list and release its resources.
>>>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>>>     
>>>>>>     	mutex_lock(&devfreq_list_lock);
>>>>>>     	list_del(&devfreq->node);
>>>>>>     	mutex_unlock(&devfreq_list_lock);
>>>>>>     
>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>>>> +
>>>>>
>>>>> Just print error with dev_err() without stopping the release step.
>>>>>
>>>>> I prefer to handle the return value if kernel API provides
>>>>> the error code.
>>>
>>> How about?
>>
>> Modified to dev_warn. This also applies to PATCH 6 so I replied there.
>>
>>>>>>     	if (devfreq->profile->exit)
>>>>>>     		devfreq->profile->exit(devfreq->dev.parent);
>>>>>>     
>>>>>>     	kfree(devfreq->time_in_state);
>>>>>>     	kfree(devfreq->trans_table);
>>>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>     	if (err) {
>>>>>>     		put_device(&devfreq->dev);
>>>>>>     		goto err_out;
>>>>>>     	}
>>>>>>     
>>>>>> +	/*
>>>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>>>> +	 * initialized (and we can handle notifications) but before the
>>>>>> +	 * governor is started (which should do an initial enforcement of
>>>>>> +	 * constraints).
>>>>>> +	 */
>>>>>
>>>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>>>> comments because the line code is not too long. But, at the present time,
>>>>> devfreq_add_device() is too long. It means that the detailed comment
>>>>> are necessary.
>>>>>
>>>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>>>> on separate patch to keep the same style. I'll send the patch to you
>>>>> for the review.
>>>>
>>>> This is very likely to result in merge conflicts, maybe wait for my
>>>> series to go in first?
>>>
>>> I'll send the separate patch after finished the review of these patches.
>>> So, if you agree, please remove this comment on this patch.
>>>
>>> You can review the detailed comments on separate patch when I send.
>> This patch already contains comments and they explain the code being
>> added. Doesn't it make more sense for comments and code to go in together?
>>
>> I think the comment is a resonable explanation as to why notifiers are
>> registered at that specific step in the initialization sequence.
> 
> If you add this comment on this patch, OK. just I have some comments.
> 
> 	/*
> 	 * Register notifiers for updates to min/max_freq after device is
> 	 * initialized (and we can handle notifications) but before the
> 
> I think that 'device is initialized' is not needed.
> It is always true, it don't need to add the additional comments.
> because dev_pm_qos_add_notifier() must need the 'devfreq->dev'.
> The this code prove the call sequence between them.

In theory if a notifier is registered too soon then it could crash on a 
NULL pointer. But looking at the code it first checks that "governor != 
NULL) so it would be harmless.

> 
> About 'us', don't use 'we'. The subject is 'devfreq' or other device instead of us.
> 
> 	 * governor is started (which should do an initial enforcement of
> 	 * constraints).
>   	 */
> 
> Actually, it doesn't matter the initialization step between governor
> and PM_QOS registration.

In theory PM QoS constraints could be modified between governor startup 
and notifier registration and that update would be lost (until the next 
one).

> If start governor and then register PM_QOS,
> the governor can decide the new frequency. And then PM_QOS request
> the new constraints for min/max frequency. On request time of PM_QOS,
> devfreq can detect this time and then apply the constraints from PM_QOS.
> The user of devfreq's PM_QOS must need the phandle or device instance
> of devfreq deivce. It means that user of devfreq's PM_QOS can request
> the any constraints of PM_QOS_MIN/MAX through PM_QOS interface.
> 
> So, it doesn't need to add the following comments
> because following comment is not always mandatory.
> " governor is started (which should do an initial enforcement of constraints)."
> 
> Also, you don't need to use parentheses on comments.
> 
> Actually, I think that following comments are enough.
> 
> 	/* Register PM QoS notifiers for updating to min/max freq */

I thought that explaning why it's done at this particular step but I'll 
just remove it, devfreq_add_device can get more comments later.

>>>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>>>> +	if (err)
>>>>>> +		goto err_devfreq;
>>>>>> +
>>>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>>>> +	if (err)
>>>>>> +		goto err_devfreq;
>>>>>> +
>>>>>>     	mutex_lock(&devfreq_list_lock);
>>>>>>     
>>>>>>     	governor = try_then_request_governor(devfreq->governor_name);
>>>>>>     	if (IS_ERR(governor)) {
>>>>>>     		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>     
>>>>>>     	return devfreq;
>>>>>>     
>>>>>>     err_init:
>>>>>>     	mutex_unlock(&devfreq_list_lock);
>>>>>> +err_devfreq:
>>>>>>     	devfreq_remove_device(devfreq);
>>>>>>     	return ERR_PTR(err);
>>>>>>     
>>>>>>     err_dev:
>>>>>>     	/*
>>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>>>> --- a/include/linux/devfreq.h
>>>>>> +++ b/include/linux/devfreq.h
>>>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>>>      * @total_trans:	Number of devfreq transitions
>>>>>>      * @trans_table:	Statistics of devfreq transitions
>>>>>>      * @time_in_state:	Statistics of devfreq states
>>>>>>      * @last_stat_updated:	The last time stat updated
>>>>>>      * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>>>      *
>>>>>>      * This structure stores the devfreq information for a give device.
>>>>>>      *
>>>>>>      * Note that when a governor accesses entries in struct devfreq in its
>>>>>>      * functions except for the context of callbacks defined in struct
>>>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>>>     	unsigned int *trans_table;
>>>>>>     	unsigned long *time_in_state;
>>>>>>     	unsigned long last_stat_updated;
>>>>>>     
>>>>>>     	struct srcu_notifier_head transition_notifier_list;
>>>>>> +
>>>>>> +	struct notifier_block nb_min;
>>>>>> +	struct notifier_block nb_max;
>>>>>>     };
>>>>>>     
>>>>>>     struct devfreq_freqs {
>>>>>>     	unsigned long old;
>>>>>>     	unsigned long new;
> 
> 


^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-30 13:16                 ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-09-30 13:16 UTC (permalink / raw)
  To: Chanwoo Choi, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 2019-09-27 4:45 AM, Chanwoo Choi wrote:
> On 19. 9. 26. 오후 10:43, Leonard Crestez wrote:
>> On 2019-09-26 4:07 AM, Chanwoo Choi wrote:
>>> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>>>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>>
>>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>>> imposed externally (for example from other devices).
>>>>>>
>>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>>> ---
>>>>>>     drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>>>     include/linux/devfreq.h   |  5 +++
>>>>>>     2 files changed, 80 insertions(+)
>>>>>>
>>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>>> index eee403e70c84..784f3e40536a 100644
>>>>>> --- a/drivers/devfreq/devfreq.c
>>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>>> @@ -22,15 +22,18 @@
>>>>>>     #include <linux/platform_device.h>
>>>>>>     #include <linux/list.h>
>>>>>>     #include <linux/printk.h>
>>>>>>     #include <linux/hrtimer.h>
>>>>>>     #include <linux/of.h>
>>>>>> +#include <linux/pm_qos.h>
>>>>>>     #include "governor.h"
>>>>>>     
>>>>>>     #define CREATE_TRACE_POINTS
>>>>>>     #include <trace/events/devfreq.h>
>>>>>>     
>>>>>> +#define HZ_PER_KHZ	1000
>>>>>> +
>>>>>>     static struct class *devfreq_class;
>>>>>>     
>>>>>>     /*
>>>>>>      * devfreq core provides delayed work based load monitoring helper
>>>>>>      * functions. Governors can use these or can implement their own
>>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>>>     static void get_freq_range(struct devfreq *devfreq,
>>>>>>     			   unsigned long *min_freq,
>>>>>>     			   unsigned long *max_freq)
>>>>>>     {
>>>>>>     	unsigned long *freq_table = devfreq->profile->freq_table;
>>>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>>>     
>>>>>>     	lockdep_assert_held(&devfreq->lock);
>>>>>>     
>>>>>>     	/*
>>>>>>     	 * Init min/max frequency from freq table.
>>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>>     	} else {
>>>>>>     		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>>>     		*max_freq = freq_table[0];
>>>>>>     	}
>>>>>>     
>>>>>> +	/* constraints from PM QoS */
>>>>>
>>>>> As I commented on patch4,
>>>>> 'constraints' -> 'Constraint' because first verb have to be used
>>>>> as the sigular verbs.
>>>>
>>>> Already discussed for another patch; I will modify to "Apply constraints
>>>> from PM QoS" instead.
>>>
>>> I agree the new comment with 'Apply constraints ... '.
>>>
>>>>
>>>>> I prefer to use following comments:
>>>>>
>>>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>>>
>>>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>>> +
>>>>>>     	/* constraints from sysfs */
>>>>>>     	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>>>     	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>>>     
>>>>>>     	/* constraints from OPP interface */
>>>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>>>     	mutex_unlock(&devfreq->lock);
>>>>>>     
>>>>>>     	return ret;
>>>>>>     }
>>>>>>     
>>>>>> +/**
>>>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>>>> + * @devfreq:    the devfreq instance.
>>>>>> + */
>>>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>>>> +{
>>>>>> +	int err;
>>>>>> +
>>>>>> +	mutex_lock(&devfreq->lock);
>>>>>> +	err = update_devfreq(devfreq);
>>>>>> +	mutex_unlock(&devfreq->lock);
>>>>>> +	if (err)
>>>>>> +		dev_err(devfreq->dev.parent,
>>>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>>>
>>>>> Is it not over 80 char?
>>>>
>>>> Yes but coding style explicitly forbids breaking strings.
>>>>
>>>>>> +				err);
>>>>>> +
>>>>>> +	return NOTIFY_OK;
>>>>>> +}
>>>>>> +
>>>>>> +/**
>>>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>>>> + * @nb:		Should be devfreq->nb_min
>>>>>> + */
>>>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>>>> +					 unsigned long val, void *ptr)
>>>>>> +{
>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>>>> +}
>>>>>> +
>>>>>> +/**
>>>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>>>> + * @nb:		Should be devfreq->nb_max
>>>>>> + */
>>>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>>>> +					 unsigned long val, void *ptr)
>>>>>> +{
>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>>>> +}
>>>>>> +
>>>>>>     /**
>>>>>>      * devfreq_dev_release() - Callback for struct device to release the device.
>>>>>>      * @dev:	the devfreq device
>>>>>>      *
>>>>>>      * Remove devfreq from the list and release its resources.
>>>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>>>     
>>>>>>     	mutex_lock(&devfreq_list_lock);
>>>>>>     	list_del(&devfreq->node);
>>>>>>     	mutex_unlock(&devfreq_list_lock);
>>>>>>     
>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>>>> +
>>>>>
>>>>> Just print error with dev_err() without stopping the release step.
>>>>>
>>>>> I prefer to handle the return value if kernel API provides
>>>>> the error code.
>>>
>>> How about?
>>
>> Modified to dev_warn. This also applies to PATCH 6 so I replied there.
>>
>>>>>>     	if (devfreq->profile->exit)
>>>>>>     		devfreq->profile->exit(devfreq->dev.parent);
>>>>>>     
>>>>>>     	kfree(devfreq->time_in_state);
>>>>>>     	kfree(devfreq->trans_table);
>>>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>     	if (err) {
>>>>>>     		put_device(&devfreq->dev);
>>>>>>     		goto err_out;
>>>>>>     	}
>>>>>>     
>>>>>> +	/*
>>>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>>>> +	 * initialized (and we can handle notifications) but before the
>>>>>> +	 * governor is started (which should do an initial enforcement of
>>>>>> +	 * constraints).
>>>>>> +	 */
>>>>>
>>>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>>>> comments because the line code is not too long. But, at the present time,
>>>>> devfreq_add_device() is too long. It means that the detailed comment
>>>>> are necessary.
>>>>>
>>>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>>>> on separate patch to keep the same style. I'll send the patch to you
>>>>> for the review.
>>>>
>>>> This is very likely to result in merge conflicts, maybe wait for my
>>>> series to go in first?
>>>
>>> I'll send the separate patch after finished the review of these patches.
>>> So, if you agree, please remove this comment on this patch.
>>>
>>> You can review the detailed comments on separate patch when I send.
>> This patch already contains comments and they explain the code being
>> added. Doesn't it make more sense for comments and code to go in together?
>>
>> I think the comment is a resonable explanation as to why notifiers are
>> registered at that specific step in the initialization sequence.
> 
> If you add this comment on this patch, OK. just I have some comments.
> 
> 	/*
> 	 * Register notifiers for updates to min/max_freq after device is
> 	 * initialized (and we can handle notifications) but before the
> 
> I think that 'device is initialized' is not needed.
> It is always true, it don't need to add the additional comments.
> because dev_pm_qos_add_notifier() must need the 'devfreq->dev'.
> The this code prove the call sequence between them.

In theory if a notifier is registered too soon then it could crash on a 
NULL pointer. But looking at the code it first checks that "governor != 
NULL) so it would be harmless.

> 
> About 'us', don't use 'we'. The subject is 'devfreq' or other device instead of us.
> 
> 	 * governor is started (which should do an initial enforcement of
> 	 * constraints).
>   	 */
> 
> Actually, it doesn't matter the initialization step between governor
> and PM_QOS registration.

In theory PM QoS constraints could be modified between governor startup 
and notifier registration and that update would be lost (until the next 
one).

> If start governor and then register PM_QOS,
> the governor can decide the new frequency. And then PM_QOS request
> the new constraints for min/max frequency. On request time of PM_QOS,
> devfreq can detect this time and then apply the constraints from PM_QOS.
> The user of devfreq's PM_QOS must need the phandle or device instance
> of devfreq deivce. It means that user of devfreq's PM_QOS can request
> the any constraints of PM_QOS_MIN/MAX through PM_QOS interface.
> 
> So, it doesn't need to add the following comments
> because following comment is not always mandatory.
> " governor is started (which should do an initial enforcement of constraints)."
> 
> Also, you don't need to use parentheses on comments.
> 
> Actually, I think that following comments are enough.
> 
> 	/* Register PM QoS notifiers for updating to min/max freq */

I thought that explaning why it's done at this particular step but I'll 
just remove it, devfreq_add_device can get more comments later.

>>>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>>>> +	if (err)
>>>>>> +		goto err_devfreq;
>>>>>> +
>>>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>>>> +	if (err)
>>>>>> +		goto err_devfreq;
>>>>>> +
>>>>>>     	mutex_lock(&devfreq_list_lock);
>>>>>>     
>>>>>>     	governor = try_then_request_governor(devfreq->governor_name);
>>>>>>     	if (IS_ERR(governor)) {
>>>>>>     		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>     
>>>>>>     	return devfreq;
>>>>>>     
>>>>>>     err_init:
>>>>>>     	mutex_unlock(&devfreq_list_lock);
>>>>>> +err_devfreq:
>>>>>>     	devfreq_remove_device(devfreq);
>>>>>>     	return ERR_PTR(err);
>>>>>>     
>>>>>>     err_dev:
>>>>>>     	/*
>>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>>>> --- a/include/linux/devfreq.h
>>>>>> +++ b/include/linux/devfreq.h
>>>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>>>      * @total_trans:	Number of devfreq transitions
>>>>>>      * @trans_table:	Statistics of devfreq transitions
>>>>>>      * @time_in_state:	Statistics of devfreq states
>>>>>>      * @last_stat_updated:	The last time stat updated
>>>>>>      * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>>>      *
>>>>>>      * This structure stores the devfreq information for a give device.
>>>>>>      *
>>>>>>      * Note that when a governor accesses entries in struct devfreq in its
>>>>>>      * functions except for the context of callbacks defined in struct
>>>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>>>     	unsigned int *trans_table;
>>>>>>     	unsigned long *time_in_state;
>>>>>>     	unsigned long last_stat_updated;
>>>>>>     
>>>>>>     	struct srcu_notifier_head transition_notifier_list;
>>>>>> +
>>>>>> +	struct notifier_block nb_min;
>>>>>> +	struct notifier_block nb_max;
>>>>>>     };
>>>>>>     
>>>>>>     struct devfreq_freqs {
>>>>>>     	unsigned long old;
>>>>>>     	unsigned long new;
> 
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-30 12:43             ` Leonard Crestez
@ 2019-09-30 21:21               ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-30 21:21 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 19. 9. 30. 오후 9:43, Leonard Crestez wrote:
> On 2019-09-26 4:14 AM, Chanwoo Choi wrote:
>> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>
>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>> imposed externally (for example from other devices).
>>>>>
>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>> ---
>>>>>    drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>>    include/linux/devfreq.h   |  5 +++
>>>>>    2 files changed, 80 insertions(+)
>>>>>
>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>> index eee403e70c84..784f3e40536a 100644
>>>>> --- a/drivers/devfreq/devfreq.c
>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>> @@ -22,15 +22,18 @@
>>>>>    #include <linux/platform_device.h>
>>>>>    #include <linux/list.h>
>>>>>    #include <linux/printk.h>
>>>>>    #include <linux/hrtimer.h>
>>>>>    #include <linux/of.h>
>>>>> +#include <linux/pm_qos.h>
>>>>>    #include "governor.h"
>>>>>    
>>>>>    #define CREATE_TRACE_POINTS
>>>>>    #include <trace/events/devfreq.h>
>>>>>    
>>>>> +#define HZ_PER_KHZ	1000
>>>>> +
>>>>>    static struct class *devfreq_class;
>>>>>    
>>>>>    /*
>>>>>     * devfreq core provides delayed work based load monitoring helper
>>>>>     * functions. Governors can use these or can implement their own
>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>>    static void get_freq_range(struct devfreq *devfreq,
>>>>>    			   unsigned long *min_freq,
>>>>>    			   unsigned long *max_freq)
>>>>>    {
>>>>>    	unsigned long *freq_table = devfreq->profile->freq_table;
>>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>>    
>>>>>    	lockdep_assert_held(&devfreq->lock);
>>>>>    
>>>>>    	/*
>>>>>    	 * Init min/max frequency from freq table.
>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>    	} else {
>>>>>    		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>>    		*max_freq = freq_table[0];
>>>>>    	}
>>>>>    
>>>>> +	/* constraints from PM QoS */
>>>>
>>>> As I commented on patch4,
>>>> 'constraints' -> 'Constraint' because first verb have to be used
>>>> as the sigular verbs.
>>>
>>> Already discussed for another patch; I will modify to "Apply constraints
>>> from PM QoS" instead.
>>>
>>>> I prefer to use following comments:
>>>>
>>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>>
>>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>> +
>>>>>    	/* constraints from sysfs */
>>>>>    	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>>    	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>>    
>>>>>    	/* constraints from OPP interface */
>>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>>    	mutex_unlock(&devfreq->lock);
>>>>>    
>>>>>    	return ret;
>>>>>    }
>>>>>    
>>>>> +/**
>>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>>> + * @devfreq:    the devfreq instance.
>>>>> + */
>>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>>> +{
>>>>> +	int err;
>>>>> +
>>>>> +	mutex_lock(&devfreq->lock);
>>>>> +	err = update_devfreq(devfreq);
>>>>> +	mutex_unlock(&devfreq->lock);
>>>>> +	if (err)
>>>>> +		dev_err(devfreq->dev.parent,
>>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>>
>>>> Is it not over 80 char?
>>>
>>> Yes but coding style explicitly forbids breaking strings.
>>
>> I want to make it within 80 char. How about following comment?
>>
>> 		dev_err(devfreq->dev.parent,
>> 			"failed to update frequency from PM QoS (%d)\n",
> 
> Yes, shrinking the comment and aligning with open parenthesis can keep 
> it under 80 chars. Maybe it could be shrunk further to
> 
>      "failed update for PM QoS"

I think that we need to specify what do update something like 'frequency'.
So, it is more proper as following:

	"failed to update frequency from PM QoS\n",

> 
>>>>> +				err);
>>>>> +
>>>>> +	return NOTIFY_OK;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>>> + * @nb:		Should be devfreq->nb_min
>>>>> + */
>>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>>> +					 unsigned long val, void *ptr)
>>>>> +{
>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>>> + * @nb:		Should be devfreq->nb_max
>>>>> + */
>>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>>> +					 unsigned long val, void *ptr)
>>>>> +{
>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>>> +}
>>>>> +
>>>>>    /**
>>>>>     * devfreq_dev_release() - Callback for struct device to release the device.
>>>>>     * @dev:	the devfreq device
>>>>>     *
>>>>>     * Remove devfreq from the list and release its resources.
>>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>>    
>>>>>    	mutex_lock(&devfreq_list_lock);
>>>>>    	list_del(&devfreq->node);
>>>>>    	mutex_unlock(&devfreq_list_lock);
>>>>>    
>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +
>>>>
>>>> Just print error with dev_err() without stopping the release step.
>>>>
>>>> I prefer to handle the return value if kernel API provides
>>>> the error code.
>>>>
>>>>>    	if (devfreq->profile->exit)
>>>>>    		devfreq->profile->exit(devfreq->dev.parent);
>>>>>    
>>>>>    	kfree(devfreq->time_in_state);
>>>>>    	kfree(devfreq->trans_table);
>>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>    	if (err) {
>>>>>    		put_device(&devfreq->dev);
>>>>>    		goto err_out;
>>>>>    	}
>>>>>    
>>>>> +	/*
>>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>>> +	 * initialized (and we can handle notifications) but before the
>>>>> +	 * governor is started (which should do an initial enforcement of
>>>>> +	 * constraints).
>>>>> +	 */
>>>>
>>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>>> comments because the line code is not too long. But, at the present time,
>>>> devfreq_add_device() is too long. It means that the detailed comment
>>>> are necessary.
>>>>
>>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>>> on separate patch to keep the same style. I'll send the patch to you
>>>> for the review.
>>>
>>> This is very likely to result in merge conflicts, maybe wait for my
>>> series to go in first?
>>>
>>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +	if (err)
>>>>> +		goto err_devfreq;
>>>>> +
>>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>>> +	if (err)
>>>>> +		goto err_devfreq;
>>>>> +
>>>>>    	mutex_lock(&devfreq_list_lock);
>>>>>    
>>>>>    	governor = try_then_request_governor(devfreq->governor_name);
>>>>>    	if (IS_ERR(governor)) {
>>>>>    		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>    
>>>>>    	return devfreq;
>>>>>    
>>>>>    err_init:
>>>>>    	mutex_unlock(&devfreq_list_lock);
>>>>> +err_devfreq:
>>>>>    	devfreq_remove_device(devfreq);
>>>>>    	return ERR_PTR(err);
>>>>>    
>>>>>    err_dev:
>>>>>    	/*
>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>>> --- a/include/linux/devfreq.h
>>>>> +++ b/include/linux/devfreq.h
>>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>>     * @total_trans:	Number of devfreq transitions
>>>>>     * @trans_table:	Statistics of devfreq transitions
>>>>>     * @time_in_state:	Statistics of devfreq states
>>>>>     * @last_stat_updated:	The last time stat updated
>>>>>     * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>>     *
>>>>>     * This structure stores the devfreq information for a give device.
>>>>>     *
>>>>>     * Note that when a governor accesses entries in struct devfreq in its
>>>>>     * functions except for the context of callbacks defined in struct
>>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>>    	unsigned int *trans_table;
>>>>>    	unsigned long *time_in_state;
>>>>>    	unsigned long last_stat_updated;
>>>>>    
>>>>>    	struct srcu_notifier_head transition_notifier_list;
>>>>> +
>>>>> +	struct notifier_block nb_min;
>>>>> +	struct notifier_block nb_max;
>>>>>    };
>>>>>    
>>>>>    struct devfreq_freqs {
>>>>>    	unsigned long old;
>>>>>    	unsigned long new;
>>>>>
>>>>
>>>>
>>>
>>
>>
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-30 21:21               ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-30 21:21 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 19. 9. 30. 오후 9:43, Leonard Crestez wrote:
> On 2019-09-26 4:14 AM, Chanwoo Choi wrote:
>> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>
>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>> imposed externally (for example from other devices).
>>>>>
>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>> ---
>>>>>    drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>>    include/linux/devfreq.h   |  5 +++
>>>>>    2 files changed, 80 insertions(+)
>>>>>
>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>> index eee403e70c84..784f3e40536a 100644
>>>>> --- a/drivers/devfreq/devfreq.c
>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>> @@ -22,15 +22,18 @@
>>>>>    #include <linux/platform_device.h>
>>>>>    #include <linux/list.h>
>>>>>    #include <linux/printk.h>
>>>>>    #include <linux/hrtimer.h>
>>>>>    #include <linux/of.h>
>>>>> +#include <linux/pm_qos.h>
>>>>>    #include "governor.h"
>>>>>    
>>>>>    #define CREATE_TRACE_POINTS
>>>>>    #include <trace/events/devfreq.h>
>>>>>    
>>>>> +#define HZ_PER_KHZ	1000
>>>>> +
>>>>>    static struct class *devfreq_class;
>>>>>    
>>>>>    /*
>>>>>     * devfreq core provides delayed work based load monitoring helper
>>>>>     * functions. Governors can use these or can implement their own
>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>>    static void get_freq_range(struct devfreq *devfreq,
>>>>>    			   unsigned long *min_freq,
>>>>>    			   unsigned long *max_freq)
>>>>>    {
>>>>>    	unsigned long *freq_table = devfreq->profile->freq_table;
>>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>>    
>>>>>    	lockdep_assert_held(&devfreq->lock);
>>>>>    
>>>>>    	/*
>>>>>    	 * Init min/max frequency from freq table.
>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>    	} else {
>>>>>    		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>>    		*max_freq = freq_table[0];
>>>>>    	}
>>>>>    
>>>>> +	/* constraints from PM QoS */
>>>>
>>>> As I commented on patch4,
>>>> 'constraints' -> 'Constraint' because first verb have to be used
>>>> as the sigular verbs.
>>>
>>> Already discussed for another patch; I will modify to "Apply constraints
>>> from PM QoS" instead.
>>>
>>>> I prefer to use following comments:
>>>>
>>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>>
>>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>> +
>>>>>    	/* constraints from sysfs */
>>>>>    	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>>    	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>>    
>>>>>    	/* constraints from OPP interface */
>>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>>    	mutex_unlock(&devfreq->lock);
>>>>>    
>>>>>    	return ret;
>>>>>    }
>>>>>    
>>>>> +/**
>>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>>> + * @devfreq:    the devfreq instance.
>>>>> + */
>>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>>> +{
>>>>> +	int err;
>>>>> +
>>>>> +	mutex_lock(&devfreq->lock);
>>>>> +	err = update_devfreq(devfreq);
>>>>> +	mutex_unlock(&devfreq->lock);
>>>>> +	if (err)
>>>>> +		dev_err(devfreq->dev.parent,
>>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>>
>>>> Is it not over 80 char?
>>>
>>> Yes but coding style explicitly forbids breaking strings.
>>
>> I want to make it within 80 char. How about following comment?
>>
>> 		dev_err(devfreq->dev.parent,
>> 			"failed to update frequency from PM QoS (%d)\n",
> 
> Yes, shrinking the comment and aligning with open parenthesis can keep 
> it under 80 chars. Maybe it could be shrunk further to
> 
>      "failed update for PM QoS"

I think that we need to specify what do update something like 'frequency'.
So, it is more proper as following:

	"failed to update frequency from PM QoS\n",

> 
>>>>> +				err);
>>>>> +
>>>>> +	return NOTIFY_OK;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>>> + * @nb:		Should be devfreq->nb_min
>>>>> + */
>>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>>> +					 unsigned long val, void *ptr)
>>>>> +{
>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>>> + * @nb:		Should be devfreq->nb_max
>>>>> + */
>>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>>> +					 unsigned long val, void *ptr)
>>>>> +{
>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>>> +}
>>>>> +
>>>>>    /**
>>>>>     * devfreq_dev_release() - Callback for struct device to release the device.
>>>>>     * @dev:	the devfreq device
>>>>>     *
>>>>>     * Remove devfreq from the list and release its resources.
>>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>>    
>>>>>    	mutex_lock(&devfreq_list_lock);
>>>>>    	list_del(&devfreq->node);
>>>>>    	mutex_unlock(&devfreq_list_lock);
>>>>>    
>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +
>>>>
>>>> Just print error with dev_err() without stopping the release step.
>>>>
>>>> I prefer to handle the return value if kernel API provides
>>>> the error code.
>>>>
>>>>>    	if (devfreq->profile->exit)
>>>>>    		devfreq->profile->exit(devfreq->dev.parent);
>>>>>    
>>>>>    	kfree(devfreq->time_in_state);
>>>>>    	kfree(devfreq->trans_table);
>>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>    	if (err) {
>>>>>    		put_device(&devfreq->dev);
>>>>>    		goto err_out;
>>>>>    	}
>>>>>    
>>>>> +	/*
>>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>>> +	 * initialized (and we can handle notifications) but before the
>>>>> +	 * governor is started (which should do an initial enforcement of
>>>>> +	 * constraints).
>>>>> +	 */
>>>>
>>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>>> comments because the line code is not too long. But, at the present time,
>>>> devfreq_add_device() is too long. It means that the detailed comment
>>>> are necessary.
>>>>
>>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>>> on separate patch to keep the same style. I'll send the patch to you
>>>> for the review.
>>>
>>> This is very likely to result in merge conflicts, maybe wait for my
>>> series to go in first?
>>>
>>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +	if (err)
>>>>> +		goto err_devfreq;
>>>>> +
>>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>>> +	if (err)
>>>>> +		goto err_devfreq;
>>>>> +
>>>>>    	mutex_lock(&devfreq_list_lock);
>>>>>    
>>>>>    	governor = try_then_request_governor(devfreq->governor_name);
>>>>>    	if (IS_ERR(governor)) {
>>>>>    		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>    
>>>>>    	return devfreq;
>>>>>    
>>>>>    err_init:
>>>>>    	mutex_unlock(&devfreq_list_lock);
>>>>> +err_devfreq:
>>>>>    	devfreq_remove_device(devfreq);
>>>>>    	return ERR_PTR(err);
>>>>>    
>>>>>    err_dev:
>>>>>    	/*
>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>>> --- a/include/linux/devfreq.h
>>>>> +++ b/include/linux/devfreq.h
>>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>>     * @total_trans:	Number of devfreq transitions
>>>>>     * @trans_table:	Statistics of devfreq transitions
>>>>>     * @time_in_state:	Statistics of devfreq states
>>>>>     * @last_stat_updated:	The last time stat updated
>>>>>     * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>>     *
>>>>>     * This structure stores the devfreq information for a give device.
>>>>>     *
>>>>>     * Note that when a governor accesses entries in struct devfreq in its
>>>>>     * functions except for the context of callbacks defined in struct
>>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>>    	unsigned int *trans_table;
>>>>>    	unsigned long *time_in_state;
>>>>>    	unsigned long last_stat_updated;
>>>>>    
>>>>>    	struct srcu_notifier_head transition_notifier_list;
>>>>> +
>>>>> +	struct notifier_block nb_min;
>>>>> +	struct notifier_block nb_max;
>>>>>    };
>>>>>    
>>>>>    struct devfreq_freqs {
>>>>>    	unsigned long old;
>>>>>    	unsigned long new;
>>>>>
>>>>
>>>>
>>>
>>
>>
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-30 13:16                 ` Leonard Crestez
@ 2019-09-30 21:42                   ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-30 21:42 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

Hi,

On 19. 9. 30. 오후 10:16, Leonard Crestez wrote:
> On 2019-09-27 4:45 AM, Chanwoo Choi wrote:
>> On 19. 9. 26. 오후 10:43, Leonard Crestez wrote:
>>> On 2019-09-26 4:07 AM, Chanwoo Choi wrote:
>>>> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>>>>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>>>
>>>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>>>> imposed externally (for example from other devices).
>>>>>>>
>>>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>>>> ---
>>>>>>>     drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>>>>     include/linux/devfreq.h   |  5 +++
>>>>>>>     2 files changed, 80 insertions(+)
>>>>>>>
>>>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>>>> index eee403e70c84..784f3e40536a 100644
>>>>>>> --- a/drivers/devfreq/devfreq.c
>>>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>>>> @@ -22,15 +22,18 @@
>>>>>>>     #include <linux/platform_device.h>
>>>>>>>     #include <linux/list.h>
>>>>>>>     #include <linux/printk.h>
>>>>>>>     #include <linux/hrtimer.h>
>>>>>>>     #include <linux/of.h>
>>>>>>> +#include <linux/pm_qos.h>
>>>>>>>     #include "governor.h"
>>>>>>>     
>>>>>>>     #define CREATE_TRACE_POINTS
>>>>>>>     #include <trace/events/devfreq.h>
>>>>>>>     
>>>>>>> +#define HZ_PER_KHZ	1000
>>>>>>> +
>>>>>>>     static struct class *devfreq_class;
>>>>>>>     
>>>>>>>     /*
>>>>>>>      * devfreq core provides delayed work based load monitoring helper
>>>>>>>      * functions. Governors can use these or can implement their own
>>>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>>>>     static void get_freq_range(struct devfreq *devfreq,
>>>>>>>     			   unsigned long *min_freq,
>>>>>>>     			   unsigned long *max_freq)
>>>>>>>     {
>>>>>>>     	unsigned long *freq_table = devfreq->profile->freq_table;
>>>>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>>>>     
>>>>>>>     	lockdep_assert_held(&devfreq->lock);
>>>>>>>     
>>>>>>>     	/*
>>>>>>>     	 * Init min/max frequency from freq table.
>>>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>>>     	} else {
>>>>>>>     		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>>>>     		*max_freq = freq_table[0];
>>>>>>>     	}
>>>>>>>     
>>>>>>> +	/* constraints from PM QoS */
>>>>>>
>>>>>> As I commented on patch4,
>>>>>> 'constraints' -> 'Constraint' because first verb have to be used
>>>>>> as the sigular verbs.
>>>>>
>>>>> Already discussed for another patch; I will modify to "Apply constraints
>>>>> from PM QoS" instead.
>>>>
>>>> I agree the new comment with 'Apply constraints ... '.
>>>>
>>>>>
>>>>>> I prefer to use following comments:
>>>>>>
>>>>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>>>>
>>>>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>>>> +
>>>>>>>     	/* constraints from sysfs */
>>>>>>>     	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>>>>     	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>>>>     
>>>>>>>     	/* constraints from OPP interface */
>>>>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>>>>     	mutex_unlock(&devfreq->lock);
>>>>>>>     
>>>>>>>     	return ret;
>>>>>>>     }
>>>>>>>     
>>>>>>> +/**
>>>>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>>>>> + * @devfreq:    the devfreq instance.
>>>>>>> + */
>>>>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>>>>> +{
>>>>>>> +	int err;
>>>>>>> +
>>>>>>> +	mutex_lock(&devfreq->lock);
>>>>>>> +	err = update_devfreq(devfreq);
>>>>>>> +	mutex_unlock(&devfreq->lock);
>>>>>>> +	if (err)
>>>>>>> +		dev_err(devfreq->dev.parent,
>>>>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>>>>
>>>>>> Is it not over 80 char?
>>>>>
>>>>> Yes but coding style explicitly forbids breaking strings.
>>>>>
>>>>>>> +				err);
>>>>>>> +
>>>>>>> +	return NOTIFY_OK;
>>>>>>> +}
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>>>>> + * @nb:		Should be devfreq->nb_min
>>>>>>> + */
>>>>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>>>>> +					 unsigned long val, void *ptr)
>>>>>>> +{
>>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>>>>> +}
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>>>>> + * @nb:		Should be devfreq->nb_max
>>>>>>> + */
>>>>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>>>>> +					 unsigned long val, void *ptr)
>>>>>>> +{
>>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>>>>> +}
>>>>>>> +
>>>>>>>     /**
>>>>>>>      * devfreq_dev_release() - Callback for struct device to release the device.
>>>>>>>      * @dev:	the devfreq device
>>>>>>>      *
>>>>>>>      * Remove devfreq from the list and release its resources.
>>>>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>>>>     
>>>>>>>     	mutex_lock(&devfreq_list_lock);
>>>>>>>     	list_del(&devfreq->node);
>>>>>>>     	mutex_unlock(&devfreq_list_lock);
>>>>>>>     
>>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>> +
>>>>>>
>>>>>> Just print error with dev_err() without stopping the release step.
>>>>>>
>>>>>> I prefer to handle the return value if kernel API provides
>>>>>> the error code.
>>>>
>>>> How about?
>>>
>>> Modified to dev_warn. This also applies to PATCH 6 so I replied there.
>>>
>>>>>>>     	if (devfreq->profile->exit)
>>>>>>>     		devfreq->profile->exit(devfreq->dev.parent);
>>>>>>>     
>>>>>>>     	kfree(devfreq->time_in_state);
>>>>>>>     	kfree(devfreq->trans_table);
>>>>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>>     	if (err) {
>>>>>>>     		put_device(&devfreq->dev);
>>>>>>>     		goto err_out;
>>>>>>>     	}
>>>>>>>     
>>>>>>> +	/*
>>>>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>>>>> +	 * initialized (and we can handle notifications) but before the
>>>>>>> +	 * governor is started (which should do an initial enforcement of
>>>>>>> +	 * constraints).
>>>>>>> +	 */
>>>>>>
>>>>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>>>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>>>>> comments because the line code is not too long. But, at the present time,
>>>>>> devfreq_add_device() is too long. It means that the detailed comment
>>>>>> are necessary.
>>>>>>
>>>>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>>>>> on separate patch to keep the same style. I'll send the patch to you
>>>>>> for the review.
>>>>>
>>>>> This is very likely to result in merge conflicts, maybe wait for my
>>>>> series to go in first?
>>>>
>>>> I'll send the separate patch after finished the review of these patches.
>>>> So, if you agree, please remove this comment on this patch.
>>>>
>>>> You can review the detailed comments on separate patch when I send.
>>> This patch already contains comments and they explain the code being
>>> added. Doesn't it make more sense for comments and code to go in together?
>>>
>>> I think the comment is a resonable explanation as to why notifiers are
>>> registered at that specific step in the initialization sequence.
>>
>> If you add this comment on this patch, OK. just I have some comments.
>>
>> 	/*
>> 	 * Register notifiers for updates to min/max_freq after device is
>> 	 * initialized (and we can handle notifications) but before the
>>
>> I think that 'device is initialized' is not needed.
>> It is always true, it don't need to add the additional comments.
>> because dev_pm_qos_add_notifier() must need the 'devfreq->dev'.
>> The this code prove the call sequence between them.
> 
> In theory if a notifier is registered too soon then it could crash on a 
> NULL pointer. But looking at the code it first checks that "governor != 
> NULL) so it would be harmless.
> 
>>
>> About 'us', don't use 'we'. The subject is 'devfreq' or other device instead of us.
>>
>> 	 * governor is started (which should do an initial enforcement of
>> 	 * constraints).
>>   	 */
>>
>> Actually, it doesn't matter the initialization step between governor
>> and PM_QOS registration.
> 
> In theory PM QoS constraints could be modified between governor startup 
> and notifier registration and that update would be lost (until the next 
> one).

Don't lose the any of PM QoS request. User can request the any frequency
through PMQoS at the any time and then devfreq consider the constraints
from PM QoS.

Also, after finished the registration of devfreq device,
the user (other device driver required the min/max freq)
can request the PM QoS on real use-case.

It is impossible to get the devfreq instance before finished
the devfreq_add_device() because the user can access the devfreq instance
devfreq_get_devfreq_by_phandle() which use 'devfreq_list'.

If devfreq_add_device() is not finished, the user cannot get
the any devfreq device from 'devfreq_list'.

> 
>> If start governor and then register PM_QOS,
>> the governor can decide the new frequency. And then PM_QOS request
>> the new constraints for min/max frequency. On request time of PM_QOS,
>> devfreq can detect this time and then apply the constraints from PM_QOS.
>> The user of devfreq's PM_QOS must need the phandle or device instance
>> of devfreq deivce. It means that user of devfreq's PM_QOS can request
>> the any constraints of PM_QOS_MIN/MAX through PM_QOS interface.
>>
>> So, it doesn't need to add the following comments
>> because following comment is not always mandatory.
>> " governor is started (which should do an initial enforcement of constraints)."
>>
>> Also, you don't need to use parentheses on comments.
>>
>> Actually, I think that following comments are enough.
>>
>> 	/* Register PM QoS notifiers for updating to min/max freq */
> 
> I thought that explaning why it's done at this particular step but I'll 
> just remove it, devfreq_add_device can get more comments later.

OK. Thanks.
I think that if the comment contains what is meaning of the code,
it is enough.

Although change the sequence between dev_pm_qos_add_notifier() and
try_then_request_governor(), in the real-case, the any issue
would not happen. Because as I commented above, the other device-driver
cannot get the devfreq instance before finished the devfreq_add_device.
It means that the user device driver cannot request the any PM QoS
constraints.

> 
>>>>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>> +	if (err)
>>>>>>> +		goto err_devfreq;
>>>>>>> +
>>>>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>>>>> +	if (err)
>>>>>>> +		goto err_devfreq;
>>>>>>> +
>>>>>>>     	mutex_lock(&devfreq_list_lock);
>>>>>>>     
>>>>>>>     	governor = try_then_request_governor(devfreq->governor_name);
>>>>>>>     	if (IS_ERR(governor)) {
>>>>>>>     		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>>     
>>>>>>>     	return devfreq;
>>>>>>>     
>>>>>>>     err_init:
>>>>>>>     	mutex_unlock(&devfreq_list_lock);
>>>>>>> +err_devfreq:
>>>>>>>     	devfreq_remove_device(devfreq);
>>>>>>>     	return ERR_PTR(err);
>>>>>>>     
>>>>>>>     err_dev:
>>>>>>>     	/*
>>>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>>>>> --- a/include/linux/devfreq.h
>>>>>>> +++ b/include/linux/devfreq.h
>>>>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>>>>      * @total_trans:	Number of devfreq transitions
>>>>>>>      * @trans_table:	Statistics of devfreq transitions
>>>>>>>      * @time_in_state:	Statistics of devfreq states
>>>>>>>      * @last_stat_updated:	The last time stat updated
>>>>>>>      * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>>>>      *
>>>>>>>      * This structure stores the devfreq information for a give device.
>>>>>>>      *
>>>>>>>      * Note that when a governor accesses entries in struct devfreq in its
>>>>>>>      * functions except for the context of callbacks defined in struct
>>>>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>>>>     	unsigned int *trans_table;
>>>>>>>     	unsigned long *time_in_state;
>>>>>>>     	unsigned long last_stat_updated;
>>>>>>>     
>>>>>>>     	struct srcu_notifier_head transition_notifier_list;
>>>>>>> +
>>>>>>> +	struct notifier_block nb_min;
>>>>>>> +	struct notifier_block nb_max;
>>>>>>>     };
>>>>>>>     
>>>>>>>     struct devfreq_freqs {
>>>>>>>     	unsigned long old;
>>>>>>>     	unsigned long new;
>>
>>
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-09-30 21:42                   ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-09-30 21:42 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

Hi,

On 19. 9. 30. 오후 10:16, Leonard Crestez wrote:
> On 2019-09-27 4:45 AM, Chanwoo Choi wrote:
>> On 19. 9. 26. 오후 10:43, Leonard Crestez wrote:
>>> On 2019-09-26 4:07 AM, Chanwoo Choi wrote:
>>>> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>>>>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>>>
>>>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>>>> imposed externally (for example from other devices).
>>>>>>>
>>>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>>>> ---
>>>>>>>     drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>>>>     include/linux/devfreq.h   |  5 +++
>>>>>>>     2 files changed, 80 insertions(+)
>>>>>>>
>>>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>>>> index eee403e70c84..784f3e40536a 100644
>>>>>>> --- a/drivers/devfreq/devfreq.c
>>>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>>>> @@ -22,15 +22,18 @@
>>>>>>>     #include <linux/platform_device.h>
>>>>>>>     #include <linux/list.h>
>>>>>>>     #include <linux/printk.h>
>>>>>>>     #include <linux/hrtimer.h>
>>>>>>>     #include <linux/of.h>
>>>>>>> +#include <linux/pm_qos.h>
>>>>>>>     #include "governor.h"
>>>>>>>     
>>>>>>>     #define CREATE_TRACE_POINTS
>>>>>>>     #include <trace/events/devfreq.h>
>>>>>>>     
>>>>>>> +#define HZ_PER_KHZ	1000
>>>>>>> +
>>>>>>>     static struct class *devfreq_class;
>>>>>>>     
>>>>>>>     /*
>>>>>>>      * devfreq core provides delayed work based load monitoring helper
>>>>>>>      * functions. Governors can use these or can implement their own
>>>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>>>>     static void get_freq_range(struct devfreq *devfreq,
>>>>>>>     			   unsigned long *min_freq,
>>>>>>>     			   unsigned long *max_freq)
>>>>>>>     {
>>>>>>>     	unsigned long *freq_table = devfreq->profile->freq_table;
>>>>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>>>>     
>>>>>>>     	lockdep_assert_held(&devfreq->lock);
>>>>>>>     
>>>>>>>     	/*
>>>>>>>     	 * Init min/max frequency from freq table.
>>>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>>>     	} else {
>>>>>>>     		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>>>>     		*max_freq = freq_table[0];
>>>>>>>     	}
>>>>>>>     
>>>>>>> +	/* constraints from PM QoS */
>>>>>>
>>>>>> As I commented on patch4,
>>>>>> 'constraints' -> 'Constraint' because first verb have to be used
>>>>>> as the sigular verbs.
>>>>>
>>>>> Already discussed for another patch; I will modify to "Apply constraints
>>>>> from PM QoS" instead.
>>>>
>>>> I agree the new comment with 'Apply constraints ... '.
>>>>
>>>>>
>>>>>> I prefer to use following comments:
>>>>>>
>>>>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>>>>
>>>>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>>>> +
>>>>>>>     	/* constraints from sysfs */
>>>>>>>     	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>>>>     	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>>>>     
>>>>>>>     	/* constraints from OPP interface */
>>>>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>>>>     	mutex_unlock(&devfreq->lock);
>>>>>>>     
>>>>>>>     	return ret;
>>>>>>>     }
>>>>>>>     
>>>>>>> +/**
>>>>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>>>>> + * @devfreq:    the devfreq instance.
>>>>>>> + */
>>>>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>>>>> +{
>>>>>>> +	int err;
>>>>>>> +
>>>>>>> +	mutex_lock(&devfreq->lock);
>>>>>>> +	err = update_devfreq(devfreq);
>>>>>>> +	mutex_unlock(&devfreq->lock);
>>>>>>> +	if (err)
>>>>>>> +		dev_err(devfreq->dev.parent,
>>>>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>>>>
>>>>>> Is it not over 80 char?
>>>>>
>>>>> Yes but coding style explicitly forbids breaking strings.
>>>>>
>>>>>>> +				err);
>>>>>>> +
>>>>>>> +	return NOTIFY_OK;
>>>>>>> +}
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>>>>> + * @nb:		Should be devfreq->nb_min
>>>>>>> + */
>>>>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>>>>> +					 unsigned long val, void *ptr)
>>>>>>> +{
>>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>>>>> +}
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>>>>> + * @nb:		Should be devfreq->nb_max
>>>>>>> + */
>>>>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>>>>> +					 unsigned long val, void *ptr)
>>>>>>> +{
>>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>>>>> +}
>>>>>>> +
>>>>>>>     /**
>>>>>>>      * devfreq_dev_release() - Callback for struct device to release the device.
>>>>>>>      * @dev:	the devfreq device
>>>>>>>      *
>>>>>>>      * Remove devfreq from the list and release its resources.
>>>>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>>>>     
>>>>>>>     	mutex_lock(&devfreq_list_lock);
>>>>>>>     	list_del(&devfreq->node);
>>>>>>>     	mutex_unlock(&devfreq_list_lock);
>>>>>>>     
>>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>> +
>>>>>>
>>>>>> Just print error with dev_err() without stopping the release step.
>>>>>>
>>>>>> I prefer to handle the return value if kernel API provides
>>>>>> the error code.
>>>>
>>>> How about?
>>>
>>> Modified to dev_warn. This also applies to PATCH 6 so I replied there.
>>>
>>>>>>>     	if (devfreq->profile->exit)
>>>>>>>     		devfreq->profile->exit(devfreq->dev.parent);
>>>>>>>     
>>>>>>>     	kfree(devfreq->time_in_state);
>>>>>>>     	kfree(devfreq->trans_table);
>>>>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>>     	if (err) {
>>>>>>>     		put_device(&devfreq->dev);
>>>>>>>     		goto err_out;
>>>>>>>     	}
>>>>>>>     
>>>>>>> +	/*
>>>>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>>>>> +	 * initialized (and we can handle notifications) but before the
>>>>>>> +	 * governor is started (which should do an initial enforcement of
>>>>>>> +	 * constraints).
>>>>>>> +	 */
>>>>>>
>>>>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>>>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>>>>> comments because the line code is not too long. But, at the present time,
>>>>>> devfreq_add_device() is too long. It means that the detailed comment
>>>>>> are necessary.
>>>>>>
>>>>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>>>>> on separate patch to keep the same style. I'll send the patch to you
>>>>>> for the review.
>>>>>
>>>>> This is very likely to result in merge conflicts, maybe wait for my
>>>>> series to go in first?
>>>>
>>>> I'll send the separate patch after finished the review of these patches.
>>>> So, if you agree, please remove this comment on this patch.
>>>>
>>>> You can review the detailed comments on separate patch when I send.
>>> This patch already contains comments and they explain the code being
>>> added. Doesn't it make more sense for comments and code to go in together?
>>>
>>> I think the comment is a resonable explanation as to why notifiers are
>>> registered at that specific step in the initialization sequence.
>>
>> If you add this comment on this patch, OK. just I have some comments.
>>
>> 	/*
>> 	 * Register notifiers for updates to min/max_freq after device is
>> 	 * initialized (and we can handle notifications) but before the
>>
>> I think that 'device is initialized' is not needed.
>> It is always true, it don't need to add the additional comments.
>> because dev_pm_qos_add_notifier() must need the 'devfreq->dev'.
>> The this code prove the call sequence between them.
> 
> In theory if a notifier is registered too soon then it could crash on a 
> NULL pointer. But looking at the code it first checks that "governor != 
> NULL) so it would be harmless.
> 
>>
>> About 'us', don't use 'we'. The subject is 'devfreq' or other device instead of us.
>>
>> 	 * governor is started (which should do an initial enforcement of
>> 	 * constraints).
>>   	 */
>>
>> Actually, it doesn't matter the initialization step between governor
>> and PM_QOS registration.
> 
> In theory PM QoS constraints could be modified between governor startup 
> and notifier registration and that update would be lost (until the next 
> one).

Don't lose the any of PM QoS request. User can request the any frequency
through PMQoS at the any time and then devfreq consider the constraints
from PM QoS.

Also, after finished the registration of devfreq device,
the user (other device driver required the min/max freq)
can request the PM QoS on real use-case.

It is impossible to get the devfreq instance before finished
the devfreq_add_device() because the user can access the devfreq instance
devfreq_get_devfreq_by_phandle() which use 'devfreq_list'.

If devfreq_add_device() is not finished, the user cannot get
the any devfreq device from 'devfreq_list'.

> 
>> If start governor and then register PM_QOS,
>> the governor can decide the new frequency. And then PM_QOS request
>> the new constraints for min/max frequency. On request time of PM_QOS,
>> devfreq can detect this time and then apply the constraints from PM_QOS.
>> The user of devfreq's PM_QOS must need the phandle or device instance
>> of devfreq deivce. It means that user of devfreq's PM_QOS can request
>> the any constraints of PM_QOS_MIN/MAX through PM_QOS interface.
>>
>> So, it doesn't need to add the following comments
>> because following comment is not always mandatory.
>> " governor is started (which should do an initial enforcement of constraints)."
>>
>> Also, you don't need to use parentheses on comments.
>>
>> Actually, I think that following comments are enough.
>>
>> 	/* Register PM QoS notifiers for updating to min/max freq */
> 
> I thought that explaning why it's done at this particular step but I'll 
> just remove it, devfreq_add_device can get more comments later.

OK. Thanks.
I think that if the comment contains what is meaning of the code,
it is enough.

Although change the sequence between dev_pm_qos_add_notifier() and
try_then_request_governor(), in the real-case, the any issue
would not happen. Because as I commented above, the other device-driver
cannot get the devfreq instance before finished the devfreq_add_device.
It means that the user device driver cannot request the any PM QoS
constraints.

> 
>>>>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>> +	if (err)
>>>>>>> +		goto err_devfreq;
>>>>>>> +
>>>>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>>>>> +	if (err)
>>>>>>> +		goto err_devfreq;
>>>>>>> +
>>>>>>>     	mutex_lock(&devfreq_list_lock);
>>>>>>>     
>>>>>>>     	governor = try_then_request_governor(devfreq->governor_name);
>>>>>>>     	if (IS_ERR(governor)) {
>>>>>>>     		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>>     
>>>>>>>     	return devfreq;
>>>>>>>     
>>>>>>>     err_init:
>>>>>>>     	mutex_unlock(&devfreq_list_lock);
>>>>>>> +err_devfreq:
>>>>>>>     	devfreq_remove_device(devfreq);
>>>>>>>     	return ERR_PTR(err);
>>>>>>>     
>>>>>>>     err_dev:
>>>>>>>     	/*
>>>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>>>>> --- a/include/linux/devfreq.h
>>>>>>> +++ b/include/linux/devfreq.h
>>>>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>>>>      * @total_trans:	Number of devfreq transitions
>>>>>>>      * @trans_table:	Statistics of devfreq transitions
>>>>>>>      * @time_in_state:	Statistics of devfreq states
>>>>>>>      * @last_stat_updated:	The last time stat updated
>>>>>>>      * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>>>>      *
>>>>>>>      * This structure stores the devfreq information for a give device.
>>>>>>>      *
>>>>>>>      * Note that when a governor accesses entries in struct devfreq in its
>>>>>>>      * functions except for the context of callbacks defined in struct
>>>>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>>>>     	unsigned int *trans_table;
>>>>>>>     	unsigned long *time_in_state;
>>>>>>>     	unsigned long last_stat_updated;
>>>>>>>     
>>>>>>>     	struct srcu_notifier_head transition_notifier_list;
>>>>>>> +
>>>>>>> +	struct notifier_block nb_min;
>>>>>>> +	struct notifier_block nb_max;
>>>>>>>     };
>>>>>>>     
>>>>>>>     struct devfreq_freqs {
>>>>>>>     	unsigned long old;
>>>>>>>     	unsigned long new;
>>
>>
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-09-30 21:42                   ` Chanwoo Choi
@ 2019-10-01  9:39                     ` Leonard Crestez
  -1 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-10-01  9:39 UTC (permalink / raw)
  To: Chanwoo Choi, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 2019-10-01 12:37 AM, Chanwoo Choi wrote:
> Hi,
> 
> On 19. 9. 30. 오후 10:16, Leonard Crestez wrote:
>> On 2019-09-27 4:45 AM, Chanwoo Choi wrote:
>>> On 19. 9. 26. 오후 10:43, Leonard Crestez wrote:
>>>> On 2019-09-26 4:07 AM, Chanwoo Choi wrote:
>>>>> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>>>>>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>>>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>>>>
>>>>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>>>>> imposed externally (for example from other devices).
>>>>>>>>
>>>>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>>>>> ---
>>>>>>>>      drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>>>>>      include/linux/devfreq.h   |  5 +++
>>>>>>>>      2 files changed, 80 insertions(+)
>>>>>>>>
>>>>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>>>>> index eee403e70c84..784f3e40536a 100644
>>>>>>>> --- a/drivers/devfreq/devfreq.c
>>>>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>>>>> @@ -22,15 +22,18 @@
>>>>>>>>      #include <linux/platform_device.h>
>>>>>>>>      #include <linux/list.h>
>>>>>>>>      #include <linux/printk.h>
>>>>>>>>      #include <linux/hrtimer.h>
>>>>>>>>      #include <linux/of.h>
>>>>>>>> +#include <linux/pm_qos.h>
>>>>>>>>      #include "governor.h"
>>>>>>>>      
>>>>>>>>      #define CREATE_TRACE_POINTS
>>>>>>>>      #include <trace/events/devfreq.h>
>>>>>>>>      
>>>>>>>> +#define HZ_PER_KHZ	1000
>>>>>>>> +
>>>>>>>>      static struct class *devfreq_class;
>>>>>>>>      
>>>>>>>>      /*
>>>>>>>>       * devfreq core provides delayed work based load monitoring helper
>>>>>>>>       * functions. Governors can use these or can implement their own
>>>>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>>>>>      static void get_freq_range(struct devfreq *devfreq,
>>>>>>>>      			   unsigned long *min_freq,
>>>>>>>>      			   unsigned long *max_freq)
>>>>>>>>      {
>>>>>>>>      	unsigned long *freq_table = devfreq->profile->freq_table;
>>>>>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>>>>>      
>>>>>>>>      	lockdep_assert_held(&devfreq->lock);
>>>>>>>>      
>>>>>>>>      	/*
>>>>>>>>      	 * Init min/max frequency from freq table.
>>>>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>>>>      	} else {
>>>>>>>>      		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>>>>>      		*max_freq = freq_table[0];
>>>>>>>>      	}
>>>>>>>>      
>>>>>>>> +	/* constraints from PM QoS */
>>>>>>>
>>>>>>> As I commented on patch4,
>>>>>>> 'constraints' -> 'Constraint' because first verb have to be used
>>>>>>> as the sigular verbs.
>>>>>>
>>>>>> Already discussed for another patch; I will modify to "Apply constraints
>>>>>> from PM QoS" instead.
>>>>>
>>>>> I agree the new comment with 'Apply constraints ... '.
>>>>>
>>>>>>
>>>>>>> I prefer to use following comments:
>>>>>>>
>>>>>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>>>>>
>>>>>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>>>>> +
>>>>>>>>      	/* constraints from sysfs */
>>>>>>>>      	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>>>>>      	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>>>>>      
>>>>>>>>      	/* constraints from OPP interface */
>>>>>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>>>>>      	mutex_unlock(&devfreq->lock);
>>>>>>>>      
>>>>>>>>      	return ret;
>>>>>>>>      }
>>>>>>>>      
>>>>>>>> +/**
>>>>>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>>>>>> + * @devfreq:    the devfreq instance.
>>>>>>>> + */
>>>>>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>>>>>> +{
>>>>>>>> +	int err;
>>>>>>>> +
>>>>>>>> +	mutex_lock(&devfreq->lock);
>>>>>>>> +	err = update_devfreq(devfreq);
>>>>>>>> +	mutex_unlock(&devfreq->lock);
>>>>>>>> +	if (err)
>>>>>>>> +		dev_err(devfreq->dev.parent,
>>>>>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>>>>>
>>>>>>> Is it not over 80 char?
>>>>>>
>>>>>> Yes but coding style explicitly forbids breaking strings.
>>>>>>
>>>>>>>> +				err);
>>>>>>>> +
>>>>>>>> +	return NOTIFY_OK;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +/**
>>>>>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>>>>>> + * @nb:		Should be devfreq->nb_min
>>>>>>>> + */
>>>>>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>>>>>> +					 unsigned long val, void *ptr)
>>>>>>>> +{
>>>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +/**
>>>>>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>>>>>> + * @nb:		Should be devfreq->nb_max
>>>>>>>> + */
>>>>>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>>>>>> +					 unsigned long val, void *ptr)
>>>>>>>> +{
>>>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>>>>>> +}
>>>>>>>> +
>>>>>>>>      /**
>>>>>>>>       * devfreq_dev_release() - Callback for struct device to release the device.
>>>>>>>>       * @dev:	the devfreq device
>>>>>>>>       *
>>>>>>>>       * Remove devfreq from the list and release its resources.
>>>>>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>>>>>      
>>>>>>>>      	mutex_lock(&devfreq_list_lock);
>>>>>>>>      	list_del(&devfreq->node);
>>>>>>>>      	mutex_unlock(&devfreq_list_lock);
>>>>>>>>      
>>>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>> +
>>>>>>>
>>>>>>> Just print error with dev_err() without stopping the release step.
>>>>>>>
>>>>>>> I prefer to handle the return value if kernel API provides
>>>>>>> the error code.
>>>>>
>>>>> How about?
>>>>
>>>> Modified to dev_warn. This also applies to PATCH 6 so I replied there.
>>>>
>>>>>>>>      	if (devfreq->profile->exit)
>>>>>>>>      		devfreq->profile->exit(devfreq->dev.parent);
>>>>>>>>      
>>>>>>>>      	kfree(devfreq->time_in_state);
>>>>>>>>      	kfree(devfreq->trans_table);
>>>>>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>>>      	if (err) {
>>>>>>>>      		put_device(&devfreq->dev);
>>>>>>>>      		goto err_out;
>>>>>>>>      	}
>>>>>>>>      
>>>>>>>> +	/*
>>>>>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>>>>>> +	 * initialized (and we can handle notifications) but before the
>>>>>>>> +	 * governor is started (which should do an initial enforcement of
>>>>>>>> +	 * constraints).
>>>>>>>> +	 */
>>>>>>>
>>>>>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>>>>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>>>>>> comments because the line code is not too long. But, at the present time,
>>>>>>> devfreq_add_device() is too long. It means that the detailed comment
>>>>>>> are necessary.
>>>>>>>
>>>>>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>>>>>> on separate patch to keep the same style. I'll send the patch to you
>>>>>>> for the review.
>>>>>>
>>>>>> This is very likely to result in merge conflicts, maybe wait for my
>>>>>> series to go in first?
>>>>>
>>>>> I'll send the separate patch after finished the review of these patches.
>>>>> So, if you agree, please remove this comment on this patch.
>>>>>
>>>>> You can review the detailed comments on separate patch when I send.
>>>> This patch already contains comments and they explain the code being
>>>> added. Doesn't it make more sense for comments and code to go in together?
>>>>
>>>> I think the comment is a resonable explanation as to why notifiers are
>>>> registered at that specific step in the initialization sequence.
>>>
>>> If you add this comment on this patch, OK. just I have some comments.
>>>
>>> 	/*
>>> 	 * Register notifiers for updates to min/max_freq after device is
>>> 	 * initialized (and we can handle notifications) but before the
>>>
>>> I think that 'device is initialized' is not needed.
>>> It is always true, it don't need to add the additional comments.
>>> because dev_pm_qos_add_notifier() must need the 'devfreq->dev'.
>>> The this code prove the call sequence between them.
>>
>> In theory if a notifier is registered too soon then it could crash on a
>> NULL pointer. But looking at the code it first checks that "governor !=
>> NULL) so it would be harmless.
>>
>>>
>>> About 'us', don't use 'we'. The subject is 'devfreq' or other device instead of us.
>>>
>>> 	 * governor is started (which should do an initial enforcement of
>>> 	 * constraints).
>>>    	 */
>>>
>>> Actually, it doesn't matter the initialization step between governor
>>> and PM_QOS registration.
>>
>> In theory PM QoS constraints could be modified between governor startup
>> and notifier registration and that update would be lost (until the next
>> one).
> 
> Don't lose the any of PM QoS request. User can request the any frequency
> through PMQoS at the any time and then devfreq consider the constraints
> from PM QoS.
> 
> Also, after finished the registration of devfreq device,
> the user (other device driver required the min/max freq)
> can request the PM QoS on real use-case.
> 
> It is impossible to get the devfreq instance before finished
> the devfreq_add_device() because the user can access the devfreq instance
> devfreq_get_devfreq_by_phandle() which use 'devfreq_list'.
> 
> If devfreq_add_device() is not finished, the user cannot get
> the any devfreq device from 'devfreq_list'.

PM QoS constraints are not on devfreq->dev but on the parent so in 
theory it's possible to add constraints during devfreq initialization.

Making PM QoS requests doesn't require fetching devfreq instances, I 
think you could call of_find_device_by_node with a phandle and register 
constraints that way.

>>> If start governor and then register PM_QOS,
>>> the governor can decide the new frequency. And then PM_QOS request
>>> the new constraints for min/max frequency. On request time of PM_QOS,
>>> devfreq can detect this time and then apply the constraints from PM_QOS.
>>> The user of devfreq's PM_QOS must need the phandle or device instance
>>> of devfreq deivce. It means that user of devfreq's PM_QOS can request
>>> the any constraints of PM_QOS_MIN/MAX through PM_QOS interface.
>>>
>>> So, it doesn't need to add the following comments
>>> because following comment is not always mandatory.
>>> " governor is started (which should do an initial enforcement of constraints)."
>>>
>>> Also, you don't need to use parentheses on comments.
>>>
>>> Actually, I think that following comments are enough.
>>>
>>> 	/* Register PM QoS notifiers for updating to min/max freq */
>>
>> I thought that explaning why it's done at this particular step but I'll
>> just remove it, devfreq_add_device can get more comments later.
> 
> OK. Thanks.
> I think that if the comment contains what is meaning of the code,
> it is enough.
> 
> Although change the sequence between dev_pm_qos_add_notifier() and
> try_then_request_governor(), in the real-case, the any issue
> would not happen. Because as I commented above, the other device-driver
> cannot get the devfreq instance before finished the devfreq_add_device.
> It means that the user device driver cannot request the any PM QoS
> constraints.
> 
>>
>>>>>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>> +	if (err)
>>>>>>>> +		goto err_devfreq;
>>>>>>>> +
>>>>>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>>>>>> +	if (err)
>>>>>>>> +		goto err_devfreq;
>>>>>>>> +
>>>>>>>>      	mutex_lock(&devfreq_list_lock);
>>>>>>>>      
>>>>>>>>      	governor = try_then_request_governor(devfreq->governor_name);
>>>>>>>>      	if (IS_ERR(governor)) {
>>>>>>>>      		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>>>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>>>      
>>>>>>>>      	return devfreq;
>>>>>>>>      
>>>>>>>>      err_init:
>>>>>>>>      	mutex_unlock(&devfreq_list_lock);
>>>>>>>> +err_devfreq:
>>>>>>>>      	devfreq_remove_device(devfreq);
>>>>>>>>      	return ERR_PTR(err);
>>>>>>>>      
>>>>>>>>      err_dev:
>>>>>>>>      	/*
>>>>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>>>>>> --- a/include/linux/devfreq.h
>>>>>>>> +++ b/include/linux/devfreq.h
>>>>>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>>>>>       * @total_trans:	Number of devfreq transitions
>>>>>>>>       * @trans_table:	Statistics of devfreq transitions
>>>>>>>>       * @time_in_state:	Statistics of devfreq states
>>>>>>>>       * @last_stat_updated:	The last time stat updated
>>>>>>>>       * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>>>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>>>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>>>>>       *
>>>>>>>>       * This structure stores the devfreq information for a give device.
>>>>>>>>       *
>>>>>>>>       * Note that when a governor accesses entries in struct devfreq in its
>>>>>>>>       * functions except for the context of callbacks defined in struct
>>>>>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>>>>>      	unsigned int *trans_table;
>>>>>>>>      	unsigned long *time_in_state;
>>>>>>>>      	unsigned long last_stat_updated;
>>>>>>>>      
>>>>>>>>      	struct srcu_notifier_head transition_notifier_list;
>>>>>>>> +
>>>>>>>> +	struct notifier_block nb_min;
>>>>>>>> +	struct notifier_block nb_max;
>>>>>>>>      };
>>>>>>>>      
>>>>>>>>      struct devfreq_freqs {
>>>>>>>>      	unsigned long old;
>>>>>>>>      	unsigned long new;
>>>
>>>
>>
> 
> 


^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-10-01  9:39                     ` Leonard Crestez
  0 siblings, 0 replies; 82+ messages in thread
From: Leonard Crestez @ 2019-10-01  9:39 UTC (permalink / raw)
  To: Chanwoo Choi, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 2019-10-01 12:37 AM, Chanwoo Choi wrote:
> Hi,
> 
> On 19. 9. 30. 오후 10:16, Leonard Crestez wrote:
>> On 2019-09-27 4:45 AM, Chanwoo Choi wrote:
>>> On 19. 9. 26. 오후 10:43, Leonard Crestez wrote:
>>>> On 2019-09-26 4:07 AM, Chanwoo Choi wrote:
>>>>> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>>>>>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>>>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>>>>
>>>>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>>>>> imposed externally (for example from other devices).
>>>>>>>>
>>>>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>>>>> ---
>>>>>>>>      drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>>>>>      include/linux/devfreq.h   |  5 +++
>>>>>>>>      2 files changed, 80 insertions(+)
>>>>>>>>
>>>>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>>>>> index eee403e70c84..784f3e40536a 100644
>>>>>>>> --- a/drivers/devfreq/devfreq.c
>>>>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>>>>> @@ -22,15 +22,18 @@
>>>>>>>>      #include <linux/platform_device.h>
>>>>>>>>      #include <linux/list.h>
>>>>>>>>      #include <linux/printk.h>
>>>>>>>>      #include <linux/hrtimer.h>
>>>>>>>>      #include <linux/of.h>
>>>>>>>> +#include <linux/pm_qos.h>
>>>>>>>>      #include "governor.h"
>>>>>>>>      
>>>>>>>>      #define CREATE_TRACE_POINTS
>>>>>>>>      #include <trace/events/devfreq.h>
>>>>>>>>      
>>>>>>>> +#define HZ_PER_KHZ	1000
>>>>>>>> +
>>>>>>>>      static struct class *devfreq_class;
>>>>>>>>      
>>>>>>>>      /*
>>>>>>>>       * devfreq core provides delayed work based load monitoring helper
>>>>>>>>       * functions. Governors can use these or can implement their own
>>>>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>>>>>      static void get_freq_range(struct devfreq *devfreq,
>>>>>>>>      			   unsigned long *min_freq,
>>>>>>>>      			   unsigned long *max_freq)
>>>>>>>>      {
>>>>>>>>      	unsigned long *freq_table = devfreq->profile->freq_table;
>>>>>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>>>>>      
>>>>>>>>      	lockdep_assert_held(&devfreq->lock);
>>>>>>>>      
>>>>>>>>      	/*
>>>>>>>>      	 * Init min/max frequency from freq table.
>>>>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>>>>      	} else {
>>>>>>>>      		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>>>>>      		*max_freq = freq_table[0];
>>>>>>>>      	}
>>>>>>>>      
>>>>>>>> +	/* constraints from PM QoS */
>>>>>>>
>>>>>>> As I commented on patch4,
>>>>>>> 'constraints' -> 'Constraint' because first verb have to be used
>>>>>>> as the sigular verbs.
>>>>>>
>>>>>> Already discussed for another patch; I will modify to "Apply constraints
>>>>>> from PM QoS" instead.
>>>>>
>>>>> I agree the new comment with 'Apply constraints ... '.
>>>>>
>>>>>>
>>>>>>> I prefer to use following comments:
>>>>>>>
>>>>>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>>>>>
>>>>>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>>>>> +
>>>>>>>>      	/* constraints from sysfs */
>>>>>>>>      	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>>>>>      	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>>>>>      
>>>>>>>>      	/* constraints from OPP interface */
>>>>>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>>>>>      	mutex_unlock(&devfreq->lock);
>>>>>>>>      
>>>>>>>>      	return ret;
>>>>>>>>      }
>>>>>>>>      
>>>>>>>> +/**
>>>>>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>>>>>> + * @devfreq:    the devfreq instance.
>>>>>>>> + */
>>>>>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>>>>>> +{
>>>>>>>> +	int err;
>>>>>>>> +
>>>>>>>> +	mutex_lock(&devfreq->lock);
>>>>>>>> +	err = update_devfreq(devfreq);
>>>>>>>> +	mutex_unlock(&devfreq->lock);
>>>>>>>> +	if (err)
>>>>>>>> +		dev_err(devfreq->dev.parent,
>>>>>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>>>>>
>>>>>>> Is it not over 80 char?
>>>>>>
>>>>>> Yes but coding style explicitly forbids breaking strings.
>>>>>>
>>>>>>>> +				err);
>>>>>>>> +
>>>>>>>> +	return NOTIFY_OK;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +/**
>>>>>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>>>>>> + * @nb:		Should be devfreq->nb_min
>>>>>>>> + */
>>>>>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>>>>>> +					 unsigned long val, void *ptr)
>>>>>>>> +{
>>>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +/**
>>>>>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>>>>>> + * @nb:		Should be devfreq->nb_max
>>>>>>>> + */
>>>>>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>>>>>> +					 unsigned long val, void *ptr)
>>>>>>>> +{
>>>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>>>>>> +}
>>>>>>>> +
>>>>>>>>      /**
>>>>>>>>       * devfreq_dev_release() - Callback for struct device to release the device.
>>>>>>>>       * @dev:	the devfreq device
>>>>>>>>       *
>>>>>>>>       * Remove devfreq from the list and release its resources.
>>>>>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>>>>>      
>>>>>>>>      	mutex_lock(&devfreq_list_lock);
>>>>>>>>      	list_del(&devfreq->node);
>>>>>>>>      	mutex_unlock(&devfreq_list_lock);
>>>>>>>>      
>>>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>> +
>>>>>>>
>>>>>>> Just print error with dev_err() without stopping the release step.
>>>>>>>
>>>>>>> I prefer to handle the return value if kernel API provides
>>>>>>> the error code.
>>>>>
>>>>> How about?
>>>>
>>>> Modified to dev_warn. This also applies to PATCH 6 so I replied there.
>>>>
>>>>>>>>      	if (devfreq->profile->exit)
>>>>>>>>      		devfreq->profile->exit(devfreq->dev.parent);
>>>>>>>>      
>>>>>>>>      	kfree(devfreq->time_in_state);
>>>>>>>>      	kfree(devfreq->trans_table);
>>>>>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>>>      	if (err) {
>>>>>>>>      		put_device(&devfreq->dev);
>>>>>>>>      		goto err_out;
>>>>>>>>      	}
>>>>>>>>      
>>>>>>>> +	/*
>>>>>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>>>>>> +	 * initialized (and we can handle notifications) but before the
>>>>>>>> +	 * governor is started (which should do an initial enforcement of
>>>>>>>> +	 * constraints).
>>>>>>>> +	 */
>>>>>>>
>>>>>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>>>>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>>>>>> comments because the line code is not too long. But, at the present time,
>>>>>>> devfreq_add_device() is too long. It means that the detailed comment
>>>>>>> are necessary.
>>>>>>>
>>>>>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>>>>>> on separate patch to keep the same style. I'll send the patch to you
>>>>>>> for the review.
>>>>>>
>>>>>> This is very likely to result in merge conflicts, maybe wait for my
>>>>>> series to go in first?
>>>>>
>>>>> I'll send the separate patch after finished the review of these patches.
>>>>> So, if you agree, please remove this comment on this patch.
>>>>>
>>>>> You can review the detailed comments on separate patch when I send.
>>>> This patch already contains comments and they explain the code being
>>>> added. Doesn't it make more sense for comments and code to go in together?
>>>>
>>>> I think the comment is a resonable explanation as to why notifiers are
>>>> registered at that specific step in the initialization sequence.
>>>
>>> If you add this comment on this patch, OK. just I have some comments.
>>>
>>> 	/*
>>> 	 * Register notifiers for updates to min/max_freq after device is
>>> 	 * initialized (and we can handle notifications) but before the
>>>
>>> I think that 'device is initialized' is not needed.
>>> It is always true, it don't need to add the additional comments.
>>> because dev_pm_qos_add_notifier() must need the 'devfreq->dev'.
>>> The this code prove the call sequence between them.
>>
>> In theory if a notifier is registered too soon then it could crash on a
>> NULL pointer. But looking at the code it first checks that "governor !=
>> NULL) so it would be harmless.
>>
>>>
>>> About 'us', don't use 'we'. The subject is 'devfreq' or other device instead of us.
>>>
>>> 	 * governor is started (which should do an initial enforcement of
>>> 	 * constraints).
>>>    	 */
>>>
>>> Actually, it doesn't matter the initialization step between governor
>>> and PM_QOS registration.
>>
>> In theory PM QoS constraints could be modified between governor startup
>> and notifier registration and that update would be lost (until the next
>> one).
> 
> Don't lose the any of PM QoS request. User can request the any frequency
> through PMQoS at the any time and then devfreq consider the constraints
> from PM QoS.
> 
> Also, after finished the registration of devfreq device,
> the user (other device driver required the min/max freq)
> can request the PM QoS on real use-case.
> 
> It is impossible to get the devfreq instance before finished
> the devfreq_add_device() because the user can access the devfreq instance
> devfreq_get_devfreq_by_phandle() which use 'devfreq_list'.
> 
> If devfreq_add_device() is not finished, the user cannot get
> the any devfreq device from 'devfreq_list'.

PM QoS constraints are not on devfreq->dev but on the parent so in 
theory it's possible to add constraints during devfreq initialization.

Making PM QoS requests doesn't require fetching devfreq instances, I 
think you could call of_find_device_by_node with a phandle and register 
constraints that way.

>>> If start governor and then register PM_QOS,
>>> the governor can decide the new frequency. And then PM_QOS request
>>> the new constraints for min/max frequency. On request time of PM_QOS,
>>> devfreq can detect this time and then apply the constraints from PM_QOS.
>>> The user of devfreq's PM_QOS must need the phandle or device instance
>>> of devfreq deivce. It means that user of devfreq's PM_QOS can request
>>> the any constraints of PM_QOS_MIN/MAX through PM_QOS interface.
>>>
>>> So, it doesn't need to add the following comments
>>> because following comment is not always mandatory.
>>> " governor is started (which should do an initial enforcement of constraints)."
>>>
>>> Also, you don't need to use parentheses on comments.
>>>
>>> Actually, I think that following comments are enough.
>>>
>>> 	/* Register PM QoS notifiers for updating to min/max freq */
>>
>> I thought that explaning why it's done at this particular step but I'll
>> just remove it, devfreq_add_device can get more comments later.
> 
> OK. Thanks.
> I think that if the comment contains what is meaning of the code,
> it is enough.
> 
> Although change the sequence between dev_pm_qos_add_notifier() and
> try_then_request_governor(), in the real-case, the any issue
> would not happen. Because as I commented above, the other device-driver
> cannot get the devfreq instance before finished the devfreq_add_device.
> It means that the user device driver cannot request the any PM QoS
> constraints.
> 
>>
>>>>>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>> +	if (err)
>>>>>>>> +		goto err_devfreq;
>>>>>>>> +
>>>>>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>>>>>> +	if (err)
>>>>>>>> +		goto err_devfreq;
>>>>>>>> +
>>>>>>>>      	mutex_lock(&devfreq_list_lock);
>>>>>>>>      
>>>>>>>>      	governor = try_then_request_governor(devfreq->governor_name);
>>>>>>>>      	if (IS_ERR(governor)) {
>>>>>>>>      		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>>>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>>>      
>>>>>>>>      	return devfreq;
>>>>>>>>      
>>>>>>>>      err_init:
>>>>>>>>      	mutex_unlock(&devfreq_list_lock);
>>>>>>>> +err_devfreq:
>>>>>>>>      	devfreq_remove_device(devfreq);
>>>>>>>>      	return ERR_PTR(err);
>>>>>>>>      
>>>>>>>>      err_dev:
>>>>>>>>      	/*
>>>>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>>>>>> --- a/include/linux/devfreq.h
>>>>>>>> +++ b/include/linux/devfreq.h
>>>>>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>>>>>       * @total_trans:	Number of devfreq transitions
>>>>>>>>       * @trans_table:	Statistics of devfreq transitions
>>>>>>>>       * @time_in_state:	Statistics of devfreq states
>>>>>>>>       * @last_stat_updated:	The last time stat updated
>>>>>>>>       * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>>>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>>>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>>>>>       *
>>>>>>>>       * This structure stores the devfreq information for a give device.
>>>>>>>>       *
>>>>>>>>       * Note that when a governor accesses entries in struct devfreq in its
>>>>>>>>       * functions except for the context of callbacks defined in struct
>>>>>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>>>>>      	unsigned int *trans_table;
>>>>>>>>      	unsigned long *time_in_state;
>>>>>>>>      	unsigned long last_stat_updated;
>>>>>>>>      
>>>>>>>>      	struct srcu_notifier_head transition_notifier_list;
>>>>>>>> +
>>>>>>>> +	struct notifier_block nb_min;
>>>>>>>> +	struct notifier_block nb_max;
>>>>>>>>      };
>>>>>>>>      
>>>>>>>>      struct devfreq_freqs {
>>>>>>>>      	unsigned long old;
>>>>>>>>      	unsigned long new;
>>>
>>>
>>
> 
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
  2019-10-01  9:39                     ` Leonard Crestez
@ 2019-10-01 21:55                       ` Chanwoo Choi
  -1 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-10-01 21:55 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Artur Świgoń,
	Saravana Kannan, Krzysztof Kozlowski, Alexandre Bailon,
	Georgi Djakov, Abel Vesa, Jacky Bai, Viresh Kumar, Lukasz Luba,
	dl-linux-imx, linux-pm, linux-arm-kernel

On 19. 10. 1. 오후 6:39, Leonard Crestez wrote:
> On 2019-10-01 12:37 AM, Chanwoo Choi wrote:
>> Hi,
>>
>> On 19. 9. 30. 오후 10:16, Leonard Crestez wrote:
>>> On 2019-09-27 4:45 AM, Chanwoo Choi wrote:
>>>> On 19. 9. 26. 오후 10:43, Leonard Crestez wrote:
>>>>> On 2019-09-26 4:07 AM, Chanwoo Choi wrote:
>>>>>> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>>>>>>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>>>>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>>>>>
>>>>>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>>>>>> imposed externally (for example from other devices).
>>>>>>>>>
>>>>>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>>>>>> ---
>>>>>>>>>      drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>>>>>>      include/linux/devfreq.h   |  5 +++
>>>>>>>>>      2 files changed, 80 insertions(+)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>>>>>> index eee403e70c84..784f3e40536a 100644
>>>>>>>>> --- a/drivers/devfreq/devfreq.c
>>>>>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>>>>>> @@ -22,15 +22,18 @@
>>>>>>>>>      #include <linux/platform_device.h>
>>>>>>>>>      #include <linux/list.h>
>>>>>>>>>      #include <linux/printk.h>
>>>>>>>>>      #include <linux/hrtimer.h>
>>>>>>>>>      #include <linux/of.h>
>>>>>>>>> +#include <linux/pm_qos.h>
>>>>>>>>>      #include "governor.h"
>>>>>>>>>      
>>>>>>>>>      #define CREATE_TRACE_POINTS
>>>>>>>>>      #include <trace/events/devfreq.h>
>>>>>>>>>      
>>>>>>>>> +#define HZ_PER_KHZ	1000
>>>>>>>>> +
>>>>>>>>>      static struct class *devfreq_class;
>>>>>>>>>      
>>>>>>>>>      /*
>>>>>>>>>       * devfreq core provides delayed work based load monitoring helper
>>>>>>>>>       * functions. Governors can use these or can implement their own
>>>>>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>>>>>>      static void get_freq_range(struct devfreq *devfreq,
>>>>>>>>>      			   unsigned long *min_freq,
>>>>>>>>>      			   unsigned long *max_freq)
>>>>>>>>>      {
>>>>>>>>>      	unsigned long *freq_table = devfreq->profile->freq_table;
>>>>>>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>>>>>>      
>>>>>>>>>      	lockdep_assert_held(&devfreq->lock);
>>>>>>>>>      
>>>>>>>>>      	/*
>>>>>>>>>      	 * Init min/max frequency from freq table.
>>>>>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>>>>>      	} else {
>>>>>>>>>      		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>>>>>>      		*max_freq = freq_table[0];
>>>>>>>>>      	}
>>>>>>>>>      
>>>>>>>>> +	/* constraints from PM QoS */
>>>>>>>>
>>>>>>>> As I commented on patch4,
>>>>>>>> 'constraints' -> 'Constraint' because first verb have to be used
>>>>>>>> as the sigular verbs.
>>>>>>>
>>>>>>> Already discussed for another patch; I will modify to "Apply constraints
>>>>>>> from PM QoS" instead.
>>>>>>
>>>>>> I agree the new comment with 'Apply constraints ... '.
>>>>>>
>>>>>>>
>>>>>>>> I prefer to use following comments:
>>>>>>>>
>>>>>>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>>>>>>
>>>>>>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>>>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>>>>>> +
>>>>>>>>>      	/* constraints from sysfs */
>>>>>>>>>      	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>>>>>>      	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>>>>>>      
>>>>>>>>>      	/* constraints from OPP interface */
>>>>>>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>>>>>>      	mutex_unlock(&devfreq->lock);
>>>>>>>>>      
>>>>>>>>>      	return ret;
>>>>>>>>>      }
>>>>>>>>>      
>>>>>>>>> +/**
>>>>>>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>>>>>>> + * @devfreq:    the devfreq instance.
>>>>>>>>> + */
>>>>>>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>>>>>>> +{
>>>>>>>>> +	int err;
>>>>>>>>> +
>>>>>>>>> +	mutex_lock(&devfreq->lock);
>>>>>>>>> +	err = update_devfreq(devfreq);
>>>>>>>>> +	mutex_unlock(&devfreq->lock);
>>>>>>>>> +	if (err)
>>>>>>>>> +		dev_err(devfreq->dev.parent,
>>>>>>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>>>>>>
>>>>>>>> Is it not over 80 char?
>>>>>>>
>>>>>>> Yes but coding style explicitly forbids breaking strings.
>>>>>>>
>>>>>>>>> +				err);
>>>>>>>>> +
>>>>>>>>> +	return NOTIFY_OK;
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +/**
>>>>>>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>>>>>>> + * @nb:		Should be devfreq->nb_min
>>>>>>>>> + */
>>>>>>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>>>>>>> +					 unsigned long val, void *ptr)
>>>>>>>>> +{
>>>>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +/**
>>>>>>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>>>>>>> + * @nb:		Should be devfreq->nb_max
>>>>>>>>> + */
>>>>>>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>>>>>>> +					 unsigned long val, void *ptr)
>>>>>>>>> +{
>>>>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>>      /**
>>>>>>>>>       * devfreq_dev_release() - Callback for struct device to release the device.
>>>>>>>>>       * @dev:	the devfreq device
>>>>>>>>>       *
>>>>>>>>>       * Remove devfreq from the list and release its resources.
>>>>>>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>>>>>>      
>>>>>>>>>      	mutex_lock(&devfreq_list_lock);
>>>>>>>>>      	list_del(&devfreq->node);
>>>>>>>>>      	mutex_unlock(&devfreq_list_lock);
>>>>>>>>>      
>>>>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>>> +
>>>>>>>>
>>>>>>>> Just print error with dev_err() without stopping the release step.
>>>>>>>>
>>>>>>>> I prefer to handle the return value if kernel API provides
>>>>>>>> the error code.
>>>>>>
>>>>>> How about?
>>>>>
>>>>> Modified to dev_warn. This also applies to PATCH 6 so I replied there.
>>>>>
>>>>>>>>>      	if (devfreq->profile->exit)
>>>>>>>>>      		devfreq->profile->exit(devfreq->dev.parent);
>>>>>>>>>      
>>>>>>>>>      	kfree(devfreq->time_in_state);
>>>>>>>>>      	kfree(devfreq->trans_table);
>>>>>>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>>>>      	if (err) {
>>>>>>>>>      		put_device(&devfreq->dev);
>>>>>>>>>      		goto err_out;
>>>>>>>>>      	}
>>>>>>>>>      
>>>>>>>>> +	/*
>>>>>>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>>>>>>> +	 * initialized (and we can handle notifications) but before the
>>>>>>>>> +	 * governor is started (which should do an initial enforcement of
>>>>>>>>> +	 * constraints).
>>>>>>>>> +	 */
>>>>>>>>
>>>>>>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>>>>>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>>>>>>> comments because the line code is not too long. But, at the present time,
>>>>>>>> devfreq_add_device() is too long. It means that the detailed comment
>>>>>>>> are necessary.
>>>>>>>>
>>>>>>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>>>>>>> on separate patch to keep the same style. I'll send the patch to you
>>>>>>>> for the review.
>>>>>>>
>>>>>>> This is very likely to result in merge conflicts, maybe wait for my
>>>>>>> series to go in first?
>>>>>>
>>>>>> I'll send the separate patch after finished the review of these patches.
>>>>>> So, if you agree, please remove this comment on this patch.
>>>>>>
>>>>>> You can review the detailed comments on separate patch when I send.
>>>>> This patch already contains comments and they explain the code being
>>>>> added. Doesn't it make more sense for comments and code to go in together?
>>>>>
>>>>> I think the comment is a resonable explanation as to why notifiers are
>>>>> registered at that specific step in the initialization sequence.
>>>>
>>>> If you add this comment on this patch, OK. just I have some comments.
>>>>
>>>> 	/*
>>>> 	 * Register notifiers for updates to min/max_freq after device is
>>>> 	 * initialized (and we can handle notifications) but before the
>>>>
>>>> I think that 'device is initialized' is not needed.
>>>> It is always true, it don't need to add the additional comments.
>>>> because dev_pm_qos_add_notifier() must need the 'devfreq->dev'.
>>>> The this code prove the call sequence between them.
>>>
>>> In theory if a notifier is registered too soon then it could crash on a
>>> NULL pointer. But looking at the code it first checks that "governor !=
>>> NULL) so it would be harmless.
>>>
>>>>
>>>> About 'us', don't use 'we'. The subject is 'devfreq' or other device instead of us.
>>>>
>>>> 	 * governor is started (which should do an initial enforcement of
>>>> 	 * constraints).
>>>>    	 */
>>>>
>>>> Actually, it doesn't matter the initialization step between governor
>>>> and PM_QOS registration.
>>>
>>> In theory PM QoS constraints could be modified between governor startup
>>> and notifier registration and that update would be lost (until the next
>>> one).
>>
>> Don't lose the any of PM QoS request. User can request the any frequency
>> through PMQoS at the any time and then devfreq consider the constraints
>> from PM QoS.
>>
>> Also, after finished the registration of devfreq device,
>> the user (other device driver required the min/max freq)
>> can request the PM QoS on real use-case.
>>
>> It is impossible to get the devfreq instance before finished
>> the devfreq_add_device() because the user can access the devfreq instance
>> devfreq_get_devfreq_by_phandle() which use 'devfreq_list'.
>>
>> If devfreq_add_device() is not finished, the user cannot get
>> the any devfreq device from 'devfreq_list'.
> 
> PM QoS constraints are not on devfreq->dev but on the parent so in 
> theory it's possible to add constraints during devfreq initialization.
> 
> Making PM QoS requests doesn't require fetching devfreq instances, I 
> think you could call of_find_device_by_node with a phandle and register 
> constraints that way.

You're right.

My comment was not enough. I mean that PM QoS depends on the devfreq->dev.parent.
If probe() of devfreq device requires the PMQoS request, it is possible to
register PM QoS. On the other hand, the other device device regardless
the devfreq device driver, they can request PM QoS constraints
after registering the parent device (devfreq->dev.parent). 

Your patch already registered the PM QoS notifier before governor start.
It is enough to show the your intention. I don't any objection of this code.
Just, the too more detailed comment make the devfreq core complicated.
As I commented, I think t hat the simple comment is enough for devfreq user.

Thanks for your explanation.

> 
>>>> If start governor and then register PM_QOS,
>>>> the governor can decide the new frequency. And then PM_QOS request
>>>> the new constraints for min/max frequency. On request time of PM_QOS,
>>>> devfreq can detect this time and then apply the constraints from PM_QOS.
>>>> The user of devfreq's PM_QOS must need the phandle or device instance
>>>> of devfreq deivce. It means that user of devfreq's PM_QOS can request
>>>> the any constraints of PM_QOS_MIN/MAX through PM_QOS interface.
>>>>
>>>> So, it doesn't need to add the following comments
>>>> because following comment is not always mandatory.
>>>> " governor is started (which should do an initial enforcement of constraints)."
>>>>
>>>> Also, you don't need to use parentheses on comments.
>>>>
>>>> Actually, I think that following comments are enough.
>>>>
>>>> 	/* Register PM QoS notifiers for updating to min/max freq */
>>>
>>> I thought that explaning why it's done at this particular step but I'll
>>> just remove it, devfreq_add_device can get more comments later.
>>
>> OK. Thanks.
>> I think that if the comment contains what is meaning of the code,
>> it is enough.
>>
>> Although change the sequence between dev_pm_qos_add_notifier() and
>> try_then_request_governor(), in the real-case, the any issue
>> would not happen. Because as I commented above, the other device-driver
>> cannot get the devfreq instance before finished the devfreq_add_device.
>> It means that the user device driver cannot request the any PM QoS
>> constraints.
>>
>>>
>>>>>>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>>> +	if (err)
>>>>>>>>> +		goto err_devfreq;
>>>>>>>>> +
>>>>>>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>>>>>>> +	if (err)
>>>>>>>>> +		goto err_devfreq;
>>>>>>>>> +
>>>>>>>>>      	mutex_lock(&devfreq_list_lock);
>>>>>>>>>      
>>>>>>>>>      	governor = try_then_request_governor(devfreq->governor_name);
>>>>>>>>>      	if (IS_ERR(governor)) {
>>>>>>>>>      		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>>>>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>>>>      
>>>>>>>>>      	return devfreq;
>>>>>>>>>      
>>>>>>>>>      err_init:
>>>>>>>>>      	mutex_unlock(&devfreq_list_lock);
>>>>>>>>> +err_devfreq:
>>>>>>>>>      	devfreq_remove_device(devfreq);
>>>>>>>>>      	return ERR_PTR(err);
>>>>>>>>>      
>>>>>>>>>      err_dev:
>>>>>>>>>      	/*
>>>>>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>>>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>>>>>>> --- a/include/linux/devfreq.h
>>>>>>>>> +++ b/include/linux/devfreq.h
>>>>>>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>>>>>>       * @total_trans:	Number of devfreq transitions
>>>>>>>>>       * @trans_table:	Statistics of devfreq transitions
>>>>>>>>>       * @time_in_state:	Statistics of devfreq states
>>>>>>>>>       * @last_stat_updated:	The last time stat updated
>>>>>>>>>       * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>>>>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>>>>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>>>>>>       *
>>>>>>>>>       * This structure stores the devfreq information for a give device.
>>>>>>>>>       *
>>>>>>>>>       * Note that when a governor accesses entries in struct devfreq in its
>>>>>>>>>       * functions except for the context of callbacks defined in struct
>>>>>>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>>>>>>      	unsigned int *trans_table;
>>>>>>>>>      	unsigned long *time_in_state;
>>>>>>>>>      	unsigned long last_stat_updated;
>>>>>>>>>      
>>>>>>>>>      	struct srcu_notifier_head transition_notifier_list;
>>>>>>>>> +
>>>>>>>>> +	struct notifier_block nb_min;
>>>>>>>>> +	struct notifier_block nb_max;
>>>>>>>>>      };
>>>>>>>>>      
>>>>>>>>>      struct devfreq_freqs {
>>>>>>>>>      	unsigned long old;
>>>>>>>>>      	unsigned long new;
>>>>
>>>>
>>>
>>
>>
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
@ 2019-10-01 21:55                       ` Chanwoo Choi
  0 siblings, 0 replies; 82+ messages in thread
From: Chanwoo Choi @ 2019-10-01 21:55 UTC (permalink / raw)
  To: Leonard Crestez, Matthias Kaehlcke
  Cc: Artur Świgoń,
	Abel Vesa, Saravana Kannan, linux-pm, Viresh Kumar, dl-linux-imx,
	Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
	Alexandre Bailon, Georgi Djakov, linux-arm-kernel, Jacky Bai

On 19. 10. 1. 오후 6:39, Leonard Crestez wrote:
> On 2019-10-01 12:37 AM, Chanwoo Choi wrote:
>> Hi,
>>
>> On 19. 9. 30. 오후 10:16, Leonard Crestez wrote:
>>> On 2019-09-27 4:45 AM, Chanwoo Choi wrote:
>>>> On 19. 9. 26. 오후 10:43, Leonard Crestez wrote:
>>>>> On 2019-09-26 4:07 AM, Chanwoo Choi wrote:
>>>>>> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>>>>>>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>>>>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>>>>>
>>>>>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>>>>>> imposed externally (for example from other devices).
>>>>>>>>>
>>>>>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>>>>>> ---
>>>>>>>>>      drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>>>>>>      include/linux/devfreq.h   |  5 +++
>>>>>>>>>      2 files changed, 80 insertions(+)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>>>>>> index eee403e70c84..784f3e40536a 100644
>>>>>>>>> --- a/drivers/devfreq/devfreq.c
>>>>>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>>>>>> @@ -22,15 +22,18 @@
>>>>>>>>>      #include <linux/platform_device.h>
>>>>>>>>>      #include <linux/list.h>
>>>>>>>>>      #include <linux/printk.h>
>>>>>>>>>      #include <linux/hrtimer.h>
>>>>>>>>>      #include <linux/of.h>
>>>>>>>>> +#include <linux/pm_qos.h>
>>>>>>>>>      #include "governor.h"
>>>>>>>>>      
>>>>>>>>>      #define CREATE_TRACE_POINTS
>>>>>>>>>      #include <trace/events/devfreq.h>
>>>>>>>>>      
>>>>>>>>> +#define HZ_PER_KHZ	1000
>>>>>>>>> +
>>>>>>>>>      static struct class *devfreq_class;
>>>>>>>>>      
>>>>>>>>>      /*
>>>>>>>>>       * devfreq core provides delayed work based load monitoring helper
>>>>>>>>>       * functions. Governors can use these or can implement their own
>>>>>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>>>>>>      static void get_freq_range(struct devfreq *devfreq,
>>>>>>>>>      			   unsigned long *min_freq,
>>>>>>>>>      			   unsigned long *max_freq)
>>>>>>>>>      {
>>>>>>>>>      	unsigned long *freq_table = devfreq->profile->freq_table;
>>>>>>>>> +	unsigned long qos_min_freq, qos_max_freq;
>>>>>>>>>      
>>>>>>>>>      	lockdep_assert_held(&devfreq->lock);
>>>>>>>>>      
>>>>>>>>>      	/*
>>>>>>>>>      	 * Init min/max frequency from freq table.
>>>>>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>>>>>>      	} else {
>>>>>>>>>      		*min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>>>>>>      		*max_freq = freq_table[0];
>>>>>>>>>      	}
>>>>>>>>>      
>>>>>>>>> +	/* constraints from PM QoS */
>>>>>>>>
>>>>>>>> As I commented on patch4,
>>>>>>>> 'constraints' -> 'Constraint' because first verb have to be used
>>>>>>>> as the sigular verbs.
>>>>>>>
>>>>>>> Already discussed for another patch; I will modify to "Apply constraints
>>>>>>> from PM QoS" instead.
>>>>>>
>>>>>> I agree the new comment with 'Apply constraints ... '.
>>>>>>
>>>>>>>
>>>>>>>> I prefer to use following comments:
>>>>>>>>
>>>>>>>> 	/* Constraint minimum/maximum frequency from PM QoS constraints */
>>>>>>>>
>>>>>>>>> +	qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>>> +	qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>>>>>> +					     DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>>> +	*min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>>>>>> +	*max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>>>>>> +
>>>>>>>>>      	/* constraints from sysfs */
>>>>>>>>>      	*min_freq = max(*min_freq, devfreq->min_freq);
>>>>>>>>>      	*max_freq = min(*max_freq, devfreq->max_freq);
>>>>>>>>>      
>>>>>>>>>      	/* constraints from OPP interface */
>>>>>>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>>>>>>      	mutex_unlock(&devfreq->lock);
>>>>>>>>>      
>>>>>>>>>      	return ret;
>>>>>>>>>      }
>>>>>>>>>      
>>>>>>>>> +/**
>>>>>>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>>>>>>> + * @devfreq:    the devfreq instance.
>>>>>>>>> + */
>>>>>>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>>>>>>> +{
>>>>>>>>> +	int err;
>>>>>>>>> +
>>>>>>>>> +	mutex_lock(&devfreq->lock);
>>>>>>>>> +	err = update_devfreq(devfreq);
>>>>>>>>> +	mutex_unlock(&devfreq->lock);
>>>>>>>>> +	if (err)
>>>>>>>>> +		dev_err(devfreq->dev.parent,
>>>>>>>>> +				"failed to update frequency for PM QoS constraints (%d)\n",
>>>>>>>>
>>>>>>>> Is it not over 80 char?
>>>>>>>
>>>>>>> Yes but coding style explicitly forbids breaking strings.
>>>>>>>
>>>>>>>>> +				err);
>>>>>>>>> +
>>>>>>>>> +	return NOTIFY_OK;
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +/**
>>>>>>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>>>>>>> + * @nb:		Should be devfreq->nb_min
>>>>>>>>> + */
>>>>>>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>>>>>>> +					 unsigned long val, void *ptr)
>>>>>>>>> +{
>>>>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +/**
>>>>>>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>>>>>>> + * @nb:		Should be devfreq->nb_max
>>>>>>>>> + */
>>>>>>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>>>>>>> +					 unsigned long val, void *ptr)
>>>>>>>>> +{
>>>>>>>>> +	return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>>      /**
>>>>>>>>>       * devfreq_dev_release() - Callback for struct device to release the device.
>>>>>>>>>       * @dev:	the devfreq device
>>>>>>>>>       *
>>>>>>>>>       * Remove devfreq from the list and release its resources.
>>>>>>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>>>>>>      
>>>>>>>>>      	mutex_lock(&devfreq_list_lock);
>>>>>>>>>      	list_del(&devfreq->node);
>>>>>>>>>      	mutex_unlock(&devfreq_list_lock);
>>>>>>>>>      
>>>>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>>>>> +			DEV_PM_QOS_MAX_FREQUENCY);
>>>>>>>>> +	dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>>>>> +			DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>>> +
>>>>>>>>
>>>>>>>> Just print error with dev_err() without stopping the release step.
>>>>>>>>
>>>>>>>> I prefer to handle the return value if kernel API provides
>>>>>>>> the error code.
>>>>>>
>>>>>> How about?
>>>>>
>>>>> Modified to dev_warn. This also applies to PATCH 6 so I replied there.
>>>>>
>>>>>>>>>      	if (devfreq->profile->exit)
>>>>>>>>>      		devfreq->profile->exit(devfreq->dev.parent);
>>>>>>>>>      
>>>>>>>>>      	kfree(devfreq->time_in_state);
>>>>>>>>>      	kfree(devfreq->trans_table);
>>>>>>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>>>>      	if (err) {
>>>>>>>>>      		put_device(&devfreq->dev);
>>>>>>>>>      		goto err_out;
>>>>>>>>>      	}
>>>>>>>>>      
>>>>>>>>> +	/*
>>>>>>>>> +	 * Register notifiers for updates to min/max_freq after device is
>>>>>>>>> +	 * initialized (and we can handle notifications) but before the
>>>>>>>>> +	 * governor is started (which should do an initial enforcement of
>>>>>>>>> +	 * constraints).
>>>>>>>>> +	 */
>>>>>>>>
>>>>>>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>>>>>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>>>>>>> comments because the line code is not too long. But, at the present time,
>>>>>>>> devfreq_add_device() is too long. It means that the detailed comment
>>>>>>>> are necessary.
>>>>>>>>
>>>>>>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>>>>>>> on separate patch to keep the same style. I'll send the patch to you
>>>>>>>> for the review.
>>>>>>>
>>>>>>> This is very likely to result in merge conflicts, maybe wait for my
>>>>>>> series to go in first?
>>>>>>
>>>>>> I'll send the separate patch after finished the review of these patches.
>>>>>> So, if you agree, please remove this comment on this patch.
>>>>>>
>>>>>> You can review the detailed comments on separate patch when I send.
>>>>> This patch already contains comments and they explain the code being
>>>>> added. Doesn't it make more sense for comments and code to go in together?
>>>>>
>>>>> I think the comment is a resonable explanation as to why notifiers are
>>>>> registered at that specific step in the initialization sequence.
>>>>
>>>> If you add this comment on this patch, OK. just I have some comments.
>>>>
>>>> 	/*
>>>> 	 * Register notifiers for updates to min/max_freq after device is
>>>> 	 * initialized (and we can handle notifications) but before the
>>>>
>>>> I think that 'device is initialized' is not needed.
>>>> It is always true, it don't need to add the additional comments.
>>>> because dev_pm_qos_add_notifier() must need the 'devfreq->dev'.
>>>> The this code prove the call sequence between them.
>>>
>>> In theory if a notifier is registered too soon then it could crash on a
>>> NULL pointer. But looking at the code it first checks that "governor !=
>>> NULL) so it would be harmless.
>>>
>>>>
>>>> About 'us', don't use 'we'. The subject is 'devfreq' or other device instead of us.
>>>>
>>>> 	 * governor is started (which should do an initial enforcement of
>>>> 	 * constraints).
>>>>    	 */
>>>>
>>>> Actually, it doesn't matter the initialization step between governor
>>>> and PM_QOS registration.
>>>
>>> In theory PM QoS constraints could be modified between governor startup
>>> and notifier registration and that update would be lost (until the next
>>> one).
>>
>> Don't lose the any of PM QoS request. User can request the any frequency
>> through PMQoS at the any time and then devfreq consider the constraints
>> from PM QoS.
>>
>> Also, after finished the registration of devfreq device,
>> the user (other device driver required the min/max freq)
>> can request the PM QoS on real use-case.
>>
>> It is impossible to get the devfreq instance before finished
>> the devfreq_add_device() because the user can access the devfreq instance
>> devfreq_get_devfreq_by_phandle() which use 'devfreq_list'.
>>
>> If devfreq_add_device() is not finished, the user cannot get
>> the any devfreq device from 'devfreq_list'.
> 
> PM QoS constraints are not on devfreq->dev but on the parent so in 
> theory it's possible to add constraints during devfreq initialization.
> 
> Making PM QoS requests doesn't require fetching devfreq instances, I 
> think you could call of_find_device_by_node with a phandle and register 
> constraints that way.

You're right.

My comment was not enough. I mean that PM QoS depends on the devfreq->dev.parent.
If probe() of devfreq device requires the PMQoS request, it is possible to
register PM QoS. On the other hand, the other device device regardless
the devfreq device driver, they can request PM QoS constraints
after registering the parent device (devfreq->dev.parent). 

Your patch already registered the PM QoS notifier before governor start.
It is enough to show the your intention. I don't any objection of this code.
Just, the too more detailed comment make the devfreq core complicated.
As I commented, I think t hat the simple comment is enough for devfreq user.

Thanks for your explanation.

> 
>>>> If start governor and then register PM_QOS,
>>>> the governor can decide the new frequency. And then PM_QOS request
>>>> the new constraints for min/max frequency. On request time of PM_QOS,
>>>> devfreq can detect this time and then apply the constraints from PM_QOS.
>>>> The user of devfreq's PM_QOS must need the phandle or device instance
>>>> of devfreq deivce. It means that user of devfreq's PM_QOS can request
>>>> the any constraints of PM_QOS_MIN/MAX through PM_QOS interface.
>>>>
>>>> So, it doesn't need to add the following comments
>>>> because following comment is not always mandatory.
>>>> " governor is started (which should do an initial enforcement of constraints)."
>>>>
>>>> Also, you don't need to use parentheses on comments.
>>>>
>>>> Actually, I think that following comments are enough.
>>>>
>>>> 	/* Register PM QoS notifiers for updating to min/max freq */
>>>
>>> I thought that explaning why it's done at this particular step but I'll
>>> just remove it, devfreq_add_device can get more comments later.
>>
>> OK. Thanks.
>> I think that if the comment contains what is meaning of the code,
>> it is enough.
>>
>> Although change the sequence between dev_pm_qos_add_notifier() and
>> try_then_request_governor(), in the real-case, the any issue
>> would not happen. Because as I commented above, the other device-driver
>> cannot get the devfreq instance before finished the devfreq_add_device.
>> It means that the user device driver cannot request the any PM QoS
>> constraints.
>>
>>>
>>>>>>>>> +	devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>>>>>> +				      DEV_PM_QOS_MIN_FREQUENCY);
>>>>>>>>> +	if (err)
>>>>>>>>> +		goto err_devfreq;
>>>>>>>>> +
>>>>>>>>> +	devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>>>>>>> +	err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>>>>>> +				      DEV_PM_QOS_MAX_FREQUENCY);
>>>>>>>>> +	if (err)
>>>>>>>>> +		goto err_devfreq;
>>>>>>>>> +
>>>>>>>>>      	mutex_lock(&devfreq_list_lock);
>>>>>>>>>      
>>>>>>>>>      	governor = try_then_request_governor(devfreq->governor_name);
>>>>>>>>>      	if (IS_ERR(governor)) {
>>>>>>>>>      		dev_err(dev, "%s: Unable to find governor for the device\n",
>>>>>>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>>>>>      
>>>>>>>>>      	return devfreq;
>>>>>>>>>      
>>>>>>>>>      err_init:
>>>>>>>>>      	mutex_unlock(&devfreq_list_lock);
>>>>>>>>> +err_devfreq:
>>>>>>>>>      	devfreq_remove_device(devfreq);
>>>>>>>>>      	return ERR_PTR(err);
>>>>>>>>>      
>>>>>>>>>      err_dev:
>>>>>>>>>      	/*
>>>>>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>>>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>>>>>>> --- a/include/linux/devfreq.h
>>>>>>>>> +++ b/include/linux/devfreq.h
>>>>>>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>>>>>>       * @total_trans:	Number of devfreq transitions
>>>>>>>>>       * @trans_table:	Statistics of devfreq transitions
>>>>>>>>>       * @time_in_state:	Statistics of devfreq states
>>>>>>>>>       * @last_stat_updated:	The last time stat updated
>>>>>>>>>       * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>>>>>>> + * @nb_min:		Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>>>>>>> + * @nb_max:		Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>>>>>>       *
>>>>>>>>>       * This structure stores the devfreq information for a give device.
>>>>>>>>>       *
>>>>>>>>>       * Note that when a governor accesses entries in struct devfreq in its
>>>>>>>>>       * functions except for the context of callbacks defined in struct
>>>>>>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>>>>>>      	unsigned int *trans_table;
>>>>>>>>>      	unsigned long *time_in_state;
>>>>>>>>>      	unsigned long last_stat_updated;
>>>>>>>>>      
>>>>>>>>>      	struct srcu_notifier_head transition_notifier_list;
>>>>>>>>> +
>>>>>>>>> +	struct notifier_block nb_min;
>>>>>>>>> +	struct notifier_block nb_max;
>>>>>>>>>      };
>>>>>>>>>      
>>>>>>>>>      struct devfreq_freqs {
>>>>>>>>>      	unsigned long old;
>>>>>>>>>      	unsigned long new;
>>>>
>>>>
>>>
>>
>>
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 82+ messages in thread

end of thread, other threads:[~2019-10-01 21:51 UTC | newest]

Thread overview: 82+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20190924101140epcas1p4abeedf42f223e65f58c88a0ddf1e4e56@epcas1p4.samsung.com>
2019-09-24 10:11 ` [PATCH v8 0/6] PM / devfreq: Add dev_pm_qos support Leonard Crestez
2019-09-24 10:11   ` Leonard Crestez
2019-09-24 10:11   ` [PATCH v8 1/6] PM / devfreq: Don't fail devfreq_dev_release if not in list Leonard Crestez
2019-09-24 10:11     ` Leonard Crestez
2019-09-24 10:11   ` [PATCH v8 2/6] PM / devfreq: Move more initialization before registration Leonard Crestez
2019-09-24 10:11     ` Leonard Crestez
2019-09-25  1:46     ` Chanwoo Choi
2019-09-25  1:46       ` Chanwoo Choi
2019-09-24 10:11   ` [PATCH v8 3/6] PM / devfreq: Don't take lock in devfreq_add_device Leonard Crestez
2019-09-24 10:11     ` Leonard Crestez
2019-09-24 10:11   ` [PATCH v8 4/6] PM / devfreq: Introduce get_freq_range helper Leonard Crestez
2019-09-24 10:11     ` Leonard Crestez
2019-09-25  1:37     ` Chanwoo Choi
2019-09-25  1:37       ` Chanwoo Choi
2019-09-25 20:55       ` Leonard Crestez
2019-09-25 20:55         ` Leonard Crestez
2019-09-26  1:06         ` Chanwoo Choi
2019-09-26  1:06           ` Chanwoo Choi
2019-09-26 14:03           ` Leonard Crestez
2019-09-26 14:03             ` Leonard Crestez
2019-09-24 10:11   ` [PATCH v8 5/6] PM / devfreq: Add PM QoS support Leonard Crestez
2019-09-24 10:11     ` Leonard Crestez
2019-09-24 19:11     ` Matthias Kaehlcke
2019-09-24 19:11       ` Matthias Kaehlcke
2019-09-24 19:22       ` Leonard Crestez
2019-09-24 19:22         ` Leonard Crestez
2019-09-25  2:17         ` Chanwoo Choi
2019-09-25  2:17           ` Chanwoo Choi
2019-09-25 19:40           ` Leonard Crestez
2019-09-25 19:40             ` Leonard Crestez
2019-09-26  1:08             ` Chanwoo Choi
2019-09-26  1:08               ` Chanwoo Choi
2019-09-25  2:15     ` Chanwoo Choi
2019-09-25  2:15       ` Chanwoo Choi
2019-09-25 16:06       ` Matthias Kaehlcke
2019-09-25 16:06         ` Matthias Kaehlcke
2019-09-25 21:18       ` Leonard Crestez
2019-09-25 21:18         ` Leonard Crestez
2019-09-26  1:12         ` Chanwoo Choi
2019-09-26  1:12           ` Chanwoo Choi
2019-09-26 13:43           ` Leonard Crestez
2019-09-26 13:43             ` Leonard Crestez
2019-09-27  1:49             ` Chanwoo Choi
2019-09-27  1:49               ` Chanwoo Choi
2019-09-30 13:16               ` Leonard Crestez
2019-09-30 13:16                 ` Leonard Crestez
2019-09-30 21:42                 ` Chanwoo Choi
2019-09-30 21:42                   ` Chanwoo Choi
2019-10-01  9:39                   ` Leonard Crestez
2019-10-01  9:39                     ` Leonard Crestez
2019-10-01 21:55                     ` Chanwoo Choi
2019-10-01 21:55                       ` Chanwoo Choi
2019-09-26  1:19         ` Chanwoo Choi
2019-09-26  1:19           ` Chanwoo Choi
2019-09-30 12:43           ` Leonard Crestez
2019-09-30 12:43             ` Leonard Crestez
2019-09-30 21:21             ` Chanwoo Choi
2019-09-30 21:21               ` Chanwoo Choi
2019-09-24 10:11   ` [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq Leonard Crestez
2019-09-24 10:11     ` Leonard Crestez
2019-09-25  2:41     ` Chanwoo Choi
2019-09-25  2:41       ` Chanwoo Choi
2019-09-25 16:45       ` Matthias Kaehlcke
2019-09-25 16:45         ` Matthias Kaehlcke
2019-09-26  1:25         ` Chanwoo Choi
2019-09-26  1:25           ` Chanwoo Choi
2019-09-26 16:04           ` Matthias Kaehlcke
2019-09-26 16:04             ` Matthias Kaehlcke
2019-09-27  1:58             ` Chanwoo Choi
2019-09-27  1:58               ` Chanwoo Choi
2019-09-25 22:11       ` Leonard Crestez
2019-09-25 22:11         ` Leonard Crestez
2019-09-26  1:26         ` Chanwoo Choi
2019-09-26  1:26           ` Chanwoo Choi
2019-09-25  1:44   ` [PATCH v8 0/6] PM / devfreq: Add dev_pm_qos support Chanwoo Choi
2019-09-25  1:44     ` Chanwoo Choi
2019-09-25 19:37     ` Leonard Crestez
2019-09-25 19:37       ` Leonard Crestez
     [not found]   ` <CGME20190924101139epcas1p4c6799a5de9bdb4e90abb74de1e881388@epcms1p4>
2019-09-25  1:58     ` [PATCH v8 2/6] PM / devfreq: Move more initialization before registration MyungJoo Ham
2019-09-25  1:58       ` MyungJoo Ham
2019-09-25 19:33       ` Leonard Crestez
2019-09-25 19:33         ` Leonard Crestez

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.