1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Library for common functions for Intel SpeedStep v.1 and v.2 support
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/moduleparam.h>
15*4882a593Smuzhiyun #include <linux/init.h>
16*4882a593Smuzhiyun #include <linux/cpufreq.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include <asm/msr.h>
19*4882a593Smuzhiyun #include <asm/tsc.h>
20*4882a593Smuzhiyun #include "speedstep-lib.h"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #define PFX "speedstep-lib: "
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
25*4882a593Smuzhiyun static int relaxed_check;
26*4882a593Smuzhiyun #else
27*4882a593Smuzhiyun #define relaxed_check 0
28*4882a593Smuzhiyun #endif
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun /*********************************************************************
31*4882a593Smuzhiyun * GET PROCESSOR CORE SPEED IN KHZ *
32*4882a593Smuzhiyun *********************************************************************/
33*4882a593Smuzhiyun
pentium3_get_frequency(enum speedstep_processor processor)34*4882a593Smuzhiyun static unsigned int pentium3_get_frequency(enum speedstep_processor processor)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun /* See table 14 of p3_ds.pdf and table 22 of 29834003.pdf */
37*4882a593Smuzhiyun static const struct {
38*4882a593Smuzhiyun unsigned int ratio; /* Frequency Multiplier (x10) */
39*4882a593Smuzhiyun u8 bitmap; /* power on configuration bits
40*4882a593Smuzhiyun [27, 25:22] (in MSR 0x2a) */
41*4882a593Smuzhiyun } msr_decode_mult[] = {
42*4882a593Smuzhiyun { 30, 0x01 },
43*4882a593Smuzhiyun { 35, 0x05 },
44*4882a593Smuzhiyun { 40, 0x02 },
45*4882a593Smuzhiyun { 45, 0x06 },
46*4882a593Smuzhiyun { 50, 0x00 },
47*4882a593Smuzhiyun { 55, 0x04 },
48*4882a593Smuzhiyun { 60, 0x0b },
49*4882a593Smuzhiyun { 65, 0x0f },
50*4882a593Smuzhiyun { 70, 0x09 },
51*4882a593Smuzhiyun { 75, 0x0d },
52*4882a593Smuzhiyun { 80, 0x0a },
53*4882a593Smuzhiyun { 85, 0x26 },
54*4882a593Smuzhiyun { 90, 0x20 },
55*4882a593Smuzhiyun { 100, 0x2b },
56*4882a593Smuzhiyun { 0, 0xff } /* error or unknown value */
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /* PIII(-M) FSB settings: see table b1-b of 24547206.pdf */
60*4882a593Smuzhiyun static const struct {
61*4882a593Smuzhiyun unsigned int value; /* Front Side Bus speed in MHz */
62*4882a593Smuzhiyun u8 bitmap; /* power on configuration bits [18: 19]
63*4882a593Smuzhiyun (in MSR 0x2a) */
64*4882a593Smuzhiyun } msr_decode_fsb[] = {
65*4882a593Smuzhiyun { 66, 0x0 },
66*4882a593Smuzhiyun { 100, 0x2 },
67*4882a593Smuzhiyun { 133, 0x1 },
68*4882a593Smuzhiyun { 0, 0xff}
69*4882a593Smuzhiyun };
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun u32 msr_lo, msr_tmp;
72*4882a593Smuzhiyun int i = 0, j = 0;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun /* read MSR 0x2a - we only need the low 32 bits */
75*4882a593Smuzhiyun rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
76*4882a593Smuzhiyun pr_debug("P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
77*4882a593Smuzhiyun msr_tmp = msr_lo;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun /* decode the FSB */
80*4882a593Smuzhiyun msr_tmp &= 0x00c0000;
81*4882a593Smuzhiyun msr_tmp >>= 18;
82*4882a593Smuzhiyun while (msr_tmp != msr_decode_fsb[i].bitmap) {
83*4882a593Smuzhiyun if (msr_decode_fsb[i].bitmap == 0xff)
84*4882a593Smuzhiyun return 0;
85*4882a593Smuzhiyun i++;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /* decode the multiplier */
89*4882a593Smuzhiyun if (processor == SPEEDSTEP_CPU_PIII_C_EARLY) {
90*4882a593Smuzhiyun pr_debug("workaround for early PIIIs\n");
91*4882a593Smuzhiyun msr_lo &= 0x03c00000;
92*4882a593Smuzhiyun } else
93*4882a593Smuzhiyun msr_lo &= 0x0bc00000;
94*4882a593Smuzhiyun msr_lo >>= 22;
95*4882a593Smuzhiyun while (msr_lo != msr_decode_mult[j].bitmap) {
96*4882a593Smuzhiyun if (msr_decode_mult[j].bitmap == 0xff)
97*4882a593Smuzhiyun return 0;
98*4882a593Smuzhiyun j++;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun pr_debug("speed is %u\n",
102*4882a593Smuzhiyun (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100));
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun return msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun
pentiumM_get_frequency(void)108*4882a593Smuzhiyun static unsigned int pentiumM_get_frequency(void)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun u32 msr_lo, msr_tmp;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
113*4882a593Smuzhiyun pr_debug("PM - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun /* see table B-2 of 24547212.pdf */
116*4882a593Smuzhiyun if (msr_lo & 0x00040000) {
117*4882a593Smuzhiyun printk(KERN_DEBUG PFX "PM - invalid FSB: 0x%x 0x%x\n",
118*4882a593Smuzhiyun msr_lo, msr_tmp);
119*4882a593Smuzhiyun return 0;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun msr_tmp = (msr_lo >> 22) & 0x1f;
123*4882a593Smuzhiyun pr_debug("bits 22-26 are 0x%x, speed is %u\n",
124*4882a593Smuzhiyun msr_tmp, (msr_tmp * 100 * 1000));
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun return msr_tmp * 100 * 1000;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
pentium_core_get_frequency(void)129*4882a593Smuzhiyun static unsigned int pentium_core_get_frequency(void)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun u32 fsb = 0;
132*4882a593Smuzhiyun u32 msr_lo, msr_tmp;
133*4882a593Smuzhiyun int ret;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun rdmsr(MSR_FSB_FREQ, msr_lo, msr_tmp);
136*4882a593Smuzhiyun /* see table B-2 of 25366920.pdf */
137*4882a593Smuzhiyun switch (msr_lo & 0x07) {
138*4882a593Smuzhiyun case 5:
139*4882a593Smuzhiyun fsb = 100000;
140*4882a593Smuzhiyun break;
141*4882a593Smuzhiyun case 1:
142*4882a593Smuzhiyun fsb = 133333;
143*4882a593Smuzhiyun break;
144*4882a593Smuzhiyun case 3:
145*4882a593Smuzhiyun fsb = 166667;
146*4882a593Smuzhiyun break;
147*4882a593Smuzhiyun case 2:
148*4882a593Smuzhiyun fsb = 200000;
149*4882a593Smuzhiyun break;
150*4882a593Smuzhiyun case 0:
151*4882a593Smuzhiyun fsb = 266667;
152*4882a593Smuzhiyun break;
153*4882a593Smuzhiyun case 4:
154*4882a593Smuzhiyun fsb = 333333;
155*4882a593Smuzhiyun break;
156*4882a593Smuzhiyun default:
157*4882a593Smuzhiyun pr_err("PCORE - MSR_FSB_FREQ undefined value\n");
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
161*4882a593Smuzhiyun pr_debug("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n",
162*4882a593Smuzhiyun msr_lo, msr_tmp);
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun msr_tmp = (msr_lo >> 22) & 0x1f;
165*4882a593Smuzhiyun pr_debug("bits 22-26 are 0x%x, speed is %u\n",
166*4882a593Smuzhiyun msr_tmp, (msr_tmp * fsb));
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun ret = (msr_tmp * fsb);
169*4882a593Smuzhiyun return ret;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun
pentium4_get_frequency(void)173*4882a593Smuzhiyun static unsigned int pentium4_get_frequency(void)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun struct cpuinfo_x86 *c = &boot_cpu_data;
176*4882a593Smuzhiyun u32 msr_lo, msr_hi, mult;
177*4882a593Smuzhiyun unsigned int fsb = 0;
178*4882a593Smuzhiyun unsigned int ret;
179*4882a593Smuzhiyun u8 fsb_code;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun /* Pentium 4 Model 0 and 1 do not have the Core Clock Frequency
182*4882a593Smuzhiyun * to System Bus Frequency Ratio Field in the Processor Frequency
183*4882a593Smuzhiyun * Configuration Register of the MSR. Therefore the current
184*4882a593Smuzhiyun * frequency cannot be calculated and has to be measured.
185*4882a593Smuzhiyun */
186*4882a593Smuzhiyun if (c->x86_model < 2)
187*4882a593Smuzhiyun return cpu_khz;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun rdmsr(0x2c, msr_lo, msr_hi);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun pr_debug("P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /* decode the FSB: see IA-32 Intel (C) Architecture Software
194*4882a593Smuzhiyun * Developer's Manual, Volume 3: System Prgramming Guide,
195*4882a593Smuzhiyun * revision #12 in Table B-1: MSRs in the Pentium 4 and
196*4882a593Smuzhiyun * Intel Xeon Processors, on page B-4 and B-5.
197*4882a593Smuzhiyun */
198*4882a593Smuzhiyun fsb_code = (msr_lo >> 16) & 0x7;
199*4882a593Smuzhiyun switch (fsb_code) {
200*4882a593Smuzhiyun case 0:
201*4882a593Smuzhiyun fsb = 100 * 1000;
202*4882a593Smuzhiyun break;
203*4882a593Smuzhiyun case 1:
204*4882a593Smuzhiyun fsb = 13333 * 10;
205*4882a593Smuzhiyun break;
206*4882a593Smuzhiyun case 2:
207*4882a593Smuzhiyun fsb = 200 * 1000;
208*4882a593Smuzhiyun break;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (!fsb)
212*4882a593Smuzhiyun printk(KERN_DEBUG PFX "couldn't detect FSB speed. "
213*4882a593Smuzhiyun "Please send an e-mail to <linux@brodo.de>\n");
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /* Multiplier. */
216*4882a593Smuzhiyun mult = msr_lo >> 24;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun pr_debug("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n",
219*4882a593Smuzhiyun fsb, mult, (fsb * mult));
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun ret = (fsb * mult);
222*4882a593Smuzhiyun return ret;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun /* Warning: may get called from smp_call_function_single. */
speedstep_get_frequency(enum speedstep_processor processor)227*4882a593Smuzhiyun unsigned int speedstep_get_frequency(enum speedstep_processor processor)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun switch (processor) {
230*4882a593Smuzhiyun case SPEEDSTEP_CPU_PCORE:
231*4882a593Smuzhiyun return pentium_core_get_frequency();
232*4882a593Smuzhiyun case SPEEDSTEP_CPU_PM:
233*4882a593Smuzhiyun return pentiumM_get_frequency();
234*4882a593Smuzhiyun case SPEEDSTEP_CPU_P4D:
235*4882a593Smuzhiyun case SPEEDSTEP_CPU_P4M:
236*4882a593Smuzhiyun return pentium4_get_frequency();
237*4882a593Smuzhiyun case SPEEDSTEP_CPU_PIII_T:
238*4882a593Smuzhiyun case SPEEDSTEP_CPU_PIII_C:
239*4882a593Smuzhiyun case SPEEDSTEP_CPU_PIII_C_EARLY:
240*4882a593Smuzhiyun return pentium3_get_frequency(processor);
241*4882a593Smuzhiyun default:
242*4882a593Smuzhiyun return 0;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun return 0;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(speedstep_get_frequency);
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun /*********************************************************************
250*4882a593Smuzhiyun * DETECT SPEEDSTEP-CAPABLE PROCESSOR *
251*4882a593Smuzhiyun *********************************************************************/
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun /* Keep in sync with the x86_cpu_id tables in the different modules */
speedstep_detect_processor(void)254*4882a593Smuzhiyun enum speedstep_processor speedstep_detect_processor(void)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun struct cpuinfo_x86 *c = &cpu_data(0);
257*4882a593Smuzhiyun u32 ebx, msr_lo, msr_hi;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun pr_debug("x86: %x, model: %x\n", c->x86, c->x86_model);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun if ((c->x86_vendor != X86_VENDOR_INTEL) ||
262*4882a593Smuzhiyun ((c->x86 != 6) && (c->x86 != 0xF)))
263*4882a593Smuzhiyun return 0;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun if (c->x86 == 0xF) {
266*4882a593Smuzhiyun /* Intel Mobile Pentium 4-M
267*4882a593Smuzhiyun * or Intel Mobile Pentium 4 with 533 MHz FSB */
268*4882a593Smuzhiyun if (c->x86_model != 2)
269*4882a593Smuzhiyun return 0;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun ebx = cpuid_ebx(0x00000001);
272*4882a593Smuzhiyun ebx &= 0x000000FF;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun pr_debug("ebx value is %x, x86_stepping is %x\n", ebx, c->x86_stepping);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun switch (c->x86_stepping) {
277*4882a593Smuzhiyun case 4:
278*4882a593Smuzhiyun /*
279*4882a593Smuzhiyun * B-stepping [M-P4-M]
280*4882a593Smuzhiyun * sample has ebx = 0x0f, production has 0x0e.
281*4882a593Smuzhiyun */
282*4882a593Smuzhiyun if ((ebx == 0x0e) || (ebx == 0x0f))
283*4882a593Smuzhiyun return SPEEDSTEP_CPU_P4M;
284*4882a593Smuzhiyun break;
285*4882a593Smuzhiyun case 7:
286*4882a593Smuzhiyun /*
287*4882a593Smuzhiyun * C-stepping [M-P4-M]
288*4882a593Smuzhiyun * needs to have ebx=0x0e, else it's a celeron:
289*4882a593Smuzhiyun * cf. 25130917.pdf / page 7, footnote 5 even
290*4882a593Smuzhiyun * though 25072120.pdf / page 7 doesn't say
291*4882a593Smuzhiyun * samples are only of B-stepping...
292*4882a593Smuzhiyun */
293*4882a593Smuzhiyun if (ebx == 0x0e)
294*4882a593Smuzhiyun return SPEEDSTEP_CPU_P4M;
295*4882a593Smuzhiyun break;
296*4882a593Smuzhiyun case 9:
297*4882a593Smuzhiyun /*
298*4882a593Smuzhiyun * D-stepping [M-P4-M or M-P4/533]
299*4882a593Smuzhiyun *
300*4882a593Smuzhiyun * this is totally strange: CPUID 0x0F29 is
301*4882a593Smuzhiyun * used by M-P4-M, M-P4/533 and(!) Celeron CPUs.
302*4882a593Smuzhiyun * The latter need to be sorted out as they don't
303*4882a593Smuzhiyun * support speedstep.
304*4882a593Smuzhiyun * Celerons with CPUID 0x0F29 may have either
305*4882a593Smuzhiyun * ebx=0x8 or 0xf -- 25130917.pdf doesn't say anything
306*4882a593Smuzhiyun * specific.
307*4882a593Smuzhiyun * M-P4-Ms may have either ebx=0xe or 0xf [see above]
308*4882a593Smuzhiyun * M-P4/533 have either ebx=0xe or 0xf. [25317607.pdf]
309*4882a593Smuzhiyun * also, M-P4M HTs have ebx=0x8, too
310*4882a593Smuzhiyun * For now, they are distinguished by the model_id
311*4882a593Smuzhiyun * string
312*4882a593Smuzhiyun */
313*4882a593Smuzhiyun if ((ebx == 0x0e) ||
314*4882a593Smuzhiyun (strstr(c->x86_model_id,
315*4882a593Smuzhiyun "Mobile Intel(R) Pentium(R) 4") != NULL))
316*4882a593Smuzhiyun return SPEEDSTEP_CPU_P4M;
317*4882a593Smuzhiyun break;
318*4882a593Smuzhiyun default:
319*4882a593Smuzhiyun break;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun return 0;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun switch (c->x86_model) {
325*4882a593Smuzhiyun case 0x0B: /* Intel PIII [Tualatin] */
326*4882a593Smuzhiyun /* cpuid_ebx(1) is 0x04 for desktop PIII,
327*4882a593Smuzhiyun * 0x06 for mobile PIII-M */
328*4882a593Smuzhiyun ebx = cpuid_ebx(0x00000001);
329*4882a593Smuzhiyun pr_debug("ebx is %x\n", ebx);
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun ebx &= 0x000000FF;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun if (ebx != 0x06)
334*4882a593Smuzhiyun return 0;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun /* So far all PIII-M processors support SpeedStep. See
337*4882a593Smuzhiyun * Intel's 24540640.pdf of June 2003
338*4882a593Smuzhiyun */
339*4882a593Smuzhiyun return SPEEDSTEP_CPU_PIII_T;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun case 0x08: /* Intel PIII [Coppermine] */
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun /* all mobile PIII Coppermines have FSB 100 MHz
344*4882a593Smuzhiyun * ==> sort out a few desktop PIIIs. */
345*4882a593Smuzhiyun rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi);
346*4882a593Smuzhiyun pr_debug("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n",
347*4882a593Smuzhiyun msr_lo, msr_hi);
348*4882a593Smuzhiyun msr_lo &= 0x00c0000;
349*4882a593Smuzhiyun if (msr_lo != 0x0080000)
350*4882a593Smuzhiyun return 0;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun /*
353*4882a593Smuzhiyun * If the processor is a mobile version,
354*4882a593Smuzhiyun * platform ID has bit 50 set
355*4882a593Smuzhiyun * it has SpeedStep technology if either
356*4882a593Smuzhiyun * bit 56 or 57 is set
357*4882a593Smuzhiyun */
358*4882a593Smuzhiyun rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi);
359*4882a593Smuzhiyun pr_debug("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n",
360*4882a593Smuzhiyun msr_lo, msr_hi);
361*4882a593Smuzhiyun if ((msr_hi & (1<<18)) &&
362*4882a593Smuzhiyun (relaxed_check ? 1 : (msr_hi & (3<<24)))) {
363*4882a593Smuzhiyun if (c->x86_stepping == 0x01) {
364*4882a593Smuzhiyun pr_debug("early PIII version\n");
365*4882a593Smuzhiyun return SPEEDSTEP_CPU_PIII_C_EARLY;
366*4882a593Smuzhiyun } else
367*4882a593Smuzhiyun return SPEEDSTEP_CPU_PIII_C;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun fallthrough;
370*4882a593Smuzhiyun default:
371*4882a593Smuzhiyun return 0;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(speedstep_detect_processor);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun /*********************************************************************
378*4882a593Smuzhiyun * DETECT SPEEDSTEP SPEEDS *
379*4882a593Smuzhiyun *********************************************************************/
380*4882a593Smuzhiyun
speedstep_get_freqs(enum speedstep_processor processor,unsigned int * low_speed,unsigned int * high_speed,unsigned int * transition_latency,void (* set_state)(unsigned int state))381*4882a593Smuzhiyun unsigned int speedstep_get_freqs(enum speedstep_processor processor,
382*4882a593Smuzhiyun unsigned int *low_speed,
383*4882a593Smuzhiyun unsigned int *high_speed,
384*4882a593Smuzhiyun unsigned int *transition_latency,
385*4882a593Smuzhiyun void (*set_state) (unsigned int state))
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun unsigned int prev_speed;
388*4882a593Smuzhiyun unsigned int ret = 0;
389*4882a593Smuzhiyun unsigned long flags;
390*4882a593Smuzhiyun ktime_t tv1, tv2;
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun if ((!processor) || (!low_speed) || (!high_speed) || (!set_state))
393*4882a593Smuzhiyun return -EINVAL;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun pr_debug("trying to determine both speeds\n");
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun /* get current speed */
398*4882a593Smuzhiyun prev_speed = speedstep_get_frequency(processor);
399*4882a593Smuzhiyun if (!prev_speed)
400*4882a593Smuzhiyun return -EIO;
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun pr_debug("previous speed is %u\n", prev_speed);
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun preempt_disable();
405*4882a593Smuzhiyun local_irq_save(flags);
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun /* switch to low state */
408*4882a593Smuzhiyun set_state(SPEEDSTEP_LOW);
409*4882a593Smuzhiyun *low_speed = speedstep_get_frequency(processor);
410*4882a593Smuzhiyun if (!*low_speed) {
411*4882a593Smuzhiyun ret = -EIO;
412*4882a593Smuzhiyun goto out;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun pr_debug("low speed is %u\n", *low_speed);
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun /* start latency measurement */
418*4882a593Smuzhiyun if (transition_latency)
419*4882a593Smuzhiyun tv1 = ktime_get();
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun /* switch to high state */
422*4882a593Smuzhiyun set_state(SPEEDSTEP_HIGH);
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun /* end latency measurement */
425*4882a593Smuzhiyun if (transition_latency)
426*4882a593Smuzhiyun tv2 = ktime_get();
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun *high_speed = speedstep_get_frequency(processor);
429*4882a593Smuzhiyun if (!*high_speed) {
430*4882a593Smuzhiyun ret = -EIO;
431*4882a593Smuzhiyun goto out;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun pr_debug("high speed is %u\n", *high_speed);
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun if (*low_speed == *high_speed) {
437*4882a593Smuzhiyun ret = -ENODEV;
438*4882a593Smuzhiyun goto out;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun /* switch to previous state, if necessary */
442*4882a593Smuzhiyun if (*high_speed != prev_speed)
443*4882a593Smuzhiyun set_state(SPEEDSTEP_LOW);
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun if (transition_latency) {
446*4882a593Smuzhiyun *transition_latency = ktime_to_us(ktime_sub(tv2, tv1));
447*4882a593Smuzhiyun pr_debug("transition latency is %u uSec\n", *transition_latency);
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun /* convert uSec to nSec and add 20% for safety reasons */
450*4882a593Smuzhiyun *transition_latency *= 1200;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun /* check if the latency measurement is too high or too low
453*4882a593Smuzhiyun * and set it to a safe value (500uSec) in that case
454*4882a593Smuzhiyun */
455*4882a593Smuzhiyun if (*transition_latency > 10000000 ||
456*4882a593Smuzhiyun *transition_latency < 50000) {
457*4882a593Smuzhiyun pr_warn("frequency transition measured seems out of range (%u nSec), falling back to a safe one of %u nSec\n",
458*4882a593Smuzhiyun *transition_latency, 500000);
459*4882a593Smuzhiyun *transition_latency = 500000;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun out:
464*4882a593Smuzhiyun local_irq_restore(flags);
465*4882a593Smuzhiyun preempt_enable();
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun return ret;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(speedstep_get_freqs);
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun #ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
472*4882a593Smuzhiyun module_param(relaxed_check, int, 0444);
473*4882a593Smuzhiyun MODULE_PARM_DESC(relaxed_check,
474*4882a593Smuzhiyun "Don't do all checks for speedstep capability.");
475*4882a593Smuzhiyun #endif
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
478*4882a593Smuzhiyun MODULE_DESCRIPTION("Library for Intel SpeedStep 1 or 2 cpufreq drivers.");
479*4882a593Smuzhiyun MODULE_LICENSE("GPL");
480