xref: /netbsd-src/sys/arch/x86/x86/powernow.c (revision 76646d9e03c9615328f50b26f06c9b57e12e065b)
1 /*	$NetBSD: powernow.c,v 1.12 2021/10/07 12:52:27 msaitoh Exp $ */
2 /*	$OpenBSD: powernow-k8.c,v 1.8 2006/06/16 05:58:50 gwk Exp $ */
3 
4 /*-
5  * Copyright (c) 2004, 2006, 2008 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Juan Romero Pardines and Martin Vegiard.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 2004-2005 Bruno Ducrot
35  * Copyright (c) 2004 FUKUDA Nobuhiko <nfukuda@spa.is.uec.ac.jp>
36  * Copyright (c) 2004 Martin Vegiard
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
56  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57  */
58 
59 #include <sys/cdefs.h>
60 __KERNEL_RCSID(0, "$NetBSD: powernow.c,v 1.12 2021/10/07 12:52:27 msaitoh Exp $");
61 
62 #include <sys/param.h>
63 #include <sys/device.h>
64 #include <sys/kmem.h>
65 #include <sys/module.h>
66 #include <sys/sysctl.h>
67 #include <sys/xcall.h>
68 
69 #include <dev/isa/isareg.h>
70 
71 #include <x86/cpuvar.h>
72 #include <x86/cputypes.h>
73 #include <x86/cpu_msr.h>
74 #include <x86/isa_machdep.h>
75 #include <x86/powernow.h>
76 #include <x86/specialreg.h>
77 
78 #ifdef __i386__
79 /*
80  * Divide each value by 10 to get the processor multiplier.
81  * Taken from powernow-k7.c/Linux by Dave Jones.
82  */
83 static int powernow_k7_fidtomult[32] = {
84 	110, 115, 120, 125, 50, 55, 60, 65,
85 	70, 75, 80, 85, 90, 95, 100, 105,
86 	30, 190, 40, 200, 130, 135, 140, 210,
87 	150, 225, 160, 165, 170, 180, -1, -1
88 };
89 
90 /*
91  * The following CPUs do not have same CPUID signature
92  * in the PST tables, but they have correct FID/VID values.
93  */
94 static struct powernow_k7_quirk {
95 	uint32_t rcpusig;	/* Correct cpu signature */
96 	uint32_t pcpusig;	/* PST cpu signature */
97 } powernow_k7_quirk[] = {
98 	{ 0x680, 0x780 },	/* Reported by Olaf 'Rhialto' Seibert */
99 	{ 0x6a0, 0x781 },	/* Reported by Eric Schnoebelen */
100 	{ 0x6a0, 0x7a0 },	/* Reported by Nino Dehne */
101 	{ 0, 0 }
102 };
103 
104 #endif	/* __i386__ */
105 
106 struct powernow_softc {
107 	device_t		   sc_dev;
108 	struct cpu_info		  *sc_ci;
109 	struct sysctllog	  *sc_log;
110 	struct powernow_cpu_state *sc_state;
111 	const char		  *sc_tech;
112 	char			  *sc_freqs;
113 	size_t			   sc_freqs_len;
114 	unsigned int		   sc_freqs_cur;
115 	int			   sc_node_target;
116 	int			   sc_node_current;
117 	int			   sc_flags;
118 };
119 
120 static int	powernow_match(device_t, cfdata_t, void *);
121 static void	powernow_attach(device_t, device_t, void *);
122 static int	powernow_detach(device_t, int);
123 static int	powernow_sysctl(device_t);
124 static int	powernow_sysctl_helper(SYSCTLFN_PROTO);
125 
126 #ifdef __i386__
127 static int	powernow_k7_init(device_t);
128 static int	powernow_k7_states(device_t, unsigned int, unsigned int);
129 static int	powernow_k7_setperf(device_t, unsigned int);
130 static bool	powernow_k7_check(uint32_t, uint32_t);
131 static int	powernow_k7_decode_pst(struct powernow_softc *, uint8_t *,int);
132 #endif
133 
134 static int	powernow_k8_init(device_t);
135 static int	powernow_k8_states(device_t, unsigned int, unsigned int);
136 static int	powernow_k8_setperf(device_t, unsigned int);
137 static uint64_t powernow_k8_fidvid(u_int fid, uint64_t vid, uint64_t ctrl);
138 static int	powernow_k8_decode_pst(struct powernow_cpu_state *, uint8_t *);
139 
140 CFATTACH_DECL_NEW(powernow, sizeof(struct powernow_softc),
141     powernow_match, powernow_attach, powernow_detach, NULL);
142 
143 static int
powernow_match(device_t parent,cfdata_t cf,void * aux)144 powernow_match(device_t parent, cfdata_t cf, void *aux)
145 {
146 	struct cpufeature_attach_args *cfaa = aux;
147 	struct cpu_info *ci = cfaa->ci;
148 	uint32_t family, regs[4];
149 
150 	if (strcmp(cfaa->name, "frequency") != 0)
151 		return 0;
152 
153 	if (cpu_vendor != CPUVENDOR_AMD)
154 		return 0;
155 
156 	family = CPUID_TO_BASEFAMILY(ci->ci_signature);
157 
158 	if (family != 0x06 && family != 0x0f)
159 		return 0;
160 	else {
161 		x86_cpuid(0x80000000, regs);
162 
163 		if (regs[0] < 0x80000007)
164 			return 0;
165 
166 		x86_cpuid(0x80000007, regs);
167 
168 		if ((regs[3] & AMD_PN_FID_VID) == AMD_PN_FID_VID)
169 			return 5;
170 	}
171 
172 	return 0;
173 }
174 
175 static void
powernow_attach(device_t parent,device_t self,void * aux)176 powernow_attach(device_t parent, device_t self, void *aux)
177 {
178 	struct powernow_softc *sc = device_private(self);
179 	struct cpufeature_attach_args *cfaa = aux;
180 	struct cpu_info *ci = cfaa->ci;
181 	uint32_t family;
182 	int rv;
183 
184 	sc->sc_ci = ci;
185 	sc->sc_dev = self;
186 
187 	sc->sc_flags = 0;
188 	sc->sc_log = NULL;
189 	sc->sc_tech = NULL;
190 	sc->sc_state = NULL;
191 	sc->sc_freqs = NULL;
192 
193 	family = CPUID_TO_BASEFAMILY(ci->ci_signature);
194 
195 	switch (family) {
196 
197 #ifdef __i386__
198 	case 0x06:
199 		rv = powernow_k7_init(self);
200 		break;
201 #endif
202 	case 0x0f:
203 		rv = powernow_k8_init(self);
204 		break;
205 
206 	default:
207 		rv = ENODEV;
208 	}
209 
210 	if (rv != 0) {
211 		aprint_normal(": failed to initialize (err %d)\n", rv);
212 		return;
213 	}
214 
215 	rv = powernow_sysctl(self);
216 
217 	if (rv != 0) {
218 		aprint_normal(": failed to initialize sysctl (err %d)\n", rv);
219 		return;
220 	}
221 
222 	KASSERT(sc->sc_tech != NULL);
223 
224 	aprint_naive("\n");
225 	aprint_normal(": AMD %s\n", sc->sc_tech);
226 
227 	(void)pmf_device_register(self, NULL, NULL);
228 }
229 
230 static int
powernow_detach(device_t self,int flags)231 powernow_detach(device_t self, int flags)
232 {
233 	struct powernow_softc *sc = device_private(self);
234 
235 	if (sc->sc_log != NULL)
236 		sysctl_teardown(&sc->sc_log);
237 
238 	if (sc->sc_state != NULL)
239 		kmem_free(sc->sc_state, sizeof(*sc->sc_state));
240 
241 	if (sc->sc_freqs != NULL)
242 		kmem_free(sc->sc_freqs, sc->sc_freqs_len);
243 
244 	pmf_device_deregister(self);
245 
246 	return 0;
247 }
248 
249 static int
powernow_sysctl(device_t self)250 powernow_sysctl(device_t self)
251 {
252 	const struct sysctlnode *freqnode, *node, *cpunode;
253 	struct powernow_softc *sc = device_private(self);
254 	int rv;
255 
256 	/*
257 	 * Setup the sysctl sub-tree machdep.powernow.
258 	 */
259 	rv = sysctl_createv(&sc->sc_log, 0, NULL, &node,
260 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
261 	    NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
262 
263 	if (rv != 0)
264 		goto fail;
265 
266 	rv = sysctl_createv(&sc->sc_log, 0, &node, &cpunode,
267 	    0, CTLTYPE_NODE, "cpu", NULL,
268 	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
269 
270 	if (rv != 0)
271 		goto fail;
272 
273 	rv = sysctl_createv(&sc->sc_log, 0, &cpunode, &freqnode,
274 	    0, CTLTYPE_NODE, "frequency", NULL,
275 	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
276 
277 	if (rv != 0)
278 		goto fail;
279 
280 	rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &node,
281 	    CTLFLAG_READWRITE, CTLTYPE_INT, "target", NULL,
282 	    powernow_sysctl_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL);
283 
284 	if (rv != 0)
285 		goto fail;
286 
287 	sc->sc_node_target = node->sysctl_num;
288 
289 	rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &node,
290 	    0, CTLTYPE_INT, "current", NULL,
291 	    powernow_sysctl_helper, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL);
292 
293 	if (rv != 0)
294 		goto fail;
295 
296 	sc->sc_node_current = node->sysctl_num;
297 
298 	rv = sysctl_createv(&sc->sc_log, 0, &freqnode, &node,
299 	    0, CTLTYPE_STRING, "available", NULL,
300 	    NULL, 0, sc->sc_freqs, sc->sc_freqs_len, CTL_CREATE, CTL_EOL);
301 
302 	if (rv != 0)
303 		goto fail;
304 
305 	return 0;
306 
307 fail:
308 	sysctl_teardown(&sc->sc_log);
309 	sc->sc_log = NULL;
310 
311 	return rv;
312 }
313 
314 static int
powernow_sysctl_helper(SYSCTLFN_ARGS)315 powernow_sysctl_helper(SYSCTLFN_ARGS)
316 {
317 	struct powernow_softc *sc;
318 	struct sysctlnode node;
319 	int fq, oldfq, error;
320 	uint32_t family;
321 	int rv;
322 
323 	fq = oldfq = 0;
324 
325 	node = *rnode;
326 	sc = node.sysctl_data;
327 
328 	if (sc->sc_state == NULL)
329 		return EOPNOTSUPP;
330 
331 	node.sysctl_data = &fq;
332 
333 	if (rnode->sysctl_num == sc->sc_node_target)
334 		fq = oldfq = sc->sc_freqs_cur;
335 	else if (rnode->sysctl_num == sc->sc_node_current)
336 		fq = sc->sc_freqs_cur;
337 	else
338 		return EOPNOTSUPP;
339 
340 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
341 
342 	if (error || newp == NULL)
343 		return error;
344 
345 	family = CPUID_TO_BASEFAMILY(sc->sc_ci->ci_signature);
346 
347 	if (rnode->sysctl_num == sc->sc_node_target && fq != oldfq) {
348 
349 		switch (family) {
350 
351 #ifdef __i386__
352 		case 0x06:
353 			rv = powernow_k7_setperf(sc->sc_dev, fq);
354 			break;
355 #endif
356 		case 0x0f:
357 			rv = powernow_k8_setperf(sc->sc_dev, fq);
358 			break;
359 
360 		default:
361 			return ENODEV;
362 		}
363 
364 		if (rv != 0)
365 			return EINVAL;
366 
367 		sc->sc_freqs_cur = fq;
368 	}
369 
370 	return 0;
371 }
372 
373 #ifdef __i386__
374 
375 static int
powernow_k7_init(device_t self)376 powernow_k7_init(device_t self)
377 {
378 	struct powernow_softc *sc = device_private(self);
379 	uint32_t currentfid, maxfid, mhz, startvid;
380 	uint64_t status;
381 	int i, rv;
382 	char tmp[6];
383 
384 	sc->sc_state = kmem_alloc(sizeof(*sc->sc_state), KM_SLEEP);
385 
386 	if (sc->sc_ci->ci_signature == AMD_ERRATA_A0_CPUSIG)
387 		sc->sc_flags |= PN7_FLAG_ERRATA_A0;
388 
389 	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
390 	maxfid = PN7_STA_MFID(status);
391 	startvid = PN7_STA_SVID(status);
392 	currentfid = PN7_STA_CFID(status);
393 
394 	mhz = sc->sc_ci->ci_data.cpu_cc_freq / 1000000;
395 	sc->sc_state->fsb = mhz / (powernow_k7_fidtomult[currentfid] / 10);
396 
397 	if (powernow_k7_states(self, maxfid, startvid) == 0) {
398 		rv = ENXIO;
399 		goto fail;
400 	}
401 
402 	if (sc->sc_state->n_states == 0) {
403 		rv = ENODEV;
404 		goto fail;
405 	}
406 
407 	sc->sc_freqs_len = sc->sc_state->n_states * (sizeof("9999 ") - 1) + 1;
408 	sc->sc_freqs = kmem_zalloc(sc->sc_freqs_len, KM_SLEEP);
409 
410 	for (i = 0; i < sc->sc_state->n_states; i++) {
411 
412 		/* Skip duplicated matches. */
413 		if (i > 0 && (sc->sc_state->state_table[i].freq ==
414 		    sc->sc_state->state_table[i - 1].freq))
415 			continue;
416 
417 		DPRINTF(("%s: cstate->state_table.freq=%d\n",
418 			__func__, sc->sc_state->state_table[i].freq));
419 		DPRINTF(("%s: fid=%d vid=%d\n", __func__,
420 			sc->sc_state->state_table[i].fid,
421 			sc->sc_state->state_table[i].vid));
422 
423 		snprintf(tmp, sizeof(tmp), "%d%s",
424 		    sc->sc_state->state_table[i].freq,
425 		    i < sc->sc_state->n_states - 1 ? " " : "");
426 
427 		DPRINTF(("%s: tmp=%s\n", __func__, tmp));
428 
429 		(void)strlcat(sc->sc_freqs, tmp, sc->sc_freqs_len);
430 	}
431 
432 	sc->sc_tech = ((sc->sc_flags & PN7_FLAG_DESKTOP_VRM) != 0) ?
433 	    "Cool`n'Quiet K7" : "Powernow! K7";
434 
435 	return 0;
436 
437 fail:
438 	kmem_free(sc->sc_state, sizeof(*sc->sc_state));
439 	sc->sc_state = NULL;
440 
441 	return rv;
442 }
443 
444 static int
powernow_k7_states(device_t self,unsigned int fid,unsigned int vid)445 powernow_k7_states(device_t self, unsigned int fid, unsigned int vid)
446 {
447 	struct powernow_softc *sc = device_private(self);
448 	struct powernow_cpu_state *cstate;
449 	struct powernow_psb_s *psb;
450 	struct powernow_pst_s *pst;
451 	uint32_t cpusig, maxpst;
452 	bool cpusig_ok;
453 	uint8_t *p;
454 
455 	cstate = sc->sc_state;
456 	cpusig = sc->sc_ci->ci_signature;
457 
458 	/*
459 	 * Look in the 0xe0000 - 0x100000 physical address
460 	 * range for the pst tables; 16 byte blocks
461 	 */
462 	for (p = (uint8_t *)ISA_HOLE_VADDR(BIOS_START);
463 	     p < (uint8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN);
464 	     p+= BIOS_STEP) {
465 
466 		if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
467 
468 			psb = (struct powernow_psb_s *)p;
469 
470 			if (psb->version != PN7_PSB_VERSION)
471 				return 0;
472 
473 			cstate->sgtc = psb->ttime * cstate->fsb;
474 
475 			if (cstate->sgtc < 100 * cstate->fsb)
476 				cstate->sgtc = 100 * cstate->fsb;
477 
478 			if (psb->flags & 1)
479 				sc->sc_flags |= PN7_FLAG_DESKTOP_VRM;
480 
481 			p += sizeof(struct powernow_psb_s);
482 
483 			for (maxpst = 0; maxpst < psb->n_pst; maxpst++) {
484 				pst = (struct powernow_pst_s*) p;
485 
486 				/*
487 				 * Some models do not have same CPUID
488 				 * signature in the PST table. Accept to
489 				 * report frequencies via a quirk table
490 				 * and fid/vid match.
491 				 */
492 				DPRINTF(("%s: cpusig=0x%x pst->sig:0x%x\n",
493 				    __func__, cpusig, pst->signature));
494 
495 				cpusig_ok = powernow_k7_check(cpusig,
496 							      pst->signature);
497 
498 				if ((cpusig_ok != false &&
499 				    (fid == pst->fid && vid == pst->vid))) {
500 					DPRINTF(("%s: pst->signature ok\n",
501 					    __func__));
502 					if (abs(cstate->fsb - pst->pll) > 5)
503 						continue;
504 					cstate->n_states = pst->n_states;
505 					return (powernow_k7_decode_pst(sc,
506 					    p + sizeof(struct powernow_pst_s),
507 					    cstate->n_states));
508 
509 				}
510 
511 				p += sizeof(struct powernow_pst_s) +
512 				    (2 * pst->n_states);
513 			}
514 		}
515 	}
516 
517 	return 0;
518 }
519 
520 static int
powernow_k7_setperf(device_t self,unsigned int freq)521 powernow_k7_setperf(device_t self, unsigned int freq)
522 {
523 	struct powernow_softc *sc = device_private(self);
524 	int cvid, cfid, vid = 0, fid = 0;
525 	uint64_t status, ctl;
526 	unsigned int i;
527 
528 	DPRINTF(("%s: cstate->n_states=%d\n",
529 		__func__, sc->sc_state->n_states));
530 
531 	for (i = 0; i < sc->sc_state->n_states; i++) {
532 
533 		if (sc->sc_state->state_table[i].freq >= freq) {
534 			DPRINTF(("%s: freq=%d\n", __func__, freq));
535 			fid = sc->sc_state->state_table[i].fid;
536 			vid = sc->sc_state->state_table[i].vid;
537 			DPRINTF(("%s: fid=%d vid=%d\n", __func__, fid, vid));
538 			break;
539 		}
540 	}
541 
542 	if (fid == 0 || vid == 0)
543 		return 0;
544 
545 	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
546 	cfid = PN7_STA_CFID(status);
547 	cvid = PN7_STA_CVID(status);
548 
549 	/*
550 	 * We're already at the requested level.
551 	 */
552 	if (fid == cfid && vid == cvid)
553 		return 0;
554 
555 	ctl = rdmsr(MSR_AMDK7_FIDVID_CTL) & PN7_CTR_FIDCHRATIO;
556 
557 	ctl |= PN7_CTR_FID(fid);
558 	ctl |= PN7_CTR_VID(vid);
559 	ctl |= PN7_CTR_SGTC(sc->sc_state->sgtc);
560 
561 	if ((sc->sc_flags & PN7_FLAG_ERRATA_A0) != 0)
562 		x86_disable_intr();
563 
564 	if (powernow_k7_fidtomult[fid] < powernow_k7_fidtomult[cfid]) {
565 
566 		wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
567 
568 		if (vid != cvid)
569 			wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
570 
571 	} else {
572 
573 		wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
574 
575 		if (fid != cfid)
576 			wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
577 	}
578 
579 	if ((sc->sc_flags & PN7_FLAG_ERRATA_A0) != 0)
580 		x86_enable_intr();
581 
582 	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
583 
584 	cfid = PN7_STA_CFID(status);
585 	cvid = PN7_STA_CVID(status);
586 
587 	if (cfid == fid || cvid == vid)
588 		freq = sc->sc_state->state_table[i].freq;
589 
590 	return 0;
591 }
592 
593 static bool
powernow_k7_check(uint32_t real_cpusig,uint32_t pst_cpusig)594 powernow_k7_check(uint32_t real_cpusig, uint32_t pst_cpusig)
595 {
596 	int j;
597 
598 	if (real_cpusig == pst_cpusig)
599 		return true;
600 
601 	for (j = 0; powernow_k7_quirk[j].rcpusig != 0; j++) {
602 
603 		if ((real_cpusig == powernow_k7_quirk[j].rcpusig) &&
604 		    (pst_cpusig == powernow_k7_quirk[j].pcpusig))
605 			return true;
606 	}
607 
608 	return false;
609 }
610 
611 static int
powernow_k7_decode_pst(struct powernow_softc * sc,uint8_t * p,int npst)612 powernow_k7_decode_pst(struct powernow_softc *sc, uint8_t *p, int npst)
613 {
614 	struct powernow_cpu_state *cstate = sc->sc_state;
615 	struct powernow_state state;
616 	int i, j, n;
617 
618 	for (n = 0, i = 0; i < npst; ++i) {
619 
620 		state.fid = *p++;
621 		state.vid = *p++;
622 		state.freq = powernow_k7_fidtomult[state.fid]/10 * cstate->fsb;
623 
624 		if ((sc->sc_flags & PN7_FLAG_ERRATA_A0) != 0 &&
625 		    (powernow_k7_fidtomult[state.fid] % 10) == 5)
626 			continue;
627 
628 		j = n;
629 
630 		while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
631 
632 			(void)memcpy(&cstate->state_table[j],
633 			    &cstate->state_table[j - 1],
634 			    sizeof(struct powernow_state));
635 
636 			--j;
637 		}
638 
639 		(void)memcpy(&cstate->state_table[j], &state,
640 		    sizeof(struct powernow_state));
641 
642 		++n;
643 	}
644 
645 	/*
646 	 * Fix powernow_max_states, if errata_a0 gave
647 	 * us less states than expected.
648 	 */
649 	cstate->n_states = n;
650 
651 	return 1;
652 }
653 
654 #endif	/* __i386__ */
655 
656 static int
powernow_k8_init(device_t self)657 powernow_k8_init(device_t self)
658 {
659 	struct powernow_softc *sc = device_private(self);
660 	uint32_t i, maxfid, maxvid;
661 	uint64_t status;
662 	int rv;
663 	char tmp[6];
664 
665 	sc->sc_state = kmem_alloc(sizeof(*sc->sc_state), KM_SLEEP);
666 
667 	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
668 	maxfid = PN8_STA_MFID(status);
669 	maxvid = PN8_STA_MVID(status);
670 
671 	if (powernow_k8_states(self, maxfid, maxvid) == 0) {
672 		rv = ENXIO;
673 		goto fail;
674 	}
675 
676 	if (sc->sc_state->n_states == 0) {
677 		rv = ENODEV;
678 		goto fail;
679 	}
680 
681 	sc->sc_freqs_len = sc->sc_state->n_states * (sizeof("9999 ") - 1) + 1;
682 	sc->sc_freqs = kmem_zalloc(sc->sc_freqs_len, KM_SLEEP);
683 
684 	for (i = 0; i < sc->sc_state->n_states; i++) {
685 
686 		DPRINTF(("%s: cstate->state_table.freq=%d\n",
687 			__func__, sc->sc_state->state_table[i].freq));
688 
689 		DPRINTF(("%s: fid=%d vid=%d\n", __func__,
690 			sc->sc_state->state_table[i].fid,
691 			sc->sc_state->state_table[i].vid));
692 
693 		snprintf(tmp, sizeof(tmp), "%d%s",
694 		    sc->sc_state->state_table[i].freq,
695 		    i < sc->sc_state->n_states - 1 ? " " : "");
696 
697 		DPRINTF(("%s: tmp=%s\n", __func__, tmp));
698 
699 		(void)strlcat(sc->sc_freqs, tmp, sc->sc_freqs_len);
700 	}
701 
702 	/*
703 	 * If start FID is different to max FID, then it is a mobile
704 	 * processor. If not, it is a low powered desktop processor.
705 	 */
706 	sc->sc_tech = (PN8_STA_SFID(status) != PN8_STA_MFID(status)) ?
707 	    "PowerNow!" : "Cool`n'Quiet";
708 
709 	return 0;
710 
711 fail:
712 	kmem_free(sc->sc_state, sizeof(*sc->sc_state));
713 	sc->sc_state = NULL;
714 
715 	return rv;
716 }
717 
718 static int
powernow_k8_states(device_t self,unsigned int fid,unsigned int vid)719 powernow_k8_states(device_t self, unsigned int fid, unsigned int vid)
720 {
721 	struct powernow_softc *sc = device_private(self);
722 	struct powernow_cpu_state *cstate;
723 	struct powernow_psb_s *psb;
724 	struct powernow_pst_s *pst;
725 	uint32_t cpusig;
726 	uint8_t *p;
727 	int i;
728 
729 	cstate = sc->sc_state;
730 	cpusig = sc->sc_ci->ci_signature;
731 
732 	DPRINTF(("%s: before the for loop\n", __func__));
733 
734 	for (p = (uint8_t *)ISA_HOLE_VADDR(BIOS_START);
735 	     p < (uint8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN); p += 16) {
736 
737 		if (memcmp(p, "AMDK7PNOW!", 10) != 0)
738 			continue;
739 
740 		DPRINTF(("%s: inside the for loop\n", __func__));
741 
742 		psb = (struct powernow_psb_s *)p;
743 
744 		if (psb->version != 0x14) {
745 			DPRINTF(("%s: psb->version != 0x14\n", __func__));
746 			return 0;
747 		}
748 
749 		cstate->vst = psb->ttime;
750 		cstate->rvo = PN8_PSB_TO_RVO(psb->reserved);
751 		cstate->irt = PN8_PSB_TO_IRT(psb->reserved);
752 		cstate->mvs = PN8_PSB_TO_MVS(psb->reserved);
753 		cstate->low = PN8_PSB_TO_BATT(psb->reserved);
754 
755 		p += sizeof(struct powernow_psb_s);
756 
757 		for (i = 0; i < psb->n_pst; ++i) {
758 
759 			pst = (struct powernow_pst_s *)p;
760 
761 			cstate->pll = pst->pll;
762 			cstate->n_states = pst->n_states;
763 
764 			if (cpusig == pst->signature &&
765 			    pst->fid == fid && pst->vid == vid) {
766 
767 				DPRINTF(("%s: cpusig = sig\n", __func__));
768 
769 				return (powernow_k8_decode_pst(cstate,
770 				    p+= sizeof(struct powernow_pst_s)));
771 			}
772 
773 			p += sizeof(struct powernow_pst_s) +
774 			    2 * cstate->n_states;
775 		}
776 	}
777 
778 	DPRINTF(("%s: returns 0!\n", __func__));
779 
780 	return 0;
781 }
782 
783 static int
powernow_k8_setperf(device_t self,unsigned int freq)784 powernow_k8_setperf(device_t self, unsigned int freq)
785 {
786 	struct powernow_softc *sc = device_private(self);
787 	int cfid, cvid, fid = 0, vid = 0;
788 	uint64_t status;
789 	unsigned int i;
790 	uint32_t val;
791 	int rvo;
792 
793 	/*
794 	 * We dont do a "pending wait" here, given
795 	 * that we need to ensure that the change
796 	 * pending bit is not stuck.
797 	 */
798 	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
799 
800 	if (PN8_STA_PENDING(status))
801 		return 1;
802 
803 	cfid = PN8_STA_CFID(status);
804 	cvid = PN8_STA_CVID(status);
805 
806 	DPRINTF(("%s: sc->sc_state->n_states=%d\n",
807 		__func__, sc->sc_state->n_states));
808 
809 	for (i = 0; i < sc->sc_state->n_states; i++) {
810 
811 		if (sc->sc_state->state_table[i].freq >= freq) {
812 			DPRINTF(("%s: freq=%d\n", __func__, freq));
813 			fid = sc->sc_state->state_table[i].fid;
814 			vid = sc->sc_state->state_table[i].vid;
815 			DPRINTF(("%s: fid=%d vid=%d\n", __func__, fid, vid));
816 			break;
817 		}
818 
819 	}
820 
821 	if (fid == cfid && vid == cvid)
822 		return 0;
823 
824 	/*
825 	 * Phase 1: raise the core voltage to the
826 	 * requested VID if frequency is going up.
827 	 */
828 	while (cvid > vid) {
829 		val = cvid - (1 << sc->sc_state->mvs);
830 		status = powernow_k8_fidvid(cfid, (val > 0) ? val : 0, 1ULL);
831 		cvid = PN8_STA_CVID(status);
832 		COUNT_OFF_VST(sc->sc_state->vst);
833 	}
834 
835 	/*
836 	 * Then raise to voltage + RVO (if required).
837 	 */
838 	for (rvo = sc->sc_state->rvo; rvo > 0 && cvid > 0; --rvo) {
839 		/*
840 		 * XXX:	It is not clear from the specification if we have
841 		 *	to do that in 0.25 step or in MVS. Therefore do it
842 		 *	as it is done under Linux.
843 		 */
844 		status = powernow_k8_fidvid(cfid, cvid - 1, 1ULL);
845 		cvid = PN8_STA_CVID(status);
846 		COUNT_OFF_VST(sc->sc_state->vst);
847 	}
848 
849 	/*
850 	 * Phase 2: change to requested core frequency.
851 	 */
852 	if (cfid != fid) {
853 		uint32_t vco_fid, vco_cfid;
854 
855 		vco_fid = FID_TO_VCO_FID(fid);
856 		vco_cfid = FID_TO_VCO_FID(cfid);
857 
858 		while (abs(vco_fid - vco_cfid) > 2) {
859 
860 			if (fid > cfid) {
861 				if (cfid > 6)
862 					val = cfid + 2;
863 				else
864 					val = FID_TO_VCO_FID(cfid) + 2;
865 			} else
866 				val = cfid - 2;
867 
868 			status = powernow_k8_fidvid(val, cvid,
869 			    (uint64_t)sc->sc_state->pll * 1000 / 5);
870 
871 			cfid = PN8_STA_CFID(status);
872 			COUNT_OFF_IRT(sc->sc_state->irt);
873 			vco_cfid = FID_TO_VCO_FID(cfid);
874 		}
875 
876 
877 		status = powernow_k8_fidvid(fid, cvid,
878 		    (uint64_t)sc->sc_state->pll * 1000 / 5);
879 
880 		cfid = PN8_STA_CFID(status);
881 		COUNT_OFF_IRT(sc->sc_state->irt);
882 	}
883 
884 	/*
885 	 * Phase 3: change to requested voltage.
886 	 */
887 	if (cvid != vid) {
888 		status = powernow_k8_fidvid(cfid, vid, 1ULL);
889 		cvid = PN8_STA_CVID(status);
890 		COUNT_OFF_VST(sc->sc_state->vst);
891 	}
892 
893 #if 0
894 	if (cfid == fid || cvid == vid)
895 		freq = sc->sc_state->state_table[i].freq;
896 #endif
897 
898 	return 0;
899 }
900 
901 static uint64_t
powernow_k8_fidvid(u_int fid,uint64_t vid,uint64_t ctrl)902 powernow_k8_fidvid(u_int fid, uint64_t vid, uint64_t ctrl)
903 {
904 	struct msr_rw_info msr;
905 	uint64_t status, xc;
906 
907 	msr.msr_read = false;
908 	msr.msr_value = (ctrl << 32) | (1ULL << 16) | (vid << 8) | fid;
909 	msr.msr_type = MSR_AMDK7_FIDVID_CTL;
910 
911 	xc = xc_broadcast(0, (xcfunc_t)x86_msr_xcall, &msr, NULL);
912 	xc_wait(xc);
913 
914 	do {
915 		status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
916 
917 	} while (PN8_STA_PENDING(status));
918 
919 	return status;
920 }
921 
922 /*
923  * Given a set of pair of FID/VID, and a number of performance
924  * states, compute a state table via an insertion sort.
925  */
926 static int
powernow_k8_decode_pst(struct powernow_cpu_state * cstate,uint8_t * p)927 powernow_k8_decode_pst(struct powernow_cpu_state *cstate, uint8_t *p)
928 {
929 	struct powernow_state state;
930 	int i, j, n;
931 
932 	for (n = 0, i = 0; i < cstate->n_states; i++) {
933 
934 		state.fid = *p++;
935 		state.vid = *p++;
936 
937 		/*
938 		 * The minimum supported frequency per the data sheet is
939 		 * 800 MHz. The maximum supported frequency is 5000 MHz.
940 		 */
941 		state.freq = 800 + state.fid * 100;
942 		j = n;
943 
944 		while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
945 
946 			(void)memcpy(&cstate->state_table[j],
947 			    &cstate->state_table[j - 1],
948 			    sizeof(struct powernow_state));
949 
950 			--j;
951 		}
952 
953 		(void)memcpy(&cstate->state_table[j], &state,
954 		    sizeof(struct powernow_state));
955 
956 		n++;
957 	}
958 
959 	return 1;
960 }
961 
962 MODULE(MODULE_CLASS_DRIVER, powernow, NULL);
963 
964 #ifdef _MODULE
965 #include "ioconf.c"
966 #endif
967 
968 static int
powernow_modcmd(modcmd_t cmd,void * aux)969 powernow_modcmd(modcmd_t cmd, void *aux)
970 {
971 	int error = 0;
972 
973 	switch (cmd) {
974 	case MODULE_CMD_INIT:
975 #ifdef _MODULE
976 		error = config_init_component(cfdriver_ioconf_powernow,
977 		    cfattach_ioconf_powernow, cfdata_ioconf_powernow);
978 #endif
979 		return error;
980 	case MODULE_CMD_FINI:
981 #ifdef _MODULE
982 		error = config_fini_component(cfdriver_ioconf_powernow,
983 		    cfattach_ioconf_powernow, cfdata_ioconf_powernow);
984 #endif
985 		return error;
986 	default:
987 		return ENOTTY;
988 	}
989 }
990