aboutsummaryrefslogtreecommitdiffstats
path: root/tools/power/cpupower/utils/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'tools/power/cpupower/utils/helpers')
-rw-r--r--tools/power/cpupower/utils/helpers/amd.c137
-rw-r--r--tools/power/cpupower/utils/helpers/bitmask.c290
-rw-r--r--tools/power/cpupower/utils/helpers/bitmask.h33
-rw-r--r--tools/power/cpupower/utils/helpers/cpuid.c145
-rw-r--r--tools/power/cpupower/utils/helpers/helpers.h180
-rw-r--r--tools/power/cpupower/utils/helpers/misc.c34
-rw-r--r--tools/power/cpupower/utils/helpers/msr.c122
-rw-r--r--tools/power/cpupower/utils/helpers/pci.c44
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c350
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.h23
-rw-r--r--tools/power/cpupower/utils/helpers/topology.c108
11 files changed, 1466 insertions, 0 deletions
diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c
new file mode 100644
index 00000000000..5e44e31fc7f
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/amd.c
@@ -0,0 +1,137 @@
1#if defined(__i386__) || defined(__x86_64__)
2#include <unistd.h>
3#include <errno.h>
4#include <stdio.h>
5#include <stdint.h>
6
7#include <pci/pci.h>
8
9#include "helpers/helpers.h"
10
11#define MSR_AMD_PSTATE_STATUS 0xc0010063
12#define MSR_AMD_PSTATE 0xc0010064
13#define MSR_AMD_PSTATE_LIMIT 0xc0010061
14
15union msr_pstate {
16 struct {
17 unsigned fid:6;
18 unsigned did:3;
19 unsigned vid:7;
20 unsigned res1:6;
21 unsigned nbdid:1;
22 unsigned res2:2;
23 unsigned nbvid:7;
24 unsigned iddval:8;
25 unsigned idddiv:2;
26 unsigned res3:21;
27 unsigned en:1;
28 } bits;
29 unsigned long long val;
30};
31
32static int get_did(int family, union msr_pstate pstate)
33{
34 int t;
35
36 if (family == 0x12)
37 t = pstate.val & 0xf;
38 else
39 t = pstate.bits.did;
40
41 return t;
42}
43
44static int get_cof(int family, union msr_pstate pstate)
45{
46 int t;
47 int fid, did;
48
49 did = get_did(family, pstate);
50
51 t = 0x10;
52 fid = pstate.bits.fid;
53 if (family == 0x11)
54 t = 0x8;
55
56 return ((100 * (fid + t)) >> did);
57 }
58
59/* Needs:
60 * cpu -> the cpu that gets evaluated
61 * cpu_family -> The cpu's family (0x10, 0x12,...)
62 * boots_states -> how much boost states the machines support
63 *
64 * Fills up:
65 * pstates -> a pointer to an array of size MAX_HW_PSTATES
66 * must be initialized with zeros.
67 * All available HW pstates (including boost states)
68 * no -> amount of pstates above array got filled up with
69 *
70 * returns zero on success, -1 on failure
71 */
72int decode_pstates(unsigned int cpu, unsigned int cpu_family,
73 int boost_states, unsigned long *pstates, int *no)
74{
75 int i, psmax, pscur;
76 union msr_pstate pstate;
77 unsigned long long val;
78
79 /* Only read out frequencies from HW when CPU might be boostable
80 to keep the code as short and clean as possible.
81 Otherwise frequencies are exported via ACPI tables.
82 */
83 if (cpu_family < 0x10 || cpu_family == 0x14)
84 return -1;
85
86 if (read_msr(cpu, MSR_AMD_PSTATE_LIMIT, &val))
87 return -1;
88
89 psmax = (val >> 4) & 0x7;
90
91 if (read_msr(cpu, MSR_AMD_PSTATE_STATUS, &val))
92 return -1;
93
94 pscur = val & 0x7;
95
96 pscur += boost_states;
97 psmax += boost_states;
98 for (i=0; i<=psmax; i++) {
99 if (i >= MAX_HW_PSTATES) {
100 fprintf(stderr, "HW pstates [%d] exceeding max [%d]\n",
101 psmax, MAX_HW_PSTATES);
102 return -1;
103 }
104 if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val))
105 return -1;
106 pstates[i] = get_cof(cpu_family, pstate);
107 }
108 *no = i;
109 return 0;
110}
111
112int amd_pci_get_num_boost_states(int *active, int *states)
113{
114 struct pci_access *pci_acc;
115 int vendor_id = 0x1022;
116 int boost_dev_ids[4] = {0x1204, 0x1604, 0x1704, 0};
117 struct pci_dev *device;
118 uint8_t val = 0;
119
120 *active = *states = 0;
121
122 device = pci_acc_init(&pci_acc, vendor_id, boost_dev_ids);
123
124 if (device == NULL)
125 return -ENODEV;
126
127 val = pci_read_byte(device, 0x15c);
128 if (val & 3)
129 *active = 1;
130 else
131 *active = 0;
132 *states = (val >> 2) & 7;
133
134 pci_cleanup(pci_acc);
135 return 0;
136}
137#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/bitmask.c b/tools/power/cpupower/utils/helpers/bitmask.c
new file mode 100644
index 00000000000..60f4d69bb20
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/bitmask.c
@@ -0,0 +1,290 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include <helpers/bitmask.h>
6
7/* How many bits in an unsigned long */
8#define bitsperlong (8 * sizeof(unsigned long))
9
10/* howmany(a,b) : how many elements of size b needed to hold all of a */
11#define howmany(x,y) (((x)+((y)-1))/(y))
12
13/* How many longs in mask of n bits */
14#define longsperbits(n) howmany(n, bitsperlong)
15
16#define max(a,b) ((a) > (b) ? (a) : (b))
17
18/*
19 * Allocate and free `struct bitmask *`
20 */
21
22/* Allocate a new `struct bitmask` with a size of n bits */
23struct bitmask *bitmask_alloc(unsigned int n)
24{
25 struct bitmask *bmp;
26
27 bmp = malloc(sizeof(*bmp));
28 if (bmp == 0)
29 return 0;
30 bmp->size = n;
31 bmp->maskp = calloc(longsperbits(n), sizeof(unsigned long));
32 if (bmp->maskp == 0) {
33 free(bmp);
34 return 0;
35 }
36 return bmp;
37}
38
39/* Free `struct bitmask` */
40void bitmask_free(struct bitmask *bmp)
41{
42 if (bmp == 0)
43 return;
44 free(bmp->maskp);
45 bmp->maskp = (unsigned long *)0xdeadcdef; /* double free tripwire */
46 free(bmp);
47}
48
49/*
50 * The routines _getbit() and _setbit() are the only
51 * routines that actually understand the layout of bmp->maskp[].
52 *
53 * On little endian architectures, this could simply be an array of
54 * bytes. But the kernel layout of bitmasks _is_ visible to userspace
55 * via the sched_(set/get)affinity calls in Linux 2.6, and on big
56 * endian architectures, it is painfully obvious that this is an
57 * array of unsigned longs.
58 */
59
60/* Return the value (0 or 1) of bit n in bitmask bmp */
61static unsigned int _getbit(const struct bitmask *bmp, unsigned int n)
62{
63 if (n < bmp->size)
64 return (bmp->maskp[n/bitsperlong] >> (n % bitsperlong)) & 1;
65 else
66 return 0;
67}
68
69/* Set bit n in bitmask bmp to value v (0 or 1) */
70static void _setbit(struct bitmask *bmp, unsigned int n, unsigned int v)
71{
72 if (n < bmp->size) {
73 if (v)
74 bmp->maskp[n/bitsperlong] |= 1UL << (n % bitsperlong);
75 else
76 bmp->maskp[n/bitsperlong] &= ~(1UL << (n % bitsperlong));
77 }
78}
79
80/*
81 * When parsing bitmask lists, only allow numbers, separated by one
82 * of the allowed next characters.
83 *
84 * The parameter 'sret' is the return from a sscanf "%u%c". It is
85 * -1 if the sscanf input string was empty. It is 0 if the first
86 * character in the sscanf input string was not a decimal number.
87 * It is 1 if the unsigned number matching the "%u" was the end of the
88 * input string. It is 2 if one or more additional characters followed
89 * the matched unsigned number. If it is 2, then 'nextc' is the first
90 * character following the number. The parameter 'ok_next_chars'
91 * is the nul-terminated list of allowed next characters.
92 *
93 * The mask term just scanned was ok if and only if either the numbers
94 * matching the %u were all of the input or if the next character in
95 * the input past the numbers was one of the allowed next characters.
96 */
97static int scan_was_ok(int sret, char nextc, const char *ok_next_chars)
98{
99 return sret == 1 ||
100 (sret == 2 && strchr(ok_next_chars, nextc) != NULL);
101}
102
103static const char *nexttoken(const char *q, int sep)
104{
105 if (q)
106 q = strchr(q, sep);
107 if (q)
108 q++;
109 return q;
110}
111
112/* Set a single bit i in bitmask */
113struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i)
114{
115 _setbit(bmp, i, 1);
116 return bmp;
117}
118
119/* Set all bits in bitmask: bmp = ~0 */
120struct bitmask *bitmask_setall(struct bitmask *bmp)
121{
122 unsigned int i;
123 for (i = 0; i < bmp->size; i++)
124 _setbit(bmp, i, 1);
125 return bmp;
126}
127
128/* Clear all bits in bitmask: bmp = 0 */
129struct bitmask *bitmask_clearall(struct bitmask *bmp)
130{
131 unsigned int i;
132 for (i = 0; i < bmp->size; i++)
133 _setbit(bmp, i, 0);
134 return bmp;
135}
136
137/* True if all bits are clear */
138int bitmask_isallclear(const struct bitmask *bmp)
139{
140 unsigned int i;
141 for (i = 0; i < bmp->size; i++)
142 if (_getbit(bmp, i))
143 return 0;
144 return 1;
145}
146
147/* True if specified bit i is set */
148int bitmask_isbitset(const struct bitmask *bmp, unsigned int i)
149{
150 return _getbit(bmp, i);
151}
152
153/* Number of lowest set bit (min) */
154unsigned int bitmask_first(const struct bitmask *bmp)
155{
156 return bitmask_next(bmp, 0);
157}
158
159/* Number of highest set bit (max) */
160unsigned int bitmask_last(const struct bitmask *bmp)
161{
162 unsigned int i;
163 unsigned int m = bmp->size;
164 for (i = 0; i < bmp->size; i++)
165 if (_getbit(bmp, i))
166 m = i;
167 return m;
168}
169
170/* Number of next set bit at or above given bit i */
171unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i)
172{
173 unsigned int n;
174 for (n = i; n < bmp->size; n++)
175 if (_getbit(bmp, n))
176 break;
177 return n;
178}
179
180/*
181 * Parses a comma-separated list of numbers and ranges of numbers,
182 * with optional ':%u' strides modifying ranges, into provided bitmask.
183 * Some examples of input lists and their equivalent simple list:
184 * Input Equivalent to
185 * 0-3 0,1,2,3
186 * 0-7:2 0,2,4,6
187 * 1,3,5-7 1,3,5,6,7
188 * 0-3:2,8-15:4 0,2,8,12
189 */
190int bitmask_parselist(const char *buf, struct bitmask *bmp)
191{
192 const char *p, *q;
193
194 bitmask_clearall(bmp);
195
196 q = buf;
197 while (p = q, q = nexttoken(q, ','), p) {
198 unsigned int a; /* begin of range */
199 unsigned int b; /* end of range */
200 unsigned int s; /* stride */
201 const char *c1, *c2; /* next tokens after '-' or ',' */
202 char nextc; /* char after sscanf %u match */
203 int sret; /* sscanf return (number of matches) */
204
205 sret = sscanf(p, "%u%c", &a, &nextc);
206 if (!scan_was_ok(sret, nextc, ",-"))
207 goto err;
208 b = a;
209 s = 1;
210 c1 = nexttoken(p, '-');
211 c2 = nexttoken(p, ',');
212 if (c1 != NULL && (c2 == NULL || c1 < c2)) {
213 sret = sscanf(c1, "%u%c", &b, &nextc);
214 if (!scan_was_ok(sret, nextc, ",:"))
215 goto err;
216 c1 = nexttoken(c1, ':');
217 if (c1 != NULL && (c2 == NULL || c1 < c2)) {
218 sret = sscanf(c1, "%u%c", &s, &nextc);
219 if (!scan_was_ok(sret, nextc, ","))
220 goto err;
221 }
222 }
223 if (!(a <= b))
224 goto err;
225 if (b >= bmp->size)
226 goto err;
227 while (a <= b) {
228 _setbit(bmp, a, 1);
229 a += s;
230 }
231 }
232 return 0;
233err:
234 bitmask_clearall(bmp);
235 return -1;
236}
237
238/*
239 * emit(buf, buflen, rbot, rtop, len)
240 *
241 * Helper routine for bitmask_displaylist(). Write decimal number
242 * or range to buf+len, suppressing output past buf+buflen, with optional
243 * comma-prefix. Return len of what would be written to buf, if it
244 * all fit.
245 */
246
247static inline int emit(char *buf, int buflen, int rbot, int rtop, int len)
248{
249 if (len > 0)
250 len += snprintf(buf + len, max(buflen - len, 0), ",");
251 if (rbot == rtop)
252 len += snprintf(buf + len, max(buflen - len, 0), "%d", rbot);
253 else
254 len += snprintf(buf + len, max(buflen - len, 0), "%d-%d", rbot, rtop);
255 return len;
256}
257
258/*
259 * Write decimal list representation of bmp to buf.
260 *
261 * Output format is a comma-separated list of decimal numbers and
262 * ranges. Consecutively set bits are shown as two hyphen-separated
263 * decimal numbers, the smallest and largest bit numbers set in
264 * the range. Output format is compatible with the format
265 * accepted as input by bitmap_parselist().
266 *
267 * The return value is the number of characters which would be
268 * generated for the given input, excluding the trailing '\0', as
269 * per ISO C99.
270 */
271
272int bitmask_displaylist(char *buf, int buflen, const struct bitmask *bmp)
273{
274 int len = 0;
275 /* current bit is 'cur', most recently seen range is [rbot, rtop] */
276 unsigned int cur, rbot, rtop;
277
278 if (buflen > 0)
279 *buf = 0;
280 rbot = cur = bitmask_first(bmp);
281 while (cur < bmp->size) {
282 rtop = cur;
283 cur = bitmask_next(bmp, cur+1);
284 if (cur >= bmp->size || cur > rtop + 1) {
285 len = emit(buf, buflen, rbot, rtop, len);
286 rbot = cur;
287 }
288 }
289 return len;
290}
diff --git a/tools/power/cpupower/utils/helpers/bitmask.h b/tools/power/cpupower/utils/helpers/bitmask.h
new file mode 100644
index 00000000000..eb289df4105
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/bitmask.h
@@ -0,0 +1,33 @@
1#ifndef __CPUPOWER_BITMASK__
2#define __CPUPOWER_BITMASK__
3
4/* Taken over from libbitmask, a project initiated from sgi:
5 * Url: http://oss.sgi.com/projects/cpusets/
6 * Unfortunately it's not very widespread, therefore relevant parts are
7 * pasted here.
8 */
9
10struct bitmask {
11 unsigned int size;
12 unsigned long *maskp;
13};
14
15struct bitmask *bitmask_alloc(unsigned int n);
16void bitmask_free(struct bitmask *bmp);
17
18struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i);
19struct bitmask *bitmask_setall(struct bitmask *bmp);
20struct bitmask *bitmask_clearall(struct bitmask *bmp);
21
22unsigned int bitmask_first(const struct bitmask *bmp);
23unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i);
24unsigned int bitmask_last(const struct bitmask *bmp);
25int bitmask_isallclear(const struct bitmask *bmp);
26int bitmask_isbitset(const struct bitmask *bmp, unsigned int i);
27
28int bitmask_parselist(const char *buf, struct bitmask *bmp);
29int bitmask_displaylist(char *buf, int len, const struct bitmask *bmp);
30
31
32
33#endif /*__CPUPOWER_BITMASK__ */
diff --git a/tools/power/cpupower/utils/helpers/cpuid.c b/tools/power/cpupower/utils/helpers/cpuid.c
new file mode 100644
index 00000000000..71021f3bb69
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/cpuid.c
@@ -0,0 +1,145 @@
1#include <stdio.h>
2#include <errno.h>
3#include <string.h>
4#include <unistd.h>
5#include <stdlib.h>
6
7#include "helpers/helpers.h"
8
9static const char *cpu_vendor_table[X86_VENDOR_MAX] = {
10 "Unknown", "GenuineIntel", "AuthenticAMD",
11};
12
13#if defined(__i386__) || defined(__x86_64__)
14
15/* from gcc */
16#include <cpuid.h>
17
18/*
19 * CPUID functions returning a single datum
20 *
21 * Define unsigned int cpuid_e[abcd]x(unsigned int op)
22 */
23#define cpuid_func(reg) \
24 unsigned int cpuid_##reg(unsigned int op) \
25 { \
26 unsigned int eax, ebx, ecx, edx; \
27 __cpuid(op, eax, ebx, ecx, edx); \
28 return reg; \
29 }
30cpuid_func(eax);
31cpuid_func(ebx);
32cpuid_func(ecx);
33cpuid_func(edx);
34
35#endif /* defined(__i386__) || defined(__x86_64__) */
36
37/* get_cpu_info
38 *
39 * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo
40 *
41 * Returns 0 on success or a negativ error code
42 *
43 * TBD: Should there be a cpuid alternative for this if /proc is not mounted?
44 */
45int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info)
46{
47 FILE *fp;
48 char value[64];
49 unsigned int proc, x;
50 unsigned int unknown = 0xffffff;
51 unsigned int cpuid_level, ext_cpuid_level;
52
53 int ret = -EINVAL;
54
55 cpu_info->vendor = X86_VENDOR_UNKNOWN;
56 cpu_info->family = unknown;
57 cpu_info->model = unknown;
58 cpu_info->stepping = unknown;
59 cpu_info->caps = 0;
60
61 fp = fopen("/proc/cpuinfo", "r");
62 if (!fp)
63 return -EIO;
64
65 while (!feof(fp)) {
66 if (!fgets(value, 64, fp))
67 continue;
68 value[63 - 1] = '\0';
69
70 if (!strncmp(value, "processor\t: ", 12)) {
71 sscanf(value, "processor\t: %u", &proc);
72 }
73 if (proc != cpu)
74 continue;
75
76 /* Get CPU vendor */
77 if (!strncmp(value, "vendor_id", 9))
78 for (x = 1; x < X86_VENDOR_MAX; x++) {
79 if (strstr(value, cpu_vendor_table[x]))
80 cpu_info->vendor = x;
81 }
82 /* Get CPU family, etc. */
83 else if (!strncmp(value, "cpu family\t: ", 13)) {
84 sscanf(value, "cpu family\t: %u",
85 &cpu_info->family);
86 }
87 else if (!strncmp(value, "model\t\t: ", 9)) {
88 sscanf(value, "model\t\t: %u",
89 &cpu_info->model);
90 }
91 else if (!strncmp(value, "stepping\t: ", 10)) {
92 sscanf(value, "stepping\t: %u",
93 &cpu_info->stepping);
94
95 /* Exit -> all values must have been set */
96 if (cpu_info->vendor == X86_VENDOR_UNKNOWN ||
97 cpu_info->family == unknown ||
98 cpu_info->model == unknown ||
99 cpu_info->stepping == unknown) {
100 ret = -EINVAL;
101 goto out;
102 }
103
104 ret = 0;
105 goto out;
106 }
107 }
108 ret = -ENODEV;
109out:
110 fclose(fp);
111 /* Get some useful CPU capabilities from cpuid */
112 if (cpu_info->vendor != X86_VENDOR_AMD &&
113 cpu_info->vendor != X86_VENDOR_INTEL)
114 return ret;
115
116 cpuid_level = cpuid_eax(0);
117 ext_cpuid_level = cpuid_eax(0x80000000);
118
119 /* Invariant TSC */
120 if (ext_cpuid_level >= 0x80000007 &&
121 (cpuid_edx(0x80000007) & (1 << 8)))
122 cpu_info->caps |= CPUPOWER_CAP_INV_TSC;
123
124 /* Aperf/Mperf registers support */
125 if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1))
126 cpu_info->caps |= CPUPOWER_CAP_APERF;
127
128 /* AMD Boost state enable/disable register */
129 if (cpu_info->vendor == X86_VENDOR_AMD) {
130 if (ext_cpuid_level >= 0x80000007 &&
131 (cpuid_edx(0x80000007) & (1 << 9)))
132 cpu_info->caps |= CPUPOWER_CAP_AMD_CBP;
133 }
134
135 /* Intel's perf-bias MSR support */
136 if (cpu_info->vendor == X86_VENDOR_INTEL) {
137 if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3)))
138 cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS;
139 }
140
141 /* printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n",
142 cpuid_level, ext_cpuid_level, cpu_info->caps);
143 */
144 return ret;
145}
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
new file mode 100644
index 00000000000..a487dadb4cf
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/helpers.h
@@ -0,0 +1,180 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 * Miscellaneous helpers which do not fit or are worth
7 * to put into separate headers
8 */
9
10#ifndef __CPUPOWERUTILS_HELPERS__
11#define __CPUPOWERUTILS_HELPERS__
12
13#include <libintl.h>
14#include <locale.h>
15
16#include "helpers/bitmask.h"
17
18/* Internationalization ****************************/
19#define _(String) gettext(String)
20#ifndef gettext_noop
21#define gettext_noop(String) String
22#endif
23#define N_(String) gettext_noop (String)
24/* Internationalization ****************************/
25
26extern int run_as_root;
27extern struct bitmask *cpus_chosen;
28
29/* Global verbose (-d) stuff *********************************/
30/*
31 * define DEBUG via global Makefile variable
32 * Debug output is sent to stderr, do:
33 * cpupower monitor 2>/tmp/debug
34 * to split debug output away from normal output
35*/
36#ifdef DEBUG
37extern int be_verbose;
38
39#define dprint(fmt, ...) { \
40 if (be_verbose) { \
41 fprintf(stderr, "%s: " fmt, \
42 __FUNCTION__, ##__VA_ARGS__); \
43 } \
44 }
45#else
46static inline void dprint(const char *fmt, ...) { }
47#endif
48extern int be_verbose;
49/* Global verbose (-v) stuff *********************************/
50
51/* cpuid and cpuinfo helpers **************************/
52enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL,
53 X86_VENDOR_AMD, X86_VENDOR_MAX};
54
55#define CPUPOWER_CAP_INV_TSC 0x00000001
56#define CPUPOWER_CAP_APERF 0x00000002
57#define CPUPOWER_CAP_AMD_CBP 0x00000004
58#define CPUPOWER_CAP_PERF_BIAS 0x00000008
59
60#define MAX_HW_PSTATES 10
61
62struct cpupower_cpu_info {
63 enum cpupower_cpu_vendor vendor;
64 unsigned int family;
65 unsigned int model;
66 unsigned int stepping;
67 /* CPU capabilities read out from cpuid */
68 unsigned long long caps;
69};
70
71/* get_cpu_info
72 *
73 * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo
74 *
75 * Returns 0 on success or a negativ error code
76 * Only used on x86, below global's struct values are zero/unknown on
77 * other archs
78 */
79extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info);
80extern struct cpupower_cpu_info cpupower_cpu_info;
81/* cpuid and cpuinfo helpers **************************/
82
83
84/* CPU topology/hierarchy parsing ******************/
85struct cpupower_topology {
86 /* Amount of CPU cores, packages and threads per core in the system */
87 unsigned int cores;
88 unsigned int pkgs;
89 unsigned int threads; /* per core */
90
91 /* Array gets mallocated with cores entries, holding per core info */
92 struct {
93 int pkg;
94 int core;
95 int cpu;
96 } *core_info;
97};
98
99extern int get_cpu_topology(struct cpupower_topology *cpu_top);
100extern void cpu_topology_release(struct cpupower_topology cpu_top);
101/* CPU topology/hierarchy parsing ******************/
102
103/* X86 ONLY ****************************************/
104#if defined(__i386__) || defined(__x86_64__)
105
106#include <pci/pci.h>
107
108/* Read/Write msr ****************************/
109extern int read_msr(int cpu, unsigned int idx, unsigned long long *val);
110extern int write_msr(int cpu, unsigned int idx, unsigned long long val);
111
112extern int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val);
113extern int msr_intel_get_perf_bias(unsigned int cpu);
114
115extern int msr_intel_has_boost_support(unsigned int cpu);
116extern int msr_intel_boost_is_active(unsigned int cpu);
117
118/* Read/Write msr ****************************/
119
120/* PCI stuff ****************************/
121extern int amd_pci_get_num_boost_states(int *active, int *states);
122extern struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id,
123 int *dev_ids);
124
125/* PCI stuff ****************************/
126
127/* AMD HW pstate decoding **************************/
128
129extern int decode_pstates(unsigned int cpu, unsigned int cpu_family,
130 int boost_states, unsigned long *pstates, int *no);
131
132/* AMD HW pstate decoding **************************/
133
134extern int cpufreq_has_boost_support(unsigned int cpu, int *support,
135 int *active, int * states);
136/*
137 * CPUID functions returning a single datum
138 */
139unsigned int cpuid_eax(unsigned int op);
140unsigned int cpuid_ebx(unsigned int op);
141unsigned int cpuid_ecx(unsigned int op);
142unsigned int cpuid_edx(unsigned int op);
143
144/* cpuid and cpuinfo helpers **************************/
145/* X86 ONLY ********************************************/
146#else
147static inline int decode_pstates(unsigned int cpu, unsigned int cpu_family,
148 int boost_states, unsigned long *pstates,
149 int *no)
150{ return -1; };
151
152static inline int read_msr(int cpu, unsigned int idx, unsigned long long *val)
153{ return -1; };
154static inline int write_msr(int cpu, unsigned int idx, unsigned long long val)
155{ return -1; };
156static inline int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val)
157{ return -1; };
158static inline int msr_intel_get_perf_bias(unsigned int cpu)
159{ return -1; };
160
161static inline int msr_intel_has_boost_support(unsigned int cpu)
162{ return -1; };
163static inline int msr_intel_boost_is_active(unsigned int cpu)
164{ return -1; };
165
166/* Read/Write msr ****************************/
167
168static inline int cpufreq_has_boost_support(unsigned int cpu, int *support,
169 int *active, int * states)
170{ return -1; }
171
172/* cpuid and cpuinfo helpers **************************/
173
174static inline unsigned int cpuid_eax(unsigned int op) { return 0; };
175static inline unsigned int cpuid_ebx(unsigned int op) { return 0; };
176static inline unsigned int cpuid_ecx(unsigned int op) { return 0; };
177static inline unsigned int cpuid_edx(unsigned int op) { return 0; };
178#endif /* defined(__i386__) || defined(__x86_64__) */
179
180#endif /* __CPUPOWERUTILS_HELPERS__ */
diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c
new file mode 100644
index 00000000000..c1566e93e0e
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/misc.c
@@ -0,0 +1,34 @@
1#if defined(__i386__) || defined(__x86_64__)
2
3#include "helpers/helpers.h"
4
5int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active, int * states)
6{
7 struct cpupower_cpu_info cpu_info;
8 int ret;
9
10 *support = *active = *states = 0;
11
12 ret = get_cpu_info(0, &cpu_info);
13 if (ret)
14 return ret;
15
16 if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_CBP) {
17 *support = 1;
18 amd_pci_get_num_boost_states(active, states);
19 if (ret <= 0)
20 return ret;
21 *support = 1;
22 } else if (cpupower_cpu_info.vendor == X86_VENDOR_INTEL) {
23 ret = msr_intel_has_boost_support(cpu);
24 if (ret <= 0)
25 return ret;
26 *support = ret;
27 ret = msr_intel_boost_is_active(cpu);
28 if (ret <= 0)
29 return ret;
30 *active = ret;
31 }
32 return 0;
33}
34#endif /* #if defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/msr.c b/tools/power/cpupower/utils/helpers/msr.c
new file mode 100644
index 00000000000..93d48bd56e5
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/msr.c
@@ -0,0 +1,122 @@
1#if defined(__i386__) || defined(__x86_64__)
2
3#include <fcntl.h>
4#include <stdio.h>
5#include <unistd.h>
6#include <stdint.h>
7
8#include "helpers/helpers.h"
9
10/* Intel specific MSRs */
11#define MSR_IA32_PERF_STATUS 0x198
12#define MSR_IA32_MISC_ENABLES 0x1a0
13#define MSR_IA32_ENERGY_PERF_BIAS 0x1b0
14
15/*
16 * read_msr
17 *
18 * Will return 0 on success and -1 on failure.
19 * Possible errno values could be:
20 * EFAULT -If the read/write did not fully complete
21 * EIO -If the CPU does not support MSRs
22 * ENXIO -If the CPU does not exist
23 */
24
25int read_msr(int cpu, unsigned int idx, unsigned long long *val)
26{
27 int fd;
28 char msr_file_name[64];
29
30 sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
31 fd = open(msr_file_name, O_RDONLY);
32 if (fd < 0)
33 return -1;
34 if (lseek(fd, idx, SEEK_CUR) == -1)
35 goto err;
36 if (read(fd, val, sizeof *val) != sizeof *val)
37 goto err;
38 close(fd);
39 return 0;
40 err:
41 close(fd);
42 return -1;
43}
44
45/*
46 * write_msr
47 *
48 * Will return 0 on success and -1 on failure.
49 * Possible errno values could be:
50 * EFAULT -If the read/write did not fully complete
51 * EIO -If the CPU does not support MSRs
52 * ENXIO -If the CPU does not exist
53 */
54int write_msr(int cpu, unsigned int idx, unsigned long long val)
55{
56 int fd;
57 char msr_file_name[64];
58
59 sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
60 fd = open(msr_file_name, O_WRONLY);
61 if (fd < 0)
62 return -1;
63 if (lseek(fd, idx, SEEK_CUR) == -1)
64 goto err;
65 if (write(fd, &val, sizeof val) != sizeof val)
66 goto err;
67 close(fd);
68 return 0;
69 err:
70 close(fd);
71 return -1;
72}
73
74int msr_intel_has_boost_support(unsigned int cpu)
75{
76 unsigned long long misc_enables;
77 int ret;
78
79 ret = read_msr(cpu, MSR_IA32_MISC_ENABLES, &misc_enables);
80 if (ret)
81 return ret;
82 return (misc_enables >> 38) & 0x1;
83}
84
85int msr_intel_boost_is_active(unsigned int cpu)
86{
87 unsigned long long perf_status;
88 int ret;
89
90 ret = read_msr(cpu, MSR_IA32_PERF_STATUS, &perf_status);
91 if (ret)
92 return ret;
93 return (perf_status >> 32) & 0x1;
94}
95
96int msr_intel_get_perf_bias(unsigned int cpu)
97{
98 unsigned long long val;
99 int ret;
100
101 if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS))
102 return -1;
103
104 ret = read_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &val);
105 if (ret)
106 return ret;
107 return val;
108}
109
110int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val)
111{
112 int ret;
113
114 if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS))
115 return -1;
116
117 ret = write_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, val);
118 if (ret)
119 return ret;
120 return 0;
121}
122#endif
diff --git a/tools/power/cpupower/utils/helpers/pci.c b/tools/power/cpupower/utils/helpers/pci.c
new file mode 100644
index 00000000000..8dcc9381371
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/pci.c
@@ -0,0 +1,44 @@
1#if defined(__i386__) || defined(__x86_64__)
2
3#include <helpers/helpers.h>
4
5/*
6 * pci_acc_init
7 *
8 * PCI access helper function depending on libpci
9 *
10 * **pacc : if a valid pci_dev is returned
11 * *pacc must be passed to pci_acc_cleanup to free it
12 *
13 * vendor_id : the pci vendor id matching the pci device to access
14 * dev_ids : device ids matching the pci device to access
15 *
16 * Returns :
17 * struct pci_dev which can be used with pci_{read,write}_* functions
18 * to access the PCI config space of matching pci devices
19 */
20struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id,
21 int *dev_ids)
22{
23 struct pci_filter filter_nb_link = { -1, -1, -1, -1, vendor_id, 0};
24 struct pci_dev *device;
25 unsigned int i;
26
27 *pacc = pci_alloc();
28 if (*pacc == NULL)
29 return NULL;
30
31 pci_init(*pacc);
32 pci_scan_bus(*pacc);
33
34 for (i = 0; dev_ids[i] != 0; i++) {
35 filter_nb_link.device = dev_ids[i];
36 for (device=(*pacc)->devices; device; device = device->next) {
37 if (pci_filter_match(&filter_nb_link, device))
38 return device;
39 }
40 }
41 pci_cleanup(*pacc);
42 return NULL;
43}
44#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
new file mode 100644
index 00000000000..0c534e79652
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -0,0 +1,350 @@
1/*
2 * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
3 * (C) 2011 Thomas Renninger <trenn@novell.com> Novell Inc.
4 *
5 * Licensed under the terms of the GNU GPL License version 2.
6 */
7
8#include <stdio.h>
9#include <errno.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/types.h>
13#include <sys/stat.h>
14#include <fcntl.h>
15#include <unistd.h>
16
17#include "helpers/sysfs.h"
18
19unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
20{
21 int fd;
22 size_t numread;
23
24 if ( ( fd = open(path, O_RDONLY) ) == -1 )
25 return 0;
26
27 numread = read(fd, buf, buflen - 1);
28 if ( numread < 1 )
29 {
30 close(fd);
31 return 0;
32 }
33
34 buf[numread] = '\0';
35 close(fd);
36
37 return numread;
38}
39
40static unsigned int sysfs_write_file(const char *path,
41 const char *value, size_t len)
42{
43 int fd;
44 size_t numwrite;
45
46 if ( ( fd = open(path, O_WRONLY) ) == -1 )
47 return 0;
48
49 numwrite = write(fd, value, len);
50 if ( numwrite < 1 )
51 {
52 close(fd);
53 return 0;
54 }
55 close(fd);
56 return numwrite;
57}
58
59/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
60
61/*
62 * helper function to read file from /sys into given buffer
63 * fname is a relative path under "cpuX/cpuidle/stateX/" dir
64 * cstates starting with 0, C0 is not counted as cstate.
65 * This means if you want C1 info, pass 0 as idlestate param
66 */
67unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
68 const char *fname, char *buf, size_t buflen)
69{
70 char path[SYSFS_PATH_MAX];
71 int fd;
72 size_t numread;
73
74 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
75 cpu, idlestate, fname);
76
77 if ( ( fd = open(path, O_RDONLY) ) == -1 )
78 return 0;
79
80 numread = read(fd, buf, buflen - 1);
81 if ( numread < 1 )
82 {
83 close(fd);
84 return 0;
85 }
86
87 buf[numread] = '\0';
88 close(fd);
89
90 return numread;
91}
92
93/* read access to files which contain one numeric value */
94
95enum idlestate_value {
96 IDLESTATE_USAGE,
97 IDLESTATE_POWER,
98 IDLESTATE_LATENCY,
99 IDLESTATE_TIME,
100 MAX_IDLESTATE_VALUE_FILES
101};
102
103static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
104 [IDLESTATE_USAGE] = "usage",
105 [IDLESTATE_POWER] = "power",
106 [IDLESTATE_LATENCY] = "latency",
107 [IDLESTATE_TIME] = "time",
108};
109
110static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
111 unsigned int idlestate,
112 enum idlestate_value which)
113{
114 unsigned long long value;
115 unsigned int len;
116 char linebuf[MAX_LINE_LEN];
117 char *endp;
118
119 if ( which >= MAX_IDLESTATE_VALUE_FILES )
120 return 0;
121
122 if ( ( len = sysfs_idlestate_read_file(cpu, idlestate,
123 idlestate_value_files[which],
124 linebuf, sizeof(linebuf))) == 0 )
125 {
126 return 0;
127 }
128
129 value = strtoull(linebuf, &endp, 0);
130
131 if ( endp == linebuf || errno == ERANGE )
132 return 0;
133
134 return value;
135}
136
137/* read access to files which contain one string */
138
139enum idlestate_string {
140 IDLESTATE_DESC,
141 IDLESTATE_NAME,
142 MAX_IDLESTATE_STRING_FILES
143};
144
145static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
146 [IDLESTATE_DESC] = "desc",
147 [IDLESTATE_NAME] = "name",
148};
149
150
151static char * sysfs_idlestate_get_one_string(unsigned int cpu,
152 unsigned int idlestate,
153 enum idlestate_string which)
154{
155 char linebuf[MAX_LINE_LEN];
156 char *result;
157 unsigned int len;
158
159 if (which >= MAX_IDLESTATE_STRING_FILES)
160 return NULL;
161
162 if ( ( len = sysfs_idlestate_read_file(cpu, idlestate,
163 idlestate_string_files[which],
164 linebuf, sizeof(linebuf))) == 0 )
165 return NULL;
166
167 if ( ( result = strdup(linebuf) ) == NULL )
168 return NULL;
169
170 if (result[strlen(result) - 1] == '\n')
171 result[strlen(result) - 1] = '\0';
172
173 return result;
174}
175
176unsigned long sysfs_get_idlestate_latency(unsigned int cpu, unsigned int idlestate)
177{
178 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
179}
180
181unsigned long sysfs_get_idlestate_usage(unsigned int cpu, unsigned int idlestate)
182{
183 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
184}
185
186unsigned long long sysfs_get_idlestate_time(unsigned int cpu, unsigned int idlestate)
187{
188 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME);
189}
190
191char * sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate)
192{
193 return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME);
194}
195
196char * sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
197{
198 return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_DESC);
199}
200
201/*
202 * Returns number of supported C-states of CPU core cpu
203 * Negativ in error case
204 * Zero if cpuidle does not export any C-states
205 */
206int sysfs_get_idlestate_count(unsigned int cpu)
207{
208 char file[SYSFS_PATH_MAX];
209 struct stat statbuf;
210 int idlestates = 1;
211
212
213 snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
214 if ( stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
215 return -ENODEV;
216
217 snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
218 if ( stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
219 return 0;
220
221 while(stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
222 snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU
223 "cpu%u/cpuidle/state%d", cpu, idlestates);
224 idlestates++;
225 }
226 idlestates--;
227 return idlestates;
228}
229
230/* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
231
232/*
233 * helper function to read file from /sys into given buffer
234 * fname is a relative path under "cpu/cpuidle/" dir
235 */
236static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
237 size_t buflen)
238{
239 char path[SYSFS_PATH_MAX];
240
241 snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname);
242
243 return sysfs_read_file(path, buf, buflen);
244}
245
246
247
248/* read access to files which contain one string */
249
250enum cpuidle_string {
251 CPUIDLE_GOVERNOR,
252 CPUIDLE_GOVERNOR_RO,
253 CPUIDLE_DRIVER,
254 MAX_CPUIDLE_STRING_FILES
255};
256
257static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = {
258 [CPUIDLE_GOVERNOR] = "current_governor",
259 [CPUIDLE_GOVERNOR_RO] = "current_governor_ro",
260 [CPUIDLE_DRIVER] = "current_driver",
261};
262
263
264static char * sysfs_cpuidle_get_one_string(enum cpuidle_string which)
265{
266 char linebuf[MAX_LINE_LEN];
267 char *result;
268 unsigned int len;
269
270 if (which >= MAX_CPUIDLE_STRING_FILES)
271 return NULL;
272
273 if ( ( len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
274 linebuf, sizeof(linebuf))) == 0 )
275 return NULL;
276
277 if ( ( result = strdup(linebuf) ) == NULL )
278 return NULL;
279
280 if (result[strlen(result) - 1] == '\n')
281 result[strlen(result) - 1] = '\0';
282
283 return result;
284}
285
286char * sysfs_get_cpuidle_governor(void)
287{
288 char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
289 if (!tmp)
290 return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
291 else
292 return tmp;
293}
294
295char * sysfs_get_cpuidle_driver(void)
296{
297 return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
298}
299/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
300
301/*
302 * Get sched_mc or sched_smt settings
303 * Pass "mc" or "smt" as argument
304 *
305 * Returns negative value on failure
306 */
307int sysfs_get_sched(const char* smt_mc)
308{
309 unsigned long value;
310 char linebuf[MAX_LINE_LEN];
311 char *endp;
312 char path[SYSFS_PATH_MAX];
313
314 if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
315 return -EINVAL;
316
317 snprintf(path, sizeof(path), PATH_TO_CPU "sched_%s_power_savings", smt_mc);
318 if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0 )
319 return -1;
320 value = strtoul(linebuf, &endp, 0);
321 if ( endp == linebuf || errno == ERANGE )
322 return -1;
323 return value;
324}
325
326/*
327 * Get sched_mc or sched_smt settings
328 * Pass "mc" or "smt" as argument
329 *
330 * Returns negative value on failure
331 */
332int sysfs_set_sched(const char* smt_mc, int val)
333{
334 char linebuf[MAX_LINE_LEN];
335 char path[SYSFS_PATH_MAX];
336 struct stat statbuf;
337
338 if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
339 return -EINVAL;
340
341 snprintf(path, sizeof(path), PATH_TO_CPU "sched_%s_power_savings", smt_mc);
342 sprintf(linebuf, "%d", val);
343
344 if ( stat(path, &statbuf) != 0 )
345 return -ENODEV;
346
347 if (sysfs_write_file(path, linebuf, MAX_LINE_LEN) == 0 )
348 return -1;
349 return 0;
350}
diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h
new file mode 100644
index 00000000000..5d02d2fc70e
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/sysfs.h
@@ -0,0 +1,23 @@
1#ifndef __CPUPOWER_HELPERS_SYSFS_H__
2#define __CPUPOWER_HELPERS_SYSFS_H__
3
4#define PATH_TO_CPU "/sys/devices/system/cpu/"
5#define MAX_LINE_LEN 255
6#define SYSFS_PATH_MAX 255
7
8extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
9
10extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, unsigned int idlestate);
11extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, unsigned int idlestate);
12extern unsigned long long sysfs_get_idlestate_time(unsigned int cpu, unsigned int idlestate);
13extern char * sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate);
14extern char * sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate);
15extern int sysfs_get_idlestate_count(unsigned int cpu);
16
17extern char * sysfs_get_cpuidle_governor(void);
18extern char * sysfs_get_cpuidle_driver(void);
19
20extern int sysfs_get_sched(const char* smt_mc);
21extern int sysfs_set_sched(const char* smt_mc, int val);
22
23#endif /* __CPUPOWER_HELPERS_SYSFS_H__ */
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c
new file mode 100644
index 00000000000..5ad842b956b
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/topology.c
@@ -0,0 +1,108 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 * ToDo: Needs to be done more properly for AMD/Intel specifics
7 */
8
9/* Helper struct for qsort, must be in sync with cpupower_topology.cpu_info */
10/* Be careful: Need to pass unsigned to the sort, so that offlined cores are
11 in the end, but double check for -1 for offlined cpus at other places */
12
13#include <stdlib.h>
14#include <stdio.h>
15#include <unistd.h>
16#include <errno.h>
17#include <fcntl.h>
18
19#include <helpers/helpers.h>
20#include <helpers/sysfs.h>
21
22/* returns -1 on failure, 0 on success */
23int sysfs_topology_read_file(unsigned int cpu, const char *fname)
24{
25 unsigned long value;
26 char linebuf[MAX_LINE_LEN];
27 char *endp;
28 char path[SYSFS_PATH_MAX];
29
30 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s",
31 cpu, fname);
32 if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0 )
33 return -1;
34 value = strtoul(linebuf, &endp, 0);
35 if ( endp == linebuf || errno == ERANGE )
36 return -1;
37 return value;
38}
39
40struct cpuid_core_info {
41 unsigned int pkg;
42 unsigned int thread;
43 unsigned int cpu;
44};
45
46static int __compare(const void *t1, const void *t2)
47{
48 struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
49 struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2;
50 if (top1->pkg < top2->pkg)
51 return -1;
52 else if (top1->pkg > top2->pkg)
53 return 1;
54 else if (top1->thread < top2->thread)
55 return -1;
56 else if (top1->thread > top2->thread)
57 return 1;
58 else if (top1->cpu < top2->cpu)
59 return -1;
60 else if (top1->cpu > top2->cpu)
61 return 1;
62 else
63 return 0;
64}
65
66/*
67 * Returns amount of cpus, negative on error, cpu_top must be
68 * passed to cpu_topology_release to free resources
69 *
70 * Array is sorted after ->pkg, ->core, then ->cpu
71 */
72int get_cpu_topology(struct cpupower_topology *cpu_top)
73{
74 int cpu, cpus = sysconf(_SC_NPROCESSORS_CONF);
75
76 cpu_top->core_info = malloc(sizeof(struct cpupower_topology) * cpus);
77 if (cpu_top->core_info == NULL)
78 return -ENOMEM;
79 cpu_top->pkgs = cpu_top->cores = 0;
80 for (cpu = 0; cpu < cpus; cpu++) {
81 cpu_top->core_info[cpu].pkg =
82 sysfs_topology_read_file(cpu, "physical_package_id");
83 if ((int)cpu_top->core_info[cpu].pkg != -1 &&
84 cpu_top->core_info[cpu].pkg > cpu_top->pkgs)
85 cpu_top->pkgs = cpu_top->core_info[cpu].pkg;
86 cpu_top->core_info[cpu].core =
87 sysfs_topology_read_file(cpu, "core_id");
88 cpu_top->core_info[cpu].cpu = cpu;
89 }
90 cpu_top->pkgs++;
91
92 qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
93 __compare);
94
95 /* Intel's cores count is not consecutively numbered, there may
96 * be a core_id of 3, but none of 2. Assume there always is 0
97 * Get amount of cores by counting duplicates in a package
98 for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) {
99 if (cpu_top->core_info[cpu].core == 0)
100 cpu_top->cores++;
101 */
102 return cpus;
103}
104
105void cpu_topology_release(struct cpupower_topology cpu_top)
106{
107 free(cpu_top.core_info);
108}