2 Copyright © 2010-2014, The AROS Development Team. All rights reserved.
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
)
42 D(bug("[processor.x86] :%s()\n", __PRETTY_FUNCTION__
));
46 /* Procedure for Pentium 4 family (NetBurst) */
47 if ((info
->Family
== CPUFAMILY_INTEL_PENTIUM4
) && (info
->Model
>= 2))
53 /* This procedure calculates the maximum frequency */
55 rdmsr(MSR_P4_EBC_FREQUENCY_ID
, &eax
, &edx
);
57 /*Intel 64 and IA-32 Architectures
58 Software Developer's Manual
59 Volume 3B:System Programming Guide, Part 2
61 switch((eax
>> 16) & 0x07)
69 case(1): fsb
= FSB_133
; break;
70 case(2): fsb
= FSB_200
; break;
71 case(3): fsb
= FSB_166
; break;
72 case(4): fsb
= FSB_333
; break;
73 default: fsb
= 0; break;
76 /* Getting multiplier at reset time */
79 info
->MaxCPUFrequency
= fsb
* mult
;
80 info
->MaxFSBFrequency
= fsb
* 4;
83 /* Procedure for Pentium M (part of Pentium Pro) family */
84 if ((info
->Family
== CPUFAMILY_INTEL_PENTIUM_PRO
) &&
86 (info
->Model
== 0x09) || /* Pentium M */
87 (info
->Model
== 0x0D) /* Pentium M */
94 /*Intel 64 and IA-32 Architectures
95 Software Developer's Manual
96 Volume 3B:System Programming Guide, Part 2
99 rdmsr(MSR_CORE_EBL_CR_POWERON
, &eax
, &edx
);
101 mult
= (eax
>> 22) & 0x1F;
103 info
->MaxCPUFrequency
= FSB_100
* mult
;
104 info
->MaxFSBFrequency
= FSB_100
* 4;
107 /* Procedure for Core (part of Pentium Pro) family (ATOM, Core, Core Duo) */
108 if ((info
->Family
== CPUFAMILY_INTEL_PENTIUM_PRO
) &&
110 (info
->Model
== 0x0E) || /* Core Duo */
111 (info
->Model
== 0x0F) || /* Core 2 Duo */
112 (info
->Model
== 0x16) || /* Core Celeron */
113 (info
->Model
== 0x17) || /* Core 2 Extreme */
114 (info
->Model
== 0x1C) /* ATOM */
122 /* This procedure calculates the maximum frequency */
124 rdmsr(MSR_CORE_FSB_FREQ
, &eax
, &edx
);
126 /*Intel 64 and IA-32 Architectures
127 Software Developer's Manual
128 Volume 3B:System Programming Guide, Part 2
132 case(5): fsb
= FSB_100
; break;
133 case(1): fsb
= FSB_133
; break;
134 case(3): fsb
= FSB_166
; break;
135 case(2): fsb
= FSB_200
; break;
136 case(0): fsb
= FSB_266
; break;
137 case(4): fsb
= FSB_333
; break;
138 case(6): fsb
= FSB_400
; break;
139 default: fsb
= 0; break;
142 rdmsr(MSR_CORE_EBL_CR_POWERON
, &eax
, &edx
);
143 /* Getting multiplier at reset time */
144 mult
= (eax
>> 22) & 0x1F;
146 info
->MaxCPUFrequency
= fsb
* mult
;
147 info
->MaxFSBFrequency
= fsb
* 4;
150 /* Procedure for Nahalem (part of Pentium Pro) family (i7, i5, i3) */
151 if ((info
->Family
== CPUFAMILY_INTEL_PENTIUM_PRO
) &&
153 (info
->Model
== 0x1A) || /* Core i7 */
154 (info
->Model
== 0x1E) || /* ? */
155 (info
->Model
== 0x1F) || /* ? */
156 (info
->Model
== 0x2E) /* ? */
163 /* This procedure calculates the maximum frequency */
165 rdmsr(MSR_NAHALEM_PLATFORM_INFO
, &eax
, &edx
);
167 /*Intel 64 and IA-32 Architectures
168 Software Developer's Manual
169 Volume 3B:System Programming Guide, Part 2
171 mult
= (eax
>> 8) & 0xFF;
173 info
->MaxCPUFrequency
= FSB_133
* mult
;
174 /* Note: FSB is not a valid concept with iX (Nahalem) processors */
175 info
->MaxFSBFrequency
= 0;
181 static VOID
ReadAMDMaxFrequencyInformation(struct X86ProcessorInformation
* info
)
185 D(bug("[processor.x86] :%s()\n", __PRETTY_FUNCTION__
));
189 if (info
->Family
== CPUFAMILY_AMD_K10
)
192 ULONG cpufid
= 0, cpudid
= 0;
194 /* AMD Family 10h Processor BKDG, page 425 */
195 rdmsr(MSR_K10_PSTATE_P0
, &eax
, &edx
);
198 cpudid
= (eax
>> 6) & 0x07;
200 info
->MaxCPUFrequency
= FSB_100
* (cpufid
+ 0x10) / (1 << cpudid
);
201 /* Note: FSB is not a valid concept with K10 processors */
202 info
->MaxFSBFrequency
= 0;
205 if ((info
->Family
== CPUFAMILY_AMD_K9
)
206 || (info
->Family
== CPUFAMILY_AMD_K8
))
208 ULONG eax
, ebx
, ecx
, edx
;
212 /* BIOS and Kernel Developer's Guide for the AMD AthlonTM 64 and
213 AMD OpteronTM Processors, page 382 */
215 /* Check for power management features */
216 if (info
->CPUIDHighestExtendedFunction
< 0x80000007)
223 /* Check avalability of FID */
224 if ((edx
& 0x02) == 0)
230 /* It should be safe to read MSR_K8_FIDVID_STATUS */
231 rdmsr(MSR_K8_FIDVID_STATUS
, &eax
, &edx
);
233 cpufid
= (eax
>> 16) & 0x3F;
235 /* Note: K8 has only even multipliers, but they match K9 ones */
236 info
->MaxCPUFrequency
= FSB_200
* (4 * 2 + cpufid
) / 2;
238 /* Note: FSB is not a valid concept with K8, K9 processors */
239 info
->MaxFSBFrequency
= 0;
246 #endif /* AROS_FLAVOUR_STANDALONE */
248 VOID
ReadMaxFrequencyInformation(struct X86ProcessorInformation
* info
)
250 D(bug("[processor.x86] :%s()\n", __PRETTY_FUNCTION__
));
252 info
->MaxCPUFrequency
= 0;
253 info
->MaxFSBFrequency
= 0;
255 #if (AROS_FLAVOUR & AROS_FLAVOUR_STANDALONE)
260 ReadIntelMaxFrequencyInformation(info
);
263 ReadAMDMaxFrequencyInformation(info
);
272 /* Currently the only method of calculating CPU Frequency is based on
273 using performance counter. Other methods might include reading power state
274 and checking with ACPI power tables or hardcoded power tables */
276 UQUAD
GetCurrentProcessorFrequency(struct X86ProcessorInformation
* info
)
278 UQUAD retFreq
= info
->MaxCPUFrequency
;
280 D(bug("[processor.x86] :%s()\n", __PRETTY_FUNCTION__
));
282 #if (AROS_FLAVOUR & AROS_FLAVOUR_STANDALONE)
285 Check if APERF/MPERF is available
286 Notes: K10, K9 - rdmsr can be used to read current PState/cpufid/cpudid
288 if (info
->APERFMPERF
)
292 UQUAD startaperf
, endaperf
, diffaperf
= 0;
293 UQUAD startmperf
, endmperf
, diffmperf
= 0;
298 for(i
= 0; i
< 10; i
++)
300 rdmsr(MSR_IA32_MPERF
, &eax
, &edx
);
301 startmperf
= (UQUAD
)edx
<< 32 | eax
;
302 rdmsr(MSR_IA32_APERF
, &eax
, &edx
);
303 startaperf
= (UQUAD
)edx
<< 32 | eax
;
305 rdmsr(MSR_IA32_MPERF
, &eax
, &edx
);
306 endmperf
= (UQUAD
)edx
<< 32 | eax
;
307 rdmsr(MSR_IA32_APERF
, &eax
, &edx
);
308 endaperf
= (UQUAD
)edx
<< 32 | eax
;
310 if ((startmperf
> endmperf
) || (startaperf
> endaperf
))
311 continue; /* Overflow error. Skip */
313 diffmperf
+= endmperf
- startmperf
;
314 diffaperf
+= endaperf
- startaperf
;
319 D(bug("[processor.x86] %s: max: %x, diffa: %x, diffm %x\n", __PRETTY_FUNCTION__
, info
->MaxCPUFrequency
, diffaperf
, diffmperf
));
321 /* Use ratio between MPERF and APERF */
323 retFreq
= info
->MaxCPUFrequency
* diffaperf
/ diffmperf
;
325 retFreq
= info
->MaxCPUFrequency
;