0001
0002 #include <linux/types.h>
0003 #include <math.h>
0004 #include <string.h>
0005
0006 #include "../../../util/debug.h"
0007 #include "../../../util/tsc.h"
0008 #include "cpuid.h"
0009
0010 u64 rdtsc(void)
0011 {
0012 unsigned int low, high;
0013
0014 asm volatile("rdtsc" : "=a" (low), "=d" (high));
0015
0016 return low | ((u64)high) << 32;
0017 }
0018
0019
0020
0021
0022
0023
0024
0025
0026 static double cpuinfo_tsc_freq(void)
0027 {
0028 double result = 0;
0029 FILE *cpuinfo;
0030 char *line = NULL;
0031 size_t len = 0;
0032
0033 cpuinfo = fopen("/proc/cpuinfo", "r");
0034 if (!cpuinfo) {
0035 pr_err("Failed to read /proc/cpuinfo for TSC frequency");
0036 return NAN;
0037 }
0038 while (getline(&line, &len, cpuinfo) > 0) {
0039 if (!strncmp(line, "model name", 10)) {
0040 char *pos = strstr(line + 11, " @ ");
0041
0042 if (pos && sscanf(pos, " @ %lfGHz", &result) == 1) {
0043 result *= 1000000000;
0044 goto out;
0045 }
0046 }
0047 }
0048 out:
0049 if (fpclassify(result) == FP_ZERO)
0050 pr_err("Failed to find TSC frequency in /proc/cpuinfo");
0051
0052 free(line);
0053 fclose(cpuinfo);
0054 return result;
0055 }
0056
0057 double arch_get_tsc_freq(void)
0058 {
0059 unsigned int a, b, c, d, lvl;
0060 static bool cached;
0061 static double tsc;
0062 char vendor[16];
0063
0064 if (cached)
0065 return tsc;
0066
0067 cached = true;
0068 get_cpuid_0(vendor, &lvl);
0069 if (!strstr(vendor, "Intel"))
0070 return 0;
0071
0072
0073
0074
0075
0076 if (lvl < 0x15) {
0077 tsc = cpuinfo_tsc_freq();
0078 return tsc;
0079 }
0080
0081 cpuid(0x15, 0, &a, &b, &c, &d);
0082
0083 if (!a || !b || !c) {
0084 tsc = cpuinfo_tsc_freq();
0085 return tsc;
0086 }
0087
0088 tsc = (double)c * (double)b / (double)a;
0089 return tsc;
0090 }