diff options
| -rw-r--r-- | MAINTAINERS | 2 | ||||
| -rw-r--r-- | arch/arm/kernel/smp.c | 24 | ||||
| -rw-r--r-- | arch/sparc/kernel/time_64.c | 28 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/intel_epb.c | 22 | ||||
| -rw-r--r-- | arch/x86/kernel/tsc.c | 2 | ||||
| -rw-r--r-- | arch/x86/kvm/x86.c | 31 | ||||
| -rw-r--r-- | drivers/base/power/domain.c | 8 | ||||
| -rw-r--r-- | drivers/cpufreq/cpufreq.c | 140 | ||||
| -rw-r--r-- | drivers/soc/imx/gpc.c | 13 | ||||
| -rw-r--r-- | include/linux/cpufreq.h | 14 | ||||
| -rw-r--r-- | include/linux/pm_domain.h | 4 |
11 files changed, 183 insertions, 105 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 0d31d2b58d8c..ee6cf4d1010c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -4133,7 +4133,9 @@ F: Documentation/admin-guide/pm/intel_pstate.rst | |||
| 4133 | F: Documentation/cpu-freq/ | 4133 | F: Documentation/cpu-freq/ |
| 4134 | F: Documentation/devicetree/bindings/cpufreq/ | 4134 | F: Documentation/devicetree/bindings/cpufreq/ |
| 4135 | F: drivers/cpufreq/ | 4135 | F: drivers/cpufreq/ |
| 4136 | F: kernel/sched/cpufreq*.c | ||
| 4136 | F: include/linux/cpufreq.h | 4137 | F: include/linux/cpufreq.h |
| 4138 | F: include/linux/sched/cpufreq.h | ||
| 4137 | F: tools/testing/selftests/cpufreq/ | 4139 | F: tools/testing/selftests/cpufreq/ |
| 4138 | 4140 | ||
| 4139 | CPU FREQUENCY DRIVERS - ARM BIG LITTLE | 4141 | CPU FREQUENCY DRIVERS - ARM BIG LITTLE |
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index c93fe0f256de..ebc53804d57b 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
| @@ -758,15 +758,20 @@ static int cpufreq_callback(struct notifier_block *nb, | |||
| 758 | unsigned long val, void *data) | 758 | unsigned long val, void *data) |
| 759 | { | 759 | { |
| 760 | struct cpufreq_freqs *freq = data; | 760 | struct cpufreq_freqs *freq = data; |
| 761 | int cpu = freq->cpu; | 761 | struct cpumask *cpus = freq->policy->cpus; |
| 762 | int cpu, first = cpumask_first(cpus); | ||
| 763 | unsigned int lpj; | ||
| 762 | 764 | ||
| 763 | if (freq->flags & CPUFREQ_CONST_LOOPS) | 765 | if (freq->flags & CPUFREQ_CONST_LOOPS) |
| 764 | return NOTIFY_OK; | 766 | return NOTIFY_OK; |
| 765 | 767 | ||
| 766 | if (!per_cpu(l_p_j_ref, cpu)) { | 768 | if (!per_cpu(l_p_j_ref, first)) { |
| 767 | per_cpu(l_p_j_ref, cpu) = | 769 | for_each_cpu(cpu, cpus) { |
| 768 | per_cpu(cpu_data, cpu).loops_per_jiffy; | 770 | per_cpu(l_p_j_ref, cpu) = |
| 769 | per_cpu(l_p_j_ref_freq, cpu) = freq->old; | 771 | per_cpu(cpu_data, cpu).loops_per_jiffy; |
| 772 | per_cpu(l_p_j_ref_freq, cpu) = freq->old; | ||
| 773 | } | ||
| 774 | |||
| 770 | if (!global_l_p_j_ref) { | 775 | if (!global_l_p_j_ref) { |
| 771 | global_l_p_j_ref = loops_per_jiffy; | 776 | global_l_p_j_ref = loops_per_jiffy; |
| 772 | global_l_p_j_ref_freq = freq->old; | 777 | global_l_p_j_ref_freq = freq->old; |
| @@ -778,10 +783,11 @@ static int cpufreq_callback(struct notifier_block *nb, | |||
| 778 | loops_per_jiffy = cpufreq_scale(global_l_p_j_ref, | 783 | loops_per_jiffy = cpufreq_scale(global_l_p_j_ref, |
| 779 | global_l_p_j_ref_freq, | 784 | global_l_p_j_ref_freq, |
| 780 | freq->new); | 785 | freq->new); |
| 781 | per_cpu(cpu_data, cpu).loops_per_jiffy = | 786 | |
| 782 | cpufreq_scale(per_cpu(l_p_j_ref, cpu), | 787 | lpj = cpufreq_scale(per_cpu(l_p_j_ref, first), |
| 783 | per_cpu(l_p_j_ref_freq, cpu), | 788 | per_cpu(l_p_j_ref_freq, first), freq->new); |
| 784 | freq->new); | 789 | for_each_cpu(cpu, cpus) |
| 790 | per_cpu(cpu_data, cpu).loops_per_jiffy = lpj; | ||
| 785 | } | 791 | } |
| 786 | return NOTIFY_OK; | 792 | return NOTIFY_OK; |
| 787 | } | 793 | } |
diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index 3eb77943ce12..89fb05f90609 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c | |||
| @@ -653,19 +653,23 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val | |||
| 653 | void *data) | 653 | void *data) |
| 654 | { | 654 | { |
| 655 | struct cpufreq_freqs *freq = data; | 655 | struct cpufreq_freqs *freq = data; |
| 656 | unsigned int cpu = freq->cpu; | 656 | unsigned int cpu; |
| 657 | struct freq_table *ft = &per_cpu(sparc64_freq_table, cpu); | 657 | struct freq_table *ft; |
| 658 | 658 | ||
| 659 | if (!ft->ref_freq) { | 659 | for_each_cpu(cpu, freq->policy->cpus) { |
| 660 | ft->ref_freq = freq->old; | 660 | ft = &per_cpu(sparc64_freq_table, cpu); |
| 661 | ft->clock_tick_ref = cpu_data(cpu).clock_tick; | 661 | |
| 662 | } | 662 | if (!ft->ref_freq) { |
| 663 | if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || | 663 | ft->ref_freq = freq->old; |
| 664 | (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { | 664 | ft->clock_tick_ref = cpu_data(cpu).clock_tick; |
| 665 | cpu_data(cpu).clock_tick = | 665 | } |
| 666 | cpufreq_scale(ft->clock_tick_ref, | 666 | |
| 667 | ft->ref_freq, | 667 | if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || |
| 668 | freq->new); | 668 | (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { |
| 669 | cpu_data(cpu).clock_tick = | ||
| 670 | cpufreq_scale(ft->clock_tick_ref, ft->ref_freq, | ||
| 671 | freq->new); | ||
| 672 | } | ||
| 669 | } | 673 | } |
| 670 | 674 | ||
| 671 | return 0; | 675 | return 0; |
diff --git a/arch/x86/kernel/cpu/intel_epb.c b/arch/x86/kernel/cpu/intel_epb.c index f4dd73396f28..ebb14a26f117 100644 --- a/arch/x86/kernel/cpu/intel_epb.c +++ b/arch/x86/kernel/cpu/intel_epb.c | |||
| @@ -97,6 +97,7 @@ static void intel_epb_restore(void) | |||
| 97 | wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, (epb & ~EPB_MASK) | val); | 97 | wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, (epb & ~EPB_MASK) | val); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | #ifdef CONFIG_PM | ||
| 100 | static struct syscore_ops intel_epb_syscore_ops = { | 101 | static struct syscore_ops intel_epb_syscore_ops = { |
| 101 | .suspend = intel_epb_save, | 102 | .suspend = intel_epb_save, |
| 102 | .resume = intel_epb_restore, | 103 | .resume = intel_epb_restore, |
| @@ -193,6 +194,25 @@ static int intel_epb_offline(unsigned int cpu) | |||
| 193 | return 0; | 194 | return 0; |
| 194 | } | 195 | } |
| 195 | 196 | ||
| 197 | static inline void register_intel_ebp_syscore_ops(void) | ||
| 198 | { | ||
| 199 | register_syscore_ops(&intel_epb_syscore_ops); | ||
| 200 | } | ||
| 201 | #else /* !CONFIG_PM */ | ||
| 202 | static int intel_epb_online(unsigned int cpu) | ||
| 203 | { | ||
| 204 | intel_epb_restore(); | ||
| 205 | return 0; | ||
| 206 | } | ||
| 207 | |||
| 208 | static int intel_epb_offline(unsigned int cpu) | ||
| 209 | { | ||
| 210 | return intel_epb_save(); | ||
| 211 | } | ||
| 212 | |||
| 213 | static inline void register_intel_ebp_syscore_ops(void) {} | ||
| 214 | #endif | ||
| 215 | |||
| 196 | static __init int intel_epb_init(void) | 216 | static __init int intel_epb_init(void) |
| 197 | { | 217 | { |
| 198 | int ret; | 218 | int ret; |
| @@ -206,7 +226,7 @@ static __init int intel_epb_init(void) | |||
| 206 | if (ret < 0) | 226 | if (ret < 0) |
| 207 | goto err_out_online; | 227 | goto err_out_online; |
| 208 | 228 | ||
| 209 | register_syscore_ops(&intel_epb_syscore_ops); | 229 | register_intel_ebp_syscore_ops(); |
| 210 | return 0; | 230 | return 0; |
| 211 | 231 | ||
| 212 | err_out_online: | 232 | err_out_online: |
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 15b5e98a86f9..356dfc555a27 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c | |||
| @@ -979,7 +979,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, | |||
| 979 | if (!(freq->flags & CPUFREQ_CONST_LOOPS)) | 979 | if (!(freq->flags & CPUFREQ_CONST_LOOPS)) |
| 980 | mark_tsc_unstable("cpufreq changes"); | 980 | mark_tsc_unstable("cpufreq changes"); |
| 981 | 981 | ||
| 982 | set_cyc2ns_scale(tsc_khz, freq->cpu, rdtsc()); | 982 | set_cyc2ns_scale(tsc_khz, freq->policy->cpu, rdtsc()); |
| 983 | } | 983 | } |
| 984 | 984 | ||
| 985 | return 0; | 985 | return 0; |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d75bb97b983c..b9591abde62a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
| @@ -6698,10 +6698,8 @@ static void kvm_hyperv_tsc_notifier(void) | |||
| 6698 | } | 6698 | } |
| 6699 | #endif | 6699 | #endif |
| 6700 | 6700 | ||
| 6701 | static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long val, | 6701 | static void __kvmclock_cpufreq_notifier(struct cpufreq_freqs *freq, int cpu) |
| 6702 | void *data) | ||
| 6703 | { | 6702 | { |
| 6704 | struct cpufreq_freqs *freq = data; | ||
| 6705 | struct kvm *kvm; | 6703 | struct kvm *kvm; |
| 6706 | struct kvm_vcpu *vcpu; | 6704 | struct kvm_vcpu *vcpu; |
| 6707 | int i, send_ipi = 0; | 6705 | int i, send_ipi = 0; |
| @@ -6745,17 +6743,12 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va | |||
| 6745 | * | 6743 | * |
| 6746 | */ | 6744 | */ |
| 6747 | 6745 | ||
| 6748 | if (val == CPUFREQ_PRECHANGE && freq->old > freq->new) | 6746 | smp_call_function_single(cpu, tsc_khz_changed, freq, 1); |
| 6749 | return 0; | ||
| 6750 | if (val == CPUFREQ_POSTCHANGE && freq->old < freq->new) | ||
| 6751 | return 0; | ||
| 6752 | |||
| 6753 | smp_call_function_single(freq->cpu, tsc_khz_changed, freq, 1); | ||
| 6754 | 6747 | ||
| 6755 | spin_lock(&kvm_lock); | 6748 | spin_lock(&kvm_lock); |
| 6756 | list_for_each_entry(kvm, &vm_list, vm_list) { | 6749 | list_for_each_entry(kvm, &vm_list, vm_list) { |
| 6757 | kvm_for_each_vcpu(i, vcpu, kvm) { | 6750 | kvm_for_each_vcpu(i, vcpu, kvm) { |
| 6758 | if (vcpu->cpu != freq->cpu) | 6751 | if (vcpu->cpu != cpu) |
| 6759 | continue; | 6752 | continue; |
| 6760 | kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); | 6753 | kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); |
| 6761 | if (vcpu->cpu != smp_processor_id()) | 6754 | if (vcpu->cpu != smp_processor_id()) |
| @@ -6777,8 +6770,24 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va | |||
| 6777 | * guest context is entered kvmclock will be updated, | 6770 | * guest context is entered kvmclock will be updated, |
| 6778 | * so the guest will not see stale values. | 6771 | * so the guest will not see stale values. |
| 6779 | */ | 6772 | */ |
| 6780 | smp_call_function_single(freq->cpu, tsc_khz_changed, freq, 1); | 6773 | smp_call_function_single(cpu, tsc_khz_changed, freq, 1); |
| 6781 | } | 6774 | } |
| 6775 | } | ||
| 6776 | |||
| 6777 | static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long val, | ||
| 6778 | void *data) | ||
| 6779 | { | ||
| 6780 | struct cpufreq_freqs *freq = data; | ||
| 6781 | int cpu; | ||
| 6782 | |||
| 6783 | if (val == CPUFREQ_PRECHANGE && freq->old > freq->new) | ||
| 6784 | return 0; | ||
| 6785 | if (val == CPUFREQ_POSTCHANGE && freq->old < freq->new) | ||
| 6786 | return 0; | ||
| 6787 | |||
| 6788 | for_each_cpu(cpu, freq->policy->cpus) | ||
| 6789 | __kvmclock_cpufreq_notifier(freq, cpu); | ||
| 6790 | |||
| 6782 | return 0; | 6791 | return 0; |
| 6783 | } | 6792 | } |
| 6784 | 6793 | ||
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 7a6aa2318915..33c30c1e6a30 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
| @@ -128,6 +128,7 @@ static const struct genpd_lock_ops genpd_spin_ops = { | |||
| 128 | #define genpd_is_always_on(genpd) (genpd->flags & GENPD_FLAG_ALWAYS_ON) | 128 | #define genpd_is_always_on(genpd) (genpd->flags & GENPD_FLAG_ALWAYS_ON) |
| 129 | #define genpd_is_active_wakeup(genpd) (genpd->flags & GENPD_FLAG_ACTIVE_WAKEUP) | 129 | #define genpd_is_active_wakeup(genpd) (genpd->flags & GENPD_FLAG_ACTIVE_WAKEUP) |
| 130 | #define genpd_is_cpu_domain(genpd) (genpd->flags & GENPD_FLAG_CPU_DOMAIN) | 130 | #define genpd_is_cpu_domain(genpd) (genpd->flags & GENPD_FLAG_CPU_DOMAIN) |
| 131 | #define genpd_is_rpm_always_on(genpd) (genpd->flags & GENPD_FLAG_RPM_ALWAYS_ON) | ||
| 131 | 132 | ||
| 132 | static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev, | 133 | static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev, |
| 133 | const struct generic_pm_domain *genpd) | 134 | const struct generic_pm_domain *genpd) |
| @@ -515,7 +516,9 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on, | |||
| 515 | * (1) The domain is configured as always on. | 516 | * (1) The domain is configured as always on. |
| 516 | * (2) When the domain has a subdomain being powered on. | 517 | * (2) When the domain has a subdomain being powered on. |
| 517 | */ | 518 | */ |
| 518 | if (genpd_is_always_on(genpd) || atomic_read(&genpd->sd_count) > 0) | 519 | if (genpd_is_always_on(genpd) || |
| 520 | genpd_is_rpm_always_on(genpd) || | ||
| 521 | atomic_read(&genpd->sd_count) > 0) | ||
| 519 | return -EBUSY; | 522 | return -EBUSY; |
| 520 | 523 | ||
| 521 | list_for_each_entry(pdd, &genpd->dev_list, list_node) { | 524 | list_for_each_entry(pdd, &genpd->dev_list, list_node) { |
| @@ -1812,7 +1815,8 @@ int pm_genpd_init(struct generic_pm_domain *genpd, | |||
| 1812 | } | 1815 | } |
| 1813 | 1816 | ||
| 1814 | /* Always-on domains must be powered on at initialization. */ | 1817 | /* Always-on domains must be powered on at initialization. */ |
| 1815 | if (genpd_is_always_on(genpd) && !genpd_status_on(genpd)) | 1818 | if ((genpd_is_always_on(genpd) || genpd_is_rpm_always_on(genpd)) && |
| 1819 | !genpd_status_on(genpd)) | ||
| 1816 | return -EINVAL; | 1820 | return -EINVAL; |
| 1817 | 1821 | ||
| 1818 | if (genpd_is_cpu_domain(genpd) && | 1822 | if (genpd_is_cpu_domain(genpd) && |
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index db779b650fce..85ff958e01f1 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
| @@ -340,11 +340,14 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy, | |||
| 340 | struct cpufreq_freqs *freqs, | 340 | struct cpufreq_freqs *freqs, |
| 341 | unsigned int state) | 341 | unsigned int state) |
| 342 | { | 342 | { |
| 343 | int cpu; | ||
| 344 | |||
| 343 | BUG_ON(irqs_disabled()); | 345 | BUG_ON(irqs_disabled()); |
| 344 | 346 | ||
| 345 | if (cpufreq_disabled()) | 347 | if (cpufreq_disabled()) |
| 346 | return; | 348 | return; |
| 347 | 349 | ||
| 350 | freqs->policy = policy; | ||
| 348 | freqs->flags = cpufreq_driver->flags; | 351 | freqs->flags = cpufreq_driver->flags; |
| 349 | pr_debug("notification %u of frequency transition to %u kHz\n", | 352 | pr_debug("notification %u of frequency transition to %u kHz\n", |
| 350 | state, freqs->new); | 353 | state, freqs->new); |
| @@ -364,10 +367,8 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy, | |||
| 364 | } | 367 | } |
| 365 | } | 368 | } |
| 366 | 369 | ||
| 367 | for_each_cpu(freqs->cpu, policy->cpus) { | 370 | srcu_notifier_call_chain(&cpufreq_transition_notifier_list, |
| 368 | srcu_notifier_call_chain(&cpufreq_transition_notifier_list, | 371 | CPUFREQ_PRECHANGE, freqs); |
| 369 | CPUFREQ_PRECHANGE, freqs); | ||
| 370 | } | ||
| 371 | 372 | ||
| 372 | adjust_jiffies(CPUFREQ_PRECHANGE, freqs); | 373 | adjust_jiffies(CPUFREQ_PRECHANGE, freqs); |
| 373 | break; | 374 | break; |
| @@ -377,11 +378,11 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy, | |||
| 377 | pr_debug("FREQ: %u - CPUs: %*pbl\n", freqs->new, | 378 | pr_debug("FREQ: %u - CPUs: %*pbl\n", freqs->new, |
| 378 | cpumask_pr_args(policy->cpus)); | 379 | cpumask_pr_args(policy->cpus)); |
| 379 | 380 | ||
| 380 | for_each_cpu(freqs->cpu, policy->cpus) { | 381 | for_each_cpu(cpu, policy->cpus) |
| 381 | trace_cpu_frequency(freqs->new, freqs->cpu); | 382 | trace_cpu_frequency(freqs->new, cpu); |
| 382 | srcu_notifier_call_chain(&cpufreq_transition_notifier_list, | 383 | |
| 383 | CPUFREQ_POSTCHANGE, freqs); | 384 | srcu_notifier_call_chain(&cpufreq_transition_notifier_list, |
| 384 | } | 385 | CPUFREQ_POSTCHANGE, freqs); |
| 385 | 386 | ||
| 386 | cpufreq_stats_record_transition(policy, freqs->new); | 387 | cpufreq_stats_record_transition(policy, freqs->new); |
| 387 | policy->cur = freqs->new; | 388 | policy->cur = freqs->new; |
| @@ -618,50 +619,52 @@ static struct cpufreq_governor *find_governor(const char *str_governor) | |||
| 618 | return NULL; | 619 | return NULL; |
| 619 | } | 620 | } |
| 620 | 621 | ||
| 622 | static int cpufreq_parse_policy(char *str_governor, | ||
| 623 | struct cpufreq_policy *policy) | ||
| 624 | { | ||
| 625 | if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { | ||
| 626 | policy->policy = CPUFREQ_POLICY_PERFORMANCE; | ||
| 627 | return 0; | ||
| 628 | } | ||
| 629 | if (!strncasecmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) { | ||
| 630 | policy->policy = CPUFREQ_POLICY_POWERSAVE; | ||
| 631 | return 0; | ||
| 632 | } | ||
| 633 | return -EINVAL; | ||
| 634 | } | ||
| 635 | |||
| 621 | /** | 636 | /** |
| 622 | * cpufreq_parse_governor - parse a governor string | 637 | * cpufreq_parse_governor - parse a governor string only for !setpolicy |
| 623 | */ | 638 | */ |
| 624 | static int cpufreq_parse_governor(char *str_governor, | 639 | static int cpufreq_parse_governor(char *str_governor, |
| 625 | struct cpufreq_policy *policy) | 640 | struct cpufreq_policy *policy) |
| 626 | { | 641 | { |
| 627 | if (cpufreq_driver->setpolicy) { | 642 | struct cpufreq_governor *t; |
| 628 | if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { | ||
| 629 | policy->policy = CPUFREQ_POLICY_PERFORMANCE; | ||
| 630 | return 0; | ||
| 631 | } | ||
| 632 | 643 | ||
| 633 | if (!strncasecmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) { | 644 | mutex_lock(&cpufreq_governor_mutex); |
| 634 | policy->policy = CPUFREQ_POLICY_POWERSAVE; | ||
| 635 | return 0; | ||
| 636 | } | ||
| 637 | } else { | ||
| 638 | struct cpufreq_governor *t; | ||
| 639 | 645 | ||
| 640 | mutex_lock(&cpufreq_governor_mutex); | 646 | t = find_governor(str_governor); |
| 647 | if (!t) { | ||
| 648 | int ret; | ||
| 641 | 649 | ||
| 642 | t = find_governor(str_governor); | 650 | mutex_unlock(&cpufreq_governor_mutex); |
| 643 | if (!t) { | ||
| 644 | int ret; | ||
| 645 | |||
| 646 | mutex_unlock(&cpufreq_governor_mutex); | ||
| 647 | 651 | ||
| 648 | ret = request_module("cpufreq_%s", str_governor); | 652 | ret = request_module("cpufreq_%s", str_governor); |
| 649 | if (ret) | 653 | if (ret) |
| 650 | return -EINVAL; | 654 | return -EINVAL; |
| 651 | 655 | ||
| 652 | mutex_lock(&cpufreq_governor_mutex); | 656 | mutex_lock(&cpufreq_governor_mutex); |
| 653 | 657 | ||
| 654 | t = find_governor(str_governor); | 658 | t = find_governor(str_governor); |
| 655 | } | 659 | } |
| 656 | if (t && !try_module_get(t->owner)) | 660 | if (t && !try_module_get(t->owner)) |
| 657 | t = NULL; | 661 | t = NULL; |
| 658 | 662 | ||
| 659 | mutex_unlock(&cpufreq_governor_mutex); | 663 | mutex_unlock(&cpufreq_governor_mutex); |
| 660 | 664 | ||
| 661 | if (t) { | 665 | if (t) { |
| 662 | policy->governor = t; | 666 | policy->governor = t; |
| 663 | return 0; | 667 | return 0; |
| 664 | } | ||
| 665 | } | 668 | } |
| 666 | 669 | ||
| 667 | return -EINVAL; | 670 | return -EINVAL; |
| @@ -783,8 +786,13 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy, | |||
| 783 | if (ret != 1) | 786 | if (ret != 1) |
| 784 | return -EINVAL; | 787 | return -EINVAL; |
| 785 | 788 | ||
| 786 | if (cpufreq_parse_governor(str_governor, &new_policy)) | 789 | if (cpufreq_driver->setpolicy) { |
| 787 | return -EINVAL; | 790 | if (cpufreq_parse_policy(str_governor, &new_policy)) |
| 791 | return -EINVAL; | ||
| 792 | } else { | ||
| 793 | if (cpufreq_parse_governor(str_governor, &new_policy)) | ||
| 794 | return -EINVAL; | ||
| 795 | } | ||
| 788 | 796 | ||
| 789 | ret = cpufreq_set_policy(policy, &new_policy); | 797 | ret = cpufreq_set_policy(policy, &new_policy); |
| 790 | 798 | ||
| @@ -1050,32 +1058,39 @@ __weak struct cpufreq_governor *cpufreq_default_governor(void) | |||
| 1050 | 1058 | ||
| 1051 | static int cpufreq_init_policy(struct cpufreq_policy *policy) | 1059 | static int cpufreq_init_policy(struct cpufreq_policy *policy) |
| 1052 | { | 1060 | { |
| 1053 | struct cpufreq_governor *gov = NULL; | 1061 | struct cpufreq_governor *gov = NULL, *def_gov = NULL; |
| 1054 | struct cpufreq_policy new_policy; | 1062 | struct cpufreq_policy new_policy; |
| 1055 | 1063 | ||
| 1056 | memcpy(&new_policy, policy, sizeof(*policy)); | 1064 | memcpy(&new_policy, policy, sizeof(*policy)); |
| 1057 | 1065 | ||
| 1058 | /* Update governor of new_policy to the governor used before hotplug */ | 1066 | def_gov = cpufreq_default_governor(); |
| 1059 | gov = find_governor(policy->last_governor); | 1067 | |
| 1060 | if (gov) { | 1068 | if (has_target()) { |
| 1061 | pr_debug("Restoring governor %s for cpu %d\n", | 1069 | /* |
| 1070 | * Update governor of new_policy to the governor used before | ||
| 1071 | * hotplug | ||
| 1072 | */ | ||
| 1073 | gov = find_governor(policy->last_governor); | ||
| 1074 | if (gov) { | ||
| 1075 | pr_debug("Restoring governor %s for cpu %d\n", | ||
| 1062 | policy->governor->name, policy->cpu); | 1076 | policy->governor->name, policy->cpu); |
| 1077 | } else { | ||
| 1078 | if (!def_gov) | ||
| 1079 | return -ENODATA; | ||
| 1080 | gov = def_gov; | ||
| 1081 | } | ||
| 1082 | new_policy.governor = gov; | ||
| 1063 | } else { | 1083 | } else { |
| 1064 | gov = cpufreq_default_governor(); | 1084 | /* Use the default policy if there is no last_policy. */ |
| 1065 | if (!gov) | 1085 | if (policy->last_policy) { |
| 1066 | return -ENODATA; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | new_policy.governor = gov; | ||
| 1070 | |||
| 1071 | /* Use the default policy if there is no last_policy. */ | ||
| 1072 | if (cpufreq_driver->setpolicy) { | ||
| 1073 | if (policy->last_policy) | ||
| 1074 | new_policy.policy = policy->last_policy; | 1086 | new_policy.policy = policy->last_policy; |
| 1075 | else | 1087 | } else { |
| 1076 | cpufreq_parse_governor(gov->name, &new_policy); | 1088 | if (!def_gov) |
| 1089 | return -ENODATA; | ||
| 1090 | cpufreq_parse_policy(def_gov->name, &new_policy); | ||
| 1091 | } | ||
| 1077 | } | 1092 | } |
| 1078 | /* set default policy */ | 1093 | |
| 1079 | return cpufreq_set_policy(policy, &new_policy); | 1094 | return cpufreq_set_policy(policy, &new_policy); |
| 1080 | } | 1095 | } |
| 1081 | 1096 | ||
| @@ -1133,6 +1148,11 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu) | |||
| 1133 | cpufreq_global_kobject, "policy%u", cpu); | 1148 | cpufreq_global_kobject, "policy%u", cpu); |
| 1134 | if (ret) { | 1149 | if (ret) { |
| 1135 | pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret); | 1150 | pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret); |
| 1151 | /* | ||
| 1152 | * The entire policy object will be freed below, but the extra | ||
| 1153 | * memory allocated for the kobject name needs to be freed by | ||
| 1154 | * releasing the kobject. | ||
| 1155 | */ | ||
| 1136 | kobject_put(&policy->kobj); | 1156 | kobject_put(&policy->kobj); |
| 1137 | goto err_free_real_cpus; | 1157 | goto err_free_real_cpus; |
| 1138 | } | 1158 | } |
diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c index 7d14a4b4e82a..29b43651c261 100644 --- a/drivers/soc/imx/gpc.c +++ b/drivers/soc/imx/gpc.c | |||
| @@ -431,10 +431,19 @@ static int imx_gpc_probe(struct platform_device *pdev) | |||
| 431 | return ret; | 431 | return ret; |
| 432 | } | 432 | } |
| 433 | 433 | ||
| 434 | /* Disable PU power down in normal operation if ERR009619 is present */ | 434 | /* |
| 435 | * Disable PU power down by runtime PM if ERR009619 is present. | ||
| 436 | * | ||
| 437 | * The PRE clock will be paused for several cycles when turning on the | ||
| 438 | * PU domain LDO from power down state. If PRE is in use at that time, | ||
| 439 | * the IPU/PRG cannot get the correct display data from the PRE. | ||
| 440 | * | ||
| 441 | * This is not a concern when the whole system enters suspend state, so | ||
| 442 | * it's safe to power down PU in this case. | ||
| 443 | */ | ||
| 435 | if (of_id_data->err009619_present) | 444 | if (of_id_data->err009619_present) |
| 436 | imx_gpc_domains[GPC_PGC_DOMAIN_PU].base.flags |= | 445 | imx_gpc_domains[GPC_PGC_DOMAIN_PU].base.flags |= |
| 437 | GENPD_FLAG_ALWAYS_ON; | 446 | GENPD_FLAG_RPM_ALWAYS_ON; |
| 438 | 447 | ||
| 439 | /* Keep DISP always on if ERR006287 is present */ | 448 | /* Keep DISP always on if ERR006287 is present */ |
| 440 | if (of_id_data->err006287_present) | 449 | if (of_id_data->err006287_present) |
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 684caf067003..d01a74fbc4db 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h | |||
| @@ -42,13 +42,6 @@ enum cpufreq_table_sorting { | |||
| 42 | CPUFREQ_TABLE_SORTED_DESCENDING | 42 | CPUFREQ_TABLE_SORTED_DESCENDING |
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | struct cpufreq_freqs { | ||
| 46 | unsigned int cpu; /* cpu nr */ | ||
| 47 | unsigned int old; | ||
| 48 | unsigned int new; | ||
| 49 | u8 flags; /* flags of cpufreq_driver, see below. */ | ||
| 50 | }; | ||
| 51 | |||
| 52 | struct cpufreq_cpuinfo { | 45 | struct cpufreq_cpuinfo { |
| 53 | unsigned int max_freq; | 46 | unsigned int max_freq; |
| 54 | unsigned int min_freq; | 47 | unsigned int min_freq; |
| @@ -156,6 +149,13 @@ struct cpufreq_policy { | |||
| 156 | struct thermal_cooling_device *cdev; | 149 | struct thermal_cooling_device *cdev; |
| 157 | }; | 150 | }; |
| 158 | 151 | ||
| 152 | struct cpufreq_freqs { | ||
| 153 | struct cpufreq_policy *policy; | ||
| 154 | unsigned int old; | ||
| 155 | unsigned int new; | ||
| 156 | u8 flags; /* flags of cpufreq_driver, see below. */ | ||
| 157 | }; | ||
| 158 | |||
| 159 | /* Only for ACPI */ | 159 | /* Only for ACPI */ |
| 160 | #define CPUFREQ_SHARED_TYPE_NONE (0) /* None */ | 160 | #define CPUFREQ_SHARED_TYPE_NONE (0) /* None */ |
| 161 | #define CPUFREQ_SHARED_TYPE_HW (1) /* HW does needed coordination */ | 161 | #define CPUFREQ_SHARED_TYPE_HW (1) /* HW does needed coordination */ |
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 0e8e356bed6a..b21f35f0ee2e 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h | |||
| @@ -53,12 +53,16 @@ | |||
| 53 | * driver must then comply with the so called, | 53 | * driver must then comply with the so called, |
| 54 | * last-man-standing algorithm, for the CPUs in the | 54 | * last-man-standing algorithm, for the CPUs in the |
| 55 | * PM domain. | 55 | * PM domain. |
| 56 | * | ||
| 57 | * GENPD_FLAG_RPM_ALWAYS_ON: Instructs genpd to always keep the PM domain | ||
| 58 | * powered on except for system suspend. | ||
| 56 | */ | 59 | */ |
| 57 | #define GENPD_FLAG_PM_CLK (1U << 0) | 60 | #define GENPD_FLAG_PM_CLK (1U << 0) |
| 58 | #define GENPD_FLAG_IRQ_SAFE (1U << 1) | 61 | #define GENPD_FLAG_IRQ_SAFE (1U << 1) |
| 59 | #define GENPD_FLAG_ALWAYS_ON (1U << 2) | 62 | #define GENPD_FLAG_ALWAYS_ON (1U << 2) |
| 60 | #define GENPD_FLAG_ACTIVE_WAKEUP (1U << 3) | 63 | #define GENPD_FLAG_ACTIVE_WAKEUP (1U << 3) |
| 61 | #define GENPD_FLAG_CPU_DOMAIN (1U << 4) | 64 | #define GENPD_FLAG_CPU_DOMAIN (1U << 4) |
| 65 | #define GENPD_FLAG_RPM_ALWAYS_ON (1U << 5) | ||
| 62 | 66 | ||
| 63 | enum gpd_status { | 67 | enum gpd_status { |
| 64 | GPD_STATE_ACTIVE = 0, /* PM domain is active */ | 68 | GPD_STATE_ACTIVE = 0, /* PM domain is active */ |
