diff options
Diffstat (limited to 'tools/power/cpupower/debug')
-rw-r--r-- | tools/power/cpupower/debug/i386/Makefile | 20 | ||||
-rw-r--r-- | tools/power/cpupower/debug/i386/centrino-decode.c | 113 | ||||
-rw-r--r-- | tools/power/cpupower/debug/i386/dump_psb.c | 196 | ||||
-rw-r--r-- | tools/power/cpupower/debug/i386/intel_gsic.c | 78 | ||||
-rw-r--r-- | tools/power/cpupower/debug/i386/powernow-k8-decode.c | 96 | ||||
-rw-r--r-- | tools/power/cpupower/debug/kernel/Makefile | 23 | ||||
-rw-r--r-- | tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c | 113 | ||||
-rw-r--r-- | tools/power/cpupower/debug/x86_64/Makefile | 14 |
8 files changed, 653 insertions, 0 deletions
diff --git a/tools/power/cpupower/debug/i386/Makefile b/tools/power/cpupower/debug/i386/Makefile new file mode 100644 index 00000000000..d08cc1ead9b --- /dev/null +++ b/tools/power/cpupower/debug/i386/Makefile | |||
@@ -0,0 +1,20 @@ | |||
1 | default: all | ||
2 | |||
3 | centrino-decode: centrino-decode.c | ||
4 | $(CC) $(CFLAGS) -o centrino-decode centrino-decode.c | ||
5 | |||
6 | dump_psb: dump_psb.c | ||
7 | $(CC) $(CFLAGS) -o dump_psb dump_psb.c | ||
8 | |||
9 | intel_gsic: intel_gsic.c | ||
10 | $(CC) $(CFLAGS) -o intel_gsic -llrmi intel_gsic.c | ||
11 | |||
12 | powernow-k8-decode: powernow-k8-decode.c | ||
13 | $(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c | ||
14 | |||
15 | all: centrino-decode dump_psb intel_gsic powernow-k8-decode | ||
16 | |||
17 | clean: | ||
18 | rm -rf centrino-decode dump_psb intel_gsic powernow-k8-decode | ||
19 | |||
20 | .PHONY: all default clean | ||
diff --git a/tools/power/cpupower/debug/i386/centrino-decode.c b/tools/power/cpupower/debug/i386/centrino-decode.c new file mode 100644 index 00000000000..7ef24cce492 --- /dev/null +++ b/tools/power/cpupower/debug/i386/centrino-decode.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * (C) 2003 - 2004 Dominik Brodowski <linux@dominikbrodowski.de> | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | * Based on code found in | ||
7 | * linux/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c | ||
8 | * and originally developed by Jeremy Fitzhardinge. | ||
9 | * | ||
10 | * USAGE: simply run it to decode the current settings on CPU 0, | ||
11 | * or pass the CPU number as argument, or pass the MSR content | ||
12 | * as argument. | ||
13 | */ | ||
14 | |||
15 | #include <stdio.h> | ||
16 | #include <stdlib.h> | ||
17 | #include <stdint.h> | ||
18 | #include <unistd.h> | ||
19 | #include <errno.h> | ||
20 | #include <fcntl.h> | ||
21 | |||
22 | #include <sys/types.h> | ||
23 | #include <sys/stat.h> | ||
24 | |||
25 | #define MCPU 32 | ||
26 | |||
27 | #define MSR_IA32_PERF_STATUS 0x198 | ||
28 | |||
29 | static int rdmsr(unsigned int cpu, unsigned int msr, | ||
30 | unsigned int *lo, unsigned int *hi) | ||
31 | { | ||
32 | int fd; | ||
33 | char file[20]; | ||
34 | unsigned long long val; | ||
35 | int retval = -1; | ||
36 | |||
37 | *lo = *hi = 0; | ||
38 | |||
39 | if (cpu > MCPU) | ||
40 | goto err1; | ||
41 | |||
42 | sprintf(file, "/dev/cpu/%d/msr", cpu); | ||
43 | fd = open(file, O_RDONLY); | ||
44 | |||
45 | if (fd < 0) | ||
46 | goto err1; | ||
47 | |||
48 | if (lseek(fd, msr, SEEK_CUR) == -1) | ||
49 | goto err2; | ||
50 | |||
51 | if (read(fd, &val, 8) != 8) | ||
52 | goto err2; | ||
53 | |||
54 | *lo = (uint32_t )(val & 0xffffffffull); | ||
55 | *hi = (uint32_t )(val>>32 & 0xffffffffull); | ||
56 | |||
57 | retval = 0; | ||
58 | err2: | ||
59 | close(fd); | ||
60 | err1: | ||
61 | return retval; | ||
62 | } | ||
63 | |||
64 | static void decode (unsigned int msr) | ||
65 | { | ||
66 | unsigned int multiplier; | ||
67 | unsigned int mv; | ||
68 | |||
69 | multiplier = ((msr >> 8) & 0xFF); | ||
70 | |||
71 | mv = (((msr & 0xFF) * 16) + 700); | ||
72 | |||
73 | printf("0x%x means multiplier %d @ %d mV\n", msr, multiplier, mv); | ||
74 | } | ||
75 | |||
76 | static int decode_live(unsigned int cpu) | ||
77 | { | ||
78 | unsigned int lo, hi; | ||
79 | int err; | ||
80 | |||
81 | err = rdmsr(cpu, MSR_IA32_PERF_STATUS, &lo, &hi); | ||
82 | |||
83 | if (err) { | ||
84 | printf("can't get MSR_IA32_PERF_STATUS for cpu %d\n", cpu); | ||
85 | printf("Possible trouble: you don't run an Enhanced SpeedStep capable cpu\n"); | ||
86 | printf("or you are not root, or the msr driver is not present\n"); | ||
87 | return 1; | ||
88 | } | ||
89 | |||
90 | decode(lo); | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | int main (int argc, char **argv) | ||
96 | { | ||
97 | unsigned int cpu, mode = 0; | ||
98 | |||
99 | if (argc < 2) | ||
100 | cpu = 0; | ||
101 | else { | ||
102 | cpu = strtoul(argv[1], NULL, 0); | ||
103 | if (cpu >= MCPU) | ||
104 | mode = 1; | ||
105 | } | ||
106 | |||
107 | if (mode) | ||
108 | decode(cpu); | ||
109 | else | ||
110 | decode_live(cpu); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
diff --git a/tools/power/cpupower/debug/i386/dump_psb.c b/tools/power/cpupower/debug/i386/dump_psb.c new file mode 100644 index 00000000000..8d6a4751425 --- /dev/null +++ b/tools/power/cpupower/debug/i386/dump_psb.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * dump_psb. (c) 2004, Dave Jones, Red Hat Inc. | ||
3 | * Licensed under the GPL v2. | ||
4 | */ | ||
5 | |||
6 | #include <fcntl.h> | ||
7 | #include <stdio.h> | ||
8 | #include <stdlib.h> | ||
9 | #include <string.h> | ||
10 | #include <unistd.h> | ||
11 | |||
12 | #define _GNU_SOURCE | ||
13 | #include <getopt.h> | ||
14 | |||
15 | #include <sys/mman.h> | ||
16 | |||
17 | #define LEN (0x100000 - 0xc0000) | ||
18 | #define OFFSET (0xc0000) | ||
19 | |||
20 | #ifndef __packed | ||
21 | #define __packed __attribute((packed)) | ||
22 | #endif | ||
23 | |||
24 | static long relevant; | ||
25 | |||
26 | static const int fid_to_mult[32] = { | ||
27 | 110, 115, 120, 125, 50, 55, 60, 65, | ||
28 | 70, 75, 80, 85, 90, 95, 100, 105, | ||
29 | 30, 190, 40, 200, 130, 135, 140, 210, | ||
30 | 150, 225, 160, 165, 170, 180, -1, -1, | ||
31 | }; | ||
32 | |||
33 | static const int vid_to_voltage[32] = { | ||
34 | 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, | ||
35 | 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, | ||
36 | 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, | ||
37 | 1075, 1050, 1024, 1000, 975, 950, 925, 0, | ||
38 | }; | ||
39 | |||
40 | struct psb_header { | ||
41 | char signature[10]; | ||
42 | u_char version; | ||
43 | u_char flags; | ||
44 | u_short settlingtime; | ||
45 | u_char res1; | ||
46 | u_char numpst; | ||
47 | } __packed; | ||
48 | |||
49 | struct pst_header { | ||
50 | u_int32_t cpuid; | ||
51 | u_char fsb; | ||
52 | u_char maxfid; | ||
53 | u_char startvid; | ||
54 | u_char numpstates; | ||
55 | } __packed; | ||
56 | |||
57 | static u_int fsb; | ||
58 | static u_int sgtc; | ||
59 | |||
60 | static int | ||
61 | decode_pst(char *p, int npstates) | ||
62 | { | ||
63 | int i; | ||
64 | int freq, fid, vid; | ||
65 | |||
66 | for (i = 0; i < npstates; ++i) { | ||
67 | fid = *p++; | ||
68 | vid = *p++; | ||
69 | freq = 100 * fid_to_mult[fid] * fsb; | ||
70 | |||
71 | printf(" %2d %8dkHz FID %02x (%2d.%01d) VID %02x (%4dmV)\n", | ||
72 | i, | ||
73 | freq, | ||
74 | fid, fid_to_mult[fid]/10, fid_to_mult[fid]%10, | ||
75 | vid, vid_to_voltage[vid]); | ||
76 | } | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static | ||
82 | void decode_psb(char *p, int numpst) | ||
83 | { | ||
84 | int i; | ||
85 | struct psb_header *psb; | ||
86 | struct pst_header *pst; | ||
87 | |||
88 | psb = (struct psb_header*) p; | ||
89 | |||
90 | if (psb->version != 0x12) | ||
91 | return; | ||
92 | |||
93 | printf("PSB version: %hhx flags: %hhx settling time %hhuus res1 %hhx num pst %hhu\n", | ||
94 | psb->version, | ||
95 | psb->flags, | ||
96 | psb->settlingtime, | ||
97 | psb->res1, | ||
98 | psb->numpst); | ||
99 | sgtc = psb->settlingtime * 100; | ||
100 | |||
101 | if (sgtc < 10000) | ||
102 | sgtc = 10000; | ||
103 | |||
104 | p = ((char *) psb) + sizeof(struct psb_header); | ||
105 | |||
106 | if (numpst < 0) | ||
107 | numpst = psb->numpst; | ||
108 | else | ||
109 | printf("Overriding number of pst :%d\n", numpst); | ||
110 | |||
111 | for (i = 0; i < numpst; i++) { | ||
112 | pst = (struct pst_header*) p; | ||
113 | |||
114 | if (relevant != 0) { | ||
115 | if (relevant!= pst->cpuid) | ||
116 | goto next_one; | ||
117 | } | ||
118 | |||
119 | printf(" PST %d cpuid %.3x fsb %hhu mfid %hhx svid %hhx numberstates %hhu\n", | ||
120 | i+1, | ||
121 | pst->cpuid, | ||
122 | pst->fsb, | ||
123 | pst->maxfid, | ||
124 | pst->startvid, | ||
125 | pst->numpstates); | ||
126 | |||
127 | fsb = pst->fsb; | ||
128 | decode_pst(p + sizeof(struct pst_header), pst->numpstates); | ||
129 | |||
130 | next_one: | ||
131 | p += sizeof(struct pst_header) + 2*pst->numpstates; | ||
132 | } | ||
133 | |||
134 | } | ||
135 | |||
136 | static struct option info_opts[] = { | ||
137 | {.name = "numpst", .has_arg=no_argument, .flag=NULL, .val='n'}, | ||
138 | }; | ||
139 | |||
140 | void print_help(void) | ||
141 | { | ||
142 | printf ("Usage: dump_psb [options]\n"); | ||
143 | printf ("Options:\n"); | ||
144 | printf (" -n, --numpst Set number of PST tables to scan\n"); | ||
145 | printf (" -r, --relevant Only display PSTs relevant to cpuid N\n"); | ||
146 | } | ||
147 | |||
148 | int | ||
149 | main(int argc, char *argv[]) | ||
150 | { | ||
151 | int fd; | ||
152 | int numpst=-1; | ||
153 | int ret=0, cont=1; | ||
154 | char *mem = NULL; | ||
155 | char *p; | ||
156 | |||
157 | do { | ||
158 | ret = getopt_long(argc, argv, "hr:n:", info_opts, NULL); | ||
159 | switch (ret){ | ||
160 | case '?': | ||
161 | case 'h': | ||
162 | print_help(); | ||
163 | cont = 0; | ||
164 | break; | ||
165 | case 'r': | ||
166 | relevant = strtol(optarg, NULL, 16); | ||
167 | break; | ||
168 | case 'n': | ||
169 | numpst = strtol(optarg, NULL, 10); | ||
170 | break; | ||
171 | case -1: | ||
172 | cont = 0; | ||
173 | break; | ||
174 | } | ||
175 | |||
176 | } while(cont); | ||
177 | |||
178 | fd = open("/dev/mem", O_RDONLY); | ||
179 | if (fd < 0) { | ||
180 | printf ("Couldn't open /dev/mem. Are you root?\n"); | ||
181 | exit(1); | ||
182 | } | ||
183 | |||
184 | mem = mmap(mem, 0x100000 - 0xc0000, PROT_READ, MAP_SHARED, fd, 0xc0000); | ||
185 | close(fd); | ||
186 | |||
187 | for (p = mem; p - mem < LEN; p+=16) { | ||
188 | if (memcmp(p, "AMDK7PNOW!", 10) == 0) { | ||
189 | decode_psb(p, numpst); | ||
190 | break; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | munmap(mem, LEN); | ||
195 | return 0; | ||
196 | } | ||
diff --git a/tools/power/cpupower/debug/i386/intel_gsic.c b/tools/power/cpupower/debug/i386/intel_gsic.c new file mode 100644 index 00000000000..53f5293c9c9 --- /dev/null +++ b/tools/power/cpupower/debug/i386/intel_gsic.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * (C) 2003 Bruno Ducrot | ||
3 | * (C) 2004 Dominik Brodowski <linux@dominikbrodowski.de> | ||
4 | * | ||
5 | * Licensed under the terms of the GNU GPL License version 2. | ||
6 | * | ||
7 | * Based on code found in | ||
8 | * linux/include/asm-i386/ist.h and linux/arch/i386/kernel/setup.c | ||
9 | * and originally developed by Andy Grover <andrew.grover@intel.com> | ||
10 | */ | ||
11 | |||
12 | #include <stdio.h> | ||
13 | #include <string.h> | ||
14 | #include <lrmi.h> | ||
15 | |||
16 | int main (void) | ||
17 | { | ||
18 | struct LRMI_regs r; | ||
19 | int retval; | ||
20 | |||
21 | if (!LRMI_init()) | ||
22 | return 0; | ||
23 | |||
24 | memset(&r, 0, sizeof(r)); | ||
25 | |||
26 | r.eax = 0x0000E980; | ||
27 | r.edx = 0x47534943; | ||
28 | |||
29 | retval = LRMI_int(0x15, &r); | ||
30 | |||
31 | if (!retval) { | ||
32 | printf("Failed!\n"); | ||
33 | return 0; | ||
34 | } | ||
35 | if (r.eax == 0x47534943) { | ||
36 | printf("BIOS supports GSIC call:\n"); | ||
37 | printf("\tsignature: %c%c%c%c\n", | ||
38 | (r.eax >> 24) & 0xff, | ||
39 | (r.eax >> 16) & 0xff, | ||
40 | (r.eax >> 8) & 0xff, | ||
41 | (r.eax) & 0xff); | ||
42 | printf("\tcommand port = 0x%.4x\n", | ||
43 | r.ebx & 0xffff); | ||
44 | printf("\tcommand = 0x%.4x\n", | ||
45 | (r.ebx >> 16) & 0xffff); | ||
46 | printf("\tevent port = 0x%.8x\n", r.ecx); | ||
47 | printf("\tflags = 0x%.8x\n", r.edx); | ||
48 | if (((r.ebx >> 16) & 0xffff) != 0x82) { | ||
49 | printf("non-default command value. If speedstep-smi " | ||
50 | "doesn't work out of the box,\nyou may want to " | ||
51 | "try out the default value by passing " | ||
52 | "smi_cmd=0x82 to the module\n ON YOUR OWN " | ||
53 | "RISK.\n"); | ||
54 | } | ||
55 | if ((r.ebx & 0xffff) != 0xb2) { | ||
56 | printf("non-default command port. If speedstep-smi " | ||
57 | "doesn't work out of the box,\nyou may want to " | ||
58 | "try out the default value by passing " | ||
59 | "smi_port=0x82 to the module\n ON YOUR OWN " | ||
60 | "RISK.\n"); | ||
61 | } | ||
62 | } else { | ||
63 | printf("BIOS DOES NOT support GSIC call. Dumping registers anyway:\n"); | ||
64 | printf("eax = 0x%.8x\n", r.eax); | ||
65 | printf("ebx = 0x%.8x\n", r.ebx); | ||
66 | printf("ecx = 0x%.8x\n", r.ecx); | ||
67 | printf("edx = 0x%.8x\n", r.edx); | ||
68 | printf("Note also that some BIOS do not support the initial " | ||
69 | "GSIC call, but the newer\nspeeedstep-smi driver may " | ||
70 | "work.\nFor this, you need to pass some arguments to " | ||
71 | "the speedstep-smi driver:\n"); | ||
72 | printf("\tsmi_cmd=0x?? smi_port=0x?? smi_sig=1\n"); | ||
73 | printf("\nUnfortunately, you have to know what exactly are " | ||
74 | "smi_cmd and smi_port, and this\nis system " | ||
75 | "dependant.\n"); | ||
76 | } | ||
77 | return 1; | ||
78 | } | ||
diff --git a/tools/power/cpupower/debug/i386/powernow-k8-decode.c b/tools/power/cpupower/debug/i386/powernow-k8-decode.c new file mode 100644 index 00000000000..638a6b3bfd9 --- /dev/null +++ b/tools/power/cpupower/debug/i386/powernow-k8-decode.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * (C) 2004 Bruno Ducrot <ducrot@poupinou.org> | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | * Based on code found in | ||
7 | * linux/arch/i386/kernel/cpu/cpufreq/powernow-k8.c | ||
8 | * and originally developed by Paul Devriendt | ||
9 | */ | ||
10 | |||
11 | #include <stdio.h> | ||
12 | #include <stdlib.h> | ||
13 | #include <stdint.h> | ||
14 | #include <unistd.h> | ||
15 | #include <errno.h> | ||
16 | #include <fcntl.h> | ||
17 | |||
18 | #include <sys/types.h> | ||
19 | #include <sys/stat.h> | ||
20 | |||
21 | #define MCPU 32 | ||
22 | |||
23 | #define MSR_FIDVID_STATUS 0xc0010042 | ||
24 | |||
25 | #define MSR_S_HI_CURRENT_VID 0x0000001f | ||
26 | #define MSR_S_LO_CURRENT_FID 0x0000003f | ||
27 | |||
28 | static int get_fidvid(uint32_t cpu, uint32_t *fid, uint32_t *vid) | ||
29 | { | ||
30 | int err = 1; | ||
31 | uint64_t msr = 0; | ||
32 | int fd; | ||
33 | char file[20]; | ||
34 | |||
35 | if (cpu > MCPU) | ||
36 | goto out; | ||
37 | |||
38 | sprintf(file, "/dev/cpu/%d/msr", cpu); | ||
39 | |||
40 | fd = open(file, O_RDONLY); | ||
41 | if (fd < 0) | ||
42 | goto out; | ||
43 | lseek(fd, MSR_FIDVID_STATUS, SEEK_CUR); | ||
44 | if (read(fd, &msr, 8) != 8) | ||
45 | goto err1; | ||
46 | |||
47 | *fid = ((uint32_t )(msr & 0xffffffffull)) & MSR_S_LO_CURRENT_FID; | ||
48 | *vid = ((uint32_t )(msr>>32 & 0xffffffffull)) & MSR_S_HI_CURRENT_VID; | ||
49 | err = 0; | ||
50 | err1: | ||
51 | close(fd); | ||
52 | out: | ||
53 | return err; | ||
54 | } | ||
55 | |||
56 | |||
57 | /* Return a frequency in MHz, given an input fid */ | ||
58 | static uint32_t find_freq_from_fid(uint32_t fid) | ||
59 | { | ||
60 | return 800 + (fid * 100); | ||
61 | } | ||
62 | |||
63 | /* Return a voltage in miliVolts, given an input vid */ | ||
64 | static uint32_t find_millivolts_from_vid(uint32_t vid) | ||
65 | { | ||
66 | return 1550-vid*25; | ||
67 | } | ||
68 | |||
69 | int main (int argc, char *argv[]) | ||
70 | { | ||
71 | int err; | ||
72 | int cpu; | ||
73 | uint32_t fid, vid; | ||
74 | |||
75 | if (argc < 2) | ||
76 | cpu = 0; | ||
77 | else | ||
78 | cpu = strtoul(argv[1], NULL, 0); | ||
79 | |||
80 | err = get_fidvid(cpu, &fid, &vid); | ||
81 | |||
82 | if (err) { | ||
83 | printf("can't get fid, vid from MSR\n"); | ||
84 | printf("Possible trouble: you don't run a powernow-k8 capable cpu\n"); | ||
85 | printf("or you are not root, or the msr driver is not present\n"); | ||
86 | exit(1); | ||
87 | } | ||
88 | |||
89 | |||
90 | printf("cpu %d currently at %d MHz and %d mV\n", | ||
91 | cpu, | ||
92 | find_freq_from_fid(fid), | ||
93 | find_millivolts_from_vid(vid)); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
diff --git a/tools/power/cpupower/debug/kernel/Makefile b/tools/power/cpupower/debug/kernel/Makefile new file mode 100644 index 00000000000..96b146fe6f8 --- /dev/null +++ b/tools/power/cpupower/debug/kernel/Makefile | |||
@@ -0,0 +1,23 @@ | |||
1 | obj-m := | ||
2 | |||
3 | KDIR := /lib/modules/$(shell uname -r)/build | ||
4 | PWD := $(shell pwd) | ||
5 | KMISC := /lib/modules/$(shell uname -r)/cpufrequtils/ | ||
6 | |||
7 | ifeq ("$(CONFIG_X86_TSC)", "y") | ||
8 | obj-m += cpufreq-test_tsc.o | ||
9 | endif | ||
10 | |||
11 | default: | ||
12 | $(MAKE) -C $(KDIR) M=$(PWD) | ||
13 | |||
14 | clean: | ||
15 | - rm -rf *.o *.ko .tmp-versions .*.cmd .*.mod.* *.mod.c | ||
16 | - rm -rf .tmp_versions* Module.symvers modules.order | ||
17 | |||
18 | install: default | ||
19 | install -d $(KMISC) | ||
20 | install -m 644 -c *.ko $(KMISC) | ||
21 | /sbin/depmod -a | ||
22 | |||
23 | all: default | ||
diff --git a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c new file mode 100644 index 00000000000..66cace601e5 --- /dev/null +++ b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * test module to check whether the TSC-based delay routine continues | ||
3 | * to work properly after cpufreq transitions. Needs ACPI to work | ||
4 | * properly. | ||
5 | * | ||
6 | * Based partly on the Power Management Timer (PMTMR) code to be found | ||
7 | * in arch/i386/kernel/timers/timer_pm.c on recent 2.6. kernels, especially | ||
8 | * code written by John Stultz. The read_pmtmr function was copied verbatim | ||
9 | * from that file. | ||
10 | * | ||
11 | * (C) 2004 Dominik Brodowski | ||
12 | * | ||
13 | * To use: | ||
14 | * 1.) pass clock=tsc to the kernel on your bootloader | ||
15 | * 2.) modprobe this module (it'll fail) | ||
16 | * 3.) change CPU frequency | ||
17 | * 4.) modprobe this module again | ||
18 | * 5.) if the third value, "diff_pmtmr", changes between 2. and 4., the | ||
19 | * TSC-based delay routine on the Linux kernel does not correctly | ||
20 | * handle the cpufreq transition. Please report this to | ||
21 | * cpufreq@vger.kernel.org | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/delay.h> | ||
28 | |||
29 | #include <asm/io.h> | ||
30 | |||
31 | #include <acpi/acpi_bus.h> | ||
32 | #include <acpi/acpi_drivers.h> | ||
33 | |||
34 | static int pm_tmr_ioport = 0; | ||
35 | |||
36 | /*helper function to safely read acpi pm timesource*/ | ||
37 | static u32 read_pmtmr(void) | ||
38 | { | ||
39 | u32 v1=0,v2=0,v3=0; | ||
40 | /* It has been reported that because of various broken | ||
41 | * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM time | ||
42 | * source is not latched, so you must read it multiple | ||
43 | * times to insure a safe value is read. | ||
44 | */ | ||
45 | do { | ||
46 | v1 = inl(pm_tmr_ioport); | ||
47 | v2 = inl(pm_tmr_ioport); | ||
48 | v3 = inl(pm_tmr_ioport); | ||
49 | } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) | ||
50 | || (v3 > v1 && v3 < v2)); | ||
51 | |||
52 | /* mask the output to 24 bits */ | ||
53 | return (v2 & 0xFFFFFF); | ||
54 | } | ||
55 | |||
56 | static int __init cpufreq_test_tsc(void) | ||
57 | { | ||
58 | u32 now, then, diff; | ||
59 | u64 now_tsc, then_tsc, diff_tsc; | ||
60 | int i; | ||
61 | |||
62 | /* the following code snipped is copied from arch/x86/kernel/acpi/boot.c | ||
63 | of Linux v2.6.25. */ | ||
64 | |||
65 | /* detect the location of the ACPI PM Timer */ | ||
66 | if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) { | ||
67 | /* FADT rev. 2 */ | ||
68 | if (acpi_gbl_FADT.xpm_timer_block.space_id != | ||
69 | ACPI_ADR_SPACE_SYSTEM_IO) | ||
70 | return 0; | ||
71 | |||
72 | pm_tmr_ioport = acpi_gbl_FADT.xpm_timer_block.address; | ||
73 | /* | ||
74 | * "X" fields are optional extensions to the original V1.0 | ||
75 | * fields, so we must selectively expand V1.0 fields if the | ||
76 | * corresponding X field is zero. | ||
77 | */ | ||
78 | if (!pm_tmr_ioport) | ||
79 | pm_tmr_ioport = acpi_gbl_FADT.pm_timer_block; | ||
80 | } else { | ||
81 | /* FADT rev. 1 */ | ||
82 | pm_tmr_ioport = acpi_gbl_FADT.pm_timer_block; | ||
83 | } | ||
84 | |||
85 | printk(KERN_DEBUG "start--> \n"); | ||
86 | then = read_pmtmr(); | ||
87 | rdtscll(then_tsc); | ||
88 | for (i=0;i<20;i++) { | ||
89 | mdelay(100); | ||
90 | now = read_pmtmr(); | ||
91 | rdtscll(now_tsc); | ||
92 | diff = (now - then) & 0xFFFFFF; | ||
93 | diff_tsc = now_tsc - then_tsc; | ||
94 | printk(KERN_DEBUG "t1: %08u t2: %08u diff_pmtmr: %08u diff_tsc: %016llu\n", then, now, diff, diff_tsc); | ||
95 | then = now; | ||
96 | then_tsc = now_tsc; | ||
97 | } | ||
98 | printk(KERN_DEBUG "<-- end \n"); | ||
99 | return -ENODEV; | ||
100 | } | ||
101 | |||
102 | static void __exit cpufreq_none(void) | ||
103 | { | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | module_init(cpufreq_test_tsc) | ||
108 | module_exit(cpufreq_none) | ||
109 | |||
110 | |||
111 | MODULE_AUTHOR("Dominik Brodowski"); | ||
112 | MODULE_DESCRIPTION("Verify the TSC cpufreq notifier working correctly -- needs ACPI-enabled system"); | ||
113 | MODULE_LICENSE ("GPL"); | ||
diff --git a/tools/power/cpupower/debug/x86_64/Makefile b/tools/power/cpupower/debug/x86_64/Makefile new file mode 100644 index 00000000000..3326217dd31 --- /dev/null +++ b/tools/power/cpupower/debug/x86_64/Makefile | |||
@@ -0,0 +1,14 @@ | |||
1 | default: all | ||
2 | |||
3 | centrino-decode: ../i386/centrino-decode.c | ||
4 | $(CC) $(CFLAGS) -o $@ $< | ||
5 | |||
6 | powernow-k8-decode: ../i386/powernow-k8-decode.c | ||
7 | $(CC) $(CFLAGS) -o $@ $< | ||
8 | |||
9 | all: centrino-decode powernow-k8-decode | ||
10 | |||
11 | clean: | ||
12 | rm -rf centrino-decode powernow-k8-decode | ||
13 | |||
14 | .PHONY: all default clean | ||