1 | /*␊ |
2 | * Copyright 2010,2011,2012 valv, cparm <armelcadetpetit@gmail.com>. All rights reserved.␊ |
3 | */␊ |
4 | #include "libsaio.h"␊ |
5 | #include "bootstruct.h"␊ |
6 | #include "modules.h"␊ |
7 | #include "Platform.h"␊ |
8 | #include "cpu.h"␊ |
9 | ␊ |
10 | #define kFixFSB␉␉ "FixFSB"␊ |
11 | #define MSR_FSB_FREQ␉␉0x000000cd␊ |
12 | #define AMD_10H_11H_CONFIG 0xc0010064␊ |
13 | #define kEnableCPUfreq␉"EnableCPUfreqModule"␊ |
14 | void CPUfreq_hook(void* arg1, void* arg2, void* arg3, void* arg4, void* arg5, void* arg6);␊ |
15 | ␊ |
16 | void CPUfreq_hook(void* arg1, void* arg2, void* arg3, void* arg4, void* arg5, void* arg6)␊ |
17 | {␉␊ |
18 | ␉int bus_ratio;␉␉␉␉ ␊ |
19 | ␉uint64_t␉msr , fsbFrequency , cpuFrequency , minfsb , maxfsb ;␊ |
20 | ␊ |
21 | uint8_t Model = (uint8_t)get_env(envModel);␉␉␉␊ |
22 | uint32_t␉␉Vendor = (uint32_t)get_env(envVendor);␉␉␉␊ |
23 | uint8_t Family = (uint8_t)get_env(envFamily);␊ |
24 | ␊ |
25 | uint8_t MaxCoef = (uint8_t)get_env(envMaxCoef);␊ |
26 | uint8_t MaxDiv = (uint8_t)get_env(envMaxDiv);␊ |
27 | uint8_t CurrDiv = (uint8_t)get_env(envCurrDiv);␊ |
28 | uint64_t FSBFrequency = get_env(envFSBFreq);␊ |
29 | uint8_t CurrCoef = (uint8_t)get_env(envCurrCoef);␊ |
30 | uint64_t CPUFrequency = get_env(envCPUFreq);␊ |
31 | ␊ |
32 | ␊ |
33 | ␉if ((Vendor == CPUID_VENDOR_INTEL ) && ((Family == 0x06) || (Family == 0x0f)))␊ |
34 | ␉{␊ |
35 | ␉␉if ((Family == 0x06 && Model >= 0x0c) || (Family == 0x0f && Model >= 0x03))␊ |
36 | ␉␉{␊ |
37 | ␉␉␉␊ |
38 | ␉␉␉if (Family == 0x06)␊ |
39 | ␉␉␉{␊ |
40 | ␉␉␉␉␊ |
41 | ␉␉␉␉bus_ratio = 0; ␉␉␉␉␉␉␉␉ ␊ |
42 | ␉␉␉␉msr = rdmsr64(MSR_FSB_FREQ); ␊ |
43 | ␉␉␉␉minfsb = 183000000; ␊ |
44 | ␉␉␉␉maxfsb = 185000000;␊ |
45 | ␉␉␉␉␊ |
46 | ␉␉␉␉bool␉␉fix_fsb = false;␉␉␉␉␊ |
47 | ␉␉␉␉uint16_t idlo;␊ |
48 | ␉␉␉␉uint8_t crlo, crhi = 0;␉␉␉␉␊ |
49 | ␉␉␉␉␊ |
50 | ␉␉␉␉switch (Model) {␊ |
51 | ␉␉␉␉␉case CPUID_MODEL_YONAH:␉␉// Core Duo/Solo, Pentium M DC␊ |
52 | ␉␉␉␉␉case CPUID_MODEL_MEROM:␉␉// Core Xeon, Core 2 DC, 65nm␊ |
53 | ␉␉␉␉␉case 0x16:␉␉␉␉␉// Celeron, Core 2 SC, 65nm␊ |
54 | ␉␉␉␉␉case CPUID_MODEL_PENRYN:␉␉// Core 2 Duo/Extreme, Xeon, 45nm␊ |
55 | ␉␉␉␉␉case CPUID_MODEL_ATOM:␉␉// Atom :)␊ |
56 | ␉␉␉␉␉case 0x27:␉␉␉␉␉// Atom Lincroft, 45nm ␊ |
57 | ␉␉␉␉␉{␊ |
58 | ␉␉␉␉␉␉getBoolForKey(kFixFSB, &fix_fsb, DEFAULT_BOOT_CONFIG); ␊ |
59 | ␉␉␉␉␉␉␊ |
60 | ␉␉␉␉␉␉if (fix_fsb)␊ |
61 | ␉␉␉␉␉␉{␊ |
62 | ␉␉␉␉␉␉␉␊ |
63 | ␉␉␉␉␉␉␉int bus = (msr >> 0) & 0x7; ␊ |
64 | ␉␉␉␉␉␉␉switch (bus) {␊ |
65 | ␉␉␉␉␉␉␉␉case 0:␊ |
66 | ␉␉␉␉␉␉␉␉␉fsbFrequency = 266666667;␊ |
67 | ␉␉␉␉␉␉␉␉␉break;␊ |
68 | ␉␉␉␉␉␉␉␉case 1:␊ |
69 | ␉␉␉␉␉␉␉␉␉fsbFrequency = 133333333;␊ |
70 | ␉␉␉␉␉␉␉␉␉break;␊ |
71 | ␉␉␉␉␉␉␉␉case 2:␊ |
72 | ␉␉␉␉␉␉␉␉␉fsbFrequency = 200000000;␊ |
73 | ␉␉␉␉␉␉␉␉␉break;␊ |
74 | ␉␉␉␉␉␉␉␉case 3:␊ |
75 | ␉␉␉␉␉␉␉␉␉fsbFrequency = 166666667;␊ |
76 | ␉␉␉␉␉␉␉␉␉break;␊ |
77 | ␉␉␉␉␉␉␉␉case 4:␊ |
78 | ␉␉␉␉␉␉␉␉␉fsbFrequency = 333333333;␊ |
79 | ␉␉␉␉␉␉␉␉␉break;␊ |
80 | ␉␉␉␉␉␉␉␉case 5:␊ |
81 | ␉␉␉␉␉␉␉␉␉fsbFrequency = 100000000;␊ |
82 | ␉␉␉␉␉␉␉␉␉break;␊ |
83 | ␉␉␉␉␉␉␉␉case 6:␊ |
84 | ␉␉␉␉␉␉␉␉␉fsbFrequency = 400000000;␊ |
85 | ␉␉␉␉␉␉␉␉␉break;␊ |
86 | ␉␉␉␉␉␉␉␉default:␊ |
87 | ␉␉␉␉␉␉␉␉␉fsbFrequency = 200000000;␉␉␉␉␉␉␉␉␉␊ |
88 | ␉␉␉␉␉␉␉␉␉break;␊ |
89 | ␉␉␉␉␉␉␉}␊ |
90 | ␉␉␉␉␉␉␉␊ |
91 | ␉␉␉␉␉␉␉␊ |
92 | ␉␉␉␉␉␉␉if (((fsbFrequency) > (minfsb) && (fsbFrequency) < (maxfsb)) || (!fsbFrequency)) ␊ |
93 | ␉␉␉␉␉␉␉{␊ |
94 | ␉␉␉␉␉␉␉␉fsbFrequency = 200000000;␊ |
95 | ␉␉␉␉␉␉␉}␊ |
96 | safe_set_env(envFSBFreq, fsbFrequency);␊ |
97 | ␉␉␉␉␉␉}␊ |
98 | ␉␉␉␉␉␉␊ |
99 | ␉␉␉␉␉␉if (getIntForKey("MaxBusRatio", &bus_ratio, DEFAULT_BOOT_CONFIG)) ␊ |
100 | ␉␉␉␉␉␉{ ␊ |
101 | ␉␉␉␉␉␉␉msr = rdmsr64(MSR_IA32_PERF_STATUS);␊ |
102 | ␉␉␉␉␉␉␉idlo = (msr >> 48) & 0xffff;␉␉␉␉␉␉␉␉␊ |
103 | ␉␉␉␉␉␉␉crlo = (idlo >> 8) & 0xff;␊ |
104 | ␉␉␉␉␉␉␉␊ |
105 | ␉␉␉␉␉␉␉//printf("CPUfreq: MinCoef: 0x%x\n",crlo);␊ |
106 | ␊ |
107 | ␊ |
108 | ␊ |
109 | ␉␉␉␉␉␉␉if (MaxCoef) ␊ |
110 | ␉␉␉␉␉␉␉{␊ |
111 | ␉␉␉␉␉␉␉␉if (MaxDiv) ␊ |
112 | ␉␉␉␉␉␉␉␉{␊ |
113 | ␉␉␉␉␉␉␉␉␉crhi = (MaxCoef * 10) + 5;␊ |
114 | ␉␉␉␉␉␉␉␉}␊ |
115 | ␉␉␉␉␉␉␉␉else ␊ |
116 | ␉␉␉␉␉␉␉␉{␊ |
117 | ␉␉␉␉␉␉␉␉␉crhi = MaxCoef * 10;␊ |
118 | ␉␉␉␉␉␉␉␉}␊ |
119 | ␉␉␉␉␉␉␉}␊ |
120 | ␉␉␉␉␉␉␉if (crlo == 0 || crhi == crlo) goto out;␉␉␉␉␉␉␉␉␊ |
121 | ␉␉␉␉␉␉␉␊ |
122 | ␉␉␉␉␉␉␉if ((bus_ratio >= (crlo *10)) && (crhi >= bus_ratio) ) ␊ |
123 | ␉␉␉␉␉␉␉␉//if (bus_ratio >= 60) ␊ |
124 | ␉␉␉␉␉␉␉{␉␉␉␉␉␉␉␉␊ |
125 | ␉␉␉␉␉␉␉␉uint8_t currdiv = 0, currcoef = 0;␊ |
126 | ␉␉␉␉␉␉␉␉␊ |
127 | ␉␉␉␉␉␉␉␉currcoef = (int)(bus_ratio / 10);␊ |
128 | ␉␉␉␉␉␉␉␉␊ |
129 | ␉␉␉␉␉␉␉␉uint8_t fdiv = bus_ratio - (currcoef * 10);␊ |
130 | ␉␉␉␉␉␉␉␉if (fdiv > 0)␊ |
131 | ␉␉␉␉␉␉␉␉␉currdiv = 1;␊ |
132 | ␉␉␉␉␉␉␉␉␊ |
133 | safe_set_env(envCurrCoef,currcoef);␊ |
134 | safe_set_env(envCurrDiv,currdiv);␊ |
135 | ␉␉␉␉␉␉␉␉␉␊ |
136 | ␉␉␉␉␉␉␉}␊ |
137 | ␉␉␉␉␉␉␉␊ |
138 | ␉␉␉␉␉␉␉␊ |
139 | ␉␉␉␉␉␉}␉␉␉␉␉␉␉␉␊ |
140 | ␉␉␉␉␉␉␊ |
141 | ␉␉␉␉␉out:␊ |
142 | ␉␉␉␉␉␉if (CurrDiv) ␊ |
143 | ␉␉␉␉␉␉{␊ |
144 | ␉␉␉␉␉␉␉cpuFrequency = (FSBFrequency * ((CurrCoef * 2) + 1) / 2);␊ |
145 | ␉␉␉␉␉␉}␊ |
146 | ␉␉␉␉␉␉else ␊ |
147 | ␉␉␉␉␉␉{␊ |
148 | ␉␉␉␉␉␉␉cpuFrequency = (FSBFrequency * CurrCoef);␊ |
149 | ␉␉␉␉␉␉}␉␉␉␉␉␉␉␊ |
150 | ␉␉␉␉␉␉␊ |
151 | safe_set_env(envCPUFreq,cpuFrequency);␊ |
152 | ␊ |
153 | ␉␉␉␉␉␉verbose("CPU: FSBFreq changed to: %dMHz\n", (uint32_t)(get_env(envFSBFreq) / 1000000));␊ |
154 | ␉␉␉␉␉␉verbose("CPU: CPUFreq changed to: %dMHz\n", (uint32_t)(get_env(envCPUFreq) / 1000000));␊ |
155 | ␉␉␉␉␉␉␊ |
156 | ␉␉␉␉␉␉break;␊ |
157 | ␉␉␉␉␉}␉␉␉␉␉␉␊ |
158 | ␉␉␉␉␉case 0x1d:␉␉// Xeon MP MP 7400␊ |
159 | ␉␉␉␉␉default:␉␉␉␉␉␉␊ |
160 | ␉␉␉␉␉␉break;␊ |
161 | ␉␉␉␉}␊ |
162 | ␉␉␉}␊ |
163 | ␉␉}␊ |
164 | ␉}␊ |
165 | ␉else if(Vendor == CPUID_VENDOR_AMD && Family == 0x0f) // valv: work in progress␊ |
166 | ␉{␊ |
167 | ␉␉␊ |
168 | uint8_t ExtFamily = get_env(envExtFamily);␊ |
169 | uint64_t␉␉TSCFrequency = get_env(envTSCFreq);␊ |
170 | ␊ |
171 | ␉␉uint8_t bus_ratio_current = 0;␊ |
172 | ␉␉␊ |
173 | ␉␉if(ExtFamily == 0x00 /* K8 */)␊ |
174 | ␉␉{␊ |
175 | ␉␉␉␊ |
176 | ␉␉␉msr = rdmsr64(K8_FIDVID_STATUS);␊ |
177 | ␉␉␉bus_ratio_current = (msr & 0x3f) / 2 + 4; ␊ |
178 | ␉␉␉CurrDiv = (msr & 0x01) * 2;␉␉␉␉␉ ␊ |
179 | ␉␉␉if (bus_ratio_current)␊ |
180 | ␉␉␉{␊ |
181 | ␉␉␉␉if (CurrDiv)␊ |
182 | ␉␉␉␉{␊ |
183 | safe_set_env(envFSBFreq,((TSCFrequency * CurrDiv)/bus_ratio_current)); // ?␊ |
184 | ␉␉␉␉}␊ |
185 | ␉␉␉␉else␊ |
186 | ␉␉␉␉{␊ |
187 | safe_set_env(envFSBFreq, (TSCFrequency/bus_ratio_current) );␉␉␉␉␉␊ |
188 | ␉␉␉␉}␊ |
189 | ␉␉␉␉//fsbFrequency = (tscFrequency / bus_ratio_max); // ?␊ |
190 | ␉␉␉}␊ |
191 | ␉␉}␊ |
192 | ␉␉else if(ExtFamily >= 0x01 /* K10+ */)␊ |
193 | ␉␉{␊ |
194 | ␉␉␉␊ |
195 | ␉␉␉msr = rdmsr64(AMD_10H_11H_CONFIG);␊ |
196 | ␉␉␉bus_ratio_current = ((msr) & 0x3F);␊ |
197 | ␉␉␉␊ |
198 | safe_set_env(envCurrDiv,((2 << ((msr >> 6) & 0x07)) / 2));␊ |
199 | ␊ |
200 | safe_set_env(envFSBFreq,(CPUFrequency/bus_ratio_current));␊ |
201 | ␉␉␉␊ |
202 | ␉␉␉␊ |
203 | ␉␉}␉␊ |
204 | ␉␉␊ |
205 | ␉␉if (!get_env(envFSBFreq)) ␊ |
206 | ␉␉{␊ |
207 | safe_set_env(envFSBFreq,(DEFAULT_FSB * 1000));␊ |
208 | ␉␉␉verbose("0 ! using the default value for FSB !\n");␊ |
209 | ␉␉}␊ |
210 | ␊ |
211 | safe_set_env(envCurrCoef, (bus_ratio_current / 10));␊ |
212 | ␊ |
213 | ␉␉safe_set_env(envCPUFreq,TSCFrequency);␊ |
214 | ␉␉␊ |
215 | ␉␉verbose("CPU (AMD): FSBFreq: %dMHz\n", (uint32_t)(get_env(envFSBFreq) / 1000000));␊ |
216 | ␉␉verbose("CPU (AMD): CPUFreq: %dMHz\n", (uint32_t)(get_env(envCPUFreq) / 1000000));␊ |
217 | ␉␉verbose("CPU (AMD): CurrCoef:␉␉␉ 0x%x\n", (uint32_t)(get_env(envCurrCoef)));␊ |
218 | ␉␉verbose("CPU (AMD): CurrDiv: 0x%x\n", (uint32_t)(get_env(envCurrDiv)));␉␊ |
219 | ␉}␉ ␊ |
220 | ␊ |
221 | }␊ |
222 | ␊ |
223 | void CPUfreq_start(void);␊ |
224 | void CPUfreq_start(void)␊ |
225 | {␉␊ |
226 | ␉if (get_env(envFeatures) & CPUID_FEATURE_MSR)␊ |
227 | {␊ |
228 | register_hook_callback("PreBoot", &CPUfreq_hook);␉␉␊ |
229 | } ␊ |
230 | else␊ |
231 | {␊ |
232 | verbose ("Unsupported CPU: CPUfreq disabled !!!\n");␉␉␊ |
233 | }␉␊ |
234 | }␊ |
235 | |