root/tools/power/cpupower/utils/helpers/cpuid.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_cpu_info

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <stdio.h>
   3 #include <errno.h>
   4 #include <string.h>
   5 #include <unistd.h>
   6 #include <stdlib.h>
   7 
   8 #include "helpers/helpers.h"
   9 
  10 static const char *cpu_vendor_table[X86_VENDOR_MAX] = {
  11         "Unknown", "GenuineIntel", "AuthenticAMD", "HygonGenuine",
  12 };
  13 
  14 #if defined(__i386__) || defined(__x86_64__)
  15 
  16 /* from gcc */
  17 #include <cpuid.h>
  18 
  19 /*
  20  * CPUID functions returning a single datum
  21  *
  22  * Define unsigned int cpuid_e[abcd]x(unsigned int op)
  23  */
  24 #define cpuid_func(reg)                                 \
  25         unsigned int cpuid_##reg(unsigned int op)       \
  26         {                                               \
  27         unsigned int eax, ebx, ecx, edx;                \
  28         __cpuid(op, eax, ebx, ecx, edx);                \
  29         return reg;                                     \
  30         }
  31 cpuid_func(eax);
  32 cpuid_func(ebx);
  33 cpuid_func(ecx);
  34 cpuid_func(edx);
  35 
  36 #endif /* defined(__i386__) || defined(__x86_64__) */
  37 
  38 /* get_cpu_info
  39  *
  40  * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo
  41  *
  42  * Returns 0 on success or a negativ error code
  43  *
  44  * TBD: Should there be a cpuid alternative for this if /proc is not mounted?
  45  */
  46 int get_cpu_info(struct cpupower_cpu_info *cpu_info)
  47 {
  48         FILE *fp;
  49         char value[64];
  50         unsigned int proc, x;
  51         unsigned int unknown = 0xffffff;
  52         unsigned int cpuid_level, ext_cpuid_level;
  53 
  54         int ret = -EINVAL;
  55 
  56         cpu_info->vendor                = X86_VENDOR_UNKNOWN;
  57         cpu_info->family                = unknown;
  58         cpu_info->model                 = unknown;
  59         cpu_info->stepping              = unknown;
  60         cpu_info->caps                  = 0;
  61 
  62         fp = fopen("/proc/cpuinfo", "r");
  63         if (!fp)
  64                 return -EIO;
  65 
  66         while (!feof(fp)) {
  67                 if (!fgets(value, 64, fp))
  68                         continue;
  69                 value[63 - 1] = '\0';
  70 
  71                 if (!strncmp(value, "processor\t: ", 12))
  72                         sscanf(value, "processor\t: %u", &proc);
  73 
  74                 if (proc != (unsigned int)base_cpu)
  75                         continue;
  76 
  77                 /* Get CPU vendor */
  78                 if (!strncmp(value, "vendor_id", 9)) {
  79                         for (x = 1; x < X86_VENDOR_MAX; x++) {
  80                                 if (strstr(value, cpu_vendor_table[x]))
  81                                         cpu_info->vendor = x;
  82                         }
  83                 /* Get CPU family, etc. */
  84                 } else if (!strncmp(value, "cpu family\t: ", 13)) {
  85                         sscanf(value, "cpu family\t: %u",
  86                                &cpu_info->family);
  87                 } else if (!strncmp(value, "model\t\t: ", 9)) {
  88                         sscanf(value, "model\t\t: %u",
  89                                &cpu_info->model);
  90                 } else if (!strncmp(value, "stepping\t: ", 10)) {
  91                         sscanf(value, "stepping\t: %u",
  92                                &cpu_info->stepping);
  93 
  94                         /* Exit -> all values must have been set */
  95                         if (cpu_info->vendor == X86_VENDOR_UNKNOWN ||
  96                             cpu_info->family == unknown ||
  97                             cpu_info->model == unknown ||
  98                             cpu_info->stepping == unknown) {
  99                                 ret = -EINVAL;
 100                                 goto out;
 101                         }
 102 
 103                         ret = 0;
 104                         goto out;
 105                 }
 106         }
 107         ret = -ENODEV;
 108 out:
 109         fclose(fp);
 110         /* Get some useful CPU capabilities from cpuid */
 111         if (cpu_info->vendor != X86_VENDOR_AMD &&
 112             cpu_info->vendor != X86_VENDOR_HYGON &&
 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 or Hygon Boost state enable/disable register */
 129         if (cpu_info->vendor == X86_VENDOR_AMD ||
 130             cpu_info->vendor == X86_VENDOR_HYGON) {
 131                 if (ext_cpuid_level >= 0x80000007 &&
 132                     (cpuid_edx(0x80000007) & (1 << 9)))
 133                         cpu_info->caps |= CPUPOWER_CAP_AMD_CBP;
 134         }
 135 
 136         if (cpu_info->vendor == X86_VENDOR_INTEL) {
 137                 if (cpuid_level >= 6 &&
 138                     (cpuid_eax(6) & (1 << 1)))
 139                         cpu_info->caps |= CPUPOWER_CAP_INTEL_IDA;
 140         }
 141 
 142         if (cpu_info->vendor == X86_VENDOR_INTEL) {
 143                 /* Intel's perf-bias MSR support */
 144                 if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3)))
 145                         cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS;
 146 
 147                 /* Intel's Turbo Ratio Limit support */
 148                 if (cpu_info->family == 6) {
 149                         switch (cpu_info->model) {
 150                         case 0x1A:      /* Core i7, Xeon 5500 series
 151                                          * Bloomfield, Gainstown NHM-EP
 152                                          */
 153                         case 0x1E:      /* Core i7 and i5 Processor
 154                                          * Clarksfield, Lynnfield, Jasper Forest
 155                                          */
 156                         case 0x1F:      /* Core i7 and i5 Processor - Nehalem */
 157                         case 0x25:      /* Westmere Client
 158                                          * Clarkdale, Arrandale
 159                                          */
 160                         case 0x2C:      /* Westmere EP - Gulftown */
 161                                 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
 162                                 break;
 163                         case 0x2A:      /* SNB */
 164                         case 0x2D:      /* SNB Xeon */
 165                         case 0x3A:      /* IVB */
 166                         case 0x3E:      /* IVB Xeon */
 167                                 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
 168                                 cpu_info->caps |= CPUPOWER_CAP_IS_SNB;
 169                                 break;
 170                         case 0x2E:      /* Nehalem-EX Xeon - Beckton */
 171                         case 0x2F:      /* Westmere-EX Xeon - Eagleton */
 172                         default:
 173                                 break;
 174                         }
 175                 }
 176         }
 177 
 178         /*      printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n",
 179                 cpuid_level, ext_cpuid_level, cpu_info->caps);
 180         */
 181         return ret;
 182 }

/* [<][>][^][v][top][bottom][index][help] */