aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2014-06-02 13:19:28 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-06-05 17:32:29 -0400
commit1c03a2d04d7ab6d27c1fef8614f08187d974bd21 (patch)
tree3d0ad7be510d75f6b3a9caa91d027e4e31e35300
parent5ece2399181a5abaf42a4cb607463770686778e6 (diff)
cpufreq: add support for intermediate (stable) frequencies
Douglas Anderson, recently pointed out an interesting problem due to which udelay() was expiring earlier than it should. 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, introduce another set of callbacks get_intermediate() and target_intermediate(), only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION unset. get_intermediate() should return a stable intermediate frequency platform wants to switch to, and target_intermediate() should set CPU to that frequency, before jumping to the frequency corresponding to 'index'. Core will take care of sending notifications and driver doesn't have to handle them in target_intermediate() or target_index(). NOTE: ->target_index() should restore to policy->restore_freq in case of failures as core would send notifications for that. Tested-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Reviewed-by: Doug Anderson <dianders@chromium.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--Documentation/cpu-freq/cpu-drivers.txt29
-rw-r--r--drivers/cpufreq/cpufreq.c67
-rw-r--r--include/linux/cpufreq.h25
3 files changed, 112 insertions, 9 deletions
diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt
index b045fe54986a..14f4e6336d88 100644
--- a/Documentation/cpu-freq/cpu-drivers.txt
+++ b/Documentation/cpu-freq/cpu-drivers.txt
@@ -26,6 +26,7 @@ Contents:
261.4 target/target_index or setpolicy? 261.4 target/target_index or setpolicy?
271.5 target/target_index 271.5 target/target_index
281.6 setpolicy 281.6 setpolicy
291.7 get_intermediate and target_intermediate
292. Frequency Table Helpers 302. Frequency Table Helpers
30 31
31 32
@@ -79,6 +80,10 @@ cpufreq_driver.attr - A pointer to a NULL-terminated list of
79 "struct freq_attr" which allow to 80 "struct freq_attr" which allow to
80 export values to sysfs. 81 export values to sysfs.
81 82
83cpufreq_driver.get_intermediate
84and target_intermediate Used to switch to stable frequency while
85 changing CPU frequency.
86
82 87
831.2 Per-CPU Initialization 881.2 Per-CPU Initialization
84-------------------------- 89--------------------------
@@ -151,7 +156,7 @@ Some cpufreq-capable processors switch the frequency between certain
151limits on their own. These shall use the ->setpolicy call 156limits on their own. These shall use the ->setpolicy call
152 157
153 158
1541.4. target/target_index 1591.5. target/target_index
155------------- 160-------------
156 161
157The target_index call has two arguments: struct cpufreq_policy *policy, 162The target_index call has two arguments: struct cpufreq_policy *policy,
@@ -160,6 +165,9 @@ and unsigned int index (into the exposed frequency table).
160The CPUfreq driver must set the new frequency when called here. The 165The CPUfreq driver must set the new frequency when called here. The
161actual frequency must be determined by freq_table[index].frequency. 166actual frequency must be determined by freq_table[index].frequency.
162 167
168It should always restore to earlier frequency (i.e. policy->restore_freq) in
169case of errors, even if we switched to intermediate frequency earlier.
170
163Deprecated: 171Deprecated:
164---------- 172----------
165The target call has three arguments: struct cpufreq_policy *policy, 173The target call has three arguments: struct cpufreq_policy *policy,
@@ -179,7 +187,7 @@ Here again the frequency table helper might assist you - see section 2
179for details. 187for details.
180 188
181 189
1821.5 setpolicy 1901.6 setpolicy
183--------------- 191---------------
184 192
185The setpolicy call only takes a struct cpufreq_policy *policy as 193The setpolicy call only takes a struct cpufreq_policy *policy as
@@ -190,6 +198,23 @@ setting when policy->policy is CPUFREQ_POLICY_PERFORMANCE, and a
190powersaving-oriented setting when CPUFREQ_POLICY_POWERSAVE. Also check 198powersaving-oriented setting when CPUFREQ_POLICY_POWERSAVE. Also check
191the reference implementation in drivers/cpufreq/longrun.c 199the reference implementation in drivers/cpufreq/longrun.c
192 200
2011.7 get_intermediate and target_intermediate
202--------------------------------------------
203
204Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION unset.
205
206get_intermediate should return a stable intermediate frequency platform wants to
207switch to, and target_intermediate() should set CPU to to that frequency, before
208jumping to the frequency corresponding to 'index'. Core will take care of
209sending notifications and driver doesn't have to handle them in
210target_intermediate() or target_index().
211
212Drivers can return '0' from get_intermediate() in case they don't wish to switch
213to intermediate frequency for some target frequency. In that case core will
214directly call ->target_index().
215
216NOTE: ->target_index() should restore to policy->restore_freq in case of
217failures as core would send notifications for that.
193 218
194 219
1952. Frequency Table Helpers 2202. Frequency Table Helpers
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index ae11dd51f81d..aed2b0cb83dc 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1816,20 +1816,55 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
1816 * GOVERNORS * 1816 * GOVERNORS *
1817 *********************************************************************/ 1817 *********************************************************************/
1818 1818
1819/* Must set freqs->new to intermediate frequency */
1820static int __target_intermediate(struct cpufreq_policy *policy,
1821 struct cpufreq_freqs *freqs, int index)
1822{
1823 int ret;
1824
1825 freqs->new = cpufreq_driver->get_intermediate(policy, index);
1826
1827 /* We don't need to switch to intermediate freq */
1828 if (!freqs->new)
1829 return 0;
1830
1831 pr_debug("%s: cpu: %d, switching to intermediate freq: oldfreq: %u, intermediate freq: %u\n",
1832 __func__, policy->cpu, freqs->old, freqs->new);
1833
1834 cpufreq_freq_transition_begin(policy, freqs);
1835 ret = cpufreq_driver->target_intermediate(policy, index);
1836 cpufreq_freq_transition_end(policy, freqs, ret);
1837
1838 if (ret)
1839 pr_err("%s: Failed to change to intermediate frequency: %d\n",
1840 __func__, ret);
1841
1842 return ret;
1843}
1844
1819static int __target_index(struct cpufreq_policy *policy, 1845static int __target_index(struct cpufreq_policy *policy,
1820 struct cpufreq_frequency_table *freq_table, int index) 1846 struct cpufreq_frequency_table *freq_table, int index)
1821{ 1847{
1822 struct cpufreq_freqs freqs; 1848 struct cpufreq_freqs freqs = {.old = policy->cur, .flags = 0};
1849 unsigned int intermediate_freq = 0;
1823 int retval = -EINVAL; 1850 int retval = -EINVAL;
1824 bool notify; 1851 bool notify;
1825 1852
1826 notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION); 1853 notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION);
1827
1828 if (notify) { 1854 if (notify) {
1829 freqs.old = policy->cur; 1855 /* Handle switching to intermediate frequency */
1830 freqs.new = freq_table[index].frequency; 1856 if (cpufreq_driver->get_intermediate) {
1831 freqs.flags = 0; 1857 retval = __target_intermediate(policy, &freqs, index);
1858 if (retval)
1859 return retval;
1860
1861 intermediate_freq = freqs.new;
1862 /* Set old freq to intermediate */
1863 if (intermediate_freq)
1864 freqs.old = freqs.new;
1865 }
1832 1866
1867 freqs.new = freq_table[index].frequency;
1833 pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n", 1868 pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
1834 __func__, policy->cpu, freqs.old, freqs.new); 1869 __func__, policy->cpu, freqs.old, freqs.new);
1835 1870
@@ -1841,9 +1876,23 @@ static int __target_index(struct cpufreq_policy *policy,
1841 pr_err("%s: Failed to change cpu frequency: %d\n", __func__, 1876 pr_err("%s: Failed to change cpu frequency: %d\n", __func__,
1842 retval); 1877 retval);
1843 1878
1844 if (notify) 1879 if (notify) {
1845 cpufreq_freq_transition_end(policy, &freqs, retval); 1880 cpufreq_freq_transition_end(policy, &freqs, retval);
1846 1881
1882 /*
1883 * Failed after setting to intermediate freq? Driver should have
1884 * reverted back to initial frequency and so should we. Check
1885 * here for intermediate_freq instead of get_intermediate, in
1886 * case we have't switched to intermediate freq at all.
1887 */
1888 if (unlikely(retval && intermediate_freq)) {
1889 freqs.old = intermediate_freq;
1890 freqs.new = policy->restore_freq;
1891 cpufreq_freq_transition_begin(policy, &freqs);
1892 cpufreq_freq_transition_end(policy, &freqs, 0);
1893 }
1894 }
1895
1847 return retval; 1896 return retval;
1848} 1897}
1849 1898
@@ -1875,6 +1924,9 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
1875 if (target_freq == policy->cur) 1924 if (target_freq == policy->cur)
1876 return 0; 1925 return 0;
1877 1926
1927 /* Save last value to restore later on errors */
1928 policy->restore_freq = policy->cur;
1929
1878 if (cpufreq_driver->target) 1930 if (cpufreq_driver->target)
1879 retval = cpufreq_driver->target(policy, target_freq, relation); 1931 retval = cpufreq_driver->target(policy, target_freq, relation);
1880 else if (cpufreq_driver->target_index) { 1932 else if (cpufreq_driver->target_index) {
@@ -2361,7 +2413,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
2361 !(driver_data->setpolicy || driver_data->target_index || 2413 !(driver_data->setpolicy || driver_data->target_index ||
2362 driver_data->target) || 2414 driver_data->target) ||
2363 (driver_data->setpolicy && (driver_data->target_index || 2415 (driver_data->setpolicy && (driver_data->target_index ||
2364 driver_data->target))) 2416 driver_data->target)) ||
2417 (!!driver_data->get_intermediate != !!driver_data->target_intermediate))
2365 return -EINVAL; 2418 return -EINVAL;
2366 2419
2367 pr_debug("trying to register driver %s\n", driver_data->name); 2420 pr_debug("trying to register driver %s\n", driver_data->name);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 3f458896d45c..ec4112d257bc 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -75,6 +75,7 @@ struct cpufreq_policy {
75 unsigned int max; /* in kHz */ 75 unsigned int max; /* in kHz */
76 unsigned int cur; /* in kHz, only needed if cpufreq 76 unsigned int cur; /* in kHz, only needed if cpufreq
77 * governors are used */ 77 * governors are used */
78 unsigned int restore_freq; /* = policy->cur before transition */
78 unsigned int suspend_freq; /* freq to set during suspend */ 79 unsigned int suspend_freq; /* freq to set during suspend */
79 80
80 unsigned int policy; /* see above */ 81 unsigned int policy; /* see above */
@@ -221,11 +222,35 @@ struct cpufreq_driver {
221 222
222 /* define one out of two */ 223 /* define one out of two */
223 int (*setpolicy) (struct cpufreq_policy *policy); 224 int (*setpolicy) (struct cpufreq_policy *policy);
225
226 /*
227 * On failure, should always restore frequency to policy->restore_freq
228 * (i.e. old freq).
229 */
224 int (*target) (struct cpufreq_policy *policy, /* Deprecated */ 230 int (*target) (struct cpufreq_policy *policy, /* Deprecated */
225 unsigned int target_freq, 231 unsigned int target_freq,
226 unsigned int relation); 232 unsigned int relation);
227 int (*target_index) (struct cpufreq_policy *policy, 233 int (*target_index) (struct cpufreq_policy *policy,
228 unsigned int index); 234 unsigned int index);
235 /*
236 * Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION
237 * unset.
238 *
239 * get_intermediate should return a stable intermediate frequency
240 * platform wants to switch to and target_intermediate() should set CPU
241 * to to that frequency, before jumping to the frequency corresponding
242 * to 'index'. Core will take care of sending notifications and driver
243 * doesn't have to handle them in target_intermediate() or
244 * target_index().
245 *
246 * Drivers can return '0' from get_intermediate() in case they don't
247 * wish to switch to intermediate frequency for some target frequency.
248 * In that case core will directly call ->target_index().
249 */
250 unsigned int (*get_intermediate)(struct cpufreq_policy *policy,
251 unsigned int index);
252 int (*target_intermediate)(struct cpufreq_policy *policy,
253 unsigned int index);
229 254
230 /* should be defined, if possible */ 255 /* should be defined, if possible */
231 unsigned int (*get) (unsigned int cpu); 256 unsigned int (*get) (unsigned int cpu);