lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <25738681139c04272b6d2ebeff244c6d36c893f7.1400133090.git.viresh.kumar@linaro.org>
Date:	Thu, 15 May 2014 11:26:51 +0530
From:	Viresh Kumar <viresh.kumar@...aro.org>
To:	rjw@...ysocki.net
Cc:	linaro-kernel@...ts.linaro.org, linux-pm@...r.kernel.org,
	linux-kernel@...r.kernel.org, arvind.chauhan@....com,
	swarren@...dia.com, nicolas.pitre@...aro.org,
	swarren@...dotorg.org, dianders@...omium.org,
	linux@....linux.org.uk, Viresh Kumar <viresh.kumar@...aro.org>
Subject: [RFC] cpufreq: send notifications for intermediate (stable) frequencies

Douglas Anderson, recently pointed out an interesting problem due to which his
udelay() was expiring earlier than it should:
https://lkml.org/lkml/2014/5/13/766

While transitioning between frequencies few platforms may temporarily switch to
a stable frequency, waiting for the main PLL to stabilize.

For example: When we transition between very low frequencies on exynos, like
between 200MHz and 300MHz, we may temporarily switch to a PLL running at 800MHz.
No CPUFREQ notification is sent for that. That means there's a period of time
when we're running at 800MHz but loops_per_jiffy is calibrated at between 200MHz
and 300MHz. And so udelay behaves badly.

To get this fixed in a generic way, lets introduce another callback safe_freq()
for the cpufreq drivers.

safe_freq() should return a stable intermediate frequency a platform might want
to switch to, before jumping to the frequency corresponding to 'index'. Core
will send the 'PRE' notification for this 'stable' frequency and 'POST' for the
'target' frequency. Though if ->target_index() fails, it will handle POST for
'stable' frequency only.

Drivers must send 'POST' notification for 'stable' freq and 'PRE' for 'target'
freq. If they can't switch to target frequency, they don't need to send any
notification.

Signed-off-by: Viresh Kumar <viresh.kumar@...aro.org>
---
Doug/Stephen,

If this doesn't look too ugly, then I would need patches from you to fix your
platforms as I am not well aware of clk hierarchy of your platforms.

 drivers/cpufreq/cpufreq.c | 13 +++++++++++--
 include/linux/cpufreq.h   | 18 ++++++++++++++++++
 2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index a05c921..8d1cb4f 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1874,11 +1874,17 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
 
 		if (notify) {
 			freqs.old = policy->cur;
-			freqs.new = freq_table[index].frequency;
+			/* Switch to some safe intermediate freq */
+			if (cpufreq_driver->safe_freq)
+				freqs.new = cpufreq_driver->safe_freq(policy,
+								      index);
+			else
+				freqs.new = freq_table[index].frequency;
 			freqs.flags = 0;
 
 			pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
-				 __func__, policy->cpu, freqs.old, freqs.new);
+				 __func__, policy->cpu, freqs.old,
+				 freq_table[index].frequency);
 
 			cpufreq_freq_transition_begin(policy, &freqs);
 		}
@@ -1887,6 +1893,9 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
 		if (retval)
 			pr_err("%s: Failed to change cpu frequency: %d\n",
 			       __func__, retval);
+		else
+			/* Send POST notification for the target frequency */
+			freqs.new = freq_table[index].frequency;
 
 		if (notify)
 			cpufreq_freq_transition_end(policy, &freqs, retval);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 3f45889..b5ba275 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -226,6 +226,24 @@ struct cpufreq_driver {
 				 unsigned int relation);
 	int	(*target_index)	(struct cpufreq_policy *policy,
 				 unsigned int index);
+	/*
+	 * Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION
+	 * unset.
+	 *
+	 * safe_freq() should return a stable intermediate frequency a platform
+	 * might want to switch to, before jumping to the frequency
+	 * corresponding to 'index'. Core will send the 'PRE' notification for
+	 * this 'stable' frequency and 'POST' for the 'target' frequency. Though
+	 * if ->target_index() fails, it will handle POST for 'stable' frequency
+	 * only.
+	 *
+	 * Drivers must send 'POST' notification for 'stable' freq and 'PRE' for
+	 * 'target' freq. If they can't switch to target frequency, they don't
+	 * need to send any notification.
+	 *
+	 */
+	unsigned int (*safe_freq)(struct cpufreq_policy *policy,
+				  unsigned int index);
 
 	/* should be defined, if possible */
 	unsigned int	(*get)	(unsigned int cpu);
-- 
2.0.0.rc2

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ