2 * longrun_linux.c - module to get LongRun(TM) status, for GNU/Linux
4 * Copyright(C) 2001 Transmeta Corporation
5 * Copyright(C) 2001 Seiichi SATO <ssato@sh.rim.or.jp>
7 * licensed under the GPL
18 #include <sys/types.h>
23 #define __USE_UNIX98 /* for pread/pwrite */
25 #define __USE_FILE_OFFSET64 /* msr/cpuid needs 64bit address with newer linuxes */
29 #define MSR_DEVICE "/dev/cpu/0/msr"
30 #define MSR_TMx86_LONGRUN 0x80868010
31 #define MSR_TMx86_LONGRUN_FLAGS 0x80868011
33 #define LONGRUN_MASK(x) ((x) & 0x0000007f)
34 #define LONGRUN_RESERVED(x) ((x) & 0xffffff80)
35 #define LONGRUN_WRITE(x, y) (LONGRUN_RESERVED(x) | LONGRUN_MASK(y))
37 #define CPUID_DEVICE "/dev/cpu/0/cpuid"
38 #define CPUID_TMx86_VENDOR_ID 0x80860000
39 #define CPUID_TMx86_PROCESSOR_INFO 0x80860001
40 #define CPUID_TMx86_LONGRUN_STATUS 0x80860007
41 #define CPUID_TMx86_FEATURE_LONGRUN(x) ((x) & 0x02)
43 static int cpuid_fd
; /* CPUID file descriptor */
44 static char *cpuid_device
; /* CPUID device name */
45 static int msr_fd
; /* MSR file descriptor */
46 static char *msr_device
; /* MSR device name */
49 read_cpuid(loff_t address
, int *eax
, int *ebx
, int *ecx
, int *edx
)
54 if (pread(cpuid_fd
, &data
, 16, address
) != 16) {
57 if (lseek(cpuid_fd
, address
, SEEK_SET
) != address
) {
61 if (read(cpuid_fd
, &data
, 16) != 16) {
77 /* note: if an output is NULL, then don't set it */
79 read_msr(loff_t address
, int *lower
, int *upper
)
84 if (pread(msr_fd
, &data
, 8, address
) != 8) {
87 if (lseek(msr_fd
, address
, SEEK_SET
) != address
) {
91 if (read(msr_fd
, &data
, 8) != 8) {
104 longrun_init(char *cpuid_dev
, char *msr_dev
)
106 int eax
, ebx
, ecx
, edx
;
108 /* set CPUID device */
109 cpuid_device
= CPUID_DEVICE
;
111 cpuid_device
= cpuid_dev
;
114 msr_device
= MSR_DEVICE
;
116 msr_device
= msr_dev
;
118 /* open CPUID device */
119 if ((cpuid_fd
= open(cpuid_device
, O_RDONLY
)) < 0) {
120 fprintf(stderr
, "error opening %s\n", cpuid_device
);
123 "make sure your kernel was compiled with CONFIG_X86_CPUID=y\n");
127 /* open MSR device */
128 if ((msr_fd
= open(msr_device
, O_RDONLY
)) < 0) {
129 fprintf(stderr
, "error opening %s\n", msr_device
);
132 "make sure your kernel was compiled with CONFIG_X86_MSR=y\n");
136 /* test for "TransmetaCPU" */
137 read_cpuid(CPUID_TMx86_VENDOR_ID
, &eax
, &ebx
, &ecx
, &edx
);
138 if (ebx
!= 0x6e617254 || ecx
!= 0x55504361 || edx
!= 0x74656d73) {
139 fprintf(stderr
, "not a Transmeta x86 CPU\n");
143 /* test for LongRun feature flag */
144 read_cpuid(CPUID_TMx86_PROCESSOR_INFO
, &eax
, &ebx
, &ecx
, &edx
);
145 if (!CPUID_TMx86_FEATURE_LONGRUN(edx
)) {
146 printf("LongRun: unsupported\n");
158 * percent: performance level (0 to 100)
159 * flags: performance/economy/unknown
164 longrun_get_stat(int *percent
, int *flags
, int *mhz
, int *voltz
)
168 /* open CPUID device */
169 if ((cpuid_fd
= open(cpuid_device
, O_RDWR
)) < 0) {
170 fprintf(stderr
, "error opening %s\n", cpuid_device
);
173 "make sure your kernel was compiled with CONFIG_X86_CPUID=y\n");
177 /* open MSR device */
178 if ((msr_fd
= open(msr_device
, O_RDWR
)) < 0) {
179 fprintf(stderr
, "error opening %s\n", msr_device
);
182 "make sure your kernel was compiled with CONFIG_X86_MSR=y\n");
186 /* frequency, voltage, performance level, */
187 read_cpuid(CPUID_TMx86_LONGRUN_STATUS
, &eax
, &ebx
, &ecx
, 0);
193 read_msr(MSR_TMx86_LONGRUN_FLAGS
, flags
, NULL
);
195 (*flags
& 1) ? LONGRUN_FLAGS_PEFORMANCE
: LONGRUN_FLAGS_ECONOMY
;