linux/tools/power/cpupower/utils/helpers/cpuid.c
<<
>>
Prefs
   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                } 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;
 107out:
 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        if (cpu_info->vendor == X86_VENDOR_INTEL) {
 134                if (cpuid_level >= 6 &&
 135                    (cpuid_eax(6) & (1 << 1)))
 136                        cpu_info->caps |= CPUPOWER_CAP_INTEL_IDA;
 137        }
 138
 139        if (cpu_info->vendor == X86_VENDOR_INTEL) {
 140                /* Intel's perf-bias MSR support */
 141                if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3)))
 142                        cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS;
 143
 144                /* Intel's Turbo Ratio Limit support */
 145                if (cpu_info->family == 6) {
 146                        switch (cpu_info->model) {
 147                        case 0x1A:      /* Core i7, Xeon 5500 series
 148                                         * Bloomfield, Gainstown NHM-EP
 149                                         */
 150                        case 0x1E:      /* Core i7 and i5 Processor
 151                                         * Clarksfield, Lynnfield, Jasper Forest
 152                                         */
 153                        case 0x1F:      /* Core i7 and i5 Processor - Nehalem */
 154                        case 0x25:      /* Westmere Client
 155                                         * Clarkdale, Arrandale
 156                                         */
 157                        case 0x2C:      /* Westmere EP - Gulftown */
 158                                cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
 159                        case 0x2A:      /* SNB */
 160                        case 0x2D:      /* SNB Xeon */
 161                        case 0x3A:      /* IVB */
 162                        case 0x3E:      /* IVB Xeon */
 163                                cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
 164                                cpu_info->caps |= CPUPOWER_CAP_IS_SNB;
 165                                break;
 166                        case 0x2E:      /* Nehalem-EX Xeon - Beckton */
 167                        case 0x2F:      /* Westmere-EX Xeon - Eagleton */
 168                        default:
 169                                break;
 170                        }
 171                }
 172        }
 173
 174        /*      printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n",
 175                cpuid_level, ext_cpuid_level, cpu_info->caps);
 176        */
 177        return ret;
 178}
 179