commented early_printk patch because of rejects.
[linux-flexiantxendom0-3.2.10.git] / arch / i386 / kernel / cpu / cpufreq / longrun.c
1 /*
2  * (C) 2002 - 2003  Dominik Brodowski <linux@brodo.de>
3  *
4  *  Licensed under the terms of the GNU GPL License version 2.
5  *
6  *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
7  */
8
9 #include <linux/kernel.h>
10 #include <linux/module.h> 
11 #include <linux/init.h>
12 #include <linux/slab.h>
13 #include <linux/cpufreq.h>
14
15 #include <asm/msr.h>
16 #include <asm/processor.h>
17 #include <asm/timex.h>
18
19 static struct cpufreq_driver    longrun_driver;
20
21 /**
22  * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz 
23  * values into per cent values. In TMTA microcode, the following is valid:
24  * performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
25  */
26 static unsigned int longrun_low_freq, longrun_high_freq;
27
28
29 /**
30  * longrun_get_policy - get the current LongRun policy
31  * @policy: struct cpufreq_policy where current policy is written into
32  *
33  * Reads the current LongRun policy by access to MSR_TMTA_LONGRUN_FLAGS
34  * and MSR_TMTA_LONGRUN_CTRL
35  */
36 static void longrun_get_policy(struct cpufreq_policy *policy)
37 {
38         u32 msr_lo, msr_hi;
39
40         rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi);
41         if (msr_lo & 0x01)
42                 policy->policy = CPUFREQ_POLICY_PERFORMANCE;
43         else
44                 policy->policy = CPUFREQ_POLICY_POWERSAVE;
45         
46         rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
47         msr_lo &= 0x0000007F;
48         msr_hi &= 0x0000007F;
49
50         policy->min = longrun_low_freq + msr_lo * 
51                 ((longrun_high_freq - longrun_low_freq) / 100);
52         policy->max = longrun_low_freq + msr_hi * 
53                 ((longrun_high_freq - longrun_low_freq) / 100);
54         policy->cpu = 0;
55 }
56
57
58 /**
59  * longrun_set_policy - sets a new CPUFreq policy
60  * @policy - new policy
61  *
62  * Sets a new CPUFreq policy on LongRun-capable processors. This function
63  * has to be called with cpufreq_driver locked.
64  */
65 static int longrun_set_policy(struct cpufreq_policy *policy)
66 {
67         u32 msr_lo, msr_hi;
68         u32 pctg_lo, pctg_hi;
69
70         if (!policy)
71                 return -EINVAL;
72
73         pctg_lo = (policy->min - longrun_low_freq) / 
74                 ((longrun_high_freq - longrun_low_freq) / 100);
75         pctg_hi = (policy->max - longrun_low_freq) / 
76                 ((longrun_high_freq - longrun_low_freq) / 100);
77
78         if (pctg_hi > 100)
79                 pctg_hi = 100;
80         if (pctg_lo > pctg_hi)
81                 pctg_lo = pctg_hi;
82
83         /* performance or economy mode */
84         rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi);
85         msr_lo &= 0xFFFFFFFE;
86         switch (policy->policy) {
87         case CPUFREQ_POLICY_PERFORMANCE:
88                 msr_lo |= 0x00000001;
89                 break;
90         case CPUFREQ_POLICY_POWERSAVE:
91                 break;
92         }
93         wrmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi);
94
95         /* lower and upper boundary */
96         rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
97         msr_lo &= 0xFFFFFF80;
98         msr_hi &= 0xFFFFFF80;
99         msr_lo |= pctg_lo;
100         msr_hi |= pctg_hi;
101         wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
102
103         return 0;
104 }
105
106
107 /**
108  * longrun_verify_poliy - verifies a new CPUFreq policy
109  *
110  * Validates a new CPUFreq policy. This function has to be called with 
111  * cpufreq_driver locked.
112  */
113 static int longrun_verify_policy(struct cpufreq_policy *policy)
114 {
115         if (!policy)
116                 return -EINVAL;
117
118         policy->cpu = 0;
119         cpufreq_verify_within_limits(policy, 
120                 policy->cpuinfo.min_freq, 
121                 policy->cpuinfo.max_freq);
122
123         if (policy->policy == CPUFREQ_POLICY_GOVERNOR)
124                 return -EINVAL;
125
126         return 0;
127 }
128
129
130 /**
131  * longrun_determine_freqs - determines the lowest and highest possible core frequency
132  *
133  * Determines the lowest and highest possible core frequencies on this CPU.
134  * This is necessary to calculate the performance percentage according to
135  * TMTA rules:
136  * performance_pctg = (target_freq - low_freq)/(high_freq - low_freq)
137  */
138 static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, 
139                                                    unsigned int *high_freq)
140 {
141         u32 msr_lo, msr_hi;
142         u32 save_lo, save_hi;
143         u32 eax, ebx, ecx, edx;
144         struct cpuinfo_x86 *c = cpu_data;
145
146         if (!low_freq || !high_freq)
147                 return -EINVAL;
148
149         if (cpu_has(c, X86_FEATURE_LRTI)) {
150                 /* if the LongRun Table Interface is present, the
151                  * detection is a bit easier: 
152                  * For minimum frequency, read out the maximum
153                  * level (msr_hi), write that into "currently 
154                  * selected level", and read out the frequency.
155                  * For maximum frequency, read out level zero.
156                  */
157                 /* minimum */
158                 rdmsr(MSR_TMTA_LRTI_READOUT, msr_lo, msr_hi);
159                 wrmsr(MSR_TMTA_LRTI_READOUT, msr_hi, msr_hi);
160                 rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi);
161                 *low_freq = msr_lo * 1000; /* to kHz */
162
163                 /* maximum */
164                 wrmsr(MSR_TMTA_LRTI_READOUT, 0, msr_hi);
165                 rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi);
166                 *high_freq = msr_lo * 1000; /* to kHz */
167
168                 if (*low_freq > *high_freq)
169                         *low_freq = *high_freq;
170                 return 0;
171         }
172
173         /* set the upper border to the value determined during TSC init */
174         *high_freq = (cpu_khz / 1000);
175         *high_freq = *high_freq * 1000;
176
177         /* get current borders */
178         rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
179         save_lo = msr_lo & 0x0000007F;
180         save_hi = msr_hi & 0x0000007F;
181
182         /* if current perf_pctg is larger than 90%, we need to decrease the
183          * upper limit to make the calculation more accurate.
184          */
185         cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
186         if (ecx > 90) {
187                 /* set to 0 to 80 perf_pctg */
188                 msr_lo &= 0xFFFFFF80;
189                 msr_hi &= 0xFFFFFF80;
190                 msr_lo |= 0;
191                 msr_hi |= 80;
192                 wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
193
194                 /* read out current core MHz and current perf_pctg */
195                 cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
196
197                 /* restore values */
198                 wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi); 
199         }
200
201         /* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
202          * eqals
203          * low_freq * ( 1 - perf_pctg) = (cur_freq - high_freq * perf_pctg)
204          *
205          * high_freq * perf_pctg is stored tempoarily into "ebx".
206          */
207         ebx = (((cpu_khz / 1000) * ecx) / 100); /* to MHz */
208
209         if ((ecx > 95) || (ecx == 0) || (eax < ebx))
210                 return -EIO;
211
212         edx = (eax - ebx) / (100 - ecx); 
213         *low_freq = edx * 1000; /* back to kHz */
214
215         if (*low_freq > *high_freq)
216                 *low_freq = *high_freq;
217
218         return 0;
219 }
220
221
222 static int longrun_cpu_init(struct cpufreq_policy *policy)
223 {
224         int                     result = 0;
225
226         /* capability check */
227         if (policy->cpu != 0)
228                 return -ENODEV;
229
230         /* detect low and high frequency */
231         result = longrun_determine_freqs(&longrun_low_freq, &longrun_high_freq);
232         if (result)
233                 return result;
234
235         /* cpuinfo and default policy values */
236         policy->cpuinfo.min_freq = longrun_low_freq;
237         policy->cpuinfo.max_freq = longrun_high_freq;
238         policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
239         longrun_get_policy(policy);
240         
241         return 0;
242 }
243
244
245 static struct cpufreq_driver longrun_driver = {
246         .verify         = longrun_verify_policy,
247         .setpolicy      = longrun_set_policy,
248         .init           = longrun_cpu_init,
249         .name           = "longrun",
250         .owner          = THIS_MODULE,
251 };
252
253
254 /**
255  * longrun_init - initializes the Transmeta Crusoe LongRun CPUFreq driver
256  *
257  * Initializes the LongRun support.
258  */
259 static int __init longrun_init(void)
260 {
261         struct cpuinfo_x86 *c = cpu_data;
262
263         if (c->x86_vendor != X86_VENDOR_TRANSMETA || 
264             !cpu_has(c, X86_FEATURE_LONGRUN))
265                 return -ENODEV;
266
267         return cpufreq_register_driver(&longrun_driver);
268 }
269
270
271 /**
272  * longrun_exit - unregisters LongRun support
273  */
274 static void __exit longrun_exit(void)
275 {
276         cpufreq_unregister_driver(&longrun_driver);
277 }
278
279
280 MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
281 MODULE_DESCRIPTION ("LongRun driver for Transmeta Crusoe processors.");
282 MODULE_LICENSE ("GPL");
283
284 module_init(longrun_init);
285 module_exit(longrun_exit);