Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
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  * Derive the TSC frequency in Hz from the /proc/cpuinfo, for example:
0021  * ...
0022  * model name      : Intel(R) Xeon(R) Gold 6154 CPU @ 3.00GHz
0023  * ...
0024  * will return 3000000000.
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      * Don't support Time Stamp Counter and
0074      * Nominal Core Crystal Clock Information Leaf.
0075      */
0076     if (lvl < 0x15) {
0077         tsc = cpuinfo_tsc_freq();
0078         return tsc;
0079     }
0080 
0081     cpuid(0x15, 0, &a, &b, &c, &d);
0082     /* TSC frequency is not enumerated */
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 }