71021f3bb69d85aca04bac6c48cbfdbd429c0dcc
[linux-2.6.git] / tools / power / cpupower / utils / helpers / cpuid.c
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
9 static 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         }
30 cpuid_func(eax);
31 cpuid_func(ebx);
32 cpuid_func(ecx);
33 cpuid_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  */
45 int 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;
109 out:
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 }