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