1 /* $OpenBSD: longrun.c,v 1.13 2007/05/25 20:32:29 krw Exp $ */
2 /*
3 * Copyright (c) 2003 Ted Unangst
4 * Copyright (c) 2001 Tamotsu Hattori
5 * All rights reserved.
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 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/sysctl.h>
35 #include <sys/timeout.h>
36
37 #include <machine/cpufunc.h>
38
39 union msrinfo {
40 u_int64_t msr;
41 uint32_t regs[2];
42 };
43
44 /*
45 * Crusoe model specific registers which interest us.
46 */
47 #define MSR_TMx86_LONGRUN 0x80868010
48 #define MSR_TMx86_LONGRUN_FLAGS 0x80868011
49
50 #define LONGRUN_MODE_MASK(x) ((x) & 0x000000007f)
51 #define LONGRUN_MODE_RESERVED(x) ((x) & 0xffffff80)
52 #define LONGRUN_MODE_WRITE(x, y) (LONGRUN_MODE_RESERVED(x) | LONGRUN_MODE_MASK(y))
53
54 void longrun_update(void *);
55
56 struct timeout longrun_timo;
57
58 void
59 longrun_init(void)
60 {
61 cpu_setperf = longrun_setperf;
62
63 timeout_set(&longrun_timo, longrun_update, NULL);
64 timeout_add(&longrun_timo, hz);
65 }
66
67 /*
68 * These are the instantaneous values used by the CPU.
69 * regs[0] = Frequency is self-evident.
70 * regs[1] = Voltage is returned in millivolts.
71 * regs[2] = Percent is amount of performance window being used, not
72 * percentage of top megahertz. (0 values are typical.)
73 */
74 void
75 longrun_update(void *arg)
76 {
77 uint32_t eflags, regs[4];
78
79 eflags = read_eflags();
80 disable_intr();
81 cpuid(0x80860007, regs);
82 enable_intr();
83 write_eflags(eflags);
84
85 cpuspeed = regs[0];
86
87 timeout_add(&longrun_timo, hz);
88 }
89
90 /*
91 * Transmeta documentation says performance window boundaries
92 * must be between 0 and 100 or a GP0 exception is generated.
93 * mode is really only a bit, 0 or 1
94 * These values will be rounded by the CPU to within the
95 * limits it handles. Typically, there are about 5 performance
96 * levels selectable.
97 */
98 void
99 longrun_setperf(int high)
100 {
101 uint32_t eflags, mode;
102 union msrinfo msrinfo;
103
104 if (high >= 50)
105 mode = 1; /* power */
106 else
107 mode = 0; /* battery */
108
109 eflags = read_eflags();
110 disable_intr();
111
112 msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN);
113 msrinfo.regs[0] = LONGRUN_MODE_WRITE(msrinfo.regs[0], 0); /* low */
114 msrinfo.regs[1] = LONGRUN_MODE_WRITE(msrinfo.regs[1], high);
115 wrmsr(MSR_TMx86_LONGRUN, msrinfo.msr);
116
117 msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN_FLAGS);
118 msrinfo.regs[0] = (msrinfo.regs[0] & ~0x01) | mode;
119 wrmsr(MSR_TMx86_LONGRUN_FLAGS, msrinfo.msr);
120
121 enable_intr();
122 write_eflags(eflags);
123
124 longrun_update(NULL);
125 }
126