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