brintos

brintos / linux-shallow public Read only

0
0
Text · 1.7 KiB · e2d6cfe Raw
92 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <linux/types.h>3#include <math.h>4#include <string.h>5#include <stdlib.h>6 7#include "../../../util/debug.h"8#include "../../../util/tsc.h"9#include "cpuid.h"10 11u64 rdtsc(void)12{13	unsigned int low, high;14 15	asm volatile("rdtsc" : "=a" (low), "=d" (high));16 17	return low | ((u64)high) << 32;18}19 20/*21 * Derive the TSC frequency in Hz from the /proc/cpuinfo, for example:22 * ...23 * model name      : Intel(R) Xeon(R) Gold 6154 CPU @ 3.00GHz24 * ...25 * will return 3000000000.26 */27static double cpuinfo_tsc_freq(void)28{29	double result = 0;30	FILE *cpuinfo;31	char *line = NULL;32	size_t len = 0;33 34	cpuinfo = fopen("/proc/cpuinfo", "r");35	if (!cpuinfo) {36		pr_err("Failed to read /proc/cpuinfo for TSC frequency\n");37		return NAN;38	}39	while (getline(&line, &len, cpuinfo) > 0) {40		if (!strncmp(line, "model name", 10)) {41			char *pos = strstr(line + 11, " @ ");42 43			if (pos && sscanf(pos, " @ %lfGHz", &result) == 1) {44				result *= 1000000000;45				goto out;46			}47		}48	}49out:50	if (fpclassify(result) == FP_ZERO)51		pr_err("Failed to find TSC frequency in /proc/cpuinfo\n");52 53	free(line);54	fclose(cpuinfo);55	return result;56}57 58double arch_get_tsc_freq(void)59{60	unsigned int a, b, c, d, lvl;61	static bool cached;62	static double tsc;63	char vendor[16];64 65	if (cached)66		return tsc;67 68	cached = true;69	get_cpuid_0(vendor, &lvl);70	if (!strstr(vendor, "Intel"))71		return 0;72 73	/*74	 * Don't support Time Stamp Counter and75	 * Nominal Core Crystal Clock Information Leaf.76	 */77	if (lvl < 0x15) {78		tsc = cpuinfo_tsc_freq();79		return tsc;80	}81 82	cpuid(0x15, 0, &a, &b, &c, &d);83	/* TSC frequency is not enumerated */84	if (!a || !b || !c) {85		tsc = cpuinfo_tsc_freq();86		return tsc;87	}88 89	tsc = (double)c * (double)b / (double)a;90	return tsc;91}92