1 /*
2 * cpufreq.c - ACPI Processor P-States Driver ($Revision: 1.4 $)
3 *
4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6 * Copyright (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de>
7 * Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
8 *
9 * Feb 2008 - Liu Jinsong <jinsong.liu@intel.com>
10 * porting acpi-cpufreq.c from Linux 2.6.23 to Xen hypervisor
11 *
12 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or (at
17 * your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License along
25 * with this program; If not, see <http://www.gnu.org/licenses/>.
26 *
27 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28 */
29 #include <xen/types.h>
30 #include <xen/errno.h>
31 #include <xen/param.h>
32 #include <xen/sched.h>
33
34 #include <asm/msr.h>
35
36 #include <acpi/cpufreq/cpufreq.h>
37
38 struct acpi_cpufreq_data *cpufreq_drv_data[NR_CPUS];
39
40 struct perf_pair {
41 union {
42 struct {
43 uint32_t lo;
44 uint32_t hi;
45 } split;
46 uint64_t whole;
47 } aperf, mperf;
48 };
49 static DEFINE_PER_CPU(struct perf_pair, gov_perf_pair);
50 static DEFINE_PER_CPU(struct perf_pair, usr_perf_pair);
51
read_measured_perf_ctrs(void * _readin)52 static void cf_check read_measured_perf_ctrs(void *_readin)
53 {
54 struct perf_pair *readin = _readin;
55
56 rdmsrl(MSR_IA32_APERF, readin->aperf.whole);
57 rdmsrl(MSR_IA32_MPERF, readin->mperf.whole);
58 }
59
60 /*
61 * Return the measured active (C0) frequency on this CPU since last call
62 * to this function.
63 * Input: cpu number
64 * Return: Average CPU frequency in terms of max frequency (zero on error)
65 *
66 * We use IA32_MPERF and IA32_APERF MSRs to get the measured performance
67 * over a period of time, while CPU is in C0 state.
68 * IA32_MPERF counts at the rate of max advertised frequency
69 * IA32_APERF counts at the rate of actual CPU frequency
70 * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and
71 * no meaning should be associated with absolute values of these MSRs.
72 */
get_measured_perf(unsigned int cpu,unsigned int flag)73 unsigned int get_measured_perf(unsigned int cpu, unsigned int flag)
74 {
75 struct cpufreq_policy *policy;
76 struct perf_pair readin, cur, *saved;
77 unsigned int perf_percent;
78
79 if (!cpu_online(cpu))
80 return 0;
81
82 policy = per_cpu(cpufreq_cpu_policy, cpu);
83 if ( !policy || !cpu_has_aperfmperf )
84 return 0;
85
86 switch (flag)
87 {
88 case GOV_GETAVG:
89 {
90 saved = &per_cpu(gov_perf_pair, cpu);
91 break;
92 }
93 case USR_GETAVG:
94 {
95 saved = &per_cpu(usr_perf_pair, cpu);
96 break;
97 }
98 default:
99 return 0;
100 }
101
102 if (cpu == smp_processor_id()) {
103 read_measured_perf_ctrs((void *)&readin);
104 } else {
105 on_selected_cpus(cpumask_of(cpu), read_measured_perf_ctrs,
106 &readin, 1);
107 }
108
109 cur.aperf.whole = readin.aperf.whole - saved->aperf.whole;
110 cur.mperf.whole = readin.mperf.whole - saved->mperf.whole;
111 saved->aperf.whole = readin.aperf.whole;
112 saved->mperf.whole = readin.mperf.whole;
113
114 if (unlikely(((unsigned long)(-1) / 100) < cur.aperf.whole)) {
115 int shift_count = 7;
116 cur.aperf.whole >>= shift_count;
117 cur.mperf.whole >>= shift_count;
118 }
119
120 if (cur.aperf.whole && cur.mperf.whole)
121 perf_percent = (cur.aperf.whole * 100) / cur.mperf.whole;
122 else
123 perf_percent = 0;
124
125 return policy->cpuinfo.perf_freq * perf_percent / 100;
126 }
127
cpufreq_driver_init(void)128 static int __init cf_check cpufreq_driver_init(void)
129 {
130 int ret = 0;
131
132 if ( cpufreq_controller == FREQCTL_xen )
133 {
134 switch ( boot_cpu_data.x86_vendor )
135 {
136 case X86_VENDOR_INTEL:
137 ret = -ENOENT;
138
139 for ( unsigned int i = 0; i < cpufreq_xen_cnt; i++ )
140 {
141 switch ( cpufreq_xen_opts[i] )
142 {
143 case CPUFREQ_xen:
144 ret = IS_ENABLED(CONFIG_INTEL) ?
145 acpi_cpufreq_register() : -ENODEV;
146 break;
147 case CPUFREQ_hwp:
148 ret = IS_ENABLED(CONFIG_INTEL) ?
149 hwp_register_driver() : -ENODEV;
150 break;
151 case CPUFREQ_none:
152 ret = 0;
153 break;
154 }
155
156 if ( !ret || ret == -EBUSY )
157 break;
158 }
159 break;
160
161 case X86_VENDOR_AMD:
162 case X86_VENDOR_HYGON:
163 ret = IS_ENABLED(CONFIG_AMD) ? powernow_register_driver() : -ENODEV;
164 break;
165 }
166 }
167
168 return ret;
169 }
170 presmp_initcall(cpufreq_driver_init);
171
cpufreq_driver_late_init(void)172 static int __init cf_check cpufreq_driver_late_init(void)
173 {
174 /*
175 * While acpi_cpufreq_driver wants to unconditionally have all hooks
176 * populated for __initconst_cf_clobber to have as much of an effect as
177 * possible, zap the .get hook here (but not in cpufreq_driver_init()),
178 * until acpi_cpufreq_cpu_init() knows whether it's wanted / needed.
179 */
180 cpufreq_driver.get = NULL;
181 return 0;
182 }
183 __initcall(cpufreq_driver_late_init);
184
cpufreq_cpu_init(unsigned int cpu)185 int cpufreq_cpu_init(unsigned int cpu)
186 {
187 /* Currently we only handle Intel, AMD and Hygon processor */
188 if ( boot_cpu_data.x86_vendor &
189 (X86_VENDOR_INTEL | X86_VENDOR_AMD | X86_VENDOR_HYGON) )
190 return cpufreq_add_cpu(cpu);
191
192 return -EOPNOTSUPP;
193 }
194