File: | arch/amd64/amd64/powernow-k8.c |
Warning: | line 505, column 4 2nd function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: powernow-k8.c,v 1.28 2018/01/14 00:33:09 bluhm Exp $ */ | |||
2 | /* | |||
3 | * Copyright (c) 2004 Martin Végiard. | |||
4 | * Copyright (c) 2004-2005 Bruno Ducrot | |||
5 | * Copyright (c) 2004 FUKUDA Nobuhiko <nfukuda@spa.is.uec.ac.jp> | |||
6 | * | |||
7 | * Redistribution and use in source and binary forms, with or without | |||
8 | * modification, are permitted provided that the following conditions | |||
9 | * are met: | |||
10 | * 1. Redistributions of source code must retain the above copyright | |||
11 | * notice, this list of conditions and the following disclaimer. | |||
12 | * 2. Redistributions in binary form must reproduce the above copyright | |||
13 | * notice, this list of conditions and the following disclaimer in the | |||
14 | * documentation and/or other materials provided with the distribution. | |||
15 | * | |||
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
26 | */ | |||
27 | /* AMD POWERNOW K8 driver */ | |||
28 | ||||
29 | #include <sys/param.h> | |||
30 | #include <sys/systm.h> | |||
31 | #include <sys/malloc.h> | |||
32 | #include <sys/sysctl.h> | |||
33 | ||||
34 | #include <dev/isa/isareg.h> | |||
35 | #include <amd64/include/isa_machdep.h> | |||
36 | ||||
37 | #include <machine/cpu.h> | |||
38 | #include <machine/cpufunc.h> | |||
39 | #include <machine/bus.h> | |||
40 | ||||
41 | #include "acpicpu.h" | |||
42 | ||||
43 | #if NACPICPU1 > 0 | |||
44 | #include <dev/acpi/acpidev.h> | |||
45 | #endif | |||
46 | ||||
47 | #define BIOS_START0xe0000 0xe0000 | |||
48 | #define BIOS_LEN0x20000 0x20000 | |||
49 | ||||
50 | extern int setperf_prio; | |||
51 | extern int perflevel; | |||
52 | ||||
53 | /* | |||
54 | * MSRs and bits used by PowerNow technology | |||
55 | */ | |||
56 | #define MSR_AMDK7_FIDVID_CTL0xc0010041 0xc0010041 | |||
57 | #define MSR_AMDK7_FIDVID_STATUS0xc0010042 0xc0010042 | |||
58 | ||||
59 | /* Bitfields used by K8 */ | |||
60 | ||||
61 | #define PN8_CTR_FID(x)((x) & 0x3f) ((x) & 0x3f) | |||
62 | #define PN8_CTR_VID(x)(((x) & 0x1f) << 8) (((x) & 0x1f) << 8) | |||
63 | #define PN8_CTR_PENDING(x)(((x) & 1) << 32) (((x) & 1) << 32) | |||
64 | ||||
65 | #define PN8_STA_CFID(x)((x) & 0x3f) ((x) & 0x3f) | |||
66 | #define PN8_STA_SFID(x)(((x) >> 8) & 0x3f) (((x) >> 8) & 0x3f) | |||
67 | #define PN8_STA_MFID(x)(((x) >> 16) & 0x3f) (((x) >> 16) & 0x3f) | |||
68 | #define PN8_STA_PENDING(x)(((x) >> 31) & 0x01) (((x) >> 31) & 0x01) | |||
69 | #define PN8_STA_CVID(x)(((x) >> 32) & 0x1f) (((x) >> 32) & 0x1f) | |||
70 | #define PN8_STA_SVID(x)(((x) >> 40) & 0x1f) (((x) >> 40) & 0x1f) | |||
71 | #define PN8_STA_MVID(x)(((x) >> 48) & 0x1f) (((x) >> 48) & 0x1f) | |||
72 | ||||
73 | /* Reserved1 to PowerNow K8 configuration */ | |||
74 | #define PN8_PSB_TO_RVO(x)((x) & 0x03) ((x) & 0x03) | |||
75 | #define PN8_PSB_TO_IRT(x)(((x) >> 2) & 0x03) (((x) >> 2) & 0x03) | |||
76 | #define PN8_PSB_TO_MVS(x)(((x) >> 4) & 0x03) (((x) >> 4) & 0x03) | |||
77 | #define PN8_PSB_TO_BATT(x)(((x) >> 6) & 0x03) (((x) >> 6) & 0x03) | |||
78 | ||||
79 | /* ACPI ctr_val status register to PowerNow K8 configuration */ | |||
80 | #define PN8_ACPI_CTRL_TO_FID(x)((x) & 0x3f) ((x) & 0x3f) | |||
81 | #define PN8_ACPI_CTRL_TO_VID(x)(((x) >> 6) & 0x1f) (((x) >> 6) & 0x1f) | |||
82 | #define PN8_ACPI_CTRL_TO_VST(x)(((x) >> 11) & 0x1f) (((x) >> 11) & 0x1f) | |||
83 | #define PN8_ACPI_CTRL_TO_MVS(x)(((x) >> 18) & 0x03) (((x) >> 18) & 0x03) | |||
84 | #define PN8_ACPI_CTRL_TO_PLL(x)(((x) >> 20) & 0x7f) (((x) >> 20) & 0x7f) | |||
85 | #define PN8_ACPI_CTRL_TO_RVO(x)(((x) >> 28) & 0x03) (((x) >> 28) & 0x03) | |||
86 | #define PN8_ACPI_CTRL_TO_IRT(x)(((x) >> 30) & 0x03) (((x) >> 30) & 0x03) | |||
87 | ||||
88 | #define PN8_PSS_CFID(x)((x) & 0x3f) ((x) & 0x3f) | |||
89 | #define PN8_PSS_CVID(x)(((x) >> 6) & 0x1f) (((x) >> 6) & 0x1f) | |||
90 | ||||
91 | #define WRITE_FIDVID(fid, vid, ctrl)wrmsr(0xc0010041, (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid))) \ | |||
92 | wrmsr(MSR_AMDK7_FIDVID_CTL0xc0010041, \ | |||
93 | (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid))) | |||
94 | ||||
95 | ||||
96 | #define COUNT_OFF_IRT(irt)(*delay_func)(10 * (1 << (irt))) DELAY(10 * (1 << (irt)))(*delay_func)(10 * (1 << (irt))) | |||
97 | #define COUNT_OFF_VST(vst)(*delay_func)(20 * (vst)) DELAY(20 * (vst))(*delay_func)(20 * (vst)) | |||
98 | ||||
99 | #define FID_TO_VCO_FID(fid)(((fid) < 8) ? (8 + ((fid) << 1)) : (fid)) \ | |||
100 | (((fid) < 8) ? (8 + ((fid) << 1)) : (fid)) | |||
101 | ||||
102 | #define POWERNOW_MAX_STATES16 16 | |||
103 | ||||
104 | struct k8pnow_state { | |||
105 | int freq; | |||
106 | uint8_t fid; | |||
107 | uint8_t vid; | |||
108 | }; | |||
109 | ||||
110 | struct k8pnow_cpu_state { | |||
111 | struct k8pnow_state state_table[POWERNOW_MAX_STATES16]; | |||
112 | unsigned int n_states; | |||
113 | unsigned int sgtc; | |||
114 | unsigned int vst; | |||
115 | unsigned int mvs; | |||
116 | unsigned int pll; | |||
117 | unsigned int rvo; | |||
118 | unsigned int irt; | |||
119 | int low; | |||
120 | }; | |||
121 | ||||
122 | struct psb_s { | |||
123 | char signature[10]; /* AMDK7PNOW! */ | |||
124 | uint8_t version; | |||
125 | uint8_t flags; | |||
126 | uint16_t ttime; /* Min Settling time */ | |||
127 | uint8_t reserved; | |||
128 | uint8_t n_pst; | |||
129 | }; | |||
130 | ||||
131 | struct pst_s { | |||
132 | uint32_t cpuid; | |||
133 | uint8_t pll; | |||
134 | uint8_t fid; | |||
135 | uint8_t vid; | |||
136 | uint8_t n_states; | |||
137 | }; | |||
138 | ||||
139 | struct k8pnow_cpu_state *k8pnow_current_state; | |||
140 | ||||
141 | int k8pnow_read_pending_wait(uint64_t *); | |||
142 | int k8pnow_decode_pst(struct k8pnow_cpu_state *, uint8_t *); | |||
143 | int k8pnow_states(struct k8pnow_cpu_state *, uint32_t, unsigned int, unsigned int); | |||
144 | void k8pnow_transition(struct k8pnow_cpu_state *e, int); | |||
145 | ||||
146 | #if NACPICPU1 > 0 | |||
147 | int k8pnow_acpi_init(struct k8pnow_cpu_state *, uint64_t); | |||
148 | void k8pnow_acpi_pss_changed(struct acpicpu_pss *, int); | |||
149 | int k8pnow_acpi_states(struct k8pnow_cpu_state *, struct acpicpu_pss *, int, | |||
150 | uint64_t); | |||
151 | #endif | |||
152 | ||||
153 | int | |||
154 | k8pnow_read_pending_wait(uint64_t *status) | |||
155 | { | |||
156 | unsigned int i = 100000; | |||
157 | ||||
158 | while (i--) { | |||
159 | *status = rdmsr(MSR_AMDK7_FIDVID_STATUS0xc0010042); | |||
160 | if (!PN8_STA_PENDING(*status)(((*status) >> 31) & 0x01)) | |||
161 | return 0; | |||
162 | ||||
163 | } | |||
164 | printf("k8pnow_read_pending_wait: change pending stuck.\n"); | |||
165 | return 1; | |||
166 | } | |||
167 | ||||
168 | void | |||
169 | k8_powernow_setperf(int level) | |||
170 | { | |||
171 | unsigned int i; | |||
172 | struct k8pnow_cpu_state *cstate; | |||
173 | ||||
174 | cstate = k8pnow_current_state; | |||
175 | ||||
176 | i = ((level * cstate->n_states) + 1) / 101; | |||
177 | if (i >= cstate->n_states) | |||
178 | i = cstate->n_states - 1; | |||
179 | ||||
180 | k8pnow_transition(cstate, i); | |||
181 | } | |||
182 | ||||
183 | void | |||
184 | k8pnow_transition(struct k8pnow_cpu_state *cstate, int level) | |||
185 | { | |||
186 | uint64_t status; | |||
187 | int cfid, cvid, fid = 0, vid = 0; | |||
188 | int rvo; | |||
189 | u_int val; | |||
190 | ||||
191 | /* | |||
192 | * We dont do a k8pnow_read_pending_wait here, need to ensure that the | |||
193 | * change pending bit isn't stuck, | |||
194 | */ | |||
195 | status = rdmsr(MSR_AMDK7_FIDVID_STATUS0xc0010042); | |||
196 | if (PN8_STA_PENDING(status)(((status) >> 31) & 0x01)) | |||
197 | return; | |||
198 | cfid = PN8_STA_CFID(status)((status) & 0x3f); | |||
199 | cvid = PN8_STA_CVID(status)(((status) >> 32) & 0x1f); | |||
200 | ||||
201 | fid = cstate->state_table[level].fid; | |||
202 | vid = cstate->state_table[level].vid; | |||
203 | ||||
204 | if (fid == cfid && vid == cvid) | |||
205 | return; | |||
206 | ||||
207 | /* | |||
208 | * Phase 1: Raise core voltage to requested VID if frequency is | |||
209 | * going up. | |||
210 | */ | |||
211 | while (cvid > vid) { | |||
212 | val = cvid - (1 << cstate->mvs); | |||
213 | WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL)wrmsr(0xc0010041, (((1ULL) << 32) | (1ULL << 16) | (((val > 0) ? val : 0) << 8) | (cfid))); | |||
214 | if (k8pnow_read_pending_wait(&status)) | |||
215 | return; | |||
216 | cvid = PN8_STA_CVID(status)(((status) >> 32) & 0x1f); | |||
217 | COUNT_OFF_VST(cstate->vst)(*delay_func)(20 * (cstate->vst)); | |||
218 | } | |||
219 | ||||
220 | /* ... then raise to voltage + RVO (if required) */ | |||
221 | for (rvo = cstate->rvo; rvo > 0 && cvid > 0; --rvo) { | |||
222 | /* XXX It's not clear from spec if we have to do that | |||
223 | * in 0.25 step or in MVS. Therefore do it as it's done | |||
224 | * under Linux */ | |||
225 | WRITE_FIDVID(cfid, cvid - 1, 1ULL)wrmsr(0xc0010041, (((1ULL) << 32) | (1ULL << 16) | ((cvid - 1) << 8) | (cfid))); | |||
226 | if (k8pnow_read_pending_wait(&status)) | |||
227 | return; | |||
228 | cvid = PN8_STA_CVID(status)(((status) >> 32) & 0x1f); | |||
229 | COUNT_OFF_VST(cstate->vst)(*delay_func)(20 * (cstate->vst)); | |||
230 | } | |||
231 | ||||
232 | /* Phase 2: change to requested core frequency */ | |||
233 | if (cfid != fid) { | |||
234 | int vco_fid, vco_cfid; | |||
235 | ||||
236 | vco_fid = FID_TO_VCO_FID(fid)(((fid) < 8) ? (8 + ((fid) << 1)) : (fid)); | |||
237 | vco_cfid = FID_TO_VCO_FID(cfid)(((cfid) < 8) ? (8 + ((cfid) << 1)) : (cfid)); | |||
238 | ||||
239 | while (abs(vco_fid - vco_cfid) > 2) { | |||
240 | if (fid > cfid) { | |||
241 | if (cfid > 6) | |||
242 | val = cfid + 2; | |||
243 | else | |||
244 | val = FID_TO_VCO_FID(cfid)(((cfid) < 8) ? (8 + ((cfid) << 1)) : (cfid)) + 2; | |||
245 | } else | |||
246 | val = cfid - 2; | |||
247 | WRITE_FIDVID(val, cvid, (uint64_t)cstate->pll * 1000 / 5)wrmsr(0xc0010041, ((((uint64_t)cstate->pll * 1000 / 5) << 32) | (1ULL << 16) | ((cvid) << 8) | (val))); | |||
248 | ||||
249 | if (k8pnow_read_pending_wait(&status)) | |||
250 | return; | |||
251 | cfid = PN8_STA_CFID(status)((status) & 0x3f); | |||
252 | COUNT_OFF_IRT(cstate->irt)(*delay_func)(10 * (1 << (cstate->irt))); | |||
253 | ||||
254 | vco_cfid = FID_TO_VCO_FID(cfid)(((cfid) < 8) ? (8 + ((cfid) << 1)) : (cfid)); | |||
255 | } | |||
256 | ||||
257 | WRITE_FIDVID(fid, cvid, (uint64_t) cstate->pll * 1000 / 5)wrmsr(0xc0010041, ((((uint64_t) cstate->pll * 1000 / 5) << 32) | (1ULL << 16) | ((cvid) << 8) | (fid))); | |||
258 | if (k8pnow_read_pending_wait(&status)) | |||
259 | return; | |||
260 | cfid = PN8_STA_CFID(status)((status) & 0x3f); | |||
261 | COUNT_OFF_IRT(cstate->irt)(*delay_func)(10 * (1 << (cstate->irt))); | |||
262 | } | |||
263 | ||||
264 | /* Phase 3: change to requested voltage */ | |||
265 | if (cvid != vid) { | |||
266 | WRITE_FIDVID(cfid, vid, 1ULL)wrmsr(0xc0010041, (((1ULL) << 32) | (1ULL << 16) | ((vid) << 8) | (cfid))); | |||
267 | if (k8pnow_read_pending_wait(&status)) | |||
268 | return; | |||
269 | cvid = PN8_STA_CVID(status)(((status) >> 32) & 0x1f); | |||
270 | COUNT_OFF_VST(cstate->vst)(*delay_func)(20 * (cstate->vst)); | |||
271 | } | |||
272 | ||||
273 | if (cfid == fid || cvid == vid) | |||
274 | cpuspeed = cstate->state_table[level].freq; | |||
275 | } | |||
276 | ||||
277 | /* | |||
278 | * Given a set of pair of fid/vid, and number of performance states, | |||
279 | * compute state_table via an insertion sort. | |||
280 | */ | |||
281 | int | |||
282 | k8pnow_decode_pst(struct k8pnow_cpu_state *cstate, uint8_t *p) | |||
283 | { | |||
284 | int i, j, n; | |||
285 | struct k8pnow_state state; | |||
286 | for (n = 0, i = 0; i < cstate->n_states; i++) { | |||
287 | state.fid = *p++; | |||
288 | state.vid = *p++; | |||
289 | ||||
290 | /* | |||
291 | * The minimum supported frequency per the data sheet is 800MHz | |||
292 | * The maximum supported frequency is 5000MHz. | |||
293 | */ | |||
294 | state.freq = 800 + state.fid * 100; | |||
295 | j = n; | |||
296 | while (j > 0 && cstate->state_table[j - 1].freq > state.freq) { | |||
297 | memcpy(&cstate->state_table[j],__builtin_memcpy((&cstate->state_table[j]), (&cstate ->state_table[j - 1]), (sizeof(struct k8pnow_state))) | |||
298 | &cstate->state_table[j - 1],__builtin_memcpy((&cstate->state_table[j]), (&cstate ->state_table[j - 1]), (sizeof(struct k8pnow_state))) | |||
299 | sizeof(struct k8pnow_state))__builtin_memcpy((&cstate->state_table[j]), (&cstate ->state_table[j - 1]), (sizeof(struct k8pnow_state))); | |||
300 | --j; | |||
301 | } | |||
302 | memcpy(&cstate->state_table[j], &state,__builtin_memcpy((&cstate->state_table[j]), (&state ), (sizeof(struct k8pnow_state))) | |||
303 | sizeof(struct k8pnow_state))__builtin_memcpy((&cstate->state_table[j]), (&state ), (sizeof(struct k8pnow_state))); | |||
304 | n++; | |||
305 | } | |||
306 | return 1; | |||
307 | } | |||
308 | ||||
309 | #if NACPICPU1 > 0 | |||
310 | ||||
311 | int | |||
312 | k8pnow_acpi_states(struct k8pnow_cpu_state * cstate, struct acpicpu_pss * pss, | |||
313 | int nstates, uint64_t status) | |||
314 | { | |||
315 | struct k8pnow_state state; | |||
316 | int j, k, n; | |||
317 | uint32_t ctrl; | |||
318 | ||||
319 | k = -1; | |||
320 | ||||
321 | for (n = 0; n < cstate->n_states; n++) { | |||
322 | if ((PN8_STA_CFID(status)((status) & 0x3f) == PN8_PSS_CFID(pss[n].pss_status)((pss[n].pss_status) & 0x3f)) && | |||
323 | (PN8_STA_CVID(status)(((status) >> 32) & 0x1f) == PN8_PSS_CVID(pss[n].pss_status)(((pss[n].pss_status) >> 6) & 0x1f))) | |||
324 | k = n; | |||
325 | ctrl = pss[n].pss_ctrl; | |||
326 | state.fid = PN8_ACPI_CTRL_TO_FID(ctrl)((ctrl) & 0x3f); | |||
327 | state.vid = PN8_ACPI_CTRL_TO_VID(ctrl)(((ctrl) >> 6) & 0x1f); | |||
328 | ||||
329 | state.freq = pss[n].pss_core_freq; | |||
330 | j = n; | |||
331 | while (j > 0 && cstate->state_table[j - 1].freq > state.freq) { | |||
332 | memcpy(&cstate->state_table[j],__builtin_memcpy((&cstate->state_table[j]), (&cstate ->state_table[j - 1]), (sizeof(struct k8pnow_state))) | |||
333 | &cstate->state_table[j - 1],__builtin_memcpy((&cstate->state_table[j]), (&cstate ->state_table[j - 1]), (sizeof(struct k8pnow_state))) | |||
334 | sizeof(struct k8pnow_state))__builtin_memcpy((&cstate->state_table[j]), (&cstate ->state_table[j - 1]), (sizeof(struct k8pnow_state))); | |||
335 | --j; | |||
336 | } | |||
337 | memcpy(&cstate->state_table[j], &state,__builtin_memcpy((&cstate->state_table[j]), (&state ), (sizeof(struct k8pnow_state))) | |||
338 | sizeof(struct k8pnow_state))__builtin_memcpy((&cstate->state_table[j]), (&state ), (sizeof(struct k8pnow_state))); | |||
339 | } | |||
340 | ||||
341 | return k; | |||
342 | } | |||
343 | ||||
344 | void | |||
345 | k8pnow_acpi_pss_changed(struct acpicpu_pss * pss, int npss) | |||
346 | { | |||
347 | int curs, needtran; | |||
348 | struct k8pnow_cpu_state *cstate, *nstate; | |||
349 | uint32_t ctrl; | |||
350 | uint64_t status; | |||
351 | ||||
352 | status = rdmsr(MSR_AMDK7_FIDVID_STATUS0xc0010042); | |||
353 | cstate = k8pnow_current_state; | |||
354 | ||||
355 | nstate = malloc(sizeof(struct k8pnow_cpu_state), M_DEVBUF2, M_NOWAIT0x0002); | |||
356 | if (!nstate) | |||
357 | return; | |||
358 | ||||
359 | curs = k8pnow_acpi_states(nstate, pss, npss, status); | |||
360 | needtran = 0; | |||
361 | ||||
362 | if (curs < 0) { | |||
363 | /* Our current opearting state is not among the ones found the new PSS */ | |||
364 | curs = ((perflevel * npss) + 1) / 101; | |||
365 | if (curs >= npss) | |||
366 | curs = npss - 1; | |||
367 | needtran = 1; | |||
368 | } | |||
369 | ||||
370 | ctrl = pss[curs].pss_ctrl; | |||
371 | ||||
372 | nstate->rvo = PN8_ACPI_CTRL_TO_RVO(ctrl)(((ctrl) >> 28) & 0x03); | |||
373 | nstate->vst = PN8_ACPI_CTRL_TO_VST(ctrl)(((ctrl) >> 11) & 0x1f); | |||
374 | nstate->mvs = PN8_ACPI_CTRL_TO_MVS(ctrl)(((ctrl) >> 18) & 0x03); | |||
375 | nstate->pll = PN8_ACPI_CTRL_TO_PLL(ctrl)(((ctrl) >> 20) & 0x7f); | |||
376 | nstate->irt = PN8_ACPI_CTRL_TO_IRT(ctrl)(((ctrl) >> 30) & 0x03); | |||
377 | nstate->low = 0; | |||
378 | nstate->n_states = npss; | |||
379 | ||||
380 | if (needtran) | |||
381 | k8pnow_transition(nstate, curs); | |||
382 | ||||
383 | free(cstate, M_DEVBUF2, sizeof(*cstate)); | |||
384 | k8pnow_current_state = nstate; | |||
385 | } | |||
386 | ||||
387 | int | |||
388 | k8pnow_acpi_init(struct k8pnow_cpu_state * cstate, uint64_t status) | |||
389 | { | |||
390 | int curs; | |||
391 | uint32_t ctrl; | |||
392 | struct acpicpu_pss *pss; | |||
393 | ||||
394 | cstate->n_states = acpicpu_fetch_pss(&pss); | |||
395 | if (cstate->n_states == 0) | |||
396 | return 0; | |||
397 | acpicpu_set_notify(k8pnow_acpi_pss_changed); | |||
398 | ||||
399 | curs = k8pnow_acpi_states(cstate, pss, cstate->n_states, status); | |||
400 | ctrl = pss[curs].pss_ctrl; | |||
401 | ||||
402 | cstate->rvo = PN8_ACPI_CTRL_TO_RVO(ctrl)(((ctrl) >> 28) & 0x03); | |||
403 | cstate->vst = PN8_ACPI_CTRL_TO_VST(ctrl)(((ctrl) >> 11) & 0x1f); | |||
404 | cstate->mvs = PN8_ACPI_CTRL_TO_MVS(ctrl)(((ctrl) >> 18) & 0x03); | |||
405 | cstate->pll = PN8_ACPI_CTRL_TO_PLL(ctrl)(((ctrl) >> 20) & 0x7f); | |||
406 | cstate->irt = PN8_ACPI_CTRL_TO_IRT(ctrl)(((ctrl) >> 30) & 0x03); | |||
407 | cstate->low = 0; | |||
408 | ||||
409 | return 1; | |||
410 | } | |||
411 | ||||
412 | #endif /* NACPICPU */ | |||
413 | ||||
414 | int | |||
415 | k8pnow_states(struct k8pnow_cpu_state *cstate, uint32_t cpusig, | |||
416 | unsigned int fid, unsigned int vid) | |||
417 | { | |||
418 | struct psb_s *psb; | |||
419 | struct pst_s *pst; | |||
420 | uint8_t *p; | |||
421 | int i; | |||
422 | ||||
423 | for (p = (u_int8_t *)ISA_HOLE_VADDR(BIOS_START)((void *) ((u_long)(0xe0000) - 0x0a0000 + atdevbase)); | |||
424 | p < (u_int8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN)((void *) ((u_long)(0xe0000 + 0x20000) - 0x0a0000 + atdevbase )); p += 16) { | |||
425 | if (memcmp(p, "AMDK7PNOW!", 10)__builtin_memcmp((p), ("AMDK7PNOW!"), (10)) == 0) { | |||
426 | psb = (struct psb_s *)p; | |||
427 | if (psb->version != 0x14) | |||
428 | return 0; | |||
429 | ||||
430 | cstate->vst = psb->ttime; | |||
431 | cstate->rvo = PN8_PSB_TO_RVO(psb->reserved)((psb->reserved) & 0x03); | |||
432 | cstate->irt = PN8_PSB_TO_IRT(psb->reserved)(((psb->reserved) >> 2) & 0x03); | |||
433 | cstate->mvs = PN8_PSB_TO_MVS(psb->reserved)(((psb->reserved) >> 4) & 0x03); | |||
434 | cstate->low = PN8_PSB_TO_BATT(psb->reserved)(((psb->reserved) >> 6) & 0x03); | |||
435 | p+= sizeof(struct psb_s); | |||
436 | ||||
437 | for(i = 0; i < psb->n_pst; ++i) { | |||
438 | pst = (struct pst_s *) p; | |||
439 | ||||
440 | cstate->pll = pst->pll; | |||
441 | cstate->n_states = pst->n_states; | |||
442 | if (cpusig == pst->cpuid && | |||
443 | pst->fid == fid && pst->vid == vid) { | |||
444 | return (k8pnow_decode_pst(cstate, | |||
445 | p+= sizeof (struct pst_s))); | |||
446 | } | |||
447 | p += sizeof(struct pst_s) + 2 | |||
448 | * cstate->n_states; | |||
449 | } | |||
450 | } | |||
451 | } | |||
452 | ||||
453 | return 0; | |||
454 | ||||
455 | } | |||
456 | ||||
457 | void | |||
458 | k8_powernow_init(struct cpu_info *ci) | |||
459 | { | |||
460 | uint64_t status; | |||
461 | u_int maxfid, maxvid, i; | |||
462 | u_int32_t extcpuid, dummy; | |||
463 | struct k8pnow_cpu_state *cstate; | |||
464 | struct k8pnow_state *state; | |||
465 | char * techname = NULL((void *)0); | |||
466 | ||||
467 | if (setperf_prio > 1) | |||
| ||||
468 | return; | |||
469 | ||||
470 | cstate = malloc(sizeof(struct k8pnow_cpu_state), M_DEVBUF2, M_NOWAIT0x0002); | |||
471 | if (!cstate) | |||
472 | return; | |||
473 | ||||
474 | cstate->n_states = 0; | |||
475 | status = rdmsr(MSR_AMDK7_FIDVID_STATUS0xc0010042); | |||
476 | maxfid = PN8_STA_MFID(status)(((status) >> 16) & 0x3f); | |||
477 | maxvid = PN8_STA_MVID(status)(((status) >> 48) & 0x1f); | |||
478 | ||||
479 | /* | |||
480 | * If start FID is different to max FID, then it is a | |||
481 | * mobile processor. If not, it is a low powered desktop | |||
482 | * processor. | |||
483 | */ | |||
484 | if (PN8_STA_SFID(status)(((status) >> 8) & 0x3f) != PN8_STA_MFID(status)(((status) >> 16) & 0x3f)) | |||
485 | techname = "PowerNow! K8"; | |||
486 | else | |||
487 | techname = "Cool'n'Quiet K8"; | |||
488 | ||||
489 | #if NACPICPU1 > 0 | |||
490 | /* If we have acpi check acpi first */ | |||
491 | if (!k8pnow_acpi_init(cstate, status)) | |||
492 | #endif | |||
493 | { | |||
494 | if (!k8pnow_states(cstate, ci->ci_signature, maxfid, maxvid)) { | |||
495 | /* Extended CPUID signature value */ | |||
496 | CPUID(0x80000001, extcpuid, dummy, dummy, dummy)__asm volatile("cpuid" : "=a" (extcpuid), "=b" (dummy), "=c" ( dummy), "=d" (dummy) : "a" (0x80000001)); | |||
497 | k8pnow_states(cstate, extcpuid, maxfid, maxvid); | |||
498 | } | |||
499 | } | |||
500 | if (cstate->n_states) { | |||
501 | printf("%s: %s %d MHz: speeds:", | |||
502 | ci->ci_dev->dv_xname, techname, cpuspeed); | |||
503 | for (i = cstate->n_states; i
| |||
504 | state = &cstate->state_table[i-1]; | |||
505 | printf(" %d", state->freq); | |||
| ||||
506 | } | |||
507 | printf(" MHz\n"); | |||
508 | k8pnow_current_state = cstate; | |||
509 | cpu_setperf = k8_powernow_setperf; | |||
510 | setperf_prio = 1; | |||
511 | return; | |||
512 | } | |||
513 | free(cstate, M_DEVBUF2, sizeof(*cstate)); | |||
514 | } |