aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/cpufreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/cpufreq/cpufreq.c')
-rw-r--r--drivers/cpufreq/cpufreq.c67
1 files changed, 60 insertions, 7 deletions
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);