define SDT/SDM_COPY to simplify copying plain bytes in structs.
[AROS.git] / arch / all-pc / processor / processor_frequency.c
blobe93daabf8697cd2f7e5e6618b23ea1609194ccc4
1 /*
2 Copyright © 2010-2017, 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", __func__));
44 ssp = SuperState();
46 /* Procedure for Pentium 4 family (NetBurst) */
47 if ((info->Family == CPUFAMILY_INTEL_PENTIUM4) && (info->Model >= 2))
49 ULONG eax, edx;
50 UQUAD fsb = 0;
51 ULONG mult = 0;
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
60 Table B-12 */
61 switch((eax >> 16) & 0x07)
63 case(0):
64 if (info->Model == 2)
65 fsb = FSB_100;
66 else
67 fsb = FSB_266;
68 break;
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 */
77 mult = eax >> 24;
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 */
91 ULONG eax, edx;
92 ULONG mult = 0;
94 /*Intel 64 and IA-32 Architectures
95 Software Developer's Manual
96 Volume 3B:System Programming Guide, Part 2
97 Table B-16 */
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 */
118 ULONG eax, edx;
119 UQUAD fsb = 0;
120 ULONG mult = 0;
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
129 Table B-3 */
130 switch(eax & 0x07)
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) /* ? */
160 ULONG mult = 0;
162 /* This procedure calculates the maximum frequency */
163 mult = rdmsri(MSR_NAHALEM_PLATFORM_INFO);
165 /*Intel 64 and IA-32 Architectures
166 Software Developer's Manual
167 Volume 3B:System Programming Guide, Part 2
168 Table B-5 */
169 mult = (mult >> 8) & 0xFF;
171 info->MaxCPUFrequency = FSB_133 * mult;
172 /* Note: FSB is not a valid concept with iX (Nahalem) processors */
173 info->MaxFSBFrequency = 0;
176 /* Procedure for SandyBridge and newer (part of Pentium Pro) family (i7, i5, i3) */
177 if ((info->Family == CPUFAMILY_INTEL_PENTIUM_PRO) &&
179 (info->Model == 0x2A) || /* SandyBridge */
180 (info->Model == 0x2D) || /* SandyBridge */
181 (info->Model == 0x3A) || /* IvyBridge */
182 (info->Model == 0x3C) || /* Haswell */
183 (info->Model == 0x45) || /* Haswell */
184 (info->Model == 0x46) || /* Haswell */
185 (info->Model == 0x3F) /* Haswell-E */
186 /* More to come... */
190 ULONG mult = 0;
192 /* This procedure calculates the maximum frequency */
193 mult = rdmsri(MSR_NAHALEM_PLATFORM_INFO);
195 /*Intel 64 and IA-32 Architectures
196 Software Developer's Manual
197 Volume 3B:System Programming Guide, Part 2
198 Table B-5 */
199 mult = (mult >> 8) & 0xFF;
201 info->MaxCPUFrequency = FSB_100 * mult;
202 /* Note: FSB is not a valid concept with iX (Nahalem) processors */
203 info->MaxFSBFrequency = 0;
206 UserState(ssp);
209 static VOID ReadAMDMaxFrequencyInformation(struct X86ProcessorInformation * info)
211 APTR ssp;
213 D(bug("[processor.x86] :%s()\n", __func__));
215 ssp = SuperState();
217 if (info->Family == CPUFAMILY_AMD_K10)
219 ULONG eax, edx;
220 ULONG cpufid = 0, cpudid = 0;
222 /* AMD Family 10h Processor BKDG, page 425 */
223 rdmsr(MSR_K10_PSTATE_P0, &eax, &edx);
225 cpufid = eax & 0x1F;
226 cpudid = (eax >> 6) & 0x07;
228 info->MaxCPUFrequency = FSB_100 * (cpufid + 0x10) / (1 << cpudid);
229 /* Note: FSB is not a valid concept with K10 processors */
230 info->MaxFSBFrequency = 0;
233 if ((info->Family == CPUFAMILY_AMD_K9)
234 || (info->Family == CPUFAMILY_AMD_K8))
236 ULONG eax, ebx, ecx, edx;
237 ULONG cpufid = 0;
238 BOOL success = TRUE;
240 /* BIOS and Kernel Developer's Guide for the AMD AthlonTM 64 and
241 AMD OpteronTM Processors, page 382 */
243 /* Check for power management features */
244 if (info->CPUIDHighestExtendedFunction < 0x80000007)
245 success = FALSE;
247 if (success)
249 cpuid(0x80000007);
251 /* Check avalability of FID */
252 if ((edx & 0x02) == 0)
253 success = FALSE;
256 if (success)
258 /* It should be safe to read MSR_K8_FIDVID_STATUS */
259 rdmsr(MSR_K8_FIDVID_STATUS, &eax, &edx);
261 cpufid = (eax >> 16) & 0x3F;
263 /* Note: K8 has only even multipliers, but they match K9 ones */
264 info->MaxCPUFrequency = FSB_200 * (4 * 2 + cpufid) / 2;
266 /* Note: FSB is not a valid concept with K8, K9 processors */
267 info->MaxFSBFrequency = 0;
271 UserState(ssp);
274 #endif /* AROS_FLAVOUR_STANDALONE */
276 VOID ReadMaxFrequencyInformation(struct X86ProcessorInformation * info)
278 D(bug("[processor.x86] :%s()\n", __func__));
280 info->MaxCPUFrequency = 0;
281 info->MaxFSBFrequency = 0;
283 #if (AROS_FLAVOUR & AROS_FLAVOUR_STANDALONE)
285 switch(info->Vendor)
287 case(VENDOR_INTEL):
288 ReadIntelMaxFrequencyInformation(info);
289 break;
290 case(VENDOR_AMD):
291 ReadAMDMaxFrequencyInformation(info);
292 break;
293 default:
294 break;
297 #endif
300 /* Currently the only method of calculating CPU Frequency is based on
301 using performance counter. Other methods might include reading power state
302 and checking with ACPI power tables or hardcoded power tables */
304 UQUAD GetCurrentProcessorFrequency(struct X86ProcessorInformation * info)
306 UQUAD retFreq = info->MaxCPUFrequency;
308 D(bug("[processor.x86] :%s()\n", __func__));
310 #if (AROS_FLAVOUR & AROS_FLAVOUR_STANDALONE)
313 Check if APERF/MPERF is available
314 Notes: K10, K9 - rdmsr can be used to read current PState/cpufid/cpudid
316 if (info->APERFMPERF)
318 APTR ssp;
319 ULONG eax, edx;
320 UQUAD startaperf, endaperf, diffaperf = 0;
321 UQUAD startmperf, endmperf, diffmperf = 0;
322 LONG i;
324 ssp = SuperState();
326 for(i = 0; i < 10; i++)
328 rdmsr(MSR_IA32_MPERF, &eax, &edx);
329 startmperf = (UQUAD)edx << 32 | eax;
330 rdmsr(MSR_IA32_APERF, &eax, &edx);
331 startaperf = (UQUAD)edx << 32 | eax;
333 rdmsr(MSR_IA32_MPERF, &eax, &edx);
334 endmperf = (UQUAD)edx << 32 | eax;
335 rdmsr(MSR_IA32_APERF, &eax, &edx);
336 endaperf = (UQUAD)edx << 32 | eax;
338 if ((startmperf > endmperf) || (startaperf > endaperf))
339 continue; /* Overflow error. Skip */
341 diffmperf += endmperf - startmperf;
342 diffaperf += endaperf - startaperf;
345 UserState(ssp);
347 D(bug("[processor.x86] %s: max: %x, diffa: %x, diffm %x\n", __func__, info->MaxCPUFrequency, diffaperf, diffmperf));
349 if (info->MaxCPUFrequency == 0)
350 ReadMaxFrequencyInformation(info);
352 /* Use ratio between MPERF and APERF */
353 if (diffmperf)
354 retFreq = info->MaxCPUFrequency * diffaperf / diffmperf;
355 else
356 retFreq = info->MaxCPUFrequency;
358 else
360 /* use PStates? */
363 #endif
365 return retFreq;