944b2c1659d8c82e93404335b48e995dca859293
[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                 } else if (!strncmp(value, "model\t\t: ", 9)) {
87                         sscanf(value, "model\t\t: %u",
88                                &cpu_info->model);
89                 } else if (!strncmp(value, "stepping\t: ", 10)) {
90                         sscanf(value, "stepping\t: %u",
91                                &cpu_info->stepping);
92
93                         /* Exit -> all values must have been set */
94                         if (cpu_info->vendor == X86_VENDOR_UNKNOWN ||
95                             cpu_info->family == unknown ||
96                             cpu_info->model == unknown ||
97                             cpu_info->stepping == unknown) {
98                                 ret = -EINVAL;
99                                 goto out;
100                         }
101
102                         ret = 0;
103                         goto out;
104                 }
105         }
106         ret = -ENODEV;
107 out:
108         fclose(fp);
109         /* Get some useful CPU capabilities from cpuid */
110         if (cpu_info->vendor != X86_VENDOR_AMD &&
111             cpu_info->vendor != X86_VENDOR_INTEL)
112                 return ret;
113
114         cpuid_level     = cpuid_eax(0);
115         ext_cpuid_level = cpuid_eax(0x80000000);
116
117         /* Invariant TSC */
118         if (ext_cpuid_level >= 0x80000007 &&
119             (cpuid_edx(0x80000007) & (1 << 8)))
120                 cpu_info->caps |= CPUPOWER_CAP_INV_TSC;
121
122         /* Aperf/Mperf registers support */
123         if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1))
124                 cpu_info->caps |= CPUPOWER_CAP_APERF;
125
126         /* AMD Boost state enable/disable register */
127         if (cpu_info->vendor == X86_VENDOR_AMD) {
128                 if (ext_cpuid_level >= 0x80000007 &&
129                     (cpuid_edx(0x80000007) & (1 << 9)))
130                         cpu_info->caps |= CPUPOWER_CAP_AMD_CBP;
131         }
132
133         /* Intel's perf-bias MSR support */
134         if (cpu_info->vendor == X86_VENDOR_INTEL) {
135                 if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3)))
136                         cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS;
137         }
138
139         /*      printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n",
140                 cpuid_level, ext_cpuid_level, cpu_info->caps);
141         */
142         return ret;
143 }