File Index
Files and directories
Sign in
FILE

cpuid.c

File preview with syntax highlighting.

linux-6.19.14/tools/power/cpupower/utils/helpers/cpuid.c C
  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
 10static 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	}
 31cpuid_func(eax);
 32cpuid_func(ebx);
 33cpuid_func(ecx);
 34cpuid_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 */
 46int 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;
108out:
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			if (cpuid_edx(0x80000007) & (1 << 9)) {
133				cpu_info->caps |= CPUPOWER_CAP_AMD_CPB;
134
135				if (cpu_info->family >= 0x17)
136					cpu_info->caps |= CPUPOWER_CAP_AMD_CPB_MSR;
137			}
138
139			if ((cpuid_edx(0x80000007) & (1 << 7)) &&
140			    cpu_info->family != 0x14) {
141				/* HW pstate was not implemented in family 0x14 */
142				cpu_info->caps |= CPUPOWER_CAP_AMD_HW_PSTATE;
143
144				if (cpu_info->family >= 0x17)
145					cpu_info->caps |= CPUPOWER_CAP_AMD_PSTATEDEF;
146			}
147		}
148
149		if (ext_cpuid_level >= 0x80000008 &&
150		    cpuid_ebx(0x80000008) & (1 << 4))
151			cpu_info->caps |= CPUPOWER_CAP_AMD_RDPRU;
152
153		if (cpupower_amd_pstate_enabled()) {
154			cpu_info->caps |= CPUPOWER_CAP_AMD_PSTATE;
155
156			/*
157			 * If AMD P-State is enabled, the firmware will treat
158			 * AMD P-State function as high priority.
159			 */
160			cpu_info->caps &= ~CPUPOWER_CAP_AMD_CPB;
161			cpu_info->caps &= ~CPUPOWER_CAP_AMD_CPB_MSR;
162			cpu_info->caps &= ~CPUPOWER_CAP_AMD_HW_PSTATE;
163			cpu_info->caps &= ~CPUPOWER_CAP_AMD_PSTATEDEF;
164		}
165	}
166
167	if (cpu_info->vendor == X86_VENDOR_INTEL) {
168		if (cpuid_level >= 6 &&
169		    (cpuid_eax(6) & (1 << 1)))
170			cpu_info->caps |= CPUPOWER_CAP_INTEL_IDA;
171	}
172
173	if (cpu_info->vendor == X86_VENDOR_INTEL) {
174		/* Intel's perf-bias MSR support */
175		if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3)))
176			cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS;
177
178		/* Intel's Turbo Ratio Limit support */
179		if (cpu_info->family == 6) {
180			switch (cpu_info->model) {
181			case 0x1A:	/* Core i7, Xeon 5500 series
182					 * Bloomfield, Gainstown NHM-EP
183					 */
184			case 0x1E:	/* Core i7 and i5 Processor
185					 * Clarksfield, Lynnfield, Jasper Forest
186					 */
187			case 0x1F:	/* Core i7 and i5 Processor - Nehalem */
188			case 0x25:	/* Westmere Client
189					 * Clarkdale, Arrandale
190					 */
191			case 0x2C:	/* Westmere EP - Gulftown */
192				cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
193				break;
194			case 0x2A:	/* SNB */
195			case 0x2D:	/* SNB Xeon */
196			case 0x3A:	/* IVB */
197			case 0x3E:	/* IVB Xeon */
198				cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
199				cpu_info->caps |= CPUPOWER_CAP_IS_SNB;
200				break;
201			case 0x2E:	/* Nehalem-EX Xeon - Beckton */
202			case 0x2F:	/* Westmere-EX Xeon - Eagleton */
203			default:
204				break;
205			}
206		}
207	}
208
209	/*	printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n",
210		cpuid_level, ext_cpuid_level, cpu_info->caps);
211	*/
212	return ret;
213}
~/ Read-only file preview.