Annotation of sys/arch/i386/i386/powernow.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: powernow.c,v 1.3 2006/12/12 23:14:27 dim Exp $ */
2: /*
3: * Copyright (c) 2004 Ted Unangst
4: * All rights reserved.
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: /*
20: * AMD K6 PowerNow driver, see AMD tech doc #23525
21: * Numerous hints from Linux cpufreq driver
22: */
23:
24: #include <sys/param.h>
25: #include <sys/sysctl.h>
26:
27: #include <machine/cpu.h>
28: #include <machine/cpufunc.h>
29: #include <machine/specialreg.h>
30: #include <machine/pio.h>
31:
32: /* table 27 in amd 23535. entries after 45 taken from linux cpufreq */
33: struct {
34: int mult; /* not actually used, maybe for cpuspeed */
35: int magic;
36: } k6_multipliers[] = {
37: { 20, 4 },
38: { 30, 5 },
39: { 35, 7 },
40: { 40, 2 },
41: { 45, 0 },
42: { 55, 3 },
43: { 50, 1 },
44: { 60, 6 },
45: };
46: #define NUM_K6_ENTRIES (sizeof k6_multipliers / sizeof k6_multipliers[0])
47:
48: int k6_maxindex; /* no setting higher than this */
49:
50: /* linux says: "it doesn't matter where, as long as it is unused */
51: #define K6PORT 0xfff0
52:
53: void
54: k6_powernow_init(void)
55: {
56: uint64_t msrval;
57: uint32_t portval;
58: int i;
59:
60: /* on */
61: msrval = K6PORT | 0x1;
62: wrmsr(MSR_K6_EPMR, msrval);
63: /* read */
64: portval = inl(K6PORT + 8);
65: /* off */
66: wrmsr(MSR_K6_EPMR, 0LL);
67:
68: portval = (portval >> 5) & 7;
69:
70: for (i = 0; i < NUM_K6_ENTRIES; i++)
71: if (portval == k6_multipliers[i].magic) {
72: k6_maxindex = i;
73: break;
74: }
75: if (i == NUM_K6_ENTRIES) {
76: printf("bad value for current multiplier\n");
77: return;
78: }
79:
80: cpu_setperf = k6_powernow_setperf;
81: }
82:
83: void
84: k6_powernow_setperf(int level)
85: {
86: uint64_t msrval;
87: uint32_t portval;
88: int index;
89:
90: index = level * k6_maxindex / 100;
91:
92: /* on */
93: msrval = K6PORT | 0x1;
94: wrmsr(MSR_K6_EPMR, msrval);
95: /* read and update */
96: portval = inl(K6PORT + 8);
97: portval &= 0xf;
98: portval |= 1 << 12 | 1 << 10 | 1 << 9 |
99: k6_multipliers[index].magic << 5;
100: outl(K6PORT + 8, portval);
101: /* off */
102: wrmsr(MSR_K6_EPMR, 0LL);
103: }
CVSweb