summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2019-04-29 05:33:58 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2019-05-10 06:20:36 -0400
commitdf24014abe3694e7c34ce5e50248611b7a93fe83 (patch)
tree98d5dc569e611f1cffec3a5c7bfeb66097c01283
parent8f5e823f9131a430b12f73e9436d7486e20c16f5 (diff)
cpufreq: Call transition notifier only once for each policy
Currently, the notifiers are called once for each CPU of the policy->cpus cpumask. It would be more optimal if the notifier can be called only once and all the relevant information be provided to it. Out of the 23 drivers that register for the transition notifiers today, only 4 of them do per-cpu updates and the callback for the rest can be called only once for the policy without any impact. This would also avoid multiple function calls to the notifier callbacks and reduce multiple iterations of notifier core's code (which does locking as well). This patch adds pointer to the cpufreq policy to the struct cpufreq_freqs, so the notifier callback has all the information available to it with a single call. The five drivers which perform per-cpu updates are updated to use the cpufreq policy. The freqs->cpu field is redundant now and is removed. Acked-by: David S. Miller <davem@davemloft.net> (sparc) Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--arch/arm/kernel/smp.c24
-rw-r--r--arch/sparc/kernel/time_64.c28
-rw-r--r--arch/x86/kernel/tsc.c2
-rw-r--r--arch/x86/kvm/x86.c31
-rw-r--r--drivers/cpufreq/cpufreq.c19
-rw-r--r--include/linux/cpufreq.h14
6 files changed, 69 insertions, 49 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index facd4240ca02..c6d37563610a 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -754,15 +754,20 @@ static int cpufreq_callback(struct notifier_block *nb,
754 unsigned long val, void *data) 754 unsigned long val, void *data)
755{ 755{
756 struct cpufreq_freqs *freq = data; 756 struct cpufreq_freqs *freq = data;
757 int cpu = freq->cpu; 757 struct cpumask *cpus = freq->policy->cpus;
758 int cpu, first = cpumask_first(cpus);
759 unsigned int lpj;
758 760
759 if (freq->flags & CPUFREQ_CONST_LOOPS) 761 if (freq->flags & CPUFREQ_CONST_LOOPS)
760 return NOTIFY_OK; 762 return NOTIFY_OK;
761 763
762 if (!per_cpu(l_p_j_ref, cpu)) { 764 if (!per_cpu(l_p_j_ref, first)) {
763 per_cpu(l_p_j_ref, cpu) = 765 for_each_cpu(cpu, cpus) {
764 per_cpu(cpu_data, cpu).loops_per_jiffy; 766 per_cpu(l_p_j_ref, cpu) =
765 per_cpu(l_p_j_ref_freq, cpu) = freq->old; 767 per_cpu(cpu_data, cpu).loops_per_jiffy;
768 per_cpu(l_p_j_ref_freq, cpu) = freq->old;
769 }
770
766 if (!global_l_p_j_ref) { 771 if (!global_l_p_j_ref) {
767 global_l_p_j_ref = loops_per_jiffy; 772 global_l_p_j_ref = loops_per_jiffy;
768 global_l_p_j_ref_freq = freq->old; 773 global_l_p_j_ref_freq = freq->old;
@@ -774,10 +779,11 @@ static int cpufreq_callback(struct notifier_block *nb,
774 loops_per_jiffy = cpufreq_scale(global_l_p_j_ref, 779 loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
775 global_l_p_j_ref_freq, 780 global_l_p_j_ref_freq,
776 freq->new); 781 freq->new);
777 per_cpu(cpu_data, cpu).loops_per_jiffy = 782
778 cpufreq_scale(per_cpu(l_p_j_ref, cpu), 783 lpj = cpufreq_scale(per_cpu(l_p_j_ref, first),
779 per_cpu(l_p_j_ref_freq, cpu), 784 per_cpu(l_p_j_ref_freq, first), freq->new);
780 freq->new); 785 for_each_cpu(cpu, cpus)
786 per_cpu(cpu_data, cpu).loops_per_jiffy = lpj;
781 } 787 }
782 return NOTIFY_OK; 788 return NOTIFY_OK;
783} 789}
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/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 b5edc8e3ce1d..22cc90baa67f 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
6701static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long val, 6701static 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
6777static 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/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 7ea217c88c2e..c66eefe928c5 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;
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
45struct 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
52struct cpufreq_cpuinfo { 45struct 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
152struct 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 */