brintos

brintos / linux-shallow public Read only

0
0
Text · 5.4 KiB · eae91f1 Raw
214 lines · c
1// SPDX-License-Identifier: GPL-2.02#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 datum21 *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_info39 *40 * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo41 *42 * Returns 0 on success or a negativ error code43 *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 treat158			 * 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 series182					 * Bloomfield, Gainstown NHM-EP183					 */184			case 0x1E:	/* Core i7 and i5 Processor185					 * Clarksfield, Lynnfield, Jasper Forest186					 */187			case 0x1F:	/* Core i7 and i5 Processor - Nehalem */188			case 0x25:	/* Westmere Client189					 * Clarkdale, Arrandale190					 */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}214