All block numbers are UQUADs. Improves large disk support.
[AROS.git] / arch / x86-all / processor / processor_frequency.c
blobacd6260a91691621b7a9f78f78d99af8e44d83eb
1 /*
2 Copyright © 2010-2011, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define DEBUG 0
8 #include <aros/config.h>
9 #include <aros/debug.h>
10 #include <proto/exec.h>
11 #include <resources/processor.h>
13 #include "processor_arch_intern.h"
16 * This code can't work on hosted because rdmsr instruction requires supervisor privilege.
17 * Hosted ports could have host-specific version of this code which would utilize host OS services.
19 #if (AROS_FLAVOUR & AROS_FLAVOUR_STANDALONE)
21 #define MSR_IA32_MPERF 0xE7
22 #define MSR_IA32_APERF 0xE8
23 #define MSR_P4_EBC_FREQUENCY_ID 0x2C
24 #define MSR_CORE_FSB_FREQ 0xCD
25 #define MSR_CORE_EBL_CR_POWERON 0x2A
26 #define MSR_NAHALEM_PLATFORM_INFO 0xCE
27 #define MSR_K10_PSTATE_P0 0xC0010064
28 #define MSR_K8_FIDVID_STATUS 0xC0010042
30 #define FSB_100 100000000ULL
31 #define FSB_133 133330000ULL
32 #define FSB_166 166670000ULL
33 #define FSB_200 200000000ULL
34 #define FSB_266 266670000ULL
35 #define FSB_333 333330000ULL
36 #define FSB_400 400000000ULL
38 static VOID ReadIntelMaxFrequencyInformation(struct X86ProcessorInformation * info)
40 APTR ssp;
42 D(bug("[processor.x86] :%s()\n", __PRETTY_FUNCTION__));
44 ssp = SuperState();
46 /* Procedure for Pentium 4 family (NetBurst) */
47 if (info->Family == CPUFAMILY_INTEL_PENTIUM4)
49 ULONG eax, edx;
50 UQUAD fsb = 0;
51 ULONG mult = 0;
53 /* Works only on model >= 2 */
54 if (info->Model < 2)
55 return;
57 /* This procesure calculates the maximum frequency */
59 rdmsr(MSR_P4_EBC_FREQUENCY_ID, &eax, &edx);
61 /*Intel 64 and IA-32 Architectures
62 Software Developer's Manual
63 Volume 3B:System Programming Guide, Part 2
64 Table B-12 */
65 switch((eax >> 16) & 0x07)
67 case(0):
68 if (info->Model == 2)
69 fsb = FSB_100;
70 else
71 fsb = FSB_266;
72 break;
73 case(1): fsb = FSB_133; break;
74 case(2): fsb = FSB_200; break;
75 case(3): fsb = FSB_166; break;
76 case(4): fsb = FSB_333; break;
77 default: fsb = 0; break;
80 /* Getting multiplier at reset time */
81 mult = eax >> 24;
83 info->MaxCPUFrequency = fsb * mult;
84 info->MaxFSBFrequency = fsb * 4;
87 /* Procedure for Pentium M (part of Pentium Pro) family */
88 if ((info->Family == CPUFAMILY_INTEL_PENTIUM_PRO) &&
90 (info->Model == 0x09) | /* Pentium M */
91 (info->Model == 0x0D) /* Pentium M */
95 ULONG eax, edx;
96 ULONG mult = 0;
98 /*Intel 64 and IA-32 Architectures
99 Software Developer's Manual
100 Volume 3B:System Programming Guide, Part 2
101 Table B-16 */
103 rdmsr(MSR_CORE_EBL_CR_POWERON, &eax, &edx);
105 mult = (eax >> 22) & 0x1F;
107 info->MaxCPUFrequency = FSB_100 * mult;
108 info->MaxFSBFrequency = FSB_100 * 4;
111 /* Procedure for Core (part of Pentium Pro) family (ATOM, Core, Core Duo) */
112 if ((info->Family == CPUFAMILY_INTEL_PENTIUM_PRO) &&
114 (info->Model == 0x0E) | /* Core Duo */
115 (info->Model == 0x0F) | /* Core 2 Duo */
116 (info->Model == 0x16) | /* Core Celeron */
117 (info->Model == 0x17) | /* Core 2 Extreeme */
118 (info->Model == 0x1C) /* ATOM */
122 ULONG eax, edx;
123 UQUAD fsb = 0;
124 ULONG mult = 0;
126 /* This procesure calculates the maximum frequency */
128 rdmsr(MSR_CORE_FSB_FREQ, &eax, &edx);
130 /*Intel 64 and IA-32 Architectures
131 Software Developer's Manual
132 Volume 3B:System Programming Guide, Part 2
133 Table B-3 */
134 switch(eax & 0x07)
136 case(5): fsb = FSB_100; break;
137 case(1): fsb = FSB_133; break;
138 case(3): fsb = FSB_166; break;
139 case(2): fsb = FSB_200; break;
140 case(0): fsb = FSB_266; break;
141 case(4): fsb = FSB_333; break;
142 case(6): fsb = FSB_400; break;
143 default: fsb = 0; break;
146 rdmsr(MSR_CORE_EBL_CR_POWERON, &eax, &edx);
147 /* Getting multiplier at reset time */
148 mult = (eax >> 22) & 0x1F;
150 info->MaxCPUFrequency = fsb * mult;
151 info->MaxFSBFrequency = fsb * 4;
154 /* Procedure for Nahalem (part of Pentium Pro) family (i7, i5, i3) */
155 if ((info->Family == CPUFAMILY_INTEL_PENTIUM_PRO) &&
157 (info->Model == 0x1A) | /* Core i7 */
158 (info->Model == 0x1E) | /* ? */
159 (info->Model == 0x1F) | /* ? */
160 (info->Model == 0x2E) /* ? */
164 ULONG eax, edx;
165 ULONG mult = 0;
167 /* This procesure calculates the maximum frequency */
169 rdmsr(MSR_NAHALEM_PLATFORM_INFO, &eax, &edx);
171 /*Intel 64 and IA-32 Architectures
172 Software Developer's Manual
173 Volume 3B:System Programming Guide, Part 2
174 Table B-5 */
175 mult = (eax >> 8) & 0xFF;
177 info->MaxCPUFrequency = FSB_133 * mult;
178 /* Note: FSB is not a valid concept with iX (Nahalem) processors */
179 info->MaxFSBFrequency = 0;
182 UserState(ssp);
185 static VOID ReadAMDMaxFrequencyInformation(struct X86ProcessorInformation * info)
187 APTR ssp;
189 D(bug("[processor.x86] :%s()\n", __PRETTY_FUNCTION__));
191 ssp = SuperState();
193 if (info->Family == CPUFAMILY_AMD_K10)
195 ULONG eax, edx;
196 ULONG cpufid = 0, cpudid = 0;
198 /* AMD Family 10h Processor BKDG, page 425 */
199 rdmsr(MSR_K10_PSTATE_P0, &eax, &edx);
201 cpufid = eax & 0x1F;
202 cpudid = (eax >> 6) & 0x07;
204 info->MaxCPUFrequency = FSB_100 * (cpufid + 0x10) / (1 << cpudid);
205 /* Note: FSB is not a valid concept with K10 processors */
206 info->MaxFSBFrequency = 0;
209 if ((info->Family == CPUFAMILY_AMD_K9) || (info->Family == CPUFAMILY_AMD_K8))
211 ULONG eax, ebx, ecx, edx;
212 ULONG cpufid = 0;
214 /* BIOS and Kernel Developer's Guide for the AMD AthlonTM 64 and
215 AMD OpteronTM Processors, page 382 */
217 /* Check for power management features */
218 if (info->CPUIDHighestExtendedFunction < 0x80000007)
219 return;
221 cpuid(0x80000007);
223 /* Check avalability of FID */
224 if ((edx & 0x02) == 0)
225 return;
227 /* It should be safe to read MSR_K8_FIDVID_STATUS */
228 rdmsr(MSR_K8_FIDVID_STATUS, &eax, &edx);
230 cpufid = (eax >> 16) & 0x3F;
232 /* Note: K8 has only even multipliers, but they match K9 ones */
233 info->MaxCPUFrequency = FSB_200 * (4 * 2 + cpufid) / 2;
235 /* Note: FSB is not a valid concept with K8, K9 processors */
236 info->MaxFSBFrequency = 0;
239 UserState(ssp);
242 #endif /* AROS_FLAVOUR_STANDALONE */
244 VOID ReadMaxFrequencyInformation(struct X86ProcessorInformation * info)
246 D(bug("[processor.x86] :%s()\n", __PRETTY_FUNCTION__));
248 info->MaxCPUFrequency = 0;
249 info->MaxFSBFrequency = 0;
251 #if (AROS_FLAVOUR & AROS_FLAVOUR_STANDALONE)
253 switch(info->Vendor)
255 case(VENDOR_INTEL):
256 ReadIntelMaxFrequencyInformation(info);
257 break;
258 case(VENDOR_AMD):
259 ReadAMDMaxFrequencyInformation(info);
260 break;
261 default:
262 break;
265 #endif
268 /* Currently the only method of calculating CPU Frequency is based on
269 using performance counter. Other methods might include reading power state
270 and checking with ACPI power tables or hardcoded power tables */
272 UQUAD GetCurrentProcessorFrequency(struct X86ProcessorInformation * info)
274 UQUAD retFreq = info->MaxCPUFrequency;
276 D(bug("[processor.x86] :%s()\n", __PRETTY_FUNCTION__));
278 #if (AROS_FLAVOUR & AROS_FLAVOUR_STANDALONE)
281 Check if APERF/MPERF is available
282 Notes: K10, K9 - rdmsr can be used to read current PState/cpufid/cpudid
284 if (info->APERFMPERF)
286 APTR ssp;
287 ULONG eax, edx;
288 UQUAD startaperf, endaperf, diffaperf = 0;
289 UQUAD startmperf, endmperf, diffmperf = 0;
290 LONG i;
292 ssp = SuperState();
294 for(i = 0; i < 10; i++)
296 rdmsr(MSR_IA32_MPERF, &eax, &edx);
297 startmperf = (UQUAD)edx << 32 | eax;
298 rdmsr(MSR_IA32_APERF, &eax, &edx);
299 startaperf = (UQUAD)edx << 32 | eax;
301 rdmsr(MSR_IA32_MPERF, &eax, &edx);
302 endmperf = (UQUAD)edx << 32 | eax;
303 rdmsr(MSR_IA32_APERF, &eax, &edx);
304 endaperf = (UQUAD)edx << 32 | eax;
306 if ((startmperf > endmperf) || (startaperf > endaperf))
307 continue; /* Overflow error. Skip */
309 diffmperf += endmperf - startmperf;
310 diffaperf += endaperf - startaperf;
313 UserState(ssp);
315 D(bug("[processor.x86] %s: max: %x, diffa: %x, diffm %x\n", __PRETTY_FUNCTION__, info->MaxCPUFrequency, diffaperf, diffmperf));
317 /* Use ratio between MPERF and APERF */
318 if (diffmperf)
319 retFreq = info->MaxCPUFrequency * diffaperf / diffmperf;
320 else
321 retFreq = info->MaxCPUFrequency;
323 else
325 /* use PStates ?*/
328 #endif
330 return retFreq;