xref: /openbsd-src/sys/arch/i386/i386/longrun.c (revision f4e7063748a2ac72b2bab4389c0a7efc72d82189)
1 /* $OpenBSD: longrun.c,v 1.18 2023/01/30 10:49:05 jsg 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/sysctl.h>
34 #include <sys/timeout.h>
35 
36 #include <machine/cpufunc.h>
37 
38 union msrinfo {
39 	u_int64_t msr;
40 	uint32_t regs[2];
41 };
42 
43 /*
44  * Crusoe model specific registers which interest us.
45  */
46 #define MSR_TMx86_LONGRUN       0x80868010
47 #define MSR_TMx86_LONGRUN_FLAGS 0x80868011
48 
49 #define LONGRUN_MODE_MASK(x) ((x) & 0x000000007f)
50 #define LONGRUN_MODE_RESERVED(x) ((x) & 0xffffff80)
51 #define LONGRUN_MODE_WRITE(x, y) (LONGRUN_MODE_RESERVED(x) | LONGRUN_MODE_MASK(y))
52 
53 void	longrun_update(void *);
54 
55 struct timeout longrun_timo;
56 
57 void
longrun_init(void)58 longrun_init(void)
59 {
60 	cpu_setperf = longrun_setperf;
61 
62 	timeout_set(&longrun_timo, longrun_update, NULL);
63 	timeout_add_sec(&longrun_timo, 1);
64 }
65 
66 /*
67  * These are the instantaneous values used by the CPU.
68  * regs[0] = Frequency is self-evident.
69  * regs[1] = Voltage is returned in millivolts.
70  * regs[2] = Percent is amount of performance window being used, not
71  * percentage of top megahertz.  (0 values are typical.)
72  */
73 void
longrun_update(void * arg)74 longrun_update(void *arg)
75 {
76 	uint32_t regs[4];
77 	u_long s;
78 
79 	s = intr_disable();
80 	cpuid(0x80860007, regs);
81 	intr_restore(s);
82 
83 	cpuspeed = regs[0];
84 
85 	timeout_add_sec(&longrun_timo, 1);
86 }
87 
88 /*
89  * Transmeta documentation says performance window boundaries
90  * must be between 0 and 100 or a GP0 exception is generated.
91  * mode is really only a bit, 0 or 1
92  * These values will be rounded by the CPU to within the
93  * limits it handles.  Typically, there are about 5 performance
94  * levels selectable.
95  */
96 void
longrun_setperf(int high)97 longrun_setperf(int high)
98 {
99  	union msrinfo msrinfo;
100 	uint32_t mode;
101 	u_long s;
102 
103 	if (high >= 50)
104 		mode = 1;	/* power */
105 	else
106 		mode = 0;	/* battery */
107 
108 	s = intr_disable();
109 
110 	msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN);
111 	msrinfo.regs[0] = LONGRUN_MODE_WRITE(msrinfo.regs[0], 0); /* low */
112 	msrinfo.regs[1] = LONGRUN_MODE_WRITE(msrinfo.regs[1], high);
113 	wrmsr(MSR_TMx86_LONGRUN, msrinfo.msr);
114 
115 	msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN_FLAGS);
116 	msrinfo.regs[0] = (msrinfo.regs[0] & ~0x01) | mode;
117 	wrmsr(MSR_TMx86_LONGRUN_FLAGS, msrinfo.msr);
118 
119 	intr_restore(s);
120 
121 	longrun_update(NULL);
122 }
123 
124