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